diff options
Diffstat (limited to 'sound')
762 files changed, 19567 insertions, 12557 deletions
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 5e46b972a3da..40e88d79c483 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -551,5 +551,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 7ea274c55900..1484fc178fa4 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -95,4 +95,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/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/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/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/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/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/core.c b/sound/aoa/soundbus/i2sbus/core.c index b8ff5cccd0c8..5431d2c49421 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -158,7 +158,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)" }; diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 07df5cc0f2d7..98b812ffbde6 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -255,24 +255,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); } 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/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 51d2ff80df16..571e9d909cdf 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -33,7 +33,7 @@ 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; @@ -79,7 +79,7 @@ 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; 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/core/Makefile b/sound/core/Makefile index b8aa886198ab..31a0623cc89d 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -24,18 +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-ump-objs := ump.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-objs := timer.o -snd-hrtimer-objs := hrtimer.o -snd-hwdep-objs := hwdep.o -snd-seq-device-objs := seq_device.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 diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 3d37e9fa7b9c..ac19d14bd574 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -285,25 +285,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 __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; @@ -315,14 +312,12 @@ static int snd_ctl_led_reset(int card_number, unsigned int group) if (!snd_ctl_led_card_valid[card_number]) return -ENXIO; led = &snd_ctl_leds[group]; -repeat: - list_for_each_entry(lctl, &led->controls, list) + 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; - goto repeat; } } if (change) diff --git a/sound/core/init.c b/sound/core/init.c index 4ed5037d8693..6b127864a1a3 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -516,6 +516,14 @@ void snd_card_disconnect(struct snd_card *card) } } +#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() */ @@ -542,10 +550,7 @@ void snd_card_disconnect(struct snd_card *card) 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); 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/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 494ec0c207fa..12aa1cef11a1 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -470,4 +470,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_native.c b/sound/core/pcm_native.c index 0b76e76823d2..521ba56392a0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2416,7 +2416,7 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, 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 }; const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 990eec7c83ad..0904aa48d88b 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -4,17 +4,17 @@ # 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-$(CONFIG_SND_SEQ_UMP) += seq_ump_convert.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-ump-client-objs := seq_ump_client.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/ 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/seq_dummy.c b/sound/core/seq/seq_dummy.c index 9308194b2d9a..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; @@ -152,7 +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) { @@ -166,12 +174,24 @@ register_client(void) if (my_client < 0) return my_client; - /* don't convert events but just pass-through */ +#if IS_ENABLED(CONFIG_SND_SEQ_UMP) client = snd_seq_kernel_client_get(my_client); if (!client) return -EINVAL; - client->filter = SNDRV_SEQ_FILTER_NO_CONVERT; + 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++) { diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c index b141024830ec..ee6ac649df83 100644 --- a/sound/core/seq/seq_ump_convert.c +++ b/sound/core/seq/seq_ump_convert.c @@ -428,7 +428,7 @@ static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest, midi1->note.group = midi2->note.group; midi1->note.status = midi2->note.status; midi1->note.channel = midi2->note.channel; - switch (midi2->note.status << 4) { + switch (midi2->note.status) { case UMP_MSG_STATUS_NOTE_ON: case UMP_MSG_STATUS_NOTE_OFF: midi1->note.note = midi2->note.note; diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c index eb90f62228c0..bfed1a25fc8f 100644 --- a/sound/core/sound_kunit.c +++ b/sound/core/sound_kunit.c @@ -45,7 +45,7 @@ struct avail_test_data { snd_pcm_uframes_t expected_avail; }; -static struct snd_format_test_data valid_fmt[] = { +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()), @@ -154,7 +154,7 @@ static void test_format_endianness(struct kunit *test) KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_2), -EINVAL); } -static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data, +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; @@ -167,7 +167,7 @@ static void _test_fill_silence(struct kunit *test, struct snd_format_test_data * static void test_format_fill_silence(struct kunit *test) { - u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES }; + static const u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES }; u8 *buffer; u32 i, j; @@ -191,7 +191,7 @@ static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size) return boundary; } -static struct avail_test_data p_avail_data[] = { +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 }, /* @@ -220,7 +220,7 @@ static void test_playback_avail(struct kunit *test) } } -static struct avail_test_data c_avail_data[] = { +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 */ @@ -308,5 +308,6 @@ static struct kunit_suite sound_utils_suite = { }; kunit_test_suite(sound_utils_suite); +MODULE_DESCRIPTION("Sound core KUnit test"); MODULE_AUTHOR("Ivan Orlov"); MODULE_LICENSE("GPL"); diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index 2c0c7092d396..a08bdd70ec9c 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -4,15 +4,15 @@ # 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-pcmtest-objs := pcmtest.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 diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 892c4e29c0a3..d6dd4b8c750a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -927,10 +927,13 @@ static const struct snd_pcm_hardware loopback_pcm_hardware = 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, 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/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/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/pcmtest.c b/sound/drivers/pcmtest.c index b8bff5522bce..21cefaf5419a 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -772,6 +772,7 @@ static void __exit mod_exit(void) 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); 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/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/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 c9f153f85ae6..d35d0a420ee0 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1180,13 +1180,11 @@ 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_FLEX(struct fw_iso_packet, template, header, + header_length, 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); @@ -1198,7 +1196,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; } 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/dice/Makefile b/sound/firewire/dice/Makefile index bac8712f9014..36e25a3cf3c6 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -1,5 +1,5 @@ # 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-weiss.o 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/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/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/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/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/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/hda/Kconfig b/sound/hda/Kconfig index 741179ccbd4e..e2ac247fc1d4 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -42,6 +42,7 @@ config SND_INTEL_NHLT 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. diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 78f487a635f8..83cceafe0d4c 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,8 +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 \ +snd-hda-core-y := 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 +snd-hda-core-y += trace.o CFLAGS_trace.o := -I$(src) # for sync with i915 gfx driver @@ -14,9 +14,9 @@ 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-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-objs := intel-sdw-acpi.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/ext/Makefile b/sound/hda/ext/Makefile index 154779bdc0ba..05883fb28d28 100644 --- a/sound/hda/ext/Makefile +++ b/sound/hda/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 := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o obj-$(CONFIG_SND_HDA_EXT_CORE) += snd-hda-ext-core.o diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 7f3a000fab0c..b5c833b9f8b9 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -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; @@ -135,14 +136,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; + int ret = -EIO; + + spin_lock_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); + + ret = snd_hdac_bus_wait_for_pio_response(bus, addr); + goto out; + } + udelay(1); + } + + dev_dbg_ratelimited(bus->dev, "send_cmd_pio timeout: IRS=%#x, val=%#x\n", + snd_hdac_chip_readw(bus, IRS), val); + +out: + spin_unlock_irq(&bus->reg_lock); + + return ret; +} + +/** + * 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; @@ -176,7 +257,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val) return 0; } -EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd); #define AZX_RIRB_EX_UNSOL_EV (1<<4) @@ -234,15 +314,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; @@ -293,6 +373,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/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 6a384b922e4f..cfdb1b73c88c 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -13,6 +13,8 @@ #include <sound/intel-nhlt.h> #include <sound/soc-acpi.h> +#include <acpi/nhlt.h> + static int dsp_driver; module_param(dsp_driver, int, 0444); @@ -557,9 +559,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; } @@ -570,15 +595,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; } diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 696a958d93e9..088cff799e0b 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -343,3 +343,29 @@ 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) + 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); + } + + return -EINVAL; +} +EXPORT_SYMBOL(intel_nhlt_ssp_device_type); diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index 5f60658c6051..d7417a40392b 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -45,6 +45,8 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx) "intel-quirk-mask", &quirk_mask); + fwnode_handle_put(link); + if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) return false; 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/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/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/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/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/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/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/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/msnd/Makefile b/sound/isa/msnd/Makefile index ec231a7b1d5e..5f8d6b472722 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_midi.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/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/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_patch.c b/sound/isa/sb/emu8000_patch.c index 8c1e7f2bfc34..ab4f988f080d 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)) @@ -177,12 +170,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/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/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/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/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_paula.c b/sound/oss/dmasound/dmasound_paula.c index 0ba8f0c4cd99..b8fad12f9e5f 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -725,7 +725,13 @@ static void __exit amiga_audio_remove(struct platform_device *pdev) dmasound_deinit(); } -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_new = __exit_p(amiga_audio_remove), .driver = { .name = "amiga-audio", @@ -734,5 +740,6 @@ static struct platform_driver amiga_audio_driver = { 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/pci/Makefile b/sound/pci/Makefile index 04cac7469139..18b673018dfd 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 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/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/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/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/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/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/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/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 fe72e7d77241..dadeda7758ce 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -189,8 +189,7 @@ static int snd_emu10k1_suspend(struct device *dev) emu->suspend = 1; - cancel_work_sync(&emu->emu1010.firmware_work); - cancel_work_sync(&emu->emu1010.clock_work); + cancel_work_sync(&emu->emu1010.work); snd_ac97_suspend(emu->ac97); diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index d36234b88fb4..ef26e4d3e2a3 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -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) - 64; + val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64 + 3; if (val >= vp->reg.loopstart) bp = best + V_OFF; } @@ -310,6 +310,7 @@ 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; @@ -321,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) @@ -330,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; @@ -362,7 +364,7 @@ start_voice(struct snd_emux_voice *vp) map = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); - addr = vp->reg.start + 64; + addr = vp->reg.start + 64 - 3; temp = vp->reg.parm.filterQ; ccca = (temp << 28) | addr; if (vp->apitch < 0xe400) @@ -371,7 +373,7 @@ start_voice(struct snd_emux_voice *vp) unsigned int shift = (vp->apitch - 0xe000) >> 10; ccca |= shift << 25; } - if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS) + if (!w_16) ccca |= CCCA_8BITSELECT; vtarget = (unsigned int)vp->vtarget << 16; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index de5c41e578e1..5b8a5ba825bd 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -652,52 +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; - - 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_irq(&emu->emu_lock); - 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_irq(&emu->emu_lock); - - return 0; -} - /* firmware file names, per model, init-fw and dock-fw (optional) */ static const char * const firmware_names[5][2] = { [EMU_MODEL_EMU1010] = { @@ -729,72 +683,68 @@ 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); - 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 + } + 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, ®); /* 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) - return; - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - 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); - return; - } - 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_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_work(struct work_struct *work) +static void emu1010_clock_event(struct snd_emu10k1 *emu) { - struct snd_emu10k1 *emu; struct snd_ctl_elem_id id; - emu = container_of(work, struct snd_emu10k1, - emu1010.clock_work); - if (emu->card->shutdown) - return; -#ifdef CONFIG_PM_SLEEP - if (emu->suspend) - return; -#endif - spin_lock_irq(&emu->reg_lock); // This is the only thing that can actually happen. emu->emu1010.clock_source = emu->emu1010.clock_fallback; @@ -805,21 +755,44 @@ static void emu1010_clock_work(struct work_struct *work) snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id); } -static void emu1010_interrupt(struct snd_emu10k1 *emu) +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 + + snd_emu1010_fpga_lock(emu); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts); - if (sts & EMU_HANA_IRQ_DOCK_LOST) { - /* 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); - } else if (sts & EMU_HANA_IRQ_DOCK) { - schedule_work(&emu->emu1010.firmware_work); - } + + // 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) - schedule_work(&emu->emu1010.clock_work); + emu1010_clock_event(emu); + + snd_emu1010_fpga_unlock(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); } /* @@ -841,32 +814,13 @@ 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, ®); - 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, ®); - 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); + 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"); - return err; + goto fail; } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ @@ -876,7 +830,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) dev_info(emu->card->dev, "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); - return -ENODEV; + err = -ENODEV; + goto fail; } dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n"); @@ -889,7 +844,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) - schedule_work(&emu->emu1010.firmware_work); + 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 */ @@ -936,7 +891,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) // so it is safe to simply enable the outputs. snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - return 0; +fail: + snd_emu1010_fpga_unlock(emu); + return err; } /* * Create the EMU10K1 instance @@ -958,10 +915,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_work_sync(&emu->emu1010.firmware_work); - cancel_work_sync(&emu->emu1010.clock_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); @@ -1540,8 +1497,8 @@ int snd_emu10k1_create(struct snd_card *card, emu->irq = -1; emu->synth = NULL; emu->get_synth_voice = NULL; - INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); - INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_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); diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c index 89890f24509f..dbfa89435ac2 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,76 @@ 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 */ + printk(KERN_WARNING "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 +108,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/emumixer.c b/sound/pci/emu10k1/emumixer.c index 0a32ea53d8c6..05b98d9b547b 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -661,7 +661,9 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.output_source[channel] != val); if (change) { emu->emu1010.output_source[channel] = val; + snd_emu1010_fpga_lock(emu); snd_emu1010_output_source_apply(emu, channel, val); + snd_emu1010_fpga_unlock(emu); } return change; } @@ -705,7 +707,9 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.input_source[channel] != val); if (change) { emu->emu1010.input_source[channel] = val; + snd_emu1010_fpga_lock(emu); snd_emu1010_input_source_apply(emu, channel, val); + snd_emu1010_fpga_unlock(emu); } return change; } @@ -774,7 +778,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct cache = cache & ~mask; change = (cache != emu->emu1010.adc_pads); if (change) { - snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache ); emu->emu1010.adc_pads = cache; } @@ -832,7 +836,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct cache = cache & ~mask; change = (cache != emu->emu1010.dac_pads); if (change) { - snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache ); emu->emu1010.dac_pads = cache; } @@ -980,6 +984,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, val = ucontrol->value.enumerated.item[0] ; if (val >= emu_ci->num) return -EINVAL; + snd_emu1010_fpga_lock(emu); spin_lock_irq(&emu->reg_lock); change = (emu->emu1010.clock_source != val); if (change) { @@ -996,6 +1001,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, } else { spin_unlock_irq(&emu->reg_lock); } + snd_emu1010_fpga_unlock(emu); return change; } @@ -1041,7 +1047,7 @@ static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.clock_fallback != val); if (change) { emu->emu1010.clock_fallback = val; - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val); + snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val); } return change; } @@ -1093,7 +1099,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; } @@ -1144,7 +1150,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; } @@ -2323,7 +2329,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, for (i = 0; i < emu_ri->n_outs; i++) emu->emu1010.output_source[i] = emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); + snd_emu1010_fpga_lock(emu); snd_emu1010_apply_sources(emu); + snd_emu1010_fpga_unlock(emu); kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu); err = snd_ctl_add(card, kctl); diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 2f80fd91017c..737c28d31b41 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -165,6 +165,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, u32 value2; if (emu->card_capabilities->emu_model) { + 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). @@ -197,6 +199,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, 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" : ""); + + snd_emu1010_fpga_unlock(emu); } 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); @@ -458,6 +462,9 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; u32 value; int i; + + snd_emu1010_fpga_lock(emu); + snd_iprintf(buffer, "EMU1010 Registers:\n\n"); for(i = 0; i < 0x40; i+=1) { @@ -496,6 +503,8 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, snd_emu_proc_emu1010_link_read(emu, buffer, 0x701); } } + + snd_emu1010_fpga_unlock(emu); } static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 74df2330015f..b60ab5671e00 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -285,24 +285,33 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 outw(value, emu->port + A_GPIO); udelay(10); outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ + udelay(10); } void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) { - unsigned long flags; + if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock))) + return; + snd_emu1010_fpga_write_locked(emu, reg, value); +} - spin_lock_irqsave(&emu->emu_lock, flags); +void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value) +{ + snd_emu1010_fpga_lock(emu); snd_emu1010_fpga_write_locked(emu, reg, value); - spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_emu1010_fpga_unlock(emu); } -static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *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; + + if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock))) + return; if (snd_BUG_ON(reg > 0x3f)) return; reg += 0x40; /* 0x40 upwards are registers. */ @@ -313,47 +322,31 @@ static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 * *value = ((inw(emu->port + A_GPIO) >> 8) & mask); } -void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) -{ - unsigned long flags; - - spin_lock_irqsave(&emu->emu_lock, flags); - snd_emu1010_fpga_read_locked(emu, reg, value); - spin_unlock_irqrestore(&emu->emu_lock, flags); -} - /* Each Destination has one and only one Source, * but one Source can feed any number of Destinations simultaneously. */ void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src) { - unsigned long flags; - if (snd_BUG_ON(dst & ~0x71f)) return; if (snd_BUG_ON(src & ~0x71f)) return; - spin_lock_irqsave(&emu->emu_lock, flags); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, src >> 8); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, src & 0x1f); - spin_unlock_irqrestore(&emu->emu_lock, flags); + snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8); + snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f); + snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8); + snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f); } u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst) { - unsigned long flags; u32 hi, lo; if (snd_BUG_ON(dst & ~0x71f)) return 0; - spin_lock_irqsave(&emu->emu_lock, flags); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8); - snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f); - snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCHI, &hi); - snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, &lo); - spin_unlock_irqrestore(&emu->emu_lock, flags); + 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; } @@ -429,6 +422,59 @@ void snd_emu1010_update_clock(struct snd_emu10k1 *emu) 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; diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 20b07117574b..d29711777161 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -565,15 +565,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); @@ -585,25 +588,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); @@ -614,8 +647,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/hda/Kconfig b/sound/pci/hda/Kconfig index f806636242ee..0da625533afc 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -128,6 +128,7 @@ config SND_HDA_SCODEC_CS35L41_I2C select SND_SOC_CS35L41_LIB select SND_HDA_SCODEC_CS35L41 select SND_HDA_CS_DSP_CONTROLS + 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. @@ -144,6 +145,7 @@ config SND_HDA_SCODEC_CS35L41_SPI select SND_SOC_CS35L41_LIB select SND_HDA_SCODEC_CS35L41 select SND_HDA_CS_DSP_CONTROLS + 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. diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 13e04e1f65de..058ca0a289e4 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -snd-hda-intel-objs := hda_intel.o -snd-hda-tegra-objs := hda_tegra.o +snd-hda-intel-y := hda_intel.o +snd-hda-tegra-y := 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 @@ -13,32 +13,32 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o 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 +snd-hda-codec-generic-y := hda_generic.o +snd-hda-codec-realtek-y := patch_realtek.o +snd-hda-codec-cmedia-y := patch_cmedia.o +snd-hda-codec-analog-y := patch_analog.o +snd-hda-codec-idt-y := patch_sigmatel.o +snd-hda-codec-si3054-y := patch_si3054.o +snd-hda-codec-cirrus-y := patch_cirrus.o +snd-hda-codec-cs8409-y := patch_cs8409.o patch_cs8409-tables.o +snd-hda-codec-ca0110-y := patch_ca0110.o +snd-hda-codec-ca0132-y := patch_ca0132.o +snd-hda-codec-conexant-y := patch_conexant.o +snd-hda-codec-via-y := patch_via.o +snd-hda-codec-hdmi-y := patch_hdmi.o hda_eld.o # side codecs -snd-hda-cirrus-scodec-objs := cirrus_scodec.o -snd-hda-cirrus-scodec-test-objs := cirrus_scodec_test.o -snd-hda-scodec-cs35l41-objs := cs35l41_hda.o cs35l41_hda_property.o -snd-hda-scodec-cs35l41-i2c-objs := cs35l41_hda_i2c.o -snd-hda-scodec-cs35l41-spi-objs := cs35l41_hda_spi.o -snd-hda-scodec-cs35l56-objs := cs35l56_hda.o -snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o -snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o -snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o -snd-hda-scodec-component-objs := hda_component.o -snd-hda-scodec-tas2781-i2c-objs := tas2781_hda_i2c.o +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-cs-dsp-ctls-y := hda_cs_dsp_ctl.o +snd-hda-scodec-component-y := hda_component.o +snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o # common driver obj-$(CONFIG_SND_HDA) := snd-hda-codec.o diff --git a/sound/pci/hda/cirrus_scodec_test.c b/sound/pci/hda/cirrus_scodec_test.c index 8ae373676bd1..e925ebe21ccb 100644 --- a/sound/pci/hda/cirrus_scodec_test.c +++ b/sound/pci/hda/cirrus_scodec_test.c @@ -366,5 +366,6 @@ static struct kunit_suite cirrus_scodec_test_suite = { 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/pci/hda/cs35l41_hda.c index d3fa6e136744..6c49e5c6cd20 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -13,6 +13,7 @@ #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" @@ -22,7 +23,6 @@ #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" @@ -37,6 +37,42 @@ #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, +}; static bool firmware_autostart = 1; module_param(firmware_autostart, bool, 0444); @@ -75,7 +111,7 @@ static const struct reg_sequence cs35l41_hda_config_dsp[] = { { 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_DAC_PCM1_SRC, 0x00000032 }, // DACPCM1_SRC = DSP1TX1 { CS35L41_ASP_TX1_SRC, 0x00000018 }, // ASPTX1 SRC = VMON { CS35L41_ASP_TX2_SRC, 0x00000019 }, // ASPTX2 SRC = IMON { CS35L41_ASP_TX3_SRC, 0x00000028 }, // ASPTX3 SRC = VPMON @@ -84,7 +120,7 @@ static const struct reg_sequence cs35l41_hda_config_dsp[] = { { 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[] = { @@ -92,11 +128,6 @@ static const struct reg_sequence cs35l41_hda_unmute[] = { { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB }; -static const struct reg_sequence cs35l41_hda_unmute_dsp[] = { - { 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 -}; - static const struct reg_sequence cs35l41_hda_mute[] = { { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, // AMP_GAIN_PCM 0.5 dB { CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM Mute @@ -117,9 +148,30 @@ static const struct cs_dsp_client_ops client_ops = { .control_remove = hda_cs_dsp_control_remove, }; +static int cs35l41_request_tuning_param_file(struct cs35l41_hda *cs35l41, char *tuning_filename, + const struct firmware **firmware, char **filename, + const char *ssid) +{ + int ret = 0; + + /* Filename is the same as the tuning file with "cfg" suffix */ + *filename = kasprintf(GFP_KERNEL, "%scfg", tuning_filename); + if (*filename == NULL) + return -ENOMEM; + + 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; + } + + 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; @@ -127,23 +179,23 @@ 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, + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART, dsp_name, hda_cs_dsp_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, + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d.%s", CS35L41_PART, dsp_name, hda_cs_dsp_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, + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-%s.%s", CS35L41_PART, dsp_name, hda_cs_dsp_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, + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s.%s", CS35L41_PART, dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], ssid, filetype); else - *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, CS35L41_PART, + *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s.%s", CS35L41_PART, dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type], filetype); @@ -184,13 +236,11 @@ 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 */ 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) @@ -201,12 +251,11 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* 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 */ 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) @@ -217,18 +266,17 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* 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 */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, - coeff_filename, CS35L41_FIRMWARE_ROOT, + coeff_filename, cs35l41->acpi_subsystem_id, NULL, cs35l41->speaker_id, "bin"); if (ret) @@ -239,18 +287,17 @@ static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41, /* 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 */ ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, - coeff_filename, CS35L41_FIRMWARE_ROOT, + coeff_filename, cs35l41->acpi_subsystem_id, NULL, cs35l41->speaker_id, "bin"); if (ret) @@ -277,13 +324,13 @@ static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41, /* fallback try cirrus/part-dspN-fwtype.wmfw */ ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename, - CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw"); + 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, - CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin"); + NULL, NULL, -1, "bin"); if (ret) { release_firmware(*wmfw_firmware); kfree(*wmfw_filename); @@ -312,12 +359,11 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41, /* 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) @@ -328,18 +374,16 @@ static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41, /* 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) @@ -361,95 +405,162 @@ fallback: coeff_firmware, coeff_filename); } -#if IS_ENABLED(CONFIG_EFI) -static int cs35l41_apply_calibration(struct cs35l41_hda *cs35l41, __be32 ambient, __be32 r0, - __be32 status, __be32 checksum) + +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); +} + +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 *)¶ms->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) { @@ -470,27 +581,35 @@ 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]); if (ret) - goto err_release; + goto err; cs35l41_add_controls(cs35l41); - 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); @@ -503,6 +622,7 @@ 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); dev_dbg(cs35l41->dev, "Unloaded Firmware\n"); @@ -553,6 +673,10 @@ static void cs35l41_hda_play_start(struct device *dev) if (cs35l41->cs_dsp.running) { 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); 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); @@ -570,6 +694,7 @@ 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); @@ -581,8 +706,13 @@ static void cs35l41_mute(struct device *dev, bool mute) } else { dev_dbg(dev, "Unmuting\n"); if (cs35l41->cs_dsp.running) { - regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp, - ARRAY_SIZE(cs35l41_hda_unmute_dsp)); + 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)); @@ -1056,6 +1186,9 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) goto clean_dsp; } + dev_info(cs35l41->dev, "Firmware Loaded - Type: %s, Gain: %d\n", + hda_cs_dsp_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain); + return 0; clean_dsp: @@ -1461,13 +1594,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; @@ -1510,26 +1686,8 @@ 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); } @@ -1808,6 +1966,10 @@ 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); @@ -1888,6 +2050,7 @@ 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); diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h index 43d55292b327..b0bebb778462 100644 --- a/sound/pci/hda/cs35l41_hda.h +++ b/sound/pci/hda/cs35l41_hda.h @@ -16,11 +16,14 @@ #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]; @@ -83,6 +86,9 @@ struct cs35l41_hda { 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; }; diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 72ec872afb8d..6a7a6d486916 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -70,6 +70,8 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "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 }, @@ -95,6 +97,7 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "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 }, @@ -108,7 +111,17 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "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 }, @@ -454,6 +467,8 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "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 }, @@ -483,6 +498,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "10431863", generic_dsd_config }, { "CSC3551", "104318D3", generic_dsd_config }, { "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 }, @@ -496,7 +512,17 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "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 }, diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 41974b3897a7..11b0570ff56d 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -644,6 +644,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) 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 */ @@ -730,8 +732,6 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * if (cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); - cs_dsp_remove(&cs35l56->cs_dsp); - if (comps[cs35l56->index].dev == dev) memset(&comps[cs35l56->index], 0, sizeof(*comps)); @@ -1002,6 +1002,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) if (ret) goto err; + regcache_cache_only(cs35l56->base.regmap, false); + ret = cs35l56_set_patch(&cs35l56->base); if (ret) goto err; @@ -1024,14 +1026,14 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) goto err; } - dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n", - cs35l56->system_name, cs35l56->amp_name); + 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)); ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); if (ret) - goto err; + goto dsp_err; /* * By default only enable one ASP1TXn, where n=amplifier index, @@ -1045,18 +1047,20 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) 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; } - cs35l56->base.init_done = true; - return 0; pm_err: pm_runtime_disable(cs35l56->base.dev); +dsp_err: + cs_dsp_remove(&cs35l56->cs_dsp); err: gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); @@ -1074,6 +1078,8 @@ void cs35l56_hda_remove(struct device *dev) component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + cs_dsp_remove(&cs35l56->cs_dsp); + kfree(cs35l56->system_name); pm_runtime_put_noidle(cs35l56->base.dev); diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c index 13beee807308..40f2f97944d5 100644 --- a/sound/pci/hda/cs35l56_hda_i2c.c +++ b/sound/pci/hda/cs35l56_hda_i2c.c @@ -56,10 +56,19 @@ static const struct i2c_device_id cs35l56_hda_i2c_id[] = { {} }; +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", - .pm = &cs35l56_hda_pm_ops, + .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, diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c index a3b2fa76663d..7f02155fe61e 100644 --- a/sound/pci/hda/cs35l56_hda_spi.c +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -56,10 +56,19 @@ static const struct spi_device_id cs35l56_hda_spi_id[] = { {} }; +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", - .pm = &cs35l56_hda_pm_ops, + .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, diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2cac337f5263..325e8f0b99a8 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -616,7 +616,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,7 +633,6 @@ static void restore_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 0; } -#endif static void hda_jackpoll_work(struct work_struct *work) { @@ -1001,9 +999,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); @@ -1238,7 +1234,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 +1245,6 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) really_cleanup_stream(codec, p); } } -#endif /* * amp access functions @@ -2858,7 +2852,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) { @@ -2966,9 +2959,6 @@ static int hda_codec_runtime_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_SLEEP static int hda_codec_pm_prepare(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); @@ -3023,22 +3013,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_suspend = pm_ptr(hda_codec_runtime_suspend), + .runtime_resume = pm_ptr(hda_codec_runtime_resume), }; /* suspend the codec at shutdown; called from driver's shutdown callback */ @@ -3425,7 +3412,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 @@ -3516,7 +3502,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 @@ -4060,12 +4045,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_component.c b/sound/pci/hda/hda_component.c index cd299d7d84ba..d02589014a3f 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -123,6 +123,21 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) return !strcmp(d + n, tmp); } +int hda_component_manager_bind(struct hda_codec *cdc, + struct hda_component *comps, int count) +{ + int i; + + /* Init shared data */ + for (i = 0; i < count; ++i) { + memset(&comps[i], 0, sizeof(comps[i])); + comps[i].codec = cdc; + } + + return component_bind_all(hda_codec_dev(cdc), comps); +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT); + int hda_component_manager_init(struct hda_codec *cdc, struct hda_component *comps, int count, const char *bus, const char *hid, @@ -143,7 +158,6 @@ int hda_component_manager_init(struct hda_codec *cdc, sm->hid = hid; sm->match_str = match_str; sm->index = i; - comps[i].codec = cdc; component_match_add(dev, &match, hda_comp_match_dev_name, sm); } diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index c80a66691b5d..c70b3de68ab2 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -75,11 +75,8 @@ int hda_component_manager_init(struct hda_codec *cdc, void hda_component_manager_free(struct hda_codec *cdc, const struct component_master_ops *ops); -static inline int hda_component_manager_bind(struct hda_codec *cdc, - struct hda_component *comps) -{ - return component_bind_all(hda_codec_dev(cdc), comps); -} +int hda_component_manager_bind(struct hda_codec *cdc, + struct hda_component *comps, int count); static inline void hda_component_manager_unbind(struct hda_codec *cdc, struct hda_component *comps) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 206306a0eb82..766734dc5be2 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_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> @@ -914,7 +914,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); @@ -928,7 +928,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); @@ -1075,11 +1075,9 @@ 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); @@ -1188,6 +1186,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; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 8556031bcd68..c2d0109866e6 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/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_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c index 463ca06036bf..e6e876998e71 100644 --- a/sound/pci/hda/hda_cs_dsp_ctl.c +++ b/sound/pci/hda/hda_cs_dsp_ctl.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <sound/soc.h> +#include <linux/cleanup.h> #include <linux/firmware/cirrus/cs_dsp.h> #include <linux/firmware/cirrus/wmfw.h> #include "hda_cs_dsp_ctl.h" @@ -51,13 +52,8 @@ static int hda_cs_dsp_coeff_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_v 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; + return cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, p, cs_ctl->len); } static int hda_cs_dsp_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) @@ -65,13 +61,8 @@ static int hda_cs_dsp_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_v 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; + return cs_dsp_coeff_lock_and_read_ctrl(cs_ctl, 0, p, cs_ctl->len); } static unsigned int wmfw_convert_flags(unsigned int in) @@ -97,11 +88,23 @@ static unsigned int wmfw_convert_flags(unsigned int in) return out; } -static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name) +static void hda_cs_dsp_free_kcontrol(struct snd_kcontrol *kctl) { + 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; + + /* NULL priv to prevent a double-free in hda_cs_dsp_control_remove() */ + cs_ctl->priv = NULL; + kfree(ctl); +} + +static void hda_cs_dsp_add_kcontrol(struct cs_dsp_coeff_ctl *cs_ctl, + const struct hda_cs_dsp_ctl_info *info, + const char *name) +{ struct snd_kcontrol_new kcontrol = {0}; struct snd_kcontrol *kctl; + struct hda_cs_dsp_coeff_ctl *ctl __free(kfree) = NULL; int ret = 0; if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) { @@ -110,6 +113,13 @@ static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char return; } + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return; + + ctl->cs_ctl = cs_ctl; + ctl->card = info->card; + kcontrol.name = name; kcontrol.info = hda_cs_dsp_coeff_info; kcontrol.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -117,20 +127,22 @@ static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char 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); + kctl->private_free = hda_cs_dsp_free_kcontrol; + ctl->kctl = kctl; + + /* snd_ctl_add() calls our private_free on error, which will kfree(ctl) */ + cs_ctl->priv = no_free_ptr(ctl); + ret = snd_ctl_add(info->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, @@ -138,7 +150,6 @@ static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, { 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; @@ -163,15 +174,7 @@ static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, " %.*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); + hda_cs_dsp_add_kcontrol(cs_ctl, info, name); } void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info) @@ -203,7 +206,9 @@ 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); + /* ctl and kctl may already have been removed by ALSA private_free */ + if (ctl && ctl->kctl) + snd_ctl_remove(ctl->card, ctl->kctl); } EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS); @@ -211,7 +216,6 @@ 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); @@ -221,13 +225,6 @@ int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, 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); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index de2a3d08c73c..f64d9dc197a3 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -6021,7 +6021,6 @@ void snd_hda_gen_free(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_gen_free); -#ifdef CONFIG_PM /** * snd_hda_gen_check_power_status - check the loopback power save state * @codec: the HDA codec @@ -6035,7 +6034,6 @@ 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 /* @@ -6048,9 +6046,7 @@ static const struct hda_codec_ops generic_patch_ops = { .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 }; /* diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index a8eea8367629..8f5ecf740c49 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -340,9 +340,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); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1b550c42db09..3500108f6ba3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_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> @@ -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 false +#define power_save_controller false #endif /* CONFIG_PM */ static int align_buffer_size = -1; @@ -289,6 +291,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 |\ @@ -890,7 +895,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); @@ -916,7 +920,7 @@ static void azx_del_card_list(struct azx *chip) } /* 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; @@ -987,7 +991,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); @@ -1046,7 +1049,7 @@ static int azx_suspend(struct device *dev) return 0; } -static int azx_resume(struct device *dev) +static int __maybe_unused azx_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1097,9 +1100,8 @@ static int azx_thaw_noirq(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -static int azx_runtime_suspend(struct device *dev) +static int __maybe_unused azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1116,7 +1118,7 @@ static int azx_runtime_suspend(struct device *dev) return 0; } -static int azx_runtime_resume(struct device *dev) +static int __maybe_unused azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1133,7 +1135,7 @@ static int azx_runtime_resume(struct device *dev) return 0; } -static int azx_runtime_idle(struct device *dev) +static int __maybe_unused azx_runtime_idle(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1159,23 +1161,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 + 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), SET_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); @@ -2206,7 +2199,6 @@ out_free: 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. @@ -2248,13 +2240,11 @@ static const struct snd_pci_quirk power_save_denylist[] = { SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0), {} }; -#endif /* CONFIG_PM */ static void set_default_power_save(struct azx *chip) { int val = power_save; -#ifdef CONFIG_PM if (pm_blacklist) { const struct snd_pci_quirk *q; @@ -2265,7 +2255,6 @@ static void set_default_power_save(struct azx *chip) val = 0; } } -#endif /* CONFIG_PM */ snd_hda_set_power_save(&chip->bus, val * 1000); } @@ -2321,10 +2310,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 @@ -2502,8 +2487,10 @@ static const struct pci_device_id azx_ids[] = { { 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_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) }, + { 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 */ @@ -2765,7 +2752,7 @@ static struct pci_driver azx_driver = { .remove = azx_remove, .shutdown = azx_shutdown, .driver = { - .pm = AZX_PM_OPS, + .pm = &azx_pm, }, }; diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/pci/hda/hda_intel_trace.h index 73a7adfa192d..2775fa81a500 100644 --- a/sound/pci/hda/hda_intel_trace.h +++ b/sound/pci/hda/hda_intel_trace.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_sysfs.c b/sound/pci/hda/hda_sysfs.c index 69ebc37a4d6f..265fd4737893 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_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, \ @@ -745,10 +743,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/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8afe6000f7da..1e9dadcdc51b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -72,7 +72,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) { @@ -118,7 +117,6 @@ static int ad198x_suspend(struct hda_codec *codec) ad198x_power_eapd(codec); return 0; } -#endif /* follow EAPD via vmaster hook */ static void ad_vmaster_eapd_hook(void *private_data, int enabled) @@ -158,10 +156,8 @@ static const struct hda_codec_ops ad198x_auto_patch_ops = { .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 }; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index aa312441604f..e4673a71551a 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -9682,7 +9682,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; @@ -9690,7 +9689,6 @@ static int ca0132_suspend(struct hda_codec *codec) 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, @@ -9698,9 +9696,7 @@ static const struct hda_codec_ops ca0132_patch_ops = { .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 = { diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 6807b4708a17..654724559355 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1128,7 +1128,6 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM /* * Manage PDREF, when transitioning to D3hot * (DAC,ADC) -> D3, PDREF=1, AFG->D3 @@ -1153,7 +1152,6 @@ static int cs421x_suspend(struct hda_codec *codec) return 0; } -#endif static const struct hda_codec_ops cs421x_patch_ops = { .build_controls = snd_hda_gen_build_controls, @@ -1161,9 +1159,7 @@ static const struct hda_codec_ops cs421x_patch_ops = { .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) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e8209178d87b..17389a3801bd 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -294,13 +294,11 @@ static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res) snd_hda_jack_unsol_event(codec, res); } -#ifdef CONFIG_PM static int cx_auto_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, @@ -308,10 +306,8 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .init = cx_auto_init, .free = cx_auto_free, .unsol_event = cx_jack_unsol_event, -#ifdef CONFIG_PM .suspend = cx_auto_suspend, .check_power_status = snd_hda_gen_check_power_status, -#endif }; /* diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c index e41316e2e983..26f3c31600d7 100644 --- a/sound/pci/hda/patch_cs8409.c +++ b/sound/pci/hda/patch_cs8409.c @@ -909,7 +909,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; @@ -948,7 +947,6 @@ 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) { @@ -1003,7 +1001,6 @@ static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned in } } -#ifdef CONFIG_PM /* Manage PDREF, when transition to D3hot */ static int cs8409_cs42l42_suspend(struct hda_codec *codec) { @@ -1025,7 +1022,6 @@ static int cs8409_cs42l42_suspend(struct hda_codec *codec) return 0; } -#endif /* Vendor specific HW configuration * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... @@ -1080,9 +1076,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { .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, @@ -1310,9 +1304,7 @@ static const struct hda_codec_ops cs8409_dolphin_patch_ops = { .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, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 495d63101186..707d203ba652 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -3,7 +3,7 @@ * * patch_hdmi.c - routines for HDMI/DisplayPort codecs * - * Copyright(c) 2008-2010 Intel Corporation. All rights reserved. + * 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> @@ -2513,7 +2513,6 @@ static void generic_hdmi_free(struct hda_codec *codec) generic_spec_free(codec); } -#ifdef CONFIG_PM static int generic_hdmi_suspend(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -2540,7 +2539,6 @@ static int generic_hdmi_resume(struct hda_codec *codec) } return 0; } -#endif static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, @@ -2548,10 +2546,8 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .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 = { @@ -2952,7 +2948,6 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec, } } -#ifdef CONFIG_PM static int i915_adlp_hdmi_suspend(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -3032,7 +3027,6 @@ static int i915_adlp_hdmi_resume(struct hda_codec *codec) return res; } -#endif /* precondition and allocation for Intel codecs */ static int alloc_intel_hdmi(struct hda_codec *codec) @@ -3167,10 +3161,8 @@ static int patch_i915_adlp_hdmi(struct hda_codec *codec) 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 } } @@ -4642,6 +4634,7 @@ 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(0x8086281d, "Meteor Lake HDMI", patch_i915_adlp_hdmi), +HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a17c36a36aa5..a696943aec0d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -109,9 +109,7 @@ struct alc_spec { /* 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; @@ -920,6 +918,8 @@ static void alc_pre_init(struct hda_codec *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) static int alc_init(struct hda_codec *codec) { @@ -945,7 +945,6 @@ static int alc_init(struct hda_codec *codec) #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; @@ -984,7 +983,6 @@ static int alc_resume(struct hda_codec *codec) hda_call_check_power_status(codec, 0x01); return 0; } -#endif /* */ @@ -994,11 +992,9 @@ static const struct hda_codec_ops alc_patch_ops = { .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 }; @@ -4039,7 +4035,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; @@ -4085,7 +4080,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) @@ -6533,6 +6527,20 @@ 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: + 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) { @@ -6791,7 +6799,7 @@ static int comp_bind(struct device *dev) struct alc_spec *spec = cdc->spec; int ret; - ret = hda_component_manager_bind(cdc, spec->comps); + ret = hda_component_manager_bind(cdc, spec->comps, ARRAY_SIZE(spec->comps)); if (ret) return ret; @@ -6875,11 +6883,38 @@ static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const st comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2); } +static void cs35l56_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(cdc, action, "i2c", "CSC3556", "-%s:00-cs35l56-hda.%d", 2); +} + +static void cs35l56_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(cdc, action, "i2c", "CSC3556", "-%s:00-cs35l56-hda.%d", 4); +} + +static void cs35l56_fixup_spi_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 2); +} + static void cs35l56_fixup_spi_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 4); } +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) + cs35l56_fixup_i2c_two(cdc, fix, action); + else + alc_fixup_inv_dmic(cdc, fix, action); +} + static void tas2781_fixup_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { @@ -7156,6 +7191,44 @@ static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec, alc245_fixup_hp_gpio_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) +{ + alc_write_coef_idx(codec, 0x10, 0x8806); /* Change MLK to GPIO3 */ + 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_coef_idx(codec, 0x10, 0x8806); /* Change MLK to GPIO3 */ + 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; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + spec->power_hook = alc287_s4_power_gpio3_default; + spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; +} + enum { ALC269_FIXUP_GPIO2, @@ -7399,6 +7472,7 @@ enum { ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, ALC298_FIXUP_LENOVO_C940_DUET7, ALC287_FIXUP_LENOVO_14IRP8_DUETITL, + ALC287_FIXUP_LENOVO_LEGION_7, ALC287_FIXUP_13S_GEN2_SPEAKERS, ALC256_FIXUP_SET_COEF_DEFAULTS, ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, @@ -7436,6 +7510,16 @@ enum { ALC256_FIXUP_ACER_SFG16_MICMUTE_LED, ALC256_FIXUP_HEADPHONE_AMP_VOL, ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX, + ALC285_FIXUP_CS35L56_SPI_2, + ALC285_FIXUP_CS35L56_I2C_2, + ALC285_FIXUP_CS35L56_I2C_4, + 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, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -7475,6 +7559,23 @@ static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec, __snd_hda_apply_fixup(codec, id, action, 0); } +/* Another hilarious PCI SSID conflict with Lenovo Legion Pro 7 16ARX8H (with + * TAS2781 codec) and Legion 7i 16IAX7 (with CS35L41 codec); + * we apply a corresponding fixup depending on the codec SSID instead + */ +static void alc287_fixup_lenovo_legion_7(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + int id; + + if (codec->core.subsystem_id == 0x17aa38a8) + id = ALC287_FIXUP_TAS2781_I2C; /* Legion Pro 7 16ARX8H */ + else + id = ALC287_FIXUP_CS35L41_I2C_2; /* Legion 7i 16IAX7 */ + __snd_hda_apply_fixup(codec, id, action, 0); +} + static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_GPIO2] = { .type = HDA_FIXUP_FUNC, @@ -9369,6 +9470,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc287_fixup_lenovo_14irp8_duetitl, }, + [ALC287_FIXUP_LENOVO_LEGION_7] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_lenovo_legion_7, + }, [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -9643,6 +9748,66 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc245_fixup_hp_spectre_x360_eu0xxx, }, + [ALC285_FIXUP_CS35L56_SPI_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l56_fixup_spi_two, + }, + [ALC285_FIXUP_CS35L56_I2C_2] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l56_fixup_i2c_two, + }, + [ALC285_FIXUP_CS35L56_I2C_4] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l56_fixup_i2c_four, + }, + [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 }, + { } + }, + .chained = true, + .chain_id = ALC285_FIXUP_CS35L56_SPI_2 + }, + [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 + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -9854,6 +10019,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), @@ -9948,7 +10114,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 0x8a2e, "HP Envy 17", 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, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4), @@ -9993,6 +10158,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 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), @@ -10013,6 +10180,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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), @@ -10037,6 +10206,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), + 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(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), @@ -10096,7 +10267,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2), 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", ALC287_FIXUP_CS35L41_I2C_2), @@ -10104,6 +10275,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS), 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), @@ -10115,12 +10287,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606", ALC285_FIXUP_CS35L56_I2C_4), SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), 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_CS35L56_I2C_2), + SND_PCI_QUIRK(0x1043, 0x1e83, "ASUS GA605W", ALC285_FIXUP_CS35L56_I2C_2), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), + 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), @@ -10133,7 +10309,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), 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), @@ -10159,7 +10335,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), 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_HEADSET_MODE), + SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_ASPIRE_HEADSET_MIC), 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), @@ -10177,6 +10353,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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), @@ -10282,6 +10459,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), @@ -10302,6 +10480,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 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), @@ -10330,9 +10510,14 @@ 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), - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7/7i", ALC287_FIXUP_LENOVO_LEGION_7), 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, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C), @@ -10341,8 +10526,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO 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_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2), + 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), 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), @@ -10403,6 +10588,8 @@ 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(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), @@ -10586,6 +10773,7 @@ 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"}, @@ -11118,10 +11306,8 @@ static int patch_alc269(struct hda_codec *codec) 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; @@ -11419,9 +11605,7 @@ static int patch_alc861(struct hda_codec *codec) if (has_cdefine_beep(codec)) spec->gen.beep_nid = 0x23; -#ifdef CONFIG_PM spec->power_hook = alc_power_eapd; -#endif alc_pre_init(codec); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 61258b0aac8d..ae1a34c68c61 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -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 } } @@ -4442,7 +4440,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,9 +4453,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, @@ -4466,9 +4460,7 @@ static const struct hda_codec_ops stac_patch_ops = { .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) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2994f85bc1b9..a8ef4bb70dd0 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -379,7 +379,6 @@ static void via_free(struct hda_codec *codec) snd_hda_gen_free(codec); } -#ifdef CONFIG_PM static int via_suspend(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -400,9 +399,7 @@ static int via_resume(struct hda_codec *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,7 +407,6 @@ 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 /* */ @@ -423,11 +419,9 @@ static const struct hda_codec_ops via_patch_ops = { .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 }; diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 4475cea8e9f7..75f7674c66ee 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -89,7 +89,7 @@ struct tas2781_hda { struct snd_kcontrol *dsp_prog_ctl; struct snd_kcontrol *dsp_conf_ctl; struct snd_kcontrol *prof_ctl; - struct snd_kcontrol *snd_ctls[3]; + struct snd_kcontrol *snd_ctls[2]; }; static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) @@ -161,8 +161,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) pm_runtime_put_autosuspend(dev); break; default: - dev_dbg(tas_hda->dev, "Playback action not supported: %d\n", - action); break; } } @@ -185,8 +183,15 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + mutex_lock(&tas_priv->codec_lock); + 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); + + mutex_unlock(&tas_priv->codec_lock); + return 0; } @@ -200,11 +205,19 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, val = clamp(nr_profile, 0, max); + mutex_lock(&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; } + mutex_unlock(&tas_priv->codec_lock); + return ret; } @@ -241,8 +254,15 @@ static int tasdevice_program_get(struct snd_kcontrol *kcontrol, { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + mutex_lock(&tas_priv->codec_lock); + 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); + + mutex_unlock(&tas_priv->codec_lock); + return 0; } @@ -257,11 +277,18 @@ static int tasdevice_program_put(struct snd_kcontrol *kcontrol, val = clamp(nr_program, 0, max); + mutex_lock(&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; } + mutex_unlock(&tas_priv->codec_lock); + return ret; } @@ -270,8 +297,15 @@ static int tasdevice_config_get(struct snd_kcontrol *kcontrol, { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + mutex_lock(&tas_priv->codec_lock); + 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); + + mutex_unlock(&tas_priv->codec_lock); + return 0; } @@ -286,54 +320,39 @@ static int tasdevice_config_put(struct snd_kcontrol *kcontrol, val = clamp(nr_config, 0, max); + mutex_lock(&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; } + mutex_unlock(&tas_priv->codec_lock); + return ret; } -/* - * 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, +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; - return tasdevice_digital_getvol(tas_priv, ucontrol, mc); -} + mutex_lock(&tas_priv->codec_lock); -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; + ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc); - return 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]); -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; + mutex_unlock(&tas_priv->codec_lock); - /* The check of the given value is in tasdevice_digital_putvol. */ - return tasdevice_digital_putvol(tas_priv, ucontrol, mc); + return ret; } static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, @@ -342,9 +361,19 @@ static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + int ret; + + mutex_lock(&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); + ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc); + + mutex_unlock(&tas_priv->codec_lock); + + return ret; } static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, @@ -352,9 +381,13 @@ static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, { struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); + mutex_lock(&tas_priv->codec_lock); + 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"); + dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", + __func__, kcontrol->id.name, tas_priv->force_fwload_status); + + mutex_unlock(&tas_priv->codec_lock); return 0; } @@ -365,14 +398,20 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); bool change, val = (bool)ucontrol->value.integer.value[0]; + mutex_lock(&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; } - dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__, - tas_priv->force_fwload_status ? "ON" : "OFF"); + + mutex_unlock(&tas_priv->codec_lock); return change; } @@ -381,9 +420,6 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv), - ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain", TAS2781_DVC_LVL, - 0, 0, 200, 1, tas2781_digital_getvol, - tas2781_digital_putvol, dvc_tlv), ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, tas2781_force_fwload_get, tas2781_force_fwload_put), }; @@ -478,10 +514,10 @@ static int tas2563_save_calibration(struct tasdevice_priv *tas_priv) static void tas2781_apply_calib(struct tasdevice_priv *tas_priv) { static const unsigned char page_array[CALIB_MAX] = { - 0x17, 0x18, 0x18, 0x0d, 0x18 + 0x17, 0x18, 0x18, 0x13, 0x18, }; static const unsigned char rgno_array[CALIB_MAX] = { - 0x74, 0x0c, 0x14, 0x3c, 0x7c + 0x74, 0x0c, 0x14, 0x70, 0x7c, }; unsigned char *data; int i, j, rc; 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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..3182c634464d 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -278,7 +278,8 @@ 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); } } @@ -290,6 +291,8 @@ static void aica_period_elapsed(struct timer_list *t) /*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? */ @@ -350,12 +353,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; + + del_timer_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 +411,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 */ diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 439fa631c342..a52afb423b46 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -66,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 diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 8376fdb217ed..fd61847dd1eb 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,32 +1,36 @@ # 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_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 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/amd/Kconfig b/sound/soc/amd/Kconfig index fa74635cee08..6dec44f516c1 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -132,17 +132,29 @@ 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 SOUNDWIRE_AMD if SND_SOC_AMD_SOUNDWIRE != n 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 && SOUNDWIRE - depends on !(SOUNDWIRE=m && SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE=y) + 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. @@ -150,7 +162,6 @@ config SND_SOC_AMD_SOUNDWIRE config SND_SOC_AMD_PS tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support" - select SND_AMD_ACP_CONFIG select SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE depends on X86 && PCI && ACPI help @@ -171,3 +182,5 @@ 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 diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index ebbe49c2bbff..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 diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 84f3d65ba52e..77cf72082e73 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -733,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/Makefile b/sound/soc/amd/acp/Makefile index 1fd581a2aa33..b068bf1f920e 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -5,23 +5,23 @@ # 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-legacy-common-objs := acp-legacy-common.o -snd-acp-pci-objs := acp-pci.o -snd-amd-sdw-acpi-objs := amd-sdw-acpi.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 #platform specific driver -snd-acp-renoir-objs := acp-renoir.o -snd-acp-rembrandt-objs := acp-rembrandt.o -snd-acp63-objs := acp63.o -snd-acp70-objs := acp70.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 acp3x-es83xx/acp3x-es83xx.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 obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index b5aff3f230be..3be7c6d55a6f 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -358,11 +358,25 @@ int smn_read(struct pci_dev *dev, u32 smn_addr) } EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON); -int check_acp_pdm(struct pci_dev *pci, struct acp_chip_info *chip) +static void check_acp3x_config(struct acp_chip_info *chip) { - struct acpi_device *pdm_dev; - const union acpi_object *obj; - u32 pdm_addr, val; + 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) { @@ -371,42 +385,94 @@ int check_acp_pdm(struct pci_dev *pci, struct acp_chip_info *chip) case ACP_CONFIG_6: case ACP_CONFIG_7: case ACP_CONFIG_8: - case ACP_CONFIG_10: 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: - return -EINVAL; + break; } +} + +void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) +{ + struct acpi_device *pdm_dev; + const union acpi_object *obj; + u32 pdm_addr; switch (chip->acp_rev) { case ACP3X_DEV: pdm_addr = ACP_RENOIR_PDM_ADDR; + check_acp3x_config(chip); break; case ACP6X_DEV: pdm_addr = ACP_REMBRANDT_PDM_ADDR; + check_acp6x_config(chip); break; case ACP63_DEV: pdm_addr = ACP63_PDM_ADDR; + check_acp6x_config(chip); break; case ACP70_DEV: pdm_addr = ACP70_PDM_ADDR; + check_acp70_config(chip); break; default: - return -EINVAL; + break; } - 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) - return 0; + 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; + } } - return -ENODEV; } -EXPORT_SYMBOL_NS_GPL(check_acp_pdm, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index 665a6ea0a2a8..a36300a4ed8a 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -217,7 +217,7 @@ 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 = snd_soc_rtd_to_codec(rtd, 0); diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 8c8b1dcac628..ad320b29e87d 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -100,7 +100,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id 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"); @@ -115,7 +114,14 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id goto unregister_dmic_dev; } - acp_init(chip); + ret = acp_init(chip); + if (ret) + goto unregister_dmic_dev; + + check_acp_config(pci, chip); + if (!chip->is_pdm_dev && !chip->is_i2s_config) + goto skip_pdev_creation; + res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL); if (!res) { ret = -ENOMEM; @@ -133,12 +139,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id } } - if (flag == FLAG_AMD_LEGACY_ONLY_DMIC) { - ret = check_acp_pdm(pci, chip); - if (ret < 0) - goto skip_pdev_creation; - } - chip->flag = flag; memset(&pdevinfo, 0, sizeof(pdevinfo)); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 5017e868f39b..d75b4eb34de8 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -138,6 +138,9 @@ struct acp_chip_info { void __iomem *base; /* ACP memory PCI base */ struct platform_device *chip_pdev; 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 */ }; struct acp_stream { @@ -212,6 +215,11 @@ 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, }; extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; @@ -240,7 +248,7 @@ void restore_acp_pdm_params(struct snd_pcm_substream *substream, int restore_acp_i2s_params(struct snd_pcm_substream *substream, struct acp_dev_data *adata, struct acp_stream *stream); -int check_acp_pdm(struct pci_dev *pci, struct acp_chip_info *chip); +void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip); static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction) { diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h index cfd6c4d07594..18da734c0e9e 100644 --- a/sound/soc/amd/acp/chip_offset_byte.h +++ b/sound/soc/amd/acp/chip_offset_byte.h @@ -20,6 +20,7 @@ #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)) diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index d6cdb6d9fdd6..357dfd016baf 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -143,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; diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile index b3c254886fd9..b5efb1c5382c 100644 --- a/sound/soc/amd/ps/Makefile +++ b/sound/soc/amd/ps/Makefile @@ -1,9 +1,9 @@ # 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-ps-sdw-dma-objs := ps-sdw-dma.o +snd-pci-ps-y := pci-ps.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 diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 66b800962f8c..2f630753278d 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -218,7 +218,7 @@ static int acp63_sdw_dma_open(struct snd_soc_component *component, struct acp_sdw_dma_stream *stream; struct snd_soc_dai *cpu_dai; struct amd_sdw_manager *amd_manager; - struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_pcm_runtime *prtd = snd_soc_substream_to_rtd(substream); int ret; runtime = substream->runtime; 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/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/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/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/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 69c68d8e7a6b..1760b5d42460 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -433,6 +433,13 @@ 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"), } 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/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/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 611da23325d3..5d208e0b4b90 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -35,10 +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_gpio.h> #include <linux/regulator/consumer.h> #include <sound/soc.h> 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/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/cirrus/Makefile b/sound/soc/cirrus/Makefile index 19a86daad660..ad606b293715 100644 --- a/sound/soc/cirrus/Makefile +++ b/sound/soc/cirrus/Makefile @@ -1,12 +1,12 @@ # 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 +snd-soc-edb93xx-y := edb93xx.o obj-$(CONFIG_SND_EP93XX_SOC_EDB93XX) += snd-soc-edb93xx.o diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f78ea2f86fa6..4afc43d3f71f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -179,7 +179,9 @@ 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_RK3308 imply SND_SOC_RK3328 imply SND_SOC_RK817 imply SND_SOC_RT274 @@ -1172,6 +1174,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 @@ -1422,6 +1425,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 @@ -1433,8 +1445,21 @@ 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_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 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7c075539dc47..b4df22186e25 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -1,397 +1,399 @@ # 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-audio-iio-aux-objs := audio-iio-aux.o -snd-soc-aw8738-objs := aw8738.o -snd-soc-aw87390-objs := aw87390.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-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-aw88395-lib-y := aw88395/aw88395_lib.o +snd-soc-aw88395-y := aw88395/aw88395.o \ aw88395/aw88395_device.o -snd-soc-aw88261-objs := aw88261.o -snd-soc-aw88399-objs := aw88399.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-cs-amp-lib-objs := cs-amp-lib.o -snd-soc-cs-amp-lib-test-objs := cs-amp-lib-test.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-cs42l43-objs := cs42l43.o cs42l43-jack.o -snd-soc-cs42l43-sdw-objs := cs42l43-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-es83xx-dsm-common-objs := es83xx-dsm-common.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-framer-objs := framer-codec.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-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-rt1017-sdca-objs := rt1017-sdca-sdw.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-rtq9128-objs := rtq9128.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-tas2781-comlib-objs := tas2781-comlib.o -snd-soc-tas2781-fmwlib-objs := tas2781-fmwlib.o -snd-soc-tas2781-i2c-objs := tas2781-i2c.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-uda1380-objs := uda1380.o -snd-soc-wcd-classh-objs := wcd-clsh-v2.o -snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o -snd-soc-wcd9335-objs := wcd9335.o -snd-soc-wcd934x-objs := wcd934x.o -snd-soc-wcd938x-objs := wcd938x.o -snd-soc-wcd938x-sdw-objs := wcd938x-sdw.o -snd-soc-wcd939x-objs := wcd939x.o -snd-soc-wcd939x-sdw-objs := wcd939x-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-wsa884x-objs := wsa884x.o -snd-soc-zl38060-objs := zl38060.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-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-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-cs53l30-y := cs53l30.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-es8316-y := es8316.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-framer-y := framer-codec.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-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-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-hdmi-codec-y := hdmi-codec.o +snd-soc-pcm1681-y := pcm1681.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-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-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-sdw-y := rt1318-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-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o +snd-soc-rt9120-y := rt9120.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-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-fmwlib-y := tas2781-fmwlib.o +snd-soc-tas2781-i2c-y := tas2781-i2c.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-uda1380-y := uda1380.o +snd-soc-wcd-classh-y := wcd-clsh-v2.o +snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o +snd-soc-wcd9335-y := wcd9335.o +snd-soc-wcd934x-y := wcd934x.o +snd-soc-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-wl1273-y := wl1273.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 @@ -594,7 +596,9 @@ 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_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 diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 68342917419e..04b5e1d5a653 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -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/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index 132b9e2cca59..2869325f9ace 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); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 3582c4b968a0..a910e252aa12 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1496,7 +1496,7 @@ 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); diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index d1392d9abccd..8bd6067df7f7 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -862,10 +862,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/adau7118-i2c.c b/sound/soc/codecs/adau7118-i2c.c index b302b28eca7c..f9dc8f4ef9a4 100644 --- a/sound/soc/codecs/adau7118-i2c.c +++ b/sound/soc/codecs/adau7118-i2c.c @@ -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/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/ak4118.c b/sound/soc/codecs/ak4118.c index 74a10108c1d4..9a43235e6a11 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -396,7 +396,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/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/ak4641.c b/sound/soc/codecs/ak4641.c index 5b7df2f0dd6a..ec33e7d73c6c 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -619,7 +619,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/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/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c index 01ef4db5407d..287ac01a3873 100644 --- a/sound/soc/codecs/cs-amp-lib.c +++ b/sound/soc/codecs/cs-amp-lib.c @@ -56,6 +56,11 @@ static int _cs_amp_write_cal_coeffs(struct cs_dsp *dsp, 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; diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index d1350ffbf3bd..96555263e10b 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -558,7 +558,7 @@ MODULE_DEVICE_TABLE(of, cs35l32_of_match); static const struct i2c_device_id cs35l32_id[] = { - {"cs35l32", 0}, + {"cs35l32"}, {} }; diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index a19a2bafb37c..b03aab147530 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -1264,7 +1264,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"}, {} }; diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index cca59de66b73..4c517231d765 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -1198,7 +1198,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); diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index ddb7d63213a3..c39b3cfe9574 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1639,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 f5bd32e434a0..bc79990615e8 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1930,7 +1930,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 a0c457c0d04b..34097996b784 100644 --- a/sound/soc/codecs/cs35l41-i2c.c +++ b/sound/soc/codecs/cs35l41-i2c.c @@ -20,10 +20,10 @@ #include "cs35l41.h" static const struct i2c_device_id cs35l41_id_i2c[] = { - { "cs35l40", 0 }, - { "cs35l41", 0 }, - { "cs35l51", 0 }, - { "cs35l53", 0 }, + { "cs35l40" }, + { "cs35l41" }, + { "cs35l51" }, + { "cs35l53" }, {} }; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index dfb4ce53491b..cb25c33cc9b9 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -772,10 +772,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, @@ -1094,6 +1093,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; @@ -1113,16 +1113,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, diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c index bc2af1ed0fe9..f5fc42dcc8c7 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); diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index 7063c400e896..2bd2ff75cd50 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -57,7 +57,7 @@ static void cs35l56_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id cs35l56_id_i2c[] = { - { "cs35l56", 0 }, + { "cs35l56" }, {} }; MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c); diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 14a5f86019aa..70ff55c1517f 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -188,8 +188,6 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) goto out; } - regcache_cache_only(cs35l56->base.regmap, false); - ret = cs35l56_init(cs35l56); if (ret < 0) { regcache_cache_only(cs35l56->base.regmap, true); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 08cac58e3ab2..8af89a263594 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -5,6 +5,7 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. +#include <linux/array_size.h> #include <linux/firmware/cirrus/wmfw.h> #include <linux/gpio/consumer.h> #include <linux/regmap.h> @@ -40,16 +41,11 @@ 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 }, - { CS35L56_ASP1_CONTROL3, 0x00000002 }, - { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, - { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, - { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, - { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, - - /* no defaults for ASP1TX mixer */ + /* + * No defaults for ASP1 control or ASP1TX mixer. See + * cs35l56_populate_asp1_register_defaults() and + * cs35l56_sync_asp1_mixer_widgets_with_firmware(). + */ { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, @@ -210,6 +206,36 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) } } +static const struct reg_sequence cs35l56_asp1_defaults[] = { + REG_SEQ0(CS35L56_ASP1_ENABLES1, 0x00000000), + REG_SEQ0(CS35L56_ASP1_CONTROL1, 0x00000028), + REG_SEQ0(CS35L56_ASP1_CONTROL2, 0x18180200), + REG_SEQ0(CS35L56_ASP1_CONTROL3, 0x00000002), + REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1, 0x03020100), + REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100), + REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018), + REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018), +}; + +/* + * The firmware can have control of the ASP so we don't provide regmap + * with defaults for these registers, to prevent a regcache_sync() from + * overwriting the firmware settings. But if the machine driver hooks up + * the ASP it means the driver is taking control of the ASP, so then the + * registers are populated with the defaults. + */ +int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base) +{ + if (!cs35l56_base->fw_owns_asp1) + return 0; + + cs35l56_base->fw_owns_asp1 = false; + + return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults, + ARRAY_SIZE(cs35l56_asp1_defaults)); +} +EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED); + /* * The firmware boot sequence can overwrite the ASP1 config registers so that * they don't match regmap's view of their values. Rewrite the values from the @@ -217,19 +243,15 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) */ int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base) { - struct reg_sequence asp1_regs[] = { - { .reg = CS35L56_ASP1_ENABLES1 }, - { .reg = CS35L56_ASP1_CONTROL1 }, - { .reg = CS35L56_ASP1_CONTROL2 }, - { .reg = CS35L56_ASP1_CONTROL3 }, - { .reg = CS35L56_ASP1_FRAME_CONTROL1 }, - { .reg = CS35L56_ASP1_FRAME_CONTROL5 }, - { .reg = CS35L56_ASP1_DATA_CONTROL1 }, - { .reg = CS35L56_ASP1_DATA_CONTROL5 }, - }; + struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)]; int i, ret; - /* Read values from regmap cache into a write sequence */ + if (cs35l56_base->fw_owns_asp1) + return 0; + + memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs)); + + /* Read current values from regmap cache into the write sequence */ for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) { ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def); if (ret) @@ -307,10 +329,10 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) reg = CS35L56_DSP1_HALO_STATE; /* - * This can't be a regmap_read_poll_timeout() because cs35l56 will NAK - * I2C until it has booted which would terminate the poll + * 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, read_ret, + 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, @@ -362,7 +384,8 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) return; cs35l56_wait_control_port_ready(); - regcache_cache_only(cs35l56_base->regmap, false); + + /* Leave in cache-only. This will be revoked when the chip has rebooted. */ } EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED); @@ -577,14 +600,14 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou cs35l56_issue_wake_event(cs35l56_base); out_sync: - regcache_cache_only(cs35l56_base->regmap, false); - 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; @@ -684,7 +707,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, SND_SOC_CS35L56_SHARED); int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base) { - u64 silicon_uid; + u64 silicon_uid = 0; int ret; /* Driver can't apply calibration to a secured part, so skip */ @@ -757,7 +780,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) * devices so the REVID needs to be determined before waiting for the * firmware to boot. */ - ret = regmap_read(cs35l56_base->regmap, CS35L56_REVID, &revid); + 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; @@ -768,7 +791,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) if (ret) return ret; - ret = regmap_read(cs35l56_base->regmap, CS35L56_DEVID, &devid); + 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; @@ -787,6 +810,9 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) 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"); diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 8d2f021fb362..758dfdf9d3ea 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -6,6 +6,7 @@ // 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> @@ -454,9 +455,14 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component); unsigned int val; + int ret; dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt); + ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); + if (ret) + return ret; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_CBC_CFC: break; @@ -530,6 +536,11 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx unsigned int rx_mask, int slots, int slot_width) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); + int ret; + + ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); + if (ret) + return ret; if ((slots == 0) || (slot_width == 0)) { dev_dbg(cs35l56->base.dev, "tdm config cleared\n"); @@ -578,6 +589,11 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream, struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); unsigned int rate = params_rate(params); u8 asp_width, asp_wl; + int ret; + + ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); + if (ret) + return ret; asp_wl = params_width(params); if (cs35l56->asp_slot_width) @@ -634,7 +650,11 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component); - int freq_id; + int freq_id, ret; + + ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base); + if (ret) + return ret; if (freq == 0) { cs35l56->sysclk_set = false; @@ -1341,6 +1361,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5 "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; } @@ -1348,6 +1369,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5 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; } @@ -1362,6 +1384,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5 */ 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"); } @@ -1369,14 +1392,17 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5 ret = devm_add_action_or_reset(cs35l56->base.dev, cs35l56_acpi_dev_release_driver_gpios, adev); - if (ret) + 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"); } @@ -1385,9 +1411,12 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5 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"); @@ -1403,6 +1432,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) cs35l56->base.cal_index = -1; cs35l56->speaker_id = -ENOENT; + /* Assume that the firmware owns ASP1 until we know different */ + cs35l56->base.fw_owns_asp1 = true; + dev_set_drvdata(cs35l56->base.dev, cs35l56); cs35l56_fill_supply_names(cs35l56->supplies); @@ -1531,6 +1563,8 @@ post_soft_reset: return ret; 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 */ diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 1ed1e60d8e53..78ffb7fa7fc5 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -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 3bbb90c827f2..67e92bfecb56 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -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/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c index 2552a1e6b82f..8d10f9328e02 100644 --- a/sound/soc/codecs/cs42l42-i2c.c +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -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"}, {} }; diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 860d5cda67bf..94685449f0f4 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2364,7 +2364,8 @@ static int cs42l43_codec_runtime_resume(struct device *dev) static int cs42l43_codec_suspend(struct device *dev) { - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + struct cs42l43_codec *priv = dev_get_drvdata(dev); + struct cs42l43 *cs42l43 = priv->core; disable_irq(cs42l43->irq); @@ -2373,7 +2374,8 @@ static int cs42l43_codec_suspend(struct device *dev) static int cs42l43_codec_suspend_noirq(struct device *dev) { - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + struct cs42l43_codec *priv = dev_get_drvdata(dev); + struct cs42l43 *cs42l43 = priv->core; enable_irq(cs42l43->irq); @@ -2382,7 +2384,8 @@ static int cs42l43_codec_suspend_noirq(struct device *dev) static int cs42l43_codec_resume(struct device *dev) { - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + struct cs42l43_codec *priv = dev_get_drvdata(dev); + struct cs42l43 *cs42l43 = priv->core; enable_irq(cs42l43->irq); @@ -2391,7 +2394,8 @@ static int cs42l43_codec_resume(struct device *dev) static int cs42l43_codec_resume_noirq(struct device *dev) { - struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + struct cs42l43_codec *priv = dev_get_drvdata(dev); + struct cs42l43 *cs42l43 = priv->core; disable_irq(cs42l43->irq); diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index 5ed2ef83dcdb..e7cc50096297 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -14,7 +14,7 @@ #include "cs42l51.h" static struct i2c_device_id cs42l51_i2c_id[] = { - {"cs42l51", 0}, + {"cs42l51"}, {} }; MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id); diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4fc8a6ae8d92..7128d4c62f50 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1215,7 +1215,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 3e3a86dab4fc..aaa10c459b52 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1330,7 +1330,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..21ba796a5cd9 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1372,7 +1372,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/cs43130.c b/sound/soc/codecs/cs43130.c index b6d829bbe3cc..be4037890fdb 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -2763,10 +2763,10 @@ MODULE_DEVICE_TABLE(acpi, cs43130_acpi_match); static const struct i2c_device_id cs43130_i2c_id[] = { - {"cs43130", 0}, - {"cs4399", 0}, - {"cs43131", 0}, - {"cs43198", 0}, + {"cs43130"}, + {"cs4399"}, + {"cs43131"}, + {"cs43198"}, {} }; diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index 2ceca5d0e5bf..d87aae31c516 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -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 ca8f21aa4837..a134ca722892 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -361,7 +361,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"}, {} }; diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index f4065555c36e..c0893146423b 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -1104,7 +1104,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" }, {} }; diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index f8b128084015..e8e22b1a1963 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1686,8 +1686,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); diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 1e232d01809c..da2d0242019e 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -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 369c62078780..a2b328f3b39f 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -2238,7 +2238,7 @@ static const struct dev_pm_ops da7213_pm = { }; static const struct i2c_device_id da7213_i2c_id[] = { - { "da7213", 0 }, + { "da7213" }, { } }; MODULE_DEVICE_TABLE(i2c, da7213_i2c_id); diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 6bc068cdcbe2..15e5e3eb592b 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -671,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; @@ -753,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; } diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index f8ca1afa8af5..b747f6fa12e4 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1546,7 +1546,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 c8a34572965d..8bb8fef2a1d1 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1511,7 +1511,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/es8316.c b/sound/soc/codecs/es8316.c index e53b2856d625..61729e5b50a8 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -887,7 +887,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/es8326.c b/sound/soc/codecs/es8326.c index 15289dadafea..833ea52638ab 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -292,11 +292,6 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = { SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0), SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL, - 4, 7, 0, 0), - SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL, - 0, 7, 0, 0), - SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), }; @@ -316,9 +311,6 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = { {"LHPMIX", NULL, "Left DAC"}, {"RHPMIX", NULL, "Right DAC"}, - {"HPOR", NULL, "HPOR Supply"}, - {"HPOL", NULL, "HPOL Supply"}, - {"HPOL", NULL, "LHPMIX"}, {"HPOR", NULL, "RHPMIX"}, }; @@ -412,9 +404,9 @@ static const struct _coeff_div coeff_div_v3[] = { {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, 0x8A, 0x1B, 0x1F, 0x3F}, - {128, 44100, 5644800, 0xE0, 0x00, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, - {128, 48000, 6144000, 0xE0, 0x00, 0x01, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {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}, @@ -423,10 +415,10 @@ static const struct _coeff_div coeff_div_v3[] = { {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, 0x8A, 0x1B, 0x1F, 0x7F}, - {256, 16000, 4096000, 0x20, 0x00, 0x01, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, - {256, 44100, 11289600, 0xE0, 0x00, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, - {256, 48000, 12288000, 0xE0, 0x00, 0x30, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, + {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}, @@ -435,10 +427,10 @@ static const struct _coeff_div coeff_div_v3[] = { {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, 0x35, 0x8A, 0x1B, 0x1F, 0x7F}, - {512, 16000, 8192000, 0x20, 0x00, 0x30, 0x35, 0x8A, 0x1B, 0x1F, 0x3F}, - {512, 44100, 22579200, 0xE0, 0x00, 0x00, 0x2D, 0xCA, 0x0A, 0x1F, 0x1F}, - {512, 48000, 24576000, 0xE0, 0x00, 0x00, 0x2D, 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}, @@ -835,7 +827,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) dev_dbg(comp->dev, "Report hp remove event\n"); snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); /* mute adc when mic path switch */ - regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); es8326->hp = 0; @@ -843,6 +834,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) 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 */ @@ -865,6 +857,8 @@ static void es8326_jack_detect_handler(struct work_struct *work) * set auto-check mode, then restart jack_detect_work after 400ms. * Don't report jack status. */ + regmap_write(es8326->regmap, ES8326_INT_SOURCE, + (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); es8326_enable_micbias(es8326->component); usleep_range(50000, 70000); @@ -891,7 +885,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) snd_soc_jack_report(es8326->jack, SND_JACK_HEADSET, SND_JACK_HEADSET); - regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33); regmap_update_bits(es8326->regmap, ES8326_PGA_PDN, 0x08, 0x08); regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, @@ -987,7 +980,7 @@ static int es8326_resume(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E); regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0); usleep_range(10000, 15000); - regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xe9); + regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xd9); regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xcb); /* set headphone default type and detect pin */ regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x83); @@ -1038,8 +1031,7 @@ static int es8326_resume(struct snd_soc_component *component) es8326_enable_micbias(es8326->component); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); - regmap_write(es8326->regmap, ES8326_INT_SOURCE, - (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk); regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, @@ -1060,6 +1052,8 @@ static int es8326_resume(struct snd_soc_component *component) es8326->hp = 0; es8326->hpl_vol = 0x03; es8326->hpr_vol = 0x03; + + es8326_irq(es8326->irq, es8326); return 0; } @@ -1070,14 +1064,18 @@ 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; } @@ -1163,8 +1161,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 = { @@ -1236,8 +1239,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); @@ -1265,6 +1291,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 ee12caef8105..c3e52e7bdef5 100644 --- a/sound/soc/codecs/es8326.h +++ b/sound/soc/codecs/es8326.h @@ -104,7 +104,7 @@ #define ES8326_MUTE (3 << 0) /* ES8326_CLK_CTL */ -#define ES8326_CLK_ON (0x7e << 0) +#define ES8326_CLK_ON (0x7f << 0) #define ES8326_CLK_OFF (0 << 0) /* ES8326_CLK_INV */ 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/hda-dai.c b/sound/soc/codecs/hda-dai.c index 7bd7ddcd810f..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> // diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index 5a58723dc0e9..ddc00927313c 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> // 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 6aa3223985be..29c88de5508b 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -230,7 +230,8 @@ static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, 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); @@ -266,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; @@ -286,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; } @@ -298,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); @@ -308,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, @@ -367,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; } @@ -381,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; } @@ -411,7 +415,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) 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; } @@ -429,7 +433,7 @@ 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; } @@ -446,7 +450,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) if (fw) { ret = snd_hda_load_patch(hcodec->bus, fw->size, fw->data); if (ret < 0) { - dev_err(&hdev->dev, "failed to load hda patch %d\n", ret); + dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret); goto error_no_pm; } release_firmware(fw); @@ -470,13 +474,13 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) 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; } @@ -484,16 +488,16 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) if (patch) { ret = patch(hcodec); if (ret < 0) { - dev_err(&hdev->dev, "patch failed %d\n", ret); + dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret); goto error_regmap; } } else { - dev_dbg(&hdev->dev, "no patch file found\n"); + dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__); } 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; } @@ -501,8 +505,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; } } @@ -548,7 +552,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) 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; } @@ -624,7 +628,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) /* 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); @@ -640,7 +644,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) 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/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/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..ab89af7965bf 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1442,7 +1442,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/max9768.c b/sound/soc/codecs/max9768.c index 8d0ca1be99c0..e4793a5d179e 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -206,7 +206,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/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 e7ec7875c4a9..1f7ff3dbcbbe 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -578,7 +578,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id max98373_i2c_id[] = { - { "max98373", 0}, + { "max98373"}, { }, }; diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 383e551f3bc7..26860882fd91 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -872,7 +872,6 @@ 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, diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c index 078adec29312..b847d7c59ec0 100644 --- a/sound/soc/codecs/max98388.c +++ b/sound/soc/codecs/max98388.c @@ -976,7 +976,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..57fa2db1e148 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -1104,7 +1104,7 @@ static int max98390_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id max98390_i2c_id[] = { - { "max98390", 0}, + { "max98390"}, {}, }; diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 8b012a85360a..c395132689b4 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -320,7 +320,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/max98520.c b/sound/soc/codecs/max98520.c index edd05253d37c..479ded22672e 100644 --- a/sound/soc/codecs/max98520.c +++ b/sound/soc/codecs/max98520.c @@ -734,7 +734,7 @@ static int max98520_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id max98520_i2c_id[] = { - { "max98520", 0}, + { "max98520"}, { }, }; diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 3b9dd158c34b..50db88fce904 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -684,7 +684,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..66c78051bd09 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -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 922ce0dc4e60..ae962bda163e 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -565,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 70db9d3ff5a5..747aa6f1d54f 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -875,7 +875,7 @@ static void max98927_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id max98927_i2c_id[] = { - { "max98927", 0}, + { "max98927"}, { }, }; diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index a45ef9d65703..c6585e8143a5 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -572,7 +572,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/mt6660.c b/sound/soc/codecs/mt6660.c index 5c50c7de26cd..39a57f643d81 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -559,7 +559,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); diff --git a/sound/soc/codecs/nau8325.c b/sound/soc/codecs/nau8325.c new file mode 100644 index 000000000000..2266f320a8f2 --- /dev/null +++ b/sound/soc/codecs/nau8325.c @@ -0,0 +1,900 @@ +// 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, + const struct i2c_device_id *id) +{ + 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 22251fb2fa1f..7e59448e7ac6 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -965,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/nau8810.c b/sound/soc/codecs/nau8810.c index 97a54059474c..dc3aaca89919 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -895,9 +895,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 012e347e6391..de5c4db05c8f 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -511,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; @@ -535,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; @@ -1697,6 +1689,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, @@ -1742,6 +1735,12 @@ static int nau8821_read_device_properties(struct device *dev, &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; } @@ -1923,7 +1922,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 62eaad130b2e..f0935ffafcbe 100644 --- a/sound/soc/codecs/nau8821.h +++ b/sound/soc/codecs/nau8821.h @@ -577,6 +577,7 @@ struct nau8821 { 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 7199d734c79f..e6909e64dfa3 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -1151,7 +1151,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..6ecd46e45923 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -215,7 +215,6 @@ struct nau8822_pll { struct nau8822 { struct device *dev; struct regmap *regmap; - int mclk_idx; struct nau8822_pll pll; int sysclk; int div_id; diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 704af1cf8cbf..f92b95b21cae 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -2003,7 +2003,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/nau8825.c b/sound/soc/codecs/nau8825.c index cd30ad649bae..bde25bc6909d 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -2934,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/pcm1681.c b/sound/soc/codecs/pcm1681.c index 316ad53bc66a..fc152496d5dc 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -291,7 +291,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/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/pcm6240.c b/sound/soc/codecs/pcm6240.c new file mode 100644 index 000000000000..86e126783a1d --- /dev/null +++ b/sound/soc/codecs/pcm6240.c @@ -0,0 +1,2217 @@ +// 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 <asm/unaligned.h> +#include <linux/firmware.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_irq.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 char *const pcmdev_ctrl_name_with_prefix[] = { + "%s Dev%d Ch%d Ana Volume", + "%s Dev%d Ch%d Digi Volume", + "%s 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_soc_kcontrol_component(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_soc_kcontrol_component(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_soc_kcontrol_component(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_kzalloc(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; + + if (comp->name_prefix) + ctrl_name = pcmdev_ctrl_name_with_prefix[name_id]; + else + 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; + } + if (comp->name_prefix) + scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + ctrl_name, comp->name_prefix, dev_no, chn); + else + 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; + + if (comp->name_prefix) + scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + "%s Profile id", comp->name_prefix); + else + 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: + if (fw_entry) + 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 (gpio_is_valid(pcm_dev->irq_info.gpio)) { + gpio_free(pcm_dev->irq_info.gpio); + free_irq(pcm_dev->irq_info.nmb, 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) +{ + const struct i2c_device_id *id = i2c_match_id(pcmdevice_i2c_id, i2c); + struct pcmdevice_priv *pcm_dev; + struct device_node *np; + unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES]; + int ret = 0, i = 0, ndev = 0; +#ifdef CONFIG_OF + const __be32 *reg, *reg_end; + int len, sw, aw; +#endif + + pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL); + if (!pcm_dev) { + ret = -ENOMEM; + goto out; + } + + pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0; + + 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; +#ifdef CONFIG_OF + aw = of_n_addr_cells(np); + sw = of_n_size_cells(np); + if (sw == 0) { + reg = (const __be32 *)of_get_property(np, + "reg", &len); + reg_end = reg + len/sizeof(*reg); + ndev = 0; + do { + dev_addrs[ndev] = of_read_number(reg, aw); + reg += aw; + ndev++; + } while (reg < reg_end); + } else { + ndev = 1; + dev_addrs[0] = i2c->addr; + } +#else + ndev = 1; + dev_addrs[0] = i2c->addr; +#endif + pcm_dev->irq_info.gpio = 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 (gpio_is_valid(pcm_dev->irq_info.gpio)) { + dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio); + + ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ"); + if (!ret) { + int gpio = pcm_dev->irq_info.gpio; + + gpio_direction_input(gpio); + pcm_dev->irq_info.nmb = gpio_to_irq(gpio); + + } else + dev_err(pcm_dev->dev, "%s: GPIO %d request error\n", + __func__, pcm_dev->irq_info.gpio); + } else + dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n", + pcm_dev->irq_info.gpio); + +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..1e125bb97286 --- /dev/null +++ b/sound/soc/codecs/pcm6240.h @@ -0,0 +1,252 @@ +/* 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_irqinfo { + int gpio; + int nmb; +}; + +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; + struct pcmdevice_irqinfo irq_info; + 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/rk3308_codec.c b/sound/soc/codecs/rk3308_codec.c new file mode 100644 index 000000000000..8b51e87a1711 --- /dev/null +++ b/sound/soc/codecs/rk3308_codec.c @@ -0,0 +1,974 @@ +// 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); + + 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) + 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/rt1011.c b/sound/soc/codecs/rt1011.c index d5285baad53a..a0e75b03e9dc 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2206,7 +2206,7 @@ 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); diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 1250cfaf2adc..0f806dde9c39 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1097,7 +1097,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); diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index 919a1f25e584..fed4da23cba2 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -608,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); diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index 4dbbd8bdaaac..7c8103a0d562 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -809,7 +809,6 @@ static const struct dev_pm_ops rt1017_sdca_pm = { static struct sdw_driver rt1017_sdca_sdw_driver = { .driver = { .name = "rt1017-sdca", - .owner = THIS_MODULE, .pm = &rt1017_sdca_pm, }, .probe = rt1017_sdca_sdw_probe, diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index ceb8baa6a20d..d989d06a2614 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -540,7 +540,7 @@ static const struct regmap_config rt1019_regmap = { }; static const struct i2c_device_id rt1019_i2c_id[] = { - { "rt1019", 0 }, + { "rt1019" }, { } }; MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id); diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 80888cbcf49c..c2b55be8d165 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -981,8 +981,8 @@ 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 63d4abf964d4..563df483a466 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -804,7 +804,6 @@ static const struct dev_pm_ops rt1308_pm = { static struct sdw_driver rt1308_sdw_driver = { .driver = { .name = "rt1308", - .owner = THIS_MODULE, .pm = &rt1308_pm, }, .probe = rt1308_sdw_probe, diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index 86afb429d423..b366338cea71 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -795,7 +795,7 @@ 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 47511f70119a..22f1ed4e03f1 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -537,7 +537,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; } @@ -577,12 +577,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__); } } @@ -759,7 +759,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; @@ -781,7 +781,6 @@ static const struct dev_pm_ops rt1316_pm = { static struct sdw_driver rt1316_sdw_driver = { .driver = { .name = "rt1316-sdca", - .owner = THIS_MODULE, .pm = &rt1316_pm, }, .probe = rt1316_sdw_probe, diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index ff364bde4a08..319f71f5e60d 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -606,7 +606,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; } @@ -631,8 +631,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; } @@ -835,7 +835,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; } @@ -855,7 +855,6 @@ static const struct dev_pm_ops rt1318_pm = { static struct sdw_driver rt1318_sdw_driver = { .driver = { .name = "rt1318-sdca", - .owner = THIS_MODULE, .pm = &rt1318_pm, }, .probe = rt1318_sdw_probe, diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 6e7843484250..bd61a257d7b5 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -1097,7 +1097,7 @@ 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); diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index f8994f4968c5..d0f533120c33 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1075,8 +1075,8 @@ 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); diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 03d9839a5de3..13aef6c5e91c 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1137,7 +1137,7 @@ 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); diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a8cdc3d6994d..2b3c0f9e178c 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1199,7 +1199,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); diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index e7aa60e73961..34461c462009 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1320,7 +1320,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 a64e66c2d3c4..12df0c4f2097 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1669,8 +1669,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); diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 174872ef35d2..16f3425a3e35 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2949,9 +2949,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); diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index e3ba04484813..05f574bf8b8f 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -444,6 +444,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; @@ -3186,6 +3187,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; @@ -3202,6 +3206,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse 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, @@ -3229,6 +3235,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; @@ -3621,8 +3630,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); @@ -4012,6 +4021,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]; @@ -4259,6 +4278,9 @@ static void rt5645_i2c_remove(struct i2c_client *i2c) 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); } @@ -4274,6 +4296,9 @@ 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 __maybe_unused rt5645_sys_suspend(struct device *dev) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 33a34bd0b405..00421a1f54bf 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2199,7 +2199,7 @@ 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); diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index fb094c0fe740..a2652fa6e1d7 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3815,8 +3815,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); diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index d5c2f0f2df98..3ac41d2c279b 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1224,7 +1224,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); diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 161dcb3915f9..9d32debd3689 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3307,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); diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 6f778c8f0832..47df14ba5278 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4635,7 +4635,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); diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 6d8e228ccb57..494ca3ce9b96 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2378,7 +2378,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); diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0e34293f3395..30bf96c35b58 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2871,9 +2871,9 @@ 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); diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 62f26ce9d476..ff9e14fad0cd 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -318,7 +318,7 @@ static const struct acpi_device_id rt5682_acpi_match[] = { 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 e67c2e19cb1a..5edf11e136b4 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -132,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; } @@ -315,8 +315,8 @@ 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; } @@ -400,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; } @@ -648,7 +648,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; } @@ -763,19 +763,19 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { + mutex_lock(&rt5682->disable_irq_lock); if (rt5682->disable_irq == true) { - mutex_lock(&rt5682->disable_irq_lock); sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); rt5682->disable_irq = false; - mutex_unlock(&rt5682->disable_irq_lock); } + 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; @@ -798,7 +798,6 @@ static const struct dev_pm_ops rt5682_pm = { static struct sdw_driver rt5682_sdw_driver = { .driver = { .name = "rt5682", - .owner = THIS_MODULE, .pm = &rt5682_pm, }, .probe = rt5682_sdw_probe, diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 12741668fdb3..f50f196d700d 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -3319,7 +3319,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/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 52c33d56b143..24cb895b759f 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -558,7 +558,6 @@ static const struct dev_pm_ops rt700_pm = { static struct sdw_driver rt700_sdw_driver = { .driver = { .name = "rt700", - .owner = THIS_MODULE, .pm = &rt700_pm, }, .probe = rt700_sdw_probe, diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 0ebf344a1b60..434b926f96c8 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; } @@ -930,14 +930,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; } @@ -945,8 +945,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; } diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 935e597022d3..f5933d2e085e 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -438,20 +438,20 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { + mutex_lock(&rt711->disable_irq_lock); if (rt711->disable_irq == true) { - mutex_lock(&rt711->disable_irq_lock); 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); } + 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; @@ -474,7 +474,6 @@ static const struct dev_pm_ops rt711_sdca_pm = { static struct sdw_driver rt711_sdca_sdw_driver = { .driver = { .name = "rt711-sdca", - .owner = THIS_MODULE, .pm = &rt711_sdca_pm, }, .probe = rt711_sdca_sdw_probe, diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 447154cb6010..1e8dbfc3ecd9 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; } @@ -1293,13 +1293,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; } @@ -1318,8 +1318,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; } diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 3f5773310ae8..8ca8bcd177ab 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -408,7 +408,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; } @@ -536,19 +536,19 @@ static int __maybe_unused rt711_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { + mutex_lock(&rt711->disable_irq_lock); if (rt711->disable_irq == true) { - mutex_lock(&rt711->disable_irq_lock); sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); rt711->disable_irq = false; - mutex_unlock(&rt711->disable_irq_lock); } + 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; } @@ -569,7 +569,6 @@ static const struct dev_pm_ops rt711_pm = { static struct sdw_driver rt711_sdw_driver = { .driver = { .name = "rt711", - .owner = THIS_MODULE, .pm = &rt711_pm, }, .probe = rt711_sdw_probe, diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 66eaed13b0d6..5446f9506a16 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; } @@ -428,7 +428,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; } @@ -1020,7 +1020,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; } @@ -1028,8 +1028,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; } diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 0926b26619bd..ee5435f3a80a 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; } @@ -317,7 +317,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; @@ -667,13 +668,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; } @@ -698,8 +699,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; } @@ -923,7 +924,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; @@ -976,7 +978,6 @@ 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, }, .probe = rt712_sdca_dmic_sdw_probe, diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 01ac555cd79b..ce337db86d1a 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -438,20 +438,21 @@ static int __maybe_unused rt712_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { + mutex_lock(&rt712->disable_irq_lock); if (rt712->disable_irq == true) { - mutex_lock(&rt712->disable_irq_lock); + 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); } + 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; @@ -474,7 +475,6 @@ static const struct dev_pm_ops rt712_sdca_pm = { static struct sdw_driver rt712_sdca_sdw_driver = { .driver = { .name = "rt712-sdca", - .owner = THIS_MODULE, .pm = &rt712_sdca_pm, }, .probe = rt712_sdca_sdw_probe, diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 6954fbe7ec5f..b503de9fda80 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -34,8 +34,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 +50,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; } @@ -1060,13 +1060,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; } @@ -1085,8 +1085,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; } @@ -1106,7 +1106,7 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, sampling_rate); break; default: - dev_err(component->dev, "Wrong DAI id\n"); + dev_err(component->dev, "%s: Wrong DAI id\n", __func__); return -EINVAL; } diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index ab54a67a27eb..c8dabb9b16b5 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -234,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; @@ -270,7 +270,6 @@ static const struct dev_pm_ops rt715_pm = { static struct sdw_driver rt715_sdw_driver = { .driver = { .name = "rt715-sdca", - .owner = THIS_MODULE, .pm = &rt715_pm, }, .probe = rt715_sdca_sdw_probe, diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 4533eedd7e18..7e10fd913812 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", - addr, value, ret); + "%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, @@ -477,7 +477,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 +485,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, @@ -834,15 +834,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; } @@ -893,8 +893,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; } @@ -933,7 +933,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", @@ -945,7 +945,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", diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 21f37babd148..ec255ada44e0 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: @@ -482,7 +483,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; } @@ -554,7 +555,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; @@ -577,7 +578,6 @@ static const struct dev_pm_ops rt715_pm = { static struct sdw_driver rt715_sdw_driver = { .driver = { .name = "rt715", - .owner = THIS_MODULE, .pm = &rt715_pm, }, .probe = rt715_sdw_probe, diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 9f732a5abd53..299c9b12377c 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -40,8 +40,8 @@ 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", - addr, value, ret); + pr_err("%s: Failed to set private value: %08x <= %04x %d\n", + __func__, addr, value, ret); } return ret; @@ -55,8 +55,8 @@ static int rt715_index_write_nid(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; } @@ -70,8 +70,8 @@ static int rt715_index_read_nid(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; } @@ -862,14 +862,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; } @@ -883,8 +883,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; } @@ -892,8 +892,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; } diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index eb76f4c675b6..b33da2215ade 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -467,13 +467,13 @@ static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { + mutex_lock(&rt722->disable_irq_lock); if (rt722->disable_irq == true) { - mutex_lock(&rt722->disable_irq_lock); sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_6); 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); } + mutex_unlock(&rt722->disable_irq_lock); goto regmap_sync; } @@ -503,7 +503,6 @@ static const struct dev_pm_ops rt722_sdca_pm = { static struct sdw_driver rt722_sdca_sdw_driver = { .driver = { .name = "rt722-sdca", - .owner = THIS_MODULE, .pm = &rt722_sdca_pm, }, .probe = rt722_sdca_sdw_probe, diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index 0e1c65a20392..e5bd9ef812de 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -35,8 +35,8 @@ int rt722_sdca_index_write(struct rt722_sdca_priv *rt722, 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; } @@ -51,8 +51,8 @@ int rt722_sdca_index_read(struct rt722_sdca_priv *rt722, 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; } @@ -663,7 +663,8 @@ static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, for (i = 0; i < p->count; i++) { err = regmap_write(rt722->mbq_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; @@ -1211,13 +1212,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; } @@ -1236,8 +1237,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; } @@ -1329,7 +1330,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, }, @@ -1438,9 +1439,12 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) int loop_check, chk_cnt = 100, ret; unsigned int calib_status = 0; - /* Read eFuse */ - rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL, - 0x4808); + /* 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); @@ -1474,9 +1478,6 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) if ((calib_status & 0x0040) == 0x0) break; } - /* 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); @@ -1489,8 +1490,21 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722) /* 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); } int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h index 44af8901352e..2464361a7958 100644 --- a/sound/soc/codecs/rt722-sdca.h +++ b/sound/soc/codecs/rt722-sdca.h @@ -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) 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 2f468f41b94d..7aa89e34657e 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -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.c b/sound/soc/codecs/sigmadsp.c index 56546e2394ab..201f74e3a7ae 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -805,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/sma1303.c b/sound/soc/codecs/sma1303.c index 61072e7574a0..980c48cbc348 100644 --- a/sound/soc/codecs/sma1303.c +++ b/sound/soc/codecs/sma1303.c @@ -1791,7 +1791,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/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/ssm2518.c b/sound/soc/codecs/ssm2518.c index d20d897407eb..06016e88dd27 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -793,7 +793,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/ssm4567.c b/sound/soc/codecs/ssm4567.c index 0a6f04d8f636..3e09c85abedb 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -471,7 +471,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 fcf0dbfbbbca..bd8848ea1ec2 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1154,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 612cc1d7eafe..d1450de92652 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1238,7 +1238,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 eedafef775e5..f7718491c899 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -363,7 +363,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/tas2552.c b/sound/soc/codecs/tas2552.c index 8c9dc318b0e8..40f5f27e74c0 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -742,7 +742,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); diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index a9838e0738cc..1dc719d726ab 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -738,7 +738,7 @@ 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); diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 99bf402eb566..67bc1c8b0131 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -702,7 +702,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/tas2780.c b/sound/soc/codecs/tas2780.c index 41076be23854..a18ccf5fb7ad 100644 --- a/sound/soc/codecs/tas2780.c +++ b/sound/soc/codecs/tas2780.c @@ -71,7 +71,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 +81,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 +626,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-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 45760fe19523..a6be81adcb83 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 // -// tasdevice-fmw.c -- TASDEVICE firmware support +// tas2781-fmwlib.c -- TASDEVICE firmware support // -// Copyright 2023 Texas Instruments, Inc. +// Copyright 2023 - 2024 Texas Instruments, Inc. // // Author: Shenghao Ding <shenghao-ding@ti.com> @@ -1878,7 +1878,7 @@ int tas2781_load_calibration(void *context, char *file_name, { struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; struct tasdevice *tasdev = &(tas_priv->tasdevice[i]); - const struct firmware *fw_entry; + const struct firmware *fw_entry = NULL; struct tasdevice_fw *tas_fmw; struct firmware fmw; int offset = 0; diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index f52c14b43f28..6d45df3b9ba4 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -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); diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index da89e8c681dd..bb0500e9d3ea 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -792,7 +792,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..386b99c8023b 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); 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/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/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index d5976c91766e..92246243ff94 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -56,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/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/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 6d9166d9116a..dbf448dd8864 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -427,7 +427,7 @@ static const struct dev_pm_ops ts3a227e_pm = { }; static const struct i2c_device_id ts3a227e_i2c_ids[] = { - { "ts3a227e", 0 }, + { "ts3a227e" }, { } }; MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids); diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 1eefc1fe6ea8..f8a3d1b40990 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -1485,8 +1485,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..850e5de9271e 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -3457,7 +3457,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/uda1380.c b/sound/soc/codecs/uda1380.c index 5c5751dc14e5..4f8fdd574585 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -782,7 +782,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/wcd934x.c b/sound/soc/codecs/wcd934x.c index 6813268e6a19..de870c7819ca 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -5967,7 +5967,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/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index 9fa6df48799b..1f59309d8c69 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -204,7 +204,7 @@ static int wm1250_ev1_probe(struct i2c_client *i2c) } static const struct i2c_device_id wm1250_ev1_i2c_id[] = { - { "wm1250-ev1", 0 }, + { "wm1250-ev1" }, { } }; MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id); diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 9571ea53cb3f..a07a443ba196 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -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 69c9c2bd7e7b..841247173d98 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2474,7 +2474,7 @@ static const struct dev_pm_ops wm2200_pm = { }; static const struct i2c_device_id wm2200_i2c_id[] = { - { "wm2200", 0 }, + { "wm2200" }, { } }; MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id); diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7ee4b45c0834..11bbc94a282c 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2670,7 +2670,7 @@ static const struct dev_pm_ops wm5100_pm = { }; static const struct i2c_device_id wm5100_i2c_id[] = { - { "wm5100", 0 }, + { "wm5100" }, { } }; MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 0e671cce8447..4a31d6f89502 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -668,7 +668,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 41b14538b03c..138eba7e577a 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -517,7 +517,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/wm8711.c b/sound/soc/codecs/wm8711.c index 7d339cc65208..a1c99bbf5aa1 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -454,7 +454,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 d9cc78fbf1ea..2cbd6b189416 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -295,7 +295,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 7f68ad0380e0..1254e583af51 100644 --- a/sound/soc/codecs/wm8731-i2c.c +++ b/sound/soc/codecs/wm8731-i2c.c @@ -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/wm8737.c b/sound/soc/codecs/wm8737.c index a0ba1e7dee98..efdc242c2ede 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -639,7 +639,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 a0848774427b..4863d6ac461b 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -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 b8d76cd001da..cae97fa3bcb0 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -802,8 +802,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 f42ed24314f3..38b76b7275e5 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1580,7 +1580,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/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index 7062a8b2f8b5..e80dad87219b 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); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 84d06c190411..e44fdf97796f 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1286,7 +1286,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 84ae1102ac88..c643b5377d3a 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2199,7 +2199,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/wm8940.c b/sound/soc/codecs/wm8940.c index b9432f8b64e5..8a532f7d750c 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -844,7 +844,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 4f4338326438..bae52a8a2e11 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -994,7 +994,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/wm8960.c b/sound/soc/codecs/wm8960.c index 7689fe3cc86d..00858b9c9568 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1549,7 +1549,7 @@ static void wm8960_i2c_remove(struct i2c_client *client) } 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/wm8961.c b/sound/soc/codecs/wm8961.c index 8f8330efb341..d1c731e25777 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -966,7 +966,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 7c6ed2983128..08d164ce3e49 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2886,7 +2886,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; @@ -2974,14 +2974,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); @@ -3938,7 +3938,7 @@ static const struct dev_pm_ops wm8962_pm = { }; static const struct i2c_device_id wm8962_i2c_id[] = { - { "wm8962", 0 }, + { "wm8962" }, { } }; MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index e88f323d28b2..b97c7d5bd4e7 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -691,7 +691,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 260bac695b20..0ee3655cad01 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -707,7 +707,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 718bfef302cc..40d22b36b7a9 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1056,7 +1056,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 b26d6a68e8d2..252b4a6cac04 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -1059,7 +1059,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/wm8988.c b/sound/soc/codecs/wm8988.c index 76f214f12ce0..f0e9d6e38dc0 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -896,7 +896,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..573bd3d487ba 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1238,7 +1238,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 590318aafaea..3bd9b362051b 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1314,7 +1314,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 5b788f35e5e4..f257980f9b56 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); @@ -1732,7 +1732,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 fc9894975a1d..a99908582a50 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -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 { diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 59ef2ef8ce00..1f9a9b636935 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2258,7 +2258,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 e738326e33ed..5c06cea09bd1 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -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); @@ -3069,7 +3069,7 @@ static void wm8996_i2c_remove(struct i2c_client *client) } 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/wm9081.c b/sound/soc/codecs/wm9081.c index e7ec799573d3..cb9d040b34d6 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1360,7 +1360,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 50c1cbccfdb9..26191bcc161d 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -606,8 +606,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/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index e451c009f2d9..c9d9a7b28efb 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -7,6 +7,7 @@ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> */ +#include <linux/array_size.h> #include <linux/ctype.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -403,13 +404,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, @@ -426,13 +422,11 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, if (!scratch) return -ENOMEM; - if (copy_from_user(scratch, 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); - } + else + ret = cs_dsp_coeff_lock_and_write_ctrl(cs_ctl, 0, scratch, size); + vfree(scratch); return ret; @@ -474,13 +468,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, @@ -683,23 +672,18 @@ 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); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 3c025dabaf7a..1253695bebd8 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1155,6 +1155,7 @@ static int wsa881x_probe(struct sdw_slave *pdev, pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 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); diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index b45eda80c196..2fe78eed3a48 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -1,30 +1,30 @@ # SPDX-License-Identifier: GPL-2.0 # 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 +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 @@ -53,7 +53,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 @@ -62,14 +62,14 @@ 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-spdif-y := imx-spdif.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 diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index bc07f26ba303..5ddc0c2fe53f 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -28,6 +28,7 @@ #include "../codecs/wm8994.h" #include "../codecs/tlv320aic31xx.h" #include "../codecs/nau8822.h" +#include "../codecs/wm8904.h" #define DRIVER_NAME "fsl-asoc-card" @@ -241,7 +242,7 @@ 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 device *dev = rtd->card->dev; @@ -709,6 +710,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; if (codec_dev) priv->codec_priv.mclk = devm_clk_get(codec_dev, NULL); + } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) { + codec_dai_name = "wm8904-hifi"; + priv->codec_priv.mclk_id = WM8904_FLL_MCLK; + priv->codec_priv.fll_id = WM8904_CLK_FLL; + priv->codec_priv.pll_id = WM8904_FLL_MCLK; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); ret = -EINVAL; @@ -935,6 +942,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-si476x", }, { .compatible = "fsl,imx-audio-wm8958", }, { .compatible = "fsl,imx-audio-nau8822", }, + { .compatible = "fsl,imx-audio-wm8904", }, {} }; MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids); diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 00852f174a69..bc41a0666856 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -135,7 +135,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 = { @@ -190,19 +189,40 @@ 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; if (of_property_read_bool(np, "fsl,enable-lpa")) { rpmsg->enable_lpa = 1; @@ -236,21 +256,10 @@ 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) goto err_pm_disable; - 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); - goto err_pm_disable; - } - return 0; err_pm_disable: diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ab6ec1974807..4ca3a16f7ac0 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1401,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; diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index 289e47c03d40..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,6 +127,7 @@ 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", @@ -126,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-card.c b/sound/soc/fsl/imx-card.c index cb8723965f2f..0e18ccabe28c 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -252,7 +252,7 @@ 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]; @@ -289,7 +289,7 @@ 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_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); @@ -405,7 +405,7 @@ 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]; diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 6f0d031c1d5f..5b9648f3b087 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -3,7 +3,7 @@ // 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> @@ -23,12 +23,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, @@ -54,8 +53,8 @@ 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)) { + 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, @@ -64,7 +63,7 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) 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); @@ -174,7 +173,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 diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index e454085c6e5c..fe47b439a818 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -32,7 +32,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0); diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index fb9244c1e9c5..b0944a07ab47 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -16,7 +16,7 @@ #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 | @@ -316,7 +316,7 @@ 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_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); @@ -461,7 +461,7 @@ 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_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; @@ -515,7 +515,7 @@ 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_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); @@ -732,9 +732,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 @@ -822,9 +819,17 @@ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = { 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, + .id_table = imx_rpmsg_pcm_id_table, .driver = { .name = IMX_PCM_DRV_NAME, .pm = &imx_rpmsg_pcm_pm_ops, diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index e5bd63dab10c..0f1ad7ad7d27 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -108,10 +108,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; @@ -127,10 +125,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]; @@ -152,6 +146,23 @@ static int imx_rpmsg_probe(struct platform_device *pdev) */ 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) { @@ -170,7 +181,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 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-card2.c b/sound/soc/generic/audio-graph-card2.c index 62606e20be9a..81e84095107e 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1197,14 +1197,12 @@ static int graph_count_c2c(struct simple_util_priv *priv, { 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 *port1 = of_get_next_child(ports, of_node_get(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); - /* * codec2codec { * ports { diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 81077d16d22f..b4876b4f259d 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -752,8 +752,6 @@ int simple_util_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"; diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index dacc29fcf24b..b69a364d619e 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -395,7 +395,7 @@ 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; diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index f442d985ab87..6f9831c6d6e0 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -401,7 +401,7 @@ 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; diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 4b9e498e3303..38b61dfd1487 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -214,6 +214,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 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/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/avs/Makefile b/sound/soc/intel/avs/Makefile index 5480500337f8..5139a019a4ad 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,17 +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 \ +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-objs += cldma.o -snd-soc-avs-objs += skl.o apl.o cnl.o icl.o tgl.o +snd-soc-avs-y += cldma.o +snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.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 c21ecaef9eba..27516ef57185 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,11 +8,28 @@ #include <linux/devcoredump.h> #include <linux/slab.h> +#include <sound/hdaudio_ext.h> #include "avs.h" #include "messages.h" #include "path.h" #include "topology.h" +static irqreturn_t avs_apl_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_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) @@ -237,8 +254,7 @@ 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_irq_handler, - .irq_thread = avs_skl_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, diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index f80f79415344..eca6ec0428bb 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> @@ -46,8 +46,7 @@ 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)(struct avs_dev *); - irqreturn_t (* const irq_thread)(struct avs_dev *); + 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); @@ -107,7 +106,7 @@ struct avs_spec { }; struct avs_fw_entry { - char *name; + const char *name; const struct firmware *fw; struct list_head node; @@ -151,7 +150,6 @@ struct avs_dev { 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; @@ -245,7 +243,6 @@ struct avs_ipc { #define AVS_IPC_RET(ret) \ (((ret) <= 0) ? (ret) : -AVS_EIPC) -irqreturn_t avs_irq_handler(struct avs_dev *adev); 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, const char *name); @@ -267,8 +264,8 @@ 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); -irqreturn_t avs_skl_irq_thread(struct avs_dev *adev); -irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev); +void avs_skl_ipc_interrupt(struct avs_dev *adev); +irqreturn_t avs_cnl_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, @@ -381,6 +378,7 @@ struct avs_apl_log_buffer_layout { 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)) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 8360ce557401..0266edeafc19 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,10 +10,10 @@ #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" @@ -434,8 +434,7 @@ static int avs_register_dmic_board(struct avs_dev *adev) struct snd_soc_acpi_mach mach = {{0}}; int ret; - 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; } @@ -523,7 +522,7 @@ static int avs_register_i2s_boards(struct avs_dev *adev) struct snd_soc_acpi_mach *mach; int ret; - if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) { + if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) { dev_dbg(adev->dev, "no I2S endpoints present\n"); return 0; } diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index 0ff21d55be24..4fbd936ffb3e 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -1,22 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-avs-da7219-objs := da7219.o -snd-soc-avs-dmic-objs := dmic.o -snd-soc-avs-es8336-objs := es8336.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-rt5514-objs := rt5514.o -snd-soc-avs-rt5663-objs := rt5663.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-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-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 diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index c018f84fe025..80c0a1a95654 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> // @@ -296,5 +296,6 @@ static struct platform_driver avs_da7219_driver = { module_platform_driver(avs_da7219_driver); +MODULE_DESCRIPTION("Intel da7219 machine driver"); MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index ba2bc7f689eb..a31aa471a1c2 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> @@ -96,4 +96,5 @@ static struct platform_driver avs_dmic_driver = { module_platform_driver(avs_dmic_driver); +MODULE_DESCRIPTION("Intel DMIC machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 1090082e7d5b..3bf37a8fd6e6 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -85,7 +85,7 @@ static const struct snd_kcontrol_new card_controls[] = { SOC_DAPM_PIN_SWITCH("Internal Mic"), }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone", .mask = SND_JACK_HEADPHONE, @@ -113,7 +113,7 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) if (!pins) return -ENOMEM; - 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, &data->jack, pins, num_pins); if (ret) return ret; @@ -326,4 +326,5 @@ static struct platform_driver avs_es8336_driver = { 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 79b4aca41333..430c070a1a0e 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> @@ -54,7 +54,7 @@ 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; @@ -155,7 +155,7 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) return 0; } -static struct snd_soc_dai_link probing_link = { +static const struct snd_soc_dai_link probing_link = { .name = "probing-LINK", .id = -1, .nonatomic = 1, @@ -191,7 +191,7 @@ 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; diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 28f254eb0d03..7e6c8d9c900b 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> @@ -54,76 +54,13 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in return 0; } -static int avs_create_dapm_routes(struct device *dev, int ssp_port, int tdm_slot, - 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, - AVS_STRING_FMT("ssp", "pb", ssp_port, tdm_slot)); - dr[0].source = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", " Tx", ssp_port, tdm_slot)); - if (!dr[0].sink || !dr[0].source) - return -ENOMEM; - - dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", " Rx", ssp_port, tdm_slot)); - dr[1].source = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "cp", ssp_port, tdm_slot)); - 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, int tdm_slot, - 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, - AVS_STRING_FMT("ssp", "pb", ssp_port, tdm_slot)); - 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, - AVS_STRING_FMT("ssp", "cp", ssp_port, tdm_slot)); - 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 snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; - int num_routes, num_widgets; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); @@ -156,26 +93,10 @@ static int avs_i2s_test_probe(struct platform_device *pdev) return ret; } - ret = avs_create_dapm_routes(dev, ssp_port, tdm_slot, &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, tdm_slot, &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); @@ -204,4 +125,5 @@ static struct platform_driver avs_i2s_test_driver = { module_platform_driver(avs_i2s_test_driver); +MODULE_DESCRIPTION("Intel i2s test machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index a83b95f25129..8d550e82b46a 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> @@ -154,4 +154,5 @@ static struct platform_driver avs_max98357a_driver = { module_platform_driver(avs_max98357a_driver) +MODULE_DESCRIPTION("Intel max98357a machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index 3b980a025e6f..fdef5a008daf 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> @@ -211,4 +211,5 @@ static struct platform_driver avs_max98373_driver = { module_platform_driver(avs_max98373_driver) +MODULE_DESCRIPTION("Intel max98373 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index 86dd2b228df3..082f311d8b84 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> @@ -208,4 +208,5 @@ static struct platform_driver avs_max98927_driver = { module_platform_driver(avs_max98927_driver) +MODULE_DESCRIPTION("Intel max98927 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index 1c1e2083f474..6ea9058fdb2a 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> @@ -67,7 +67,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, @@ -96,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) @@ -313,4 +313,5 @@ static struct platform_driver avs_nau8825_driver = { module_platform_driver(avs_nau8825_driver) +MODULE_DESCRIPTION("Intel nau8825 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index a9469b5ecb40..1cdc285ab810 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> @@ -69,4 +69,5 @@ static struct platform_driver avs_probe_mb_driver = { module_platform_driver(avs_probe_mb_driver); +MODULE_DESCRIPTION("Intel probe machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index bfcb8845fd15..9fcce86c6eb4 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> @@ -75,7 +75,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, @@ -102,7 +102,8 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime) 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; @@ -276,4 +277,5 @@ static struct platform_driver avs_rt274_driver = { module_platform_driver(avs_rt274_driver); +MODULE_DESCRIPTION("Intel rt274 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 28d7d86b1cc9..f157f2d19efb 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> @@ -38,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, @@ -63,8 +63,8 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime) 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; @@ -247,4 +247,5 @@ static struct platform_driver avs_rt286_driver = { module_platform_driver(avs_rt286_driver); +MODULE_DESCRIPTION("Intel rt286 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 80f490b9e118..1e85242c8dd2 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> @@ -49,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, @@ -74,8 +74,8 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime) 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; @@ -266,4 +266,5 @@ static struct platform_driver avs_rt298_driver = { module_platform_driver(avs_rt298_driver); +MODULE_DESCRIPTION("Intel rt298 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index 60105f453ae2..cfa146b6cf08 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2023 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2023 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -192,4 +192,5 @@ static struct platform_driver avs_rt5514_driver = { module_platform_driver(avs_rt5514_driver); +MODULE_DESCRIPTION("Intel rt5514 machine driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index b4762c2a7bf2..44f857e90969 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2022-2023 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2023 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -43,7 +43,7 @@ static const struct snd_soc_dapm_route card_routes[] = { { "IN1N", NULL, "Headset Mic" }, }; -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, @@ -265,4 +265,5 @@ static struct platform_driver avs_rt5663_driver = { 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 243f979fda98..0dcc6392a0cc 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> @@ -80,7 +80,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "IN1P", NULL, "Headset Mic" }, }; -static struct snd_soc_jack_pin card_jack_pins[] = { +static const struct snd_soc_jack_pin card_jack_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -341,5 +341,6 @@ static struct platform_driver avs_rt5682_driver = { module_platform_driver(avs_rt5682_driver) +MODULE_DESCRIPTION("Intel rt5682 machine driver"); MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 4a0e136835ff..63bbfc30f35e 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> @@ -37,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[] = { @@ -158,7 +156,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_ssm4567-adi"; + card->name = "avs_ssm4567"; card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -172,7 +170,6 @@ 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) @@ -200,4 +197,5 @@ static struct platform_driver avs_ssm4567_driver = { module_platform_driver(avs_ssm4567_driver) +MODULE_DESCRIPTION("Intel ssm4567 machine driver"); MODULE_LICENSE("GPL"); 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 223d3431ab81..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> */ @@ -24,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 index 5423c29ecc4e..bd3c4bb8bf5a 100644 --- a/sound/soc/intel/avs/cnl.c +++ b/sound/soc/intel/avs/cnl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -10,44 +10,73 @@ #include "avs.h" #include "messages.h" -irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev) +static void avs_cnl_ipc_interrupt(struct avs_dev *adev) { - union avs_reply_msg msg; - u32 hipctdr, hipctdd, hipctda; - - hipctdr = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR); - hipctdd = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD); - - /* Ensure DSP sent new response to process. */ - if (!(hipctdr & CNL_ADSP_HIPCTDR_BUSY)) - return IRQ_NONE; - - msg.primary = hipctdr; - msg.ext.val = 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); - /* Unmask busy interrupt. */ - snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCCTL, - AVS_ADSP_HIPCCTL_BUSY, AVS_ADSP_HIPCCTL_BUSY); - - return IRQ_HANDLED; + 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, - .irq_handler = avs_irq_handler, - .irq_thread = avs_cnl_irq_thread, + .dsp_interrupt = avs_cnl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_hda_load_basefw, .load_lib = avs_hda_load_library, diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c index 3dfa2e9816db..dc7dc45e0a0a 100644 --- a/sound/soc/intel/avs/control.c +++ b/sound/soc/intel/avs/control.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: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // Cezary Rojewski <cezary.rojewski@intel.com> diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h index 08631bde13c3..d9fac3569e8d 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> diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index d7f8940099ce..f2dc82a2abc7 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,15 +14,16 @@ // 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" @@ -209,15 +210,13 @@ 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); @@ -257,67 +256,55 @@ 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); - snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream); - - /* 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); + /* Unmask GIE, masked in irq_handler(). */ + snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN); return IRQ_HANDLED; } @@ -326,14 +313,23 @@ static irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id) { struct avs_dev *adev = dev_id; - return avs_dsp_op(adev, irq_handler); + return avs_hda_irq_handler(irq, &adev->base.core); } 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; + + status = readl(bus->ppcap + AZX_REG_PP_PPSTS); + if (status & AZX_PPCTL_PIE) + avs_dsp_op(adev, dsp_interrupt); - return avs_dsp_op(adev, irq_thread); + /* Unmask GIE, masked in irq_handler(). */ + snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN); + + return IRQ_HANDLED; } static int avs_hdac_acquire_irq(struct avs_dev *adev) @@ -343,13 +339,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); @@ -530,8 +526,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); @@ -548,9 +542,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); diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index 4dfbff0ce508..3fc2bbb63369 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> diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c index aa03af4473e9..7b47e52c2b39 100644 --- a/sound/soc/intel/avs/dsp.c +++ b/sound/soc/intel/avs/dsp.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> diff --git a/sound/soc/intel/avs/icl.c b/sound/soc/intel/avs/icl.c index 9d9921e1cd4d..f8d327ea2656 100644 --- a/sound/soc/intel/avs/icl.c +++ b/sound/soc/intel/avs/icl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -52,22 +52,25 @@ union avs_icl_memwnd2_slot_type { 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[PAGE_SIZE]; + u8 rsvd[SZ_4K]; }; - u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][PAGE_SIZE]; + 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 }) @@ -89,8 +92,7 @@ static int avs_icl_slot_offset(struct avs_dev *adev, union avs_icl_memwnd2_slot_ 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) + - avs_skl_log_buffer_offset(adev, i); + return offsetof(struct avs_icl_memwnd2, slot_array) + i * SZ_4K; return -ENXIO; } @@ -110,6 +112,10 @@ int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core) 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; } @@ -182,8 +188,7 @@ const struct avs_dsp_ops avs_icl_dsp_ops = { .power = avs_dsp_core_power, .reset = avs_dsp_core_reset, .stall = avs_dsp_core_stall, - .irq_handler = avs_irq_handler, - .irq_thread = avs_cnl_irq_thread, + .dsp_interrupt = avs_cnl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_icl_load_basefw, .load_lib = avs_hda_load_library, diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index ad0e535b3c2e..4fba46e77c47 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> @@ -301,54 +301,6 @@ void avs_dsp_process_response(struct avs_dev *adev, u64 header) complete(&ipc->busy_completion); } -irqreturn_t avs_irq_handler(struct avs_dev *adev) -{ - struct avs_ipc *ipc = adev->ipc; - const struct avs_spec *const spec = adev->spec; - 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, 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) { - /* - * As an extra precaution, mask done interrupt. Code executed - * due to complete() found below does not assume any masking. - */ - snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, - AVS_ADSP_HIPCCTL_DONE, 0); - - complete(&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); - /* unmask done interrupt */ - snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, - AVS_ADSP_HIPCCTL_DONE, - AVS_ADSP_HIPCCTL_DONE); - ret = IRQ_HANDLED; - } - - /* DSP sent new response to process */ - if (hipc_rsp & spec->hipc->rsp_busy_mask) { - /* mask busy interrupt */ - snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, - AVS_ADSP_HIPCCTL_BUSY, 0); - - ret = IRQ_WAKE_THREAD; - } - - return ret; -} - static bool avs_ipc_is_busy(struct avs_ipc *ipc) { struct avs_dev *adev = to_avs_dev(ipc->dev); diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 8e34d3536082..890efd2f1fea 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> @@ -56,6 +56,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 +65,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) { @@ -535,7 +537,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++; @@ -698,7 +700,7 @@ 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); diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index f874e4f0d95f..ec458bd51b10 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> diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 4e609a08863c..d0bdb7d9266c 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> @@ -93,12 +93,14 @@ 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); enum avs_module_msg_type { AVS_MOD_INIT_INSTANCE = 0, @@ -155,6 +157,7 @@ union avs_module_msg { } ext; }; } __packed; +static_assert(sizeof(union avs_module_msg) == 8); #define AVS_IPC_NOT_SUPPORTED 15 @@ -190,6 +193,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, @@ -226,6 +230,7 @@ union avs_notify_msg { } ext; }; } __packed; +static_assert(sizeof(union avs_notify_msg) == 8); #define AVS_MSG(hdr) { .val = hdr } @@ -264,6 +269,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; @@ -272,6 +278,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; @@ -279,6 +286,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 { @@ -332,6 +340,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); @@ -367,11 +376,13 @@ struct avs_skl_log_state { u32 enable; u32 min_priority; } __packed; +static_assert(sizeof(struct avs_skl_log_state) == 8); struct avs_skl_log_state_info { u32 core_mask; struct avs_skl_log_state logs_core[]; } __packed; +static_assert(sizeof(struct avs_skl_log_state_info) == 4); struct avs_apl_log_state_info { u32 aging_timer_period; @@ -379,6 +390,7 @@ struct avs_apl_log_state_info { u32 core_mask; 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, @@ -403,6 +415,7 @@ struct avs_icl_log_state_info { 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); @@ -521,6 +534,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; @@ -537,12 +551,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; @@ -559,11 +575,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) { @@ -577,6 +595,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); @@ -680,6 +699,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; @@ -688,12 +708,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; @@ -703,6 +725,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, @@ -726,6 +749,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; @@ -735,6 +759,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 \ @@ -747,16 +772,18 @@ union avs_gtw_attributes { u32 rsvd:31; }; } __packed; +static_assert(sizeof(union avs_gtw_attributes) == 4); 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; @@ -764,6 +791,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; @@ -772,22 +800,26 @@ struct avs_volume_cfg { u32 reserved; /* alignment */ u64 curve_duration; } __packed; +static_assert(sizeof(struct avs_volume_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; @@ -796,21 +828,25 @@ struct avs_updown_mixer_cfg { s32 coefficients[AVS_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; @@ -818,6 +854,7 @@ 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; @@ -828,11 +865,13 @@ struct avs_asrc_cfg { 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); /* Module runtime parameters */ @@ -845,6 +884,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, @@ -878,6 +918,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, @@ -894,6 +935,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, @@ -906,6 +948,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/path.c b/sound/soc/intel/avs/path.c index e785fc2a7008..f31d5e2caa7b 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" @@ -143,16 +144,17 @@ static bool avs_dma_type_is_input(u32 dma_type) static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) { - 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; + struct acpi_nhlt_format_config *ep_blob; + struct acpi_nhlt_endpoint *ep; union avs_connector_node_id node_id = {0}; - size_t cfg_size, data_size = 0; + size_t cfg_size, data_size; void *data = NULL; u32 dma_type; int ret; + data_size = sizeof(cfg->gtw_cfg.config); dma_type = t->cfg_ext->copier.dma_type; node_id.dma_type = dma_type; @@ -174,18 +176,18 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) 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); + ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, + ACPI_NHLT_DEVICETYPE_CODEC, direction, + t->cfg_ext->copier.vindex.i2s.instance); + ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq, + fmt->valid_bit_depth, fmt->bit_depth); if (!ep_blob) { dev_err(adev->dev, "no I2S ep_blob found\n"); return -ENOENT; } - data = ep_blob->caps; - data_size = ep_blob->size; + data = ep_blob->config.capabilities; + data_size = ep_blob->config.capabilities_size; /* I2S gateway's vindex is statically assigned in topology */ node_id.vindex = t->cfg_ext->copier.vindex.val; @@ -199,17 +201,16 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) 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); + ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, direction, 0); + ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq, + fmt->valid_bit_depth, fmt->bit_depth); if (!ep_blob) { dev_err(adev->dev, "no DMIC ep_blob found\n"); return -ENOENT; } - data = ep_blob->caps; - data_size = ep_blob->size; + data = ep_blob->config.capabilities; + data_size = ep_blob->config.capabilities_size; /* DMIC gateway's vindex is statically assigned in topology */ node_id.vindex = t->cfg_ext->copier.vindex.val; @@ -233,10 +234,7 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) break; } - cfg_size = sizeof(*cfg) + data_size; - /* Every config-BLOB contains gateway attributes. */ - if (data_size) - cfg_size -= sizeof(cfg->gtw_cfg.config.attrs); + cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config) + data_size; if (cfg_size > AVS_MAILBOX_SIZE) return -EINVAL; @@ -254,7 +252,7 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) /* 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); + memcpy(&cfg->gtw_cfg.config.blob, data, data_size); mod->gtw_attrs = cfg->gtw_cfg.config.attrs; @@ -367,6 +365,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; @@ -710,8 +709,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); diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h index 657f7b093e80..bfd253c9fa95 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> diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 2cafbc392cdb..88e711875004 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> @@ -22,13 +22,13 @@ 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_substream *substream; }; @@ -56,15 +56,14 @@ 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 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->dev); + 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); @@ -77,6 +76,7 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d data->substream = substream; data->template = template; + data->adev = adev; snd_soc_dai_set_dma_data(dai, substream, data); if (rtd->dai_link->ignore_suspend) @@ -85,6 +85,20 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } +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--; + + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(data); +} + static int avs_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *fe_hw_params, struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, @@ -92,7 +106,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); @@ -109,7 +122,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); @@ -137,8 +150,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; @@ -159,28 +171,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 = snd_soc_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) { @@ -209,11 +199,6 @@ 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) { @@ -265,40 +250,60 @@ 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) { - 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_stream *link_stream; + struct avs_dma_data *data; + struct hda_codec *codec; + int ret; + + ret = avs_dai_startup(substream, dai); + if (ret) + return ret; + + codec = dev_to_hda_codec(snd_soc_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) { + avs_dai_shutdown(substream, dai); + return -EBUSY; + } + + data = snd_soc_dai_get_dma_data(dai, substream); + data->link_stream = link_stream; + substream->runtime->private_data = link_stream; + return 0; } 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 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) @@ -315,7 +320,7 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn 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; @@ -339,13 +344,16 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; struct hdac_ext_link *link; + struct avs_dma_data *data; struct hda_codec *codec; struct hdac_bus *bus; unsigned int format_val; unsigned int bits; int ret; - link_stream = runtime->private_data; + data = snd_soc_dai_get_dma_data(dai, substream); + link_stream = data->link_stream; + if (link_stream->link_prepared) return 0; @@ -356,6 +364,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn stream_info->sig_bits); format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); + snd_hdac_ext_stream_decouple(bus, link_stream, true); snd_hdac_ext_stream_reset(link_stream); snd_hdac_ext_stream_setup(link_stream, format_val); @@ -366,7 +375,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_hdac_ext_bus_link_set_stream_id(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; @@ -378,14 +387,12 @@ 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 = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_stream; 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: @@ -394,7 +401,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) { @@ -417,7 +424,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) @@ -441,82 +448,106 @@ 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 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 const struct snd_pcm_hw_constraint_list hw_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; + 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; -const struct snd_soc_dai_ops avs_dai_fe_ops; + if (rule->var == SNDRV_PCM_HW_PARAM_PERIOD_SIZE) + to.min /= params_periods(params); -static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) + 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; + static const unsigned int rates[] = { + 8000, 11025, 12000, 16000, + 22050, 24000, 32000, 44100, + 48000, 64000, 88200, 96000, + 128000, 176400, 192000, + }; + static const struct snd_pcm_hw_constraint_list rate_list = { + .count = ARRAY_SIZE(rates), + .list = rates, + }; + 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; + + ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &rate_list); + 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 ret; +} + +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) { - ret = -EBUSY; - goto err; + avs_dai_shutdown(substream, dai); + return -EBUSY; } data->host_stream = host_stream; - ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto err; - - /* avoid wrap-around with wall-clock */ - ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000); - if (ret < 0) - goto err; - - ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); - if (ret < 0) - goto err; - snd_pcm_set_sync(substream); dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p", __func__, hdac_stream(host_stream)->stream_tag, substream); return 0; - -err: - kfree(data); - return ret; } static void avs_dai_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 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); 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, @@ -608,9 +639,9 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so struct snd_pcm_runtime *runtime = substream->runtime; 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; unsigned int format_val; + struct hdac_bus *bus; unsigned int bits; int ret; @@ -620,6 +651,8 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so if (hdac_stream(host_stream)->prepared) return 0; + bus = hdac_stream(host_stream)->bus; + snd_hdac_ext_stream_decouple(bus, data->host_stream, true); snd_hdac_stream_reset(hdac_stream(host_stream)); stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); @@ -635,7 +668,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so if (ret < 0) return ret; - ret = avs_dai_prepare(adev, substream, dai); + ret = avs_dai_prepare(substream, dai); if (ret) return ret; @@ -1416,7 +1449,7 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen mach = dev_get_platdata(component->card->dev); codec = mach->pdata; - sprintf(name, "%s-cpu", dev_name(&codec->core.dev)); + snprintf(name, sizeof(name), "%s-cpu", dev_name(&codec->core.dev)); for_each_component_dais_safe(component, dai, save) { int stream; @@ -1544,8 +1577,6 @@ static int avs_component_hda_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_stream; - struct hda_codec *codec; if (!rtd->dai_link->no_pcm) { struct snd_pcm_hardware hwparams = avs_pcm_hardware; @@ -1577,30 +1608,6 @@ static int avs_component_hda_open(struct snd_soc_component *component, return snd_soc_set_runtime_hwparams(substream, &hwparams); } - codec = dev_to_hda_codec(snd_soc_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 = snd_soc_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; } @@ -1611,7 +1618,6 @@ static const struct snd_soc_component_driver avs_hda_component_driver = { .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, diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 817e543036f2..f0b010956303 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> @@ -19,8 +19,11 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id struct avs_probe_cfg cfg = {{0}}; struct avs_module_entry mentry; 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 @@ -39,11 +42,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) diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h index 6126adca500c..f76e91cff2a9 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> diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c index d19f8953993f..34f859d6e5a4 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,31 +10,67 @@ #include <linux/slab.h> #include <sound/hdaudio_ext.h> #include "avs.h" +#include "cldma.h" #include "messages.h" -irqreturn_t avs_skl_irq_thread(struct avs_dev *adev) +void avs_skl_ipc_interrupt(struct avs_dev *adev) { - union avs_reply_msg msg; - u32 hipct, hipcte; + const struct avs_spec *spec = adev->spec; + u32 hipc_ack, hipc_rsp; - hipct = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT); - hipcte = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE); + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0); - /* Ensure DSP sent new response to process. */ - if (!(hipct & SKL_ADSP_HIPCT_BUSY)) - return IRQ_NONE; + hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); + hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); - msg.primary = hipct; - msg.ext.val = hipcte; - avs_dsp_process_response(adev, msg.val); + /* DSP acked host's request. */ + if (hipc_ack & spec->hipc->ack_done_mask) { + complete(&adev->ipc->done_completion); - /* 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); + /* 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); + } - return IRQ_HANDLED; + /* 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 @@ -128,8 +164,7 @@ 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_irq_handler, - .irq_thread = avs_skl_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, diff --git a/sound/soc/intel/avs/sysfs.c b/sound/soc/intel/avs/sysfs.c index cce21636fbc0..74b2e6f38d76 100644 --- a/sound/soc/intel/avs/sysfs.c +++ b/sound/soc/intel/avs/sysfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c index 0e052e7f6bac..a9019ff5e3af 100644 --- a/sound/soc/intel/avs/tgl.c +++ b/sound/soc/intel/avs/tgl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -39,8 +39,7 @@ 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, - .irq_handler = avs_irq_handler, - .irq_thread = avs_cnl_irq_thread, + .dsp_interrupt = avs_cnl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_icl_load_basefw, .load_lib = avs_hda_load_library, diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 13061bd1488b..02bae207f6ec 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> @@ -1582,6 +1582,8 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, 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; diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 6a59dd766603..7892e3797f63 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> 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/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 index 0b82a98ed024..5ee569c39380 100644 --- a/sound/soc/intel/avs/utils.h +++ b/sound/soc/intel/avs/utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2023 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 18ac3ce0752e..3ed81ab649c5 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -41,9 +41,6 @@ config SND_SOC_INTEL_SOF_CIRRUS_COMMON config SND_SOC_INTEL_SOF_NUVOTON_COMMON tristate -config SND_SOC_INTEL_SOF_SSP_COMMON - tristate - config SND_SOC_INTEL_SOF_BOARD_HELPERS tristate @@ -304,26 +301,21 @@ 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" + tristate "Broxton with DA7219 and MAX98357A 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 + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC help This adds support for ASoC machine driver for Broxton-P platforms - with DA7219 + MAX98357A/MAX98390 I2S audio codec. + with DA7219 + MAX98357A I2S audio codec. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". @@ -436,30 +428,21 @@ 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". @@ -490,6 +473,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH 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 @@ -503,7 +487,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_INTEL_SOF_MAXIM_COMMON select SND_SOC_INTEL_SOF_REALTEK_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with rt5650 or rt5682 codec. @@ -521,7 +505,7 @@ config SND_SOC_INTEL_SOF_CS42L42_MACH 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_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with cs42l42 codec. @@ -574,7 +558,7 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH select SND_SOC_INTEL_SOF_MAXIM_COMMON select SND_SOC_INTEL_SOF_NUVOTON_COMMON select SND_SOC_INTEL_SOF_REALTEK_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with nau8825 codec. @@ -587,28 +571,21 @@ 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". @@ -623,9 +600,11 @@ config SND_SOC_INTEL_SOF_DA7219_MACH 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_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with Dialog DA7219 I2S audio codec. @@ -645,7 +624,7 @@ config SND_SOC_INTEL_SOF_SSP_AMP_MACH select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_INTEL_SOF_REALTEK_COMMON select SND_SOC_INTEL_SOF_CIRRUS_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with RT1308/CS35L41 I2S audio codec. @@ -677,7 +656,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE - select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_MAX98363 select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW @@ -699,10 +677,10 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_CS42L43_SDW select MFD_CS42L43 select MFD_CS42L43_SDW + 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 bbf796a5f7ba..dc6fe110f279 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,47 +1,46 @@ # 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-sof_da7219-objs := sof_da7219.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-ehl-rt5660-objs := ehl_rt5660.o -snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o -snd-soc-sof-sdw-objs += sof_sdw.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-bxt-da7219_max98357a-y := bxt_da7219_max98357a.o +snd-soc-sst-bxt-rt298-y := bxt_rt298.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-kbl_da7219_max98357a-y := kbl_da7219_max98357a.o +snd-soc-kbl_da7219_max98927-y := kbl_da7219_max98927.o +snd-soc-kbl_rt5663_max98927-y := kbl_rt5663_max98927.o +snd-soc-kbl_rt5663_rt5514_max98927-y := kbl_rt5663_rt5514_max98927.o +snd-soc-kbl_rt5660-y := kbl_rt5660.o +snd-soc-skl_rt286-y := skl_rt286.o +snd-soc-skl_hda_dsp-y := skl_hda_dsp_generic.o skl_hda_dsp_common.o +snd-skl_nau88l25_max98357a-y := skl_nau88l25_max98357a.o +snd-soc-skl_nau88l25_ssm4567-y := skl_nau88l25_ssm4567.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_maxim.o sof_sdw_rt_amp.o \ + bridge_cs35l56.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_rt722_sdca.o \ + sof_sdw_rt712_sdca.o sof_sdw_rt722_sdca.o \ + sof_sdw_rt_dmic.o \ sof_sdw_cs42l42.o sof_sdw_cs42l43.o \ sof_sdw_cs_amp.o \ sof_sdw_dmic.o \ @@ -52,11 +51,10 @@ 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_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_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 @@ -71,7 +69,6 @@ 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 @@ -86,23 +83,20 @@ 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-objs += sof_nuvoton_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-ssp-common-objs += sof_ssp_common.o -obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON) += snd-soc-intel-sof-ssp-common.o - -snd-soc-intel-sof-board-helpers-objs += sof_board_helpers.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_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index 7f20159c23e5..58db09d9b6e1 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> diff --git a/sound/soc/intel/boards/bridge_cs35l56.c b/sound/soc/intel/boards/bridge_cs35l56.c new file mode 100644 index 000000000000..c3995e724aed --- /dev/null +++ b/sound/soc/intel/boards/bridge_cs35l56.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Intel SOF Machine Driver with Cirrus Logic 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 "sof_sdw_common.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 bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->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(&card->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(&card->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 = 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 bridge_params = { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +SND_SOC_DAILINK_DEFS(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 = bridge_cs35l56_asp_init, + .c2c_params = &bridge_params, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC, + SND_SOC_DAILINK_REG(bridge_dai), +}; + +int bridge_cs35l56_count_sidecar(struct snd_soc_card *card, + int *num_dais, int *num_devs) +{ + if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { + (*num_dais)++; + (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes); + } + + return 0; +} + +int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf) +{ + if (sof_sdw_quirk & SOF_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; +} + +int bridge_cs35l56_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + if (sof_sdw_quirk & SOF_SIDECAR_AMPS) + info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes); + + return 0; +} diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 540f7a29310a..e1082bfe5ca9 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -2,7 +2,7 @@ /* * Intel Broxton-P I2S Machine Driver * - * Copyright (C) 2016, Intel Corporation. All rights reserved. + * Copyright (C) 2016, Intel Corporation * * Modified from: * Intel Skylake I2S Machine driver @@ -24,14 +24,9 @@ #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]; @@ -44,7 +39,6 @@ struct bxt_hdmi_pcm { struct bxt_card_private { struct list_head hdmi_pcm_list; bool common_hdmi_codec_drv; - int spkamp; }; enum { @@ -91,17 +85,9 @@ static const struct snd_kcontrol_new broxton_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -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), @@ -112,17 +98,9 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { 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"}, @@ -153,20 +131,10 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, { "Line Out", 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"}, @@ -177,17 +145,6 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"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", @@ -231,10 +188,7 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) int clk_freq; /* Configure sysclk for codec */ - if (soc_intel_is_cml()) - clk_freq = 24000000; - else - clk_freq = 19200000; + clk_freq = 19200000; ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN); @@ -453,10 +407,6 @@ SND_SOC_DAILINK_DEF(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"))); @@ -654,76 +604,15 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; -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; + int 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; @@ -768,6 +657,7 @@ static struct snd_soc_card broxton_audio_card = { .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = bxt_card_late_probe, }; @@ -784,70 +674,8 @@ static int broxton_audio_probe(struct platform_device *pdev) 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++) { - if (!broxton_dais[i].codecs->dai_name) - continue; - - /* 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++) { - if (!broxton_dais[i].codecs->dai_name) - continue; - - /* 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; @@ -865,8 +693,6 @@ static int broxton_audio_probe(struct platform_device *pdev) 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); diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index c0eb65c14aa9..dce6a2086f2a 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -2,7 +2,7 @@ /* * Intel Broxton-P I2S Machine Driver * - * Copyright (C) 2014-2016, Intel Corporation. All rights reserved. + * Copyright (C) 2014-2016, Intel Corporation * * Modified from: * Intel Skylake I2S Machine driver @@ -574,6 +574,7 @@ static struct snd_soc_card broxton_rt298 = { .dapm_routes = broxton_rt298_map, .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = bxt_card_late_probe, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 05f38d1f7d82..b41a1147f1c3 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -636,28 +636,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), }, { 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 679a09b63ea5..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 = snd_soc_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 = snd_soc_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 = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_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 = snd_soc_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 = snd_soc_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/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c deleted file mode 100644 index 657e4658234c..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 = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dai *codec_dai = snd_soc_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 = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_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 = snd_soc_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 = snd_soc_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..fda5a92b0006 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> diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c index 2a2fe27dff0e..1826a4dfd0f3 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> diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index a5d8965303a8..9dbc15f9d1c9 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -639,6 +639,7 @@ static struct snd_soc_card kabylake_audio_card_da7219_m98357a = { .dapm_routes = kabylake_map, .num_dapm_routes = ARRAY_SIZE(kabylake_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 98c11ec0adc0..e662da5af83b 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -1036,6 +1036,7 @@ static struct snd_soc_card kbl_audio_card_da7219_m98927 = { .codec_conf = max98927_codec_conf, .num_configs = ARRAY_SIZE(max98927_codec_conf), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; @@ -1054,6 +1055,7 @@ static struct snd_soc_card kbl_audio_card_max98927 = { .codec_conf = max98927_codec_conf, .num_configs = ARRAY_SIZE(max98927_codec_conf), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; @@ -1071,6 +1073,7 @@ static struct snd_soc_card kbl_audio_card_da7219_m98373 = { .codec_conf = max98373_codec_conf, .num_configs = ARRAY_SIZE(max98373_codec_conf), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; @@ -1088,6 +1091,7 @@ static struct snd_soc_card kbl_audio_card_max98373 = { .codec_conf = max98373_codec_conf, .num_configs = ARRAY_SIZE(max98373_codec_conf), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c index 30e0aca161cd..894d127c482a 100644 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -518,6 +518,7 @@ static struct snd_soc_card kabylake_audio_card_rt5660 = { .dapm_routes = kabylake_rt5660_map, .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 9071b1f1cbd0..e16c42e81eca 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -3,7 +3,7 @@ * Intel Kabylake I2S Machine Driver with MAXIM98927 * and RT5663 Codecs * - * Copyright (C) 2017, Intel Corporation. All rights reserved. + * Copyright (C) 2017, Intel Corporation * * Modified from: * Intel Skylake I2S Machine driver @@ -966,6 +966,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = { .codec_conf = max98927_codec_conf, .num_configs = ARRAY_SIZE(max98927_codec_conf), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; @@ -982,6 +983,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = { .dapm_routes = kabylake_5663_map, .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 178fe9c37df6..a9501cd106ff 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -3,7 +3,7 @@ * Intel Kabylake I2S Machine Driver with MAXIM98927 * RT5514 and RT5663 Codecs * - * Copyright (C) 2017, Intel Corporation. All rights reserved. + * Copyright (C) 2017, Intel Corporation * * Modified from: * Intel Kabylake I2S Machine driver supporting MAXIM98927 and @@ -791,6 +791,7 @@ static struct snd_soc_card kabylake_audio_card = { .codec_conf = max98927_codec_conf, .num_configs = ARRAY_SIZE(max98927_codec_conf), .fully_routed = true, + .disable_route_checks = true, .late_probe = kabylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index 4b0b3959182e..19b814dee4ad 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -28,6 +28,7 @@ struct skl_hda_hdmi_pcm { }; struct skl_hda_private { + struct snd_soc_card card; struct list_head hdmi_pcm_list; int pcm_count; int dai_index; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 6e172719c979..88d91c0280bb 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -92,19 +92,6 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) 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 @@ -115,9 +102,9 @@ static char hda_soc_components[30]; #define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000 -static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) +static int skl_hda_fill_card_info(struct snd_soc_card *card, + 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; @@ -199,6 +186,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; struct skl_hda_private *ctx; + struct snd_soc_card *card; int ret; dev_dbg(&pdev->dev, "entry\n"); @@ -213,30 +201,44 @@ static int skl_hda_audio_probe(struct platform_device *pdev) if (!mach) return -EINVAL; - snd_soc_card_set_drvdata(&hda_soc_card, ctx); + card = &ctx->card; + card->name = "hda-dsp", + card->owner = THIS_MODULE, + card->dai_link = skl_hda_be_dai_links, + card->dapm_widgets = skl_hda_widgets, + card->dapm_routes = skl_hda_map, + card->add_dai_link = skl_hda_add_dai_link, + card->fully_routed = true, + card->late_probe = skl_hda_card_late_probe, + + snd_soc_card_set_drvdata(card, ctx); - ret = skl_hda_fill_card_info(&mach->mach_params); + ret = skl_hda_fill_card_info(card, &mach->mach_params); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); return ret; } - ctx->pcm_count = hda_soc_card.num_links; + ctx->pcm_count = 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 (!snd_soc_acpi_sof_parent(&pdev->dev)) + card->disable_route_checks = true; 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 = 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; } diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 0e7025834594..91fe9834aab4 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -3,7 +3,7 @@ * Intel Skylake I2S Machine Driver with MAXIM98357A * and NAU88L25 * - * Copyright (C) 2015, Intel Corporation. All rights reserved. + * Copyright (C) 2015, Intel Corporation */ #include <linux/module.h> @@ -654,6 +654,7 @@ static struct snd_soc_card skylake_audio_card = { .dapm_routes = skylake_map, .num_dapm_routes = ARRAY_SIZE(skylake_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = skylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index fadc25a536b4..d53bf3516c0d 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -2,12 +2,12 @@ /* * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567 * - * Copyright (C) 2015, Intel Corporation. All rights reserved. + * Copyright (C) 2015, Intel Corporation * * Modified from: * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567 * - * Copyright (C) 2015, Intel Corporation. All rights reserved. + * Copyright (C) 2015, Intel Corporation */ #include <linux/module.h> diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index c59c60e28091..3ea03f814403 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -2,12 +2,12 @@ /* * Intel Skylake I2S Machine Driver * - * Copyright (C) 2014-2015, Intel Corporation. All rights reserved. + * Copyright (C) 2014-2015, Intel Corporation * * Modified from: * Intel Broadwell Wildcatpoint SST Audio * - * Copyright (C) 2013, Intel Corporation. All rights reserved. + * Copyright (C) 2013, Intel Corporation */ #include <linux/module.h> @@ -523,6 +523,7 @@ static struct snd_soc_card skylake_rt286 = { .dapm_routes = skylake_rt286_map, .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), .fully_routed = true, + .disable_route_checks = true, .late_probe = skylake_card_late_probe, }; diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 088894ff4165..7519c545cbe2 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation #include <sound/soc.h> #include "../common/soc-intel-quirks.h" @@ -74,6 +74,11 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd) * DAI Link Helpers */ +enum sof_dmic_be_type { + SOF_DMIC_01, + SOF_DMIC_16K, +}; + /* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */ #define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \ SOF_LINK_DMIC01, \ @@ -97,14 +102,14 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; -int sof_intel_board_set_codec_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec codec_type, int ssp_codec) +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: codec %s, ssp %d\n", be_id, - sof_ssp_get_codec_name(codec_type), ssp_codec); + 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); @@ -144,11 +149,9 @@ int sof_intel_board_set_codec_link(struct device *dev, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_codec_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_dmic_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_dmic_be_type be_type) +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; @@ -196,16 +199,14 @@ int sof_intel_board_set_dmic_link(struct device *dev, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_dmic_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_intel_hdmi_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int hdmi_id, bool idisp_codec) +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: intel hdmi, hdmi id %d, idisp codec %d\n", - be_id, hdmi_id, idisp_codec); + 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); @@ -256,16 +257,15 @@ int sof_intel_board_set_intel_hdmi_link(struct device *dev, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_intel_hdmi_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_ssp_amp_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec amp_type, int ssp_amp) +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, - sof_ssp_get_codec_name(amp_type), ssp_amp); + 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); @@ -298,11 +298,9 @@ int sof_intel_board_set_ssp_amp_link(struct device *dev, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_bt_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_bt) +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; @@ -341,11 +339,9 @@ int sof_intel_board_set_bt_link(struct device *dev, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_hdmi_in_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_hdmi) +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; @@ -383,7 +379,6 @@ int sof_intel_board_set_hdmi_in_link(struct device *dev, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); static int calculate_num_links(struct sof_card_private *ctx) { @@ -427,6 +422,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, int ret; int ssp_hdmi_in = 0; unsigned long link_order, link; + unsigned long link_ids, be_id; num_links = calculate_num_links(ctx); @@ -440,22 +436,34 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, else link_order = DEFAULT_LINK_ORDER; - dev_dbg(dev, "create dai links, link_order 0x%lx\n", 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 = sof_intel_board_set_codec_link(dev, &links[idx], - idx, - ctx->codec_type, - ctx->ssp_codec); + 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); @@ -471,8 +479,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, continue; /* at least we have dmic01 */ - ret = sof_intel_board_set_dmic_link(dev, &links[idx], - idx, SOF_DMIC_01); + 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); @@ -487,8 +494,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, continue; /* set up 2 BE links at most */ - ret = sof_intel_board_set_dmic_link(dev, &links[idx], - idx, SOF_DMIC_16K); + 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); @@ -500,10 +507,9 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, case SOF_LINK_IDISP_HDMI: /* idisp HDMI */ for (i = 1; i <= ctx->hdmi_num; i++) { - ret = sof_intel_board_set_intel_hdmi_link(dev, - &links[idx], - idx, i, - ctx->hdmi.idisp_codec); + 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); @@ -511,6 +517,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, } idx++; + be_id++; } break; case SOF_LINK_AMP: @@ -518,10 +525,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, if (ctx->amp_type == CODEC_NONE) continue; - ret = sof_intel_board_set_ssp_amp_link(dev, &links[idx], - idx, - ctx->amp_type, - ctx->ssp_amp); + 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); @@ -536,8 +541,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, if (!ctx->bt_offload_present) continue; - ret = sof_intel_board_set_bt_link(dev, &links[idx], idx, - ctx->ssp_bt); + 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); @@ -549,10 +554,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, case SOF_LINK_HDMI_IN: /* HDMI-In */ for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { - ret = sof_intel_board_set_hdmi_in_link(dev, - &links[idx], - idx, - ssp_hdmi_in); + 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); @@ -560,6 +563,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, } idx++; + be_id++; } break; case SOF_LINK_NONE: @@ -584,26 +588,51 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, } EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, - const char * const dai_name[], int num_dais) +struct sof_card_private * +sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk) { - struct snd_soc_dai *dai; - int index; - int i; + struct sof_card_private *ctx; - for (index = 0; index < num_dais; index++) - for_each_rtd_codec_dais(rtd, i, dai) - if (strstr(dai->name, dai_name[index])) { - dev_dbg(rtd->card->dev, "get dai %s\n", dai->name); - return dai; - } + 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 NULL; + return ctx; } -EXPORT_SYMBOL_NS(get_codec_dai_by_name, SND_SOC_INTEL_SOF_BOARD_HELPERS); +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_INTEL_SOF_SSP_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 index f42d5d640321..dfcc2c5c25cc 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -7,8 +7,46 @@ #define __SOF_INTEL_BOARD_HELPERS_H #include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> #include "sof_hdmi_common.h" -#include "sof_ssp_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, @@ -33,15 +71,42 @@ enum { (((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 + * + * @is_jsl_board: true for JSL boards + * @mclk_en: true for mclk pin is connected + * @pll_bypass: true for PLL bypass mode + */ +struct sof_da7219_private { + bool is_jsl_board; + 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; }; /* @@ -61,14 +126,16 @@ struct sof_rt5682_private { * @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 sof_ssp_codec codec_type; - enum sof_ssp_codec amp_type; + enum snd_soc_acpi_intel_codec codec_type; + enum snd_soc_acpi_intel_codec amp_type; int dmic_be_num; int hdmi_num; @@ -84,41 +151,22 @@ struct sof_card_private { 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; }; }; -enum sof_dmic_be_type { - SOF_DMIC_01, - SOF_DMIC_16K, -}; - 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); - -int sof_intel_board_set_codec_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec codec_type, int ssp_codec); -int sof_intel_board_set_dmic_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_dmic_be_type be_type); -int sof_intel_board_set_intel_hdmi_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int hdmi_id, bool idisp_codec); -int sof_intel_board_set_ssp_amp_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec amp_type, int ssp_amp); -int sof_intel_board_set_bt_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_bt); -int sof_intel_board_set_hdmi_in_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_hdmi); - -struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, - const char * const dai_name[], int num_dais); +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.h b/sound/soc/intel/boards/sof_cirrus_common.h index d4ecf8d023d1..1c87637b9ef7 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.h +++ b/sound/soc/intel/boards/sof_cirrus_common.h @@ -9,7 +9,7 @@ #define __SOF_CIRRUS_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Cirrus Logic CS35L41/CS35L53 diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 323b86c42ef9..f4fee2ee0d63 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -22,23 +22,6 @@ #include "../common/soc-intel-quirks.h" #include "sof_board_helpers.h" #include "sof_maxim_common.h" -#include "sof_ssp_common.h" - -#define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0)) -#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_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) static struct snd_soc_jack_pin jack_pins[] = { { @@ -52,7 +35,7 @@ static struct snd_soc_jack_pin jack_pins[] = { }; /* Default: SSP2 */ -static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2); +static unsigned long sof_cs42l42_quirk = SOF_SSP_PORT_CODEC(2); static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) { @@ -229,48 +212,26 @@ static int sof_audio_probe(struct platform_device *pdev) struct sof_card_private *ctx; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_cs42l42_quirk); + if (!ctx) + return -ENOMEM; if (soc_intel_is_glk()) { ctx->dmic_be_num = 1; - ctx->hdmi_num = 3; /* overwrite the DAI link order for GLK boards */ ctx->link_order_overwrite = GLK_LINK_ORDER; - } else { - ctx->dmic_be_num = 2; - ctx->hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >> - SOF_CS42L42_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; } if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); - - /* port number of peripherals attached to ssp interface */ - ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> - SOF_CS42L42_SSP_BT_SHIFT; - - ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> - SOF_CS42L42_SSP_AMP_SHIFT; - - ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; - - if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) - ctx->bt_offload_present = true; - /* update dai_link */ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx); if (ret) @@ -293,21 +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_CS42L42_SSP_AMP(1)), + .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_CS42L42_SSP_AMP(1)), + .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_CS42L42_SSP_AMP(1) | - SOF_CS42L42_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_PRESENT | - SOF_CS42L42_SSP_BT(2)), + .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)), }, { } }; @@ -329,4 +305,3 @@ MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); 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_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c index 6eb5a6144e97..886771e9b9d6 100644 --- a/sound/soc/intel/boards/sof_da7219.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -15,35 +15,27 @@ #include <sound/soc-acpi.h> #include <sound/sof.h> #include "../../codecs/da7219.h" -#include "hda_dsp_common.h" -#include "sof_hdmi_common.h" +#include "sof_board_helpers.h" #include "sof_maxim_common.h" -#include "sof_ssp_common.h" -/* Board Quirks */ +/* 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" -struct card_private { - struct snd_soc_jack headset_jack; - struct sof_hdmi_private hdmi; - enum sof_ssp_codec codec_type; - enum sof_ssp_codec amp_type; - - unsigned int pll_bypass:1; -}; - 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 card_private *ctx = snd_soc_card_get_drvdata(card); + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai *codec_dai; int ret = 0; - if (ctx->pll_bypass) + if (ctx->da7219.pll_bypass) return ret; /* PLL SRM mode */ @@ -74,8 +66,6 @@ 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"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), }; static const struct snd_soc_dapm_widget widgets[] = { @@ -83,14 +73,9 @@ static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_LINE("Line Out", 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[] = { @@ -102,9 +87,6 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, { "Line Out", NULL, "Platform Clock" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, }; static struct snd_soc_jack_pin jack_pins[] = { @@ -124,7 +106,7 @@ static struct snd_soc_jack_pin jack_pins[] = { static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) { - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + 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; @@ -147,7 +129,8 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * 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 (mclk_rate == 12288000 || mclk_rate == 24576000) { + 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); @@ -157,7 +140,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ctx->pll_bypass = 1; + ctx->da7219.pll_bypass = true; } /* @@ -188,6 +171,13 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) 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 max98373_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -222,215 +212,11 @@ static const struct snd_soc_ops max98373_ops = { .hw_params = max98373_hw_params, }; -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 = snd_soc_rtd_to_codec(rtd, 0); - - ctx->hdmi.hdmi_comp = dai->component; - - return 0; -} - static int card_late_probe(struct snd_soc_card *card) { - struct card_private *ctx = snd_soc_card_get_drvdata(card); - - 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); + return sof_intel_board_card_late_probe(card); } -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(ssp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); -SND_SOC_DAILINK_DEF(dummy_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-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_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(idisp4_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin"))); -SND_SOC_DAILINK_DEF(idisp4_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4"))); - -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 jsl_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 */ - SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, 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_dai_link adl_dais[] = { - /* Back End DAI links */ - { - .name = "SSP0-Codec", - .id = 0, - .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 = 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), - }, - { - .name = "iDisp4", - .id = 6, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), - }, - { - .name = "SSP1-Codec", - .id = 7, - .no_pcm = 1, - .dpcm_playback = 1, - /* feedback stream or firmware-generated echo reference */ - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform), - }, - { - .name = "SSP2-BT", - .id = 8, - .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp2_pin, dummy_codec, platform), - }, -}; - static struct snd_soc_card card_da7219 = { .name = "da7219", /* the sof- prefix is added by the core */ .owner = THIS_MODULE, @@ -444,82 +230,218 @@ static struct snd_soc_card card_da7219 = { .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); + + if (ctx->da7219.is_jsl_board) { + ctx->amp_link->ops = &max98373_ops; /* use local ops */ + } else { + /* TBD: implement the amp for later platform */ + dev_err(dev, "max98373 not support yet\n"); + return -EINVAL; + } + 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 snd_soc_dai_link *dai_links; - struct card_private *ctx; + struct sof_card_private *ctx; + char *card_name; unsigned long board_quirk = 0; - int ret, amp_idx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + int ret; if (pdev->id_entry && pdev->id_entry->driver_data) board_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + 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_JSL_BOARD) { + 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_MAX98360A: - card_da7219.name = devm_kstrdup(&pdev->dev, - "da7219max98360a", - GFP_KERNEL); + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "glkda7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; break; - case CODEC_MAX98373: - card_da7219.name = devm_kstrdup(&pdev->dev, "da7219max", - GFP_KERNEL); + 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) { + ctx->da7219.is_jsl_board = true; - dai_links = jsl_dais; - amp_idx = 0; + /* 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.num_links = ARRAY_SIZE(jsl_dais); - } else { - dai_links = adl_dais; - amp_idx = 7; + 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.num_links = ARRAY_SIZE(adl_dais); + card_da7219.name = card_name; + break; + default: + break; + } } - dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + if (board_quirk & SOF_DA7219_MCLK_EN) + ctx->da7219.mclk_en = true; - /* speaker amp */ + /* 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_MAX98360A: - max_98360a_dai_link(&dai_links[amp_idx]); - break; case CODEC_MAX98373: - dai_links[amp_idx].codecs = max_98373_components; - dai_links[amp_idx].num_codecs = ARRAY_SIZE(max_98373_components); - dai_links[amp_idx].init = max_98373_spk_codec_init; - if (board_quirk & SOF_DA7219_JSL_BOARD) { - dai_links[amp_idx].ops = &max98373_ops; /* use local ops */ - } else { - /* TBD: implement the amp for later platform */ - dev_err(&pdev->dev, "max98373 not support yet\n"); - return -EINVAL; - } - 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.dai_link = dai_links; - card_da7219.dev = &pdev->dev; ret = snd_soc_fixup_dai_links_platform_name(&card_da7219, @@ -534,16 +456,48 @@ static int audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { - .name = "jsl_mx98373_da7219", - .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD), + .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 = "jsl_mx98360_da7219", - .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD), + .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 = "adl_mx98360_da7219", - /* no quirk needed for this board */ + .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), }, { } }; @@ -564,6 +518,5 @@ 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_HDA_DSP_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_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index cf2974718271..6c40ecc04723 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_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/module.h> #include <linux/string.h> #include <sound/pcm.h> @@ -10,8 +10,23 @@ #include <sound/soc-dai.h> #include <sound/soc-dapm.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) { @@ -24,14 +39,16 @@ static unsigned int get_num_codecs(const char *hid) 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[] = { { @@ -44,7 +61,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, @@ -54,7 +71,6 @@ 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); static int max_98373_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -81,7 +97,7 @@ static int max_98373_hw_params(struct snd_pcm_substream *substream, 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 = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -124,26 +140,60 @@ 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; + 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(&card->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(&card->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) { @@ -177,6 +227,17 @@ 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_cml_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), + .name_prefix = "Right", + }, +}; + static struct snd_soc_codec_conf max_98390_codec_conf[] = { { .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), @@ -229,6 +290,7 @@ static int max_98390_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 *dai_link = rtd->dai_link; struct snd_soc_dai *codec_dai; int i, ret; @@ -238,13 +300,24 @@ static int max_98390_hw_params(struct snd_pcm_substream *substream, return -ENODEV; } - 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; + 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; @@ -287,6 +360,22 @@ static int max_98390_init(struct snd_soc_pcm_runtime *rtd) fallthrough; case 2: /* add regular speakers dapm route */ + ret = snd_soc_dapm_new_controls(&card->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(&card->dapm, max_98390_dapm_routes, ARRAY_SIZE(max_98390_dapm_routes)); if (ret) { @@ -337,6 +426,10 @@ void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) 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; diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index fe0212fbad8e..3d34c7dae6f5 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -11,7 +11,7 @@ #define __SOF_MAXIM_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Maxim MAX98373 @@ -20,13 +20,8 @@ #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 diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 719c2fbaf515..c08b4eef0bcb 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -24,27 +24,8 @@ #include "sof_realtek_common.h" #include "sof_maxim_common.h" #include "sof_nuvoton_common.h" -#include "sof_ssp_common.h" - -#define SOF_NAU8825_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_NAU8825_SSP_CODEC_MASK (GENMASK(2, 0)) -#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) - -static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0); + +static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0); static struct snd_soc_jack_pin jack_pins[] = { { @@ -159,15 +140,11 @@ static int sof_card_late_probe(struct snd_soc_card *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_route sof_map[] = { @@ -236,10 +213,7 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, max_98360a_dai_link(ctx->amp_link); break; case CODEC_MAX98373: - ctx->amp_link->codecs = max_98373_components; - ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); - ctx->amp_link->init = max_98373_spk_codec_init; - ctx->amp_link->ops = &max_98373_ops; + max_98373_dai_link(dev, ctx->amp_link); break; case CODEC_NAU8318: nau8318_set_dai_link(ctx->amp_link); @@ -264,41 +238,19 @@ static int sof_audio_probe(struct platform_device *pdev) struct sof_card_private *ctx; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); - dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk); - /* default number of DMIC DAI's */ - ctx->dmic_be_num = 2; - ctx->hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >> - SOF_NAU8825_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk); + if (!ctx) + return -ENOMEM; if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - /* port number of peripherals attached to ssp interface */ - ctx->ssp_bt = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ctx->ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> - SOF_NAU8825_SSP_AMP_SHIFT; - - ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; - - if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - ctx->bt_offload_present = true; - /* update dai_link */ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx); if (ret) @@ -312,10 +264,10 @@ static int sof_audio_probe(struct platform_device *pdev) case CODEC_RT1015P: sof_rt1015p_codec_conf(&sof_audio_card_nau8825); break; - case CODEC_NONE: case CODEC_MAX98360A: case CODEC_NAU8318: case CODEC_RT1019P: + case CODEC_NONE: /* no codec conf required */ break; default: @@ -339,34 +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_NAU8825_SSP_AMP(2) | - SOF_NAU8825_NUM_HDMIDEV(4)), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .name = "adl_nau8825_def", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - 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(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "rpl_nau8825_def", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - 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(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_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), }, { } }; @@ -392,4 +343,3 @@ 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); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_nuvoton_common.h b/sound/soc/intel/boards/sof_nuvoton_common.h index 53a84f9a67c0..8a0f283260e7 100644 --- a/sound/soc/intel/boards/sof_nuvoton_common.h +++ b/sound/soc/intel/boards/sof_nuvoton_common.h @@ -9,7 +9,7 @@ #define __SOF_NUVOTON_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Nuvoton NAU8318 diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index 80c8687cd1da..dda346e0f737 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,6 +129,8 @@ 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, @@ -118,28 +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; + 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(&card->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(&card->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(&card->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(&card->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); -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); @@ -149,59 +314,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) { @@ -219,12 +346,22 @@ static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->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(&card->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(&card->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,7 +370,7 @@ 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; } @@ -241,11 +378,6 @@ 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); @@ -348,8 +480,42 @@ 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; + unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID); + int ret; + + switch (num_codecs) { + case 2: + ret = snd_soc_dapm_new_controls(&card->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(&rtd->card->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) @@ -486,6 +652,20 @@ static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; + ret = snd_soc_dapm_new_controls(&card->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(&card->dapm, rt1019p_dapm_routes, ARRAY_SIZE(rt1019p_dapm_routes)); if (ret) { diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index e3fa2924c1c1..876290555c22 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -11,7 +11,7 @@ #define __SOF_REALTEK_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Realtek ALC1011 @@ -23,15 +23,14 @@ #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 RT1015P_ACPI_HID ":00" -#define RT1015P_DEV1_NAME RT1015P_ACPI_HID ":01" void sof_rt1015p_dai_link(struct snd_soc_dai_link *link); void sof_rt1015p_codec_conf(struct snd_soc_card *card); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 640d17c6cd35..6fc6eb0c5172 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -27,37 +27,13 @@ #include "sof_board_helpers.h" #include "sof_maxim_common.h" #include "sof_realtek_common.h" -#include "sof_ssp_common.h" - -#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_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) - -/* 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) - -/* HDMI capture*/ -#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27 -#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27)) -#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ - (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) + +/* 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); + SOF_SSP_PORT_CODEC(0); static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) { @@ -72,7 +48,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, @@ -80,7 +56,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, @@ -89,25 +65,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_SSP_CODEC(1)), - }, - { - .callback = sof_rt5682_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), - }, - .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - 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, @@ -116,9 +74,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_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, @@ -128,9 +86,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_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, @@ -139,9 +97,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_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, @@ -150,9 +108,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_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, @@ -160,11 +118,10 @@ 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_RT5682_SSP_AMP(0) | - SOF_RT5682_NUM_HDMIDEV(3) | - 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 ), }, {} @@ -189,7 +146,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) int extra_jack_data; int ret, mclk_freq; - if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + 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); @@ -230,7 +187,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) } } - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + if (ctx->rt5682.is_legacy_cpu) { /* * The firmware might enable the clock at * boot (this information may or may not @@ -302,8 +259,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, 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) { + 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, @@ -351,25 +308,12 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - pll_in = params_rate(params) * 50; - } - - 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: - pll_id = RT5682S_PLL2; - clk_id = RT5682S_SCLK_S_PLL2; - break; - default: - dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type); - return -EINVAL; + /* 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; @@ -392,6 +336,40 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, 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); @@ -444,16 +422,11 @@ static int sof_card_late_probe(struct snd_soc_card *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_route sof_map[] = { @@ -465,6 +438,17 @@ static const struct snd_soc_dapm_route sof_map[] = { { "IN1P", NULL, "Headset Mic" }, }; +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" }, @@ -476,6 +460,22 @@ static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; + ret = snd_soc_dapm_new_controls(&card->dapm, rt5650_spk_widgets, + ARRAY_SIZE(rt5650_spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n", + ret); + return ret; + } + + 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(&card->dapm, rt5650_spk_dapm_routes, ARRAY_SIZE(rt5650_spk_dapm_routes)); if (ret) @@ -591,16 +591,13 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, max_98360a_dai_link(ctx->amp_link); break; case CODEC_MAX98373: - ctx->amp_link->codecs = max_98373_components; - ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); - ctx->amp_link->init = max_98373_spk_codec_init; - ctx->amp_link->ops = &max_98373_ops; + 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(ctx->amp_link); + sof_rt1011_dai_link(dev, ctx->amp_link); break; case CODEC_RT1015: sof_rt1015_dai_link(ctx->amp_link); @@ -626,90 +623,112 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, 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_acpi_mach *mach = pdev->dev.platform_data; struct sof_card_private *ctx; + char *card_name; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - 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); - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + 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; if (ctx->codec_type == CODEC_RT5650) { - sof_audio_card_rt5682.name = devm_kstrdup(&pdev->dev, "rt5650", - GFP_KERNEL); + card_name = devm_kstrdup(&pdev->dev, "rt5650", GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; /* create speaker dai link also */ if (ctx->amp_type == CODEC_NONE) ctx->amp_type = CODEC_RT5650; } + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + 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; - /* default quirk for legacy cpu */ - sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_BYTCHT_EN | - SOF_RT5682_SSP_CODEC(2); - } else { - ctx->dmic_be_num = 2; - ctx->hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >> - SOF_RT5682_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; - - if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) - ctx->hdmi.idisp_codec = true; - } - - /* need to get main clock from pmc */ - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { - ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); - if (IS_ERR(ctx->rt5682.mclk)) { - ret = PTR_ERR(ctx->rt5682.mclk); - - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); - return ret; + } 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->rt5682.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); - - /* port number/mask of peripherals attached to ssp interface */ - ctx->ssp_mask_hdmi_in = (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; - - ctx->ssp_bt = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; + if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + ctx->rt5682.mclk_en = true; - ctx->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); - ctx->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; + } - if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - ctx->bt_offload_present = true; + ret = clk_prepare_enable(ctx->rt5682.mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "could not configure MCLK state"); + return ret; + } + } + } /* update dai_link */ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx); @@ -725,7 +744,7 @@ static int sof_audio_probe(struct platform_device *pdev) max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); break; case CODEC_RT1011: - sof_rt1011_codec_conf(&sof_audio_card_rt5682); + sof_rt1011_codec_conf(&pdev->dev, &sof_audio_card_rt5682); break; case CODEC_RT1015: sof_rt1015_codec_conf(&sof_audio_card_rt5682); @@ -733,11 +752,11 @@ static int sof_audio_probe(struct platform_device *pdev) case CODEC_RT1015P: sof_rt1015p_codec_conf(&sof_audio_card_rt5682); break; - case CODEC_NONE: case CODEC_MAX98357A: case CODEC_MAX98360A: case CODEC_RT1019P: case CODEC_RT5650: + case CODEC_NONE: /* no codec conf required */ break; default: @@ -762,100 +781,94 @@ static int sof_audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { .name = "sof_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2)), + }, + { + .name = "glk_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "icl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0)), }, { - .name = "cml_rt1015_rt5682", + .name = "cml_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), }, { .name = "jsl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), }, { .name = "tgl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - 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_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - 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_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_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(1) | - SOF_RT5682_NUM_HDMIDEV(3) | + SOF_SSP_PORT_CODEC(1) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_HDMI_CAPTURE_SSP_MASK(0x5)), + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { .name = "rpl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - 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 = "rpl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - 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 = "rpl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(1) | - SOF_RT5682_NUM_HDMIDEV(3) | + SOF_SSP_PORT_CODEC(1) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_HDMI_CAPTURE_SSP_MASK(0x5)), - }, - { - .name = "mtl_mx98357_rt5682", - .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(3) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - }, - { - .name = "mtl_mx98360_rt5682", - .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(3)), + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { .name = "mtl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(2) | - SOF_RT5682_SSP_AMP(0) | - SOF_RT5682_NUM_HDMIDEV(3) | - SOF_BT_OFFLOAD_SSP(1) | - 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), }, { } }; @@ -881,4 +894,3 @@ MODULE_LICENSE("GPL v2"); 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); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 08f330ed5c2e..e41b0d95e0ff 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -5,6 +5,7 @@ * sof_sdw - ASOC Machine driver for Intel SoundWire platforms */ +#include <linux/bitmap.h> #include <linux/device.h> #include <linux/dmi.h> #include <linux/module.h> @@ -26,7 +27,7 @@ static void log_quirks(struct device *dev) 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"); + dev_err(dev, "quirk SOF_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) @@ -35,7 +36,11 @@ static void log_quirks(struct device *dev) 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"); + dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n"); + if (sof_sdw_quirk & SOF_CODEC_SPKR) + dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n"); + if (sof_sdw_quirk & SOF_SIDECAR_AMPS) + dev_dbg(dev, "quirk SOF_SIDECAR_AMPS enabled\n"); } static int sof_sdw_quirk_cb(const struct dmi_system_id *id) @@ -77,8 +82,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, @@ -86,8 +90,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 */ { @@ -138,8 +141,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, @@ -148,8 +150,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, @@ -159,7 +160,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -170,8 +170,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), + SOF_SDW_PCH_DMIC), }, { /* @@ -255,8 +254,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, @@ -287,7 +285,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -298,8 +295,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, @@ -308,8 +304,7 @@ 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 | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(SOF_SDW_TGL_HDMI), }, { .callback = sof_sdw_quirk_cb, @@ -318,8 +313,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -328,8 +322,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, @@ -338,8 +331,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, @@ -348,8 +340,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, @@ -358,8 +349,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, @@ -368,8 +358,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, @@ -397,8 +386,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { 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, @@ -426,8 +414,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, @@ -436,8 +432,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, @@ -446,8 +441,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, @@ -456,8 +450,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, @@ -466,8 +459,7 @@ 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), }, /* MeteorLake devices */ { @@ -495,6 +487,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { 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, @@ -514,6 +515,68 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; +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 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 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 snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, + const char * const dai_name[], + int num_dais) +{ + struct snd_soc_dai *dai; + int index; + int i; + + for (index = 0; index < num_dais; index++) + for_each_rtd_codec_dais(rtd, i, dai) + if (strstr(dai->name, dai_name[index])) { + dev_dbg(rtd->card->dev, "get dai %s\n", dai->name); + return dai; + } + + return NULL; +} + /* these wrappers are only needed to avoid typecast compilation errors */ int sdw_startup(struct snd_pcm_substream *substream) { @@ -662,6 +725,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_JACK, .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, .rtd_init = rt700_rtd_init, + .controls = rt700_controls, + .num_controls = ARRAY_SIZE(rt700_controls), + .widgets = rt700_widgets, + .num_widgets = ARRAY_SIZE(rt700_widgets), }, }, .dai_num = 1, @@ -678,6 +745,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt_sdca_jack_init, .exit = sof_sdw_rt_sdca_jack_exit, .rtd_init = 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, @@ -694,6 +765,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt711_init, .exit = sof_sdw_rt711_exit, .rtd_init = 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, @@ -710,13 +785,23 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt_sdca_jack_init, .exit = sof_sdw_rt_sdca_jack_exit, .rtd_init = 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", .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, .rtd_init = rt712_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 = 2, @@ -730,7 +815,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt712-sdca-dmic-aif1", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt712_sdca_dmic_rtd_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 1, @@ -747,6 +832,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt_sdca_jack_init, .exit = sof_sdw_rt_sdca_jack_exit, .rtd_init = 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, @@ -760,7 +849,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt712-sdca-dmic-aif1", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt712_sdca_dmic_rtd_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 1, @@ -777,6 +866,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt_amp_init, .exit = sof_sdw_rt_amp_exit, .rtd_init = 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, @@ -793,6 +886,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt_amp_init, .exit = sof_sdw_rt_amp_exit, .rtd_init = 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, @@ -808,6 +905,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .init = sof_sdw_rt_amp_init, .exit = sof_sdw_rt_amp_exit, .rtd_init = 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, @@ -819,10 +920,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dais = { { .direction = {false, true}, - .dai_name = "rt715-aif2", + .dai_name = "rt715-sdca-aif2", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_sdca_rtd_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 1, @@ -834,10 +935,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dais = { { .direction = {false, true}, - .dai_name = "rt715-aif2", + .dai_name = "rt715-sdca-aif2", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_sdca_rtd_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 1, @@ -852,7 +953,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt715-aif2", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_rtd_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 1, @@ -867,7 +968,7 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt715-aif2", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_rtd_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 1, @@ -883,6 +984,11 @@ static struct sof_sdw_codec_info codec_info_list[] = { .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, + .rtd_init = 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}, @@ -890,14 +996,20 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_AMP, /* No feedback capability is provided by rt722-sdca codec driver*/ .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt722_spk_init, + .init = sof_sdw_rt_amp_init, + .exit = sof_sdw_rt_amp_exit, + .rtd_init = rt722_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 = "rt722-sdca-aif3", .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .init = sof_sdw_rt722_sdca_dmic_init, + .rtd_init = rt_dmic_rtd_init, }, }, .dai_num = 3, @@ -912,6 +1024,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, .init = sof_sdw_maxim_init, .rtd_init = maxim_spk_rtd_init, + .controls = maxim_controls, + .num_controls = ARRAY_SIZE(maxim_controls), + .widgets = maxim_widgets, + .num_widgets = ARRAY_SIZE(maxim_widgets), }, }, .dai_num = 1, @@ -926,6 +1042,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, .init = sof_sdw_maxim_init, .rtd_init = maxim_spk_rtd_init, + .controls = maxim_controls, + .num_controls = ARRAY_SIZE(maxim_controls), + .widgets = maxim_widgets, + .num_widgets = ARRAY_SIZE(maxim_widgets), }, }, .dai_num = 1, @@ -939,6 +1059,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_JACK, .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, .rtd_init = 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, @@ -953,6 +1077,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, .init = sof_sdw_cs_amp_init, .rtd_init = cs_spk_rtd_init, + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), }, }, .dai_num = 1, @@ -966,6 +1092,10 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_JACK, .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, .rtd_init = 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, @@ -973,6 +1103,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { { .part_id = 0x4243, .codec_name = "cs42l43-codec", + .count_sidecar = bridge_cs35l56_count_sidecar, + .add_sidecar = bridge_cs35l56_add_sidecar, .dais = { { .direction = {true, false}, @@ -980,6 +1112,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_JACK, .dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, .rtd_init = cs42l43_hs_rtd_init, + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), }, { .direction = {false, true}, @@ -987,6 +1121,8 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, .rtd_init = cs42l43_dmic_rtd_init, + .widgets = generic_dmic_widgets, + .num_widgets = ARRAY_SIZE(generic_dmic_widgets), }, { .direction = {false, true}, @@ -994,8 +1130,19 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_type = SOF_SDW_DAI_TYPE_JACK, .dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID}, }, + { + .direction = {true, false}, + .dai_name = "cs42l43-dp6", + .dai_type = SOF_SDW_DAI_TYPE_AMP, + .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, + .init = sof_sdw_cs42l43_spk_init, + .rtd_init = cs42l43_spk_rtd_init, + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + .quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS, + }, }, - .dai_num = 3, + .dai_num = 4, }, { .part_id = 0xaaaa, /* generic codec mockup */ @@ -1006,7 +1153,6 @@ static struct sof_sdw_codec_info codec_info_list[] = { .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, @@ -1020,7 +1166,6 @@ static struct sof_sdw_codec_info codec_info_list[] = { .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, @@ -1034,7 +1179,6 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "sdw-mockup-aif1", .dai_type = SOF_SDW_DAI_TYPE_AMP, .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = NULL, }, }, .dai_num = 1, @@ -1048,14 +1192,13 @@ static struct sof_sdw_codec_info codec_info_list[] = { .direction = {false, true}, .dai_type = SOF_SDW_DAI_TYPE_MIC, .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .init = NULL, }, }, .dai_num = 1, }, }; -static inline int find_codec_info_part(const u64 adr) +static struct sof_sdw_codec_info *find_codec_info_part(const u64 adr) { unsigned int part_id, sdw_version; int i; @@ -1070,102 +1213,41 @@ static inline int find_codec_info_part(const u64 adr) 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; + return &codec_info_list[i]; - return -EINVAL; + return NULL; } -static inline int find_codec_info_acpi(const u8 *acpi_id) +static struct sof_sdw_codec_info *find_codec_info_acpi(const u8 *acpi_id) { int i; if (!acpi_id[0]) - return -EINVAL; + 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 i; + return &codec_info_list[i]; - return -EINVAL; + return NULL; } -/* - * 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_dailink_info(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - int *sdw_be_num, int *codecs_num) +static struct sof_sdw_codec_info *find_codec_info_dai(const char *dai_name, + int *dai_index) { - bool group_visited[SDW_MAX_GROUPS]; - bool no_aggregation; - int i; - int j; - - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - *sdw_be_num = 0; - - if (!adr_link) - return -EINVAL; - - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_visited[i] = false; - - for (; adr_link->num_adr; adr_link++) { - const struct snd_soc_acpi_endpoint *endpoint; - struct sof_sdw_codec_info *codec_info; - int codec_index; - int stream; - u64 adr; - - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; - - for (i = 0; i < adr_link->num_adr; i++) { - adr = 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]; - - *codecs_num += codec_info->dai_num; - - 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; - } - - endpoint = adr_link->adr_d[i].endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x\n", - adr_link->mask); - return -EINVAL; - } - - 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; + int i, j; - /* count BE for each non-aggregated slave or group */ - if (!endpoint->aggregated || no_aggregation || - !group_visited[endpoint->group_id]) - (*sdw_be_num)++; - } + 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]; } - - if (endpoint->aggregated) - group_visited[endpoint->group_id] = true; } } - return 0; + return NULL; } static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, @@ -1250,395 +1332,558 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, return true; } -static int fill_sdw_codec_dlc(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link_component *codec, - int adr_index, int dai_index) +static const char *get_codec_name(struct device *dev, + const struct sof_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index) { - unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; u64 adr = adr_link->adr_d[adr_index].adr; - int codec_index; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - - 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); - - if (codec_info_list[codec_index].codec_name) - codec->name = devm_kstrdup(dev, - codec_info_list[codec_index].codec_name, - GFP_KERNEL); + 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 (codec_info->codec_name) + return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, class_id, adr_index)) - codec->name = 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", + link_id, mfg_id, part_id, class_id); else - codec->name = devm_kasprintf(dev, GFP_KERNEL, - "sdw:0:%01x:%04x:%04x:%02x:%01x", link_id, - mfg_id, part_id, class_id, unique_id); + return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", + link_id, mfg_id, part_id, class_id, unique_id); - if (!codec->name) - return -ENOMEM; - - codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; - - return 0; + return NULL; } -static int set_codec_init_func(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link *dai_links, - bool playback, int group_id, int adr_index, int dai_index) +static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) { - int i = adr_index; + struct snd_soc_card *card = rtd->card; + struct sof_sdw_codec_info *codec_info; + struct snd_soc_dai *dai; + int dai_index; + int ret; + int i; + + for_each_rtd_codec_dais(rtd, i, dai) { + codec_info = find_codec_info_dai(dai->name, &dai_index); + if (!codec_info) + return -EINVAL; - 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 adr_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) + * 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. */ - for ( ; i < adr_link->num_adr; i++) { - int codec_index; + if (codec_info->dais[dai_index].rtd_init_done) + continue; - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; + /* + * Add card controls and dapm widgets for the first codec dai. + * The controls and widgets will be used for all codec dais. + */ - /* The group_id is > 0 iff the codec is aggregated */ - if (adr_link->adr_d[i].endpoints->group_id != group_id) - continue; + if (i > 0) + goto skip_add_controls_widgets; - if (codec_info_list[codec_index].dais[dai_index].init) - codec_info_list[codec_index].dais[dai_index].init(card, - adr_link, - dai_links, - &codec_info_list[codec_index], - playback); - if (!group_id) - return 0; + 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(&card->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; + } } - i = 0; - adr_link++; - } while (adr_link->mask); +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; + } + codec_info->dais[dai_index].rtd_init_done = true; + } 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, - int adr_index) -{ - bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - int i; +struct sof_sdw_endpoint { + struct list_head list; - if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { - cpu_dai_id[0] = ffs(adr_link->mask) - 1; - *cpu_dai_num = 1; - *codec_num = 1; - *group_id = 0; - return 0; - } + u32 link_mask; + const char *codec_name; + const char *name_prefix; + bool include_sidecar; - *codec_num = 0; - *cpu_dai_num = 0; - *group_id = adr_link->adr_d[adr_index].endpoints->group_id; + struct sof_sdw_codec_info *codec_info; + const struct sof_sdw_dai_info *dai_info; +}; - /* Count endpoints with the same group_id in the adr_link */ - for (; adr_link && adr_link->num_adr; adr_link++) { - unsigned int link_codecs = 0; +struct sof_sdw_dailink { + bool initialised; - 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) - link_codecs++; - } + u8 group_id; + u32 link_mask[SNDRV_PCM_STREAM_LAST + 1]; + int num_devs[SNDRV_PCM_STREAM_LAST + 1]; + struct list_head endpoints; +}; - if (link_codecs) { - *codec_num += link_codecs; +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; - if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { - dev_err(dev, "cpu_dai_id array overflowed\n"); - return -EINVAL; - } +static int count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +{ + 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; - cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; - } + 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++) + *num_ends += adr_link->adr_d[i].num_endpoints; } + dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); + return 0; } -static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps, - int codec_num, int cpu_num) +static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks, + const struct snd_soc_acpi_endpoint *new) { - int step; - int i; + while (dailinks->initialised) { + if (new->aggregated && dailinks->group_id == new->group_id) + return dailinks; - step = codec_num / cpu_num; - for (i = 0; i < codec_num; i++) { - sdw_codec_ch_maps[i].cpu = i / step; - sdw_codec_ch_maps[i].codec = i; + dailinks++; } -} -static inline int find_codec_info_dai(const char *dai_name, int *dai_index) -{ - int i, j; + INIT_LIST_HEAD(&dailinks->endpoints); + dailinks->group_id = new->group_id; + dailinks->initialised = true; - 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 i; - } - } - } - - return -EINVAL; + return dailinks; } -static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) +static int parse_sdw_endpoints(struct snd_soc_card *card, + struct sof_sdw_dailink *sof_dais, + struct sof_sdw_endpoint *sof_ends, + int *num_devs) { - struct sof_sdw_codec_info *codec_info; - struct snd_soc_dai *dai; - int codec_index; - int dai_index; + struct device *dev = card->dev; + struct 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 sof_sdw_endpoint *sof_end = sof_ends; + int num_dais = 0; + int i, j; int ret; - int i; - for_each_rtd_codec_dais(rtd, i, dai) { - codec_index = find_codec_info_dai(dai->name, &dai_index); - if (codec_index < 0) - return -EINVAL; + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { + int num_link_dailinks = 0; - codec_info = &codec_info_list[codec_index]; - /* - * 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; - if (codec_info->dais[dai_index].rtd_init) { - ret = codec_info->dais[dai_index].rtd_init(rtd); - if (ret) - return ret; + if (!is_power_of_2(adr_link->mask)) { + dev_err(dev, "link with multiple mask bits: 0x%x\n", + adr_link->mask); + return -EINVAL; } - codec_info->dais[dai_index].rtd_init_done = true; - } - return 0; -} - -static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; + struct sof_sdw_codec_info *codec_info; + const char *codec_name; -static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, - struct snd_soc_dai_link *dai_links, int sdw_be_num, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_codec_conf *codec_conf, - int codec_count, int *be_id, - int *codec_conf_index, - bool *ignore_pch_dmic, - bool append_dai_type, - int adr_index, - int dai_index) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct device *dev = card->dev; - const struct snd_soc_acpi_link_adr *adr_link_next; - struct snd_soc_dai_link_component *codecs; - struct snd_soc_dai_link_component *cpus; - struct sof_sdw_codec_info *codec_info; - int cpu_dai_id[SDW_MAX_CPU_DAIS]; - int cpu_dai_num; - unsigned int group_id; - int codec_dlc_index = 0; - int codec_index; - int codec_num; - int stream; - int i = 0; - int j, k; - int ret; + if (!adr_dev->name_prefix) { + dev_err(dev, "codec 0x%llx does not have a name prefix\n", + adr_dev->adr); + return -EINVAL; + } - ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, adr_index); - if (ret) - return ret; + codec_info = find_codec_info_part(adr_dev->adr); + if (!codec_info) + return -EINVAL; - codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); - if (!codecs) - return -ENOMEM; + ctx->ignore_pch_dmic |= codec_info->ignore_pch_dmic; - /* generate codec name on different links in the same group */ - j = adr_index; - for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && - i < cpu_dai_num; adr_link_next++) { - /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) - continue; + codec_name = get_codec_name(dev, codec_info, adr_link, i); + if (!codec_name) + return -ENOMEM; - /* j reset after loop, adr_index only applies to first link */ - for (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) { - const struct snd_soc_acpi_endpoint *endpoints; + dev_dbg(dev, "Adding prefix %s for %s\n", + adr_dev->name_prefix, codec_name); - endpoints = adr_link_next->adr_d[j].endpoints; + sof_end->name_prefix = adr_dev->name_prefix; - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; + if (codec_info->count_sidecar && codec_info->add_sidecar) { + ret = codec_info->count_sidecar(card, &num_dais, num_devs); + if (ret) + return ret; - /* sanity check */ - if (*codec_conf_index >= codec_count) { - dev_err(dev, "codec_conf array overflowed\n"); - return -EINVAL; + sof_end->include_sidecar = true; } - ret = fill_sdw_codec_dlc(dev, adr_link_next, - &codecs[codec_dlc_index], - j, dai_index); - if (ret) - return ret; + for (j = 0; j < adr_dev->num_endpoints; j++) { + const struct snd_soc_acpi_endpoint *adr_end; + const struct sof_sdw_dai_info *dai_info; + struct sof_sdw_dailink *sof_dai; + int stream; + + adr_end = &adr_dev->endpoints[j]; + dai_info = &codec_info->dais[adr_end->num]; + sof_dai = find_dailink(sof_dais, adr_end); + + if (dai_info->quirk && !(dai_info->quirk & sof_sdw_quirk)) + continue; + + dev_dbg(dev, + "Add dev: %d, 0x%llx end: %d, %s, %c/%c to %s: %d\n", + ffs(adr_link->mask) - 1, adr_dev->adr, + adr_end->num, type_strings[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; + } - codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; - codec_conf[*codec_conf_index].name_prefix = - adr_link_next->adr_d[j].name_prefix; + 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 += !sof_dai->num_devs[stream]; + sof_dai->num_devs[stream]++; + sof_dai->link_mask[stream] |= adr_link->mask; + } + } - codec_dlc_index++; - (*codec_conf_index)++; + num_link_dailinks += !!list_empty(&sof_dai->endpoints); + list_add_tail(&sof_end->list, &sof_dai->endpoints); + + sof_end->link_mask = adr_link->mask; + sof_end->codec_name = codec_name; + sof_end->codec_info = codec_info; + sof_end->dai_info = dai_info; + sof_end++; + } } - j = 0; - /* check next link to create codec dai in the processed group */ - i++; + ctx->append_dai_type |= (num_link_dailinks > 1); } - /* find codec info to create BE DAI */ - codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); - if (codec_index < 0) - return codec_index; - codec_info = &codec_info_list[codec_index]; + return num_dais; +} - if (codec_info->ignore_pch_dmic) - *ignore_pch_dmic = true; +static int create_sdw_dailink(struct snd_soc_card *card, + struct sof_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 mc_private *ctx = snd_soc_card_get_drvdata(card); + struct sof_sdw_endpoint *sof_end; + 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) { - struct snd_soc_dai_link_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", }; + 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 cur_link = 0; + int i = 0, j = 0; + char *name; - if (!codec_info->dais[dai_index].direction[stream]) + if (!sof_dai->num_devs[stream]) continue; - *be_id = codec_info->dais[dai_index].dailink[stream]; + sof_end = list_first_entry(&sof_dai->endpoints, + struct sof_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; } - sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, - sizeof(*sdw_codec_ch_maps), GFP_KERNEL); - if (!sdw_codec_ch_maps) - return -ENOMEM; - /* create stream name according to first link id */ - if (append_dai_type) { + if (ctx->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 { + 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], cpu_dai_id[0]); - } + sdw_stream_name[stream], + ffs(sof_end->link_mask) - 1); if (!name) return -ENOMEM; - cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL); + cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); if (!cpus) 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], - ctx->sdw_pin_index[cpu_dai_id[k]]++); - if (!cpu_name) - return -ENOMEM; + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; - cpus[k].dai_name = cpu_name; - } + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); + if (!codec_maps) + return -ENOMEM; - /* - * 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\n", *link_index); - return -EINVAL; + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (!sof_end->dai_info->direction[stream]) + continue; + + if (cur_link != sof_end->link_mask) { + int link_num = ffs(sof_end->link_mask) - 1; + int pin_num = ctx->sdw_pin_index[link_num]++; + + cur_link = sof_end->link_mask; + + 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++; + } + + codec_maps[j].cpu = i - 1; + 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(i != num_cpus || j != num_codecs); + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, dai_links + *link_index, be_id, name, - playback, capture, cpus, cpu_dai_num, codecs, codec_num, + init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, codecs, num_codecs, sof_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[*link_index].nonatomic = true; - - set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); - dai_links[*link_index].ch_maps = sdw_codec_ch_maps; - ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, - playback, group_id, adr_index, dai_index); - if (ret < 0) { - dev_err(dev, "failed to init codec %d\n", codec_index); + (*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 sof_sdw_dailink *sof_dais, + struct snd_soc_codec_conf **codec_conf) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + int ret, i; + + for (i = 0; i < SDW_MAX_LINKS; i++) + ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; + + /* generate DAI links by each sdw link */ + while (sof_dais->initialised) { + int current_be_id; + + ret = create_sdw_dailink(card, sof_dais, dai_links, + ¤t_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_ssp_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct sof_sdw_codec_info *ssp_info, + unsigned long ssp_mask) +{ + struct device *dev = card->dev; + int i, j = 0; + int ret; + + 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++); + int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; + int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; + + ret = init_simple_dai_link(dev, *dai_links, be_id, name, + playback, capture, cpu_dai_name, + codec_name, ssp_info->dais[0].dai_name, + NULL, ssp_info->ops); + if (ret) + return ret; + + ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); + if (ret < 0) + return ret; + + (*dai_links)++; + } + + return 0; +} + +static int create_dmic_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) +{ + struct device *dev = card->dev; + int ret; + + ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic01", + 0, 1, // DMIC only supports capture + "DMIC01 Pin", "dmic-codec", "dmic-hifi", + sof_sdw_dmic_init, NULL); + if (ret) + return ret; + + (*dai_links)++; + + ret = init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", + 0, 1, // DMIC only supports capture + "DMIC16k Pin", "dmic-codec", "dmic-hifi", + /* don't call sof_sdw_dmic_init() twice */ + NULL, NULL); + if (ret) + return ret; + + (*dai_links)++; + + return 0; +} + +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 mc_private *ctx = snd_soc_card_get_drvdata(card); + int i, ret; + + 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); + char *codec_name, *codec_dai_name; + + if (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"; } + + ret = init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 0, // HDMI only supports playback + cpu_dai_name, codec_name, codec_dai_name, + i == 0 ? sof_sdw_hdmi_init : NULL, NULL); + if (ret) + return ret; + + (*dai_links)++; } return 0; } +static int create_bt_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) +{ + struct device *dev = card->dev; + int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); + int ret; + + ret = init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 1, cpu_dai_name, snd_soc_dummy_dlc.name, + snd_soc_dummy_dlc.dai_name, NULL, 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; @@ -1646,38 +1891,51 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; - bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION); struct snd_soc_codec_conf *codec_conf; - bool append_dai_type = false; - bool ignore_pch_dmic = false; - int codec_conf_num = 0; - int codec_conf_index = 0; - bool group_generated[SDW_MAX_GROUPS] = { }; - int ssp_codec_index, ssp_mask; + struct sof_sdw_codec_info *ssp_info; + struct sof_sdw_endpoint *sof_ends; + struct sof_sdw_dailink *sof_dais; + int num_devs = 0; + int num_ends = 0; struct snd_soc_dai_link *dai_links; - int num_links, link_index = 0; - char *name, *cpu_dai_name; - char *codec_name, *codec_dai_name; - int i, j, be_id = 0; - int codec_index; + int num_links; + int be_id = 0; int hdmi_num; + unsigned long ssp_mask; int ret; - ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num); + ret = count_sdw_endpoints(card, &num_devs, &num_ends); if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d\n", ret); + 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) { + ret = -ENOMEM; + goto err_dai; + } + + ret = parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + 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); - if (ssp_codec_index >= 0) { + ssp_info = find_codec_info_acpi(mach->id); + if (ssp_info) { ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); ssp_num = hweight_long(ssp_mask); } @@ -1701,204 +1959,73 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) sdw_be_num, ssp_num, dmic_num, ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); + codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + if (!codec_conf) { + ret = -ENOMEM; + goto err_end; + } + /* 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) - return -ENOMEM; - - /* allocate codec conf, will be populated when dailinks are created */ - codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), - GFP_KERNEL); - if (!codec_conf) - return -ENOMEM; - - /* SDW */ - if (!sdw_be_num) - goto SSP; - - for (i = 0; i < SDW_MAX_LINKS; i++) - ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; - - for (; adr_link->num_adr; adr_link++) { - /* - * 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. - */ - 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[j].adr))) { - append_dai_type = true; - goto out; - } - } - } + if (!dai_links) { + ret = -ENOMEM; + goto err_end; } -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; - /* this group has been generated */ - if (endpoint->aggregated && - group_generated[endpoint->group_id]) - continue; - - /* 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++) { - int current_be_id; - - ret = create_sdw_dailink(card, &link_index, dai_links, - sdw_be_num, adr_link, - codec_conf, codec_conf_num, - ¤t_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\n", link_index); - 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; - } + card->codec_conf = codec_conf; + card->num_configs = num_devs; + card->dai_link = dai_links; + card->num_links = num_links; - if (aggregation && endpoint->aggregated) - group_generated[endpoint->group_id] = true; - } + /* SDW */ + if (sdw_be_num) { + ret = create_sdw_dailinks(card, &dai_links, &be_id, + sof_dais, &codec_conf); + if (ret) + 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; - - if (!(ssp_mask & 0x1)) - continue; - - info = &codec_info_list[ssp_codec_index]; - - name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); - cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); - codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", - info->acpi_id, j++); - - playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; - capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, - playback, capture, cpu_dai_name, - codec_name, info->dais[0].dai_name, - NULL, info->ops); + if (ssp_num) { + ret = create_ssp_dailinks(card, &dai_links, &be_id, + ssp_info, ssp_mask); if (ret) - return ret; - - ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); - if (ret < 0) - return ret; - - link_index++; + goto err_end; } -DMIC: /* dmic */ if (dmic_num > 0) { - if (ignore_pch_dmic) { + if (ctx->ignore_pch_dmic) { dev_warn(dev, "Ignoring PCH DMIC\n"); - goto HDMI; + } else { + ret = create_dmic_dailinks(card, &dai_links, &be_id); + if (ret) + goto err_end; } - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic01", - 0, 1, // DMIC only supports capture - "DMIC01 Pin", "dmic-codec", "dmic-hifi", - sof_sdw_dmic_init, NULL); - if (ret) - return ret; - - link_index++; - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic16k", - 0, 1, // DMIC only supports capture - "DMIC16k Pin", "dmic-codec", "dmic-hifi", - /* don't call sof_sdw_dmic_init() twice */ - NULL, NULL); - if (ret) - return ret; - - link_index++; } -HDMI: /* HDMI */ - for (i = 0; i < hdmi_num; i++) { - name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); - cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); - - if (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"; - } - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, - 1, 0, // HDMI only supports playback - cpu_dai_name, codec_name, codec_dai_name, - i == 0 ? sof_sdw_hdmi_init : NULL, NULL); - if (ret) - return ret; - - link_index++; - } + ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); + if (ret) + goto err_end; + /* BT */ if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, - 1, 1, cpu_dai_name, snd_soc_dummy_dlc.name, - snd_soc_dummy_dlc.dai_name, NULL, NULL); + ret = create_bt_dailinks(card, &dai_links, &be_id); if (ret) - return ret; + goto err_end; } - card->dai_link = dai_links; - card->num_links = num_links; + WARN_ON(codec_conf != card->codec_conf + card->num_configs); + WARN_ON(dai_links != card->dai_link + card->num_links); - card->codec_conf = codec_conf; - card->num_configs = codec_conf_num; +err_end: + kfree(sof_ends); +err_dai: + kfree(sof_dais); - return 0; + return ret; } static int sof_sdw_card_late_probe(struct snd_soc_card *card) @@ -1922,15 +2049,6 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *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) @@ -1982,20 +2100,24 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card) static int mc_probe(struct platform_device *pdev) { - struct snd_soc_card *card = &card_sof_sdw; struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); + struct snd_soc_card *card; struct mc_private *ctx; int amp_num = 0, i; int ret; - card->dev = &pdev->dev; - - dev_dbg(card->dev, "Entry\n"); + dev_dbg(&pdev->dev, "Entry\n"); - ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + card = &ctx->card; + card->dev = &pdev->dev; + card->name = "soundwire", + card->owner = THIS_MODULE, + card->late_probe = sof_sdw_card_late_probe, + snd_soc_card_set_drvdata(card, ctx); dmi_check_system(sof_sdw_quirk_table); @@ -2031,9 +2153,7 @@ static int mc_probe(struct platform_device *pdev) 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; @@ -2046,8 +2166,6 @@ 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(card->dev, card); if (ret) { @@ -2092,4 +2210,3 @@ 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_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index b1d57034361c..3dfba6f6b95d 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -45,12 +45,26 @@ enum { }; #define SOF_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) +/* Deprecated and no longer supported by the code */ #define SOF_SDW_FOUR_SPK BIT(4) #define SOF_SDW_TGL_HDMI BIT(5) #define SOF_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)) +/* Deprecated and no longer supported by the code */ #define SOF_SDW_NO_AGGREGATION BIT(14) +/* If a CODEC has an optional speaker output, this quirk will enable it */ +#define SOF_CODEC_SPKR BIT(15) +/* + * If the CODEC has additional devices attached directly to it. + * + * For the cs42l43: + * - 0 - No speaker output + * - SOF_CODEC_SPKR - CODEC internal speaker + * - SOF_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker + * - SOF_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported + */ +#define SOF_SIDECAR_AMPS BIT(16) /* BT audio offload: reserve 3 bits for future */ #define SOF_BT_OFFLOAD_SSP_SHIFT 15 @@ -63,7 +77,7 @@ enum { #define SOF_SDW_DAI_TYPE_AMP 1 #define SOF_SDW_DAI_TYPE_MIC 2 -#define SOF_SDW_MAX_DAI_NUM 3 +#define SOF_SDW_MAX_DAI_NUM 8 struct sof_sdw_codec_info; @@ -72,14 +86,18 @@ struct sof_sdw_dai_info { const char *dai_name; const int dai_type; const int dailink[2]; /* dailink id for each direction */ + const struct snd_kcontrol_new *controls; + const int num_controls; + const struct snd_soc_dapm_widget *widgets; + const int num_widgets; 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); - int (*rtd_init)(struct snd_soc_pcm_runtime *rtd); + int (*rtd_init)(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); bool rtd_init_done; /* Indicate that the rtd_init callback is done */ + unsigned long quirk; }; struct sof_sdw_codec_info { @@ -94,19 +112,32 @@ struct sof_sdw_codec_info { const int dai_num; int (*codec_card_late_probe)(struct snd_soc_card *card); + + int (*count_sidecar)(struct snd_soc_card *card, + int *num_dais, int *num_devs); + int (*add_sidecar)(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf); }; struct mc_private { + struct snd_soc_card card; struct snd_soc_jack sdw_headset; struct sof_hdmi_private hdmi; struct device *headset_codec_dev; /* only one headset per card */ struct device *amp_dev1, *amp_dev2; /* To store SDW Pin index for each SoundWire link */ unsigned int sdw_pin_index[SDW_MAX_LINKS]; + bool append_dai_type; + bool ignore_pch_dmic; }; extern unsigned long sof_sdw_quirk; +struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, + const char * const dai_name[], + int num_dais); + 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); @@ -125,7 +156,6 @@ 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); @@ -133,7 +163,6 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l /* 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); @@ -144,53 +173,54 @@ 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); -/* RT722-SDCA support */ -int sof_sdw_rt722_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_rt722_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); - /* 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); +/* CS42L43 support */ +int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + /* CS AMP support */ +int bridge_cs35l56_count_sidecar(struct snd_soc_card *card, + int *num_dais, int *num_devs); +int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf); +int bridge_cs35l56_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + int sof_sdw_cs_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); /* dai_link init callbacks */ -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd); -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd); -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd); -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd); +int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); #endif diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/intel/boards/sof_sdw_cs42l42.c index 0dc297f7de01..fdb75fc71c26 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l42.c +++ b/sound/soc/intel/boards/sof_sdw_cs42l42.c @@ -15,14 +15,8 @@ #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include "sof_board_helpers.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), -}; - static const struct snd_soc_dapm_route cs42l42_map[] = { /* HP jack connectors - unknown if we have jack detection */ {"Headphone", NULL, "cs42l42 HP"}, @@ -31,11 +25,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", @@ -51,7 +40,7 @@ static const char * const jack_codecs[] = { "cs42l42" }; -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd) +int 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); @@ -71,20 +60,6 @@ int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd) 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, ARRAY_SIZE(cs42l42_map)); diff --git a/sound/soc/intel/boards/sof_sdw_cs42l43.c b/sound/soc/intel/boards/sof_sdw_cs42l43.c index a9b6edac2ecd..b7e2750c1074 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l43.c +++ b/sound/soc/intel/boards/sof_sdw_cs42l43.c @@ -18,11 +18,6 @@ #include <sound/soc-dapm.h> #include "sof_sdw_common.h" -static const struct snd_soc_dapm_widget cs42l43_hs_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - static const struct snd_soc_dapm_route cs42l43_hs_map[] = { { "Headphone", NULL, "cs42l43 AMP3_OUT" }, { "Headphone", NULL, "cs42l43 AMP4_OUT" }, @@ -30,8 +25,11 @@ static const struct snd_soc_dapm_route cs42l43_hs_map[] = { { "cs42l43 ADC1_IN1_N", NULL, "Headset Mic" }, }; -static const struct snd_soc_dapm_widget cs42l43_dmic_widgets[] = { - SND_SOC_DAPM_MIC("DMIC", NULL), +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[] = { @@ -50,7 +48,7 @@ static struct snd_soc_jack_pin sof_jack_pins[] = { }, }; -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd) +int 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 mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); @@ -63,13 +61,6 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd) if (!card->components) return -ENOMEM; - ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_hs_widgets, - ARRAY_SIZE(cs42l43_hs_widgets)); - if (ret) { - dev_err(card->dev, "cs42l43 hs widgets addition failed: %d\n", ret); - return ret; - } - ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_hs_map, ARRAY_SIZE(cs42l43_hs_map)); if (ret) { @@ -108,7 +99,43 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) +int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + if (!(sof_sdw_quirk & SOF_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_dapm_add_routes(&card->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; +} + +int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* Do init on playback link only. */ + if (!playback) + return 0; + + info->amp_num++; + + return bridge_cs35l56_spk_init(card, dai_links, info, playback); +} + +int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -118,13 +145,6 @@ int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) if (!card->components) return -ENOMEM; - ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_dmic_widgets, - ARRAY_SIZE(cs42l43_dmic_widgets)); - if (ret) { - dev_err(card->dev, "cs42l43 dmic widgets addition failed: %d\n", ret); - return ret; - } - ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_dmic_map, ARRAY_SIZE(cs42l43_dmic_map)); if (ret) diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c index 56cf75bc6cc4..10e08207619a 100644 --- a/sound/soc/intel/boards/sof_sdw_cs_amp.c +++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c @@ -14,17 +14,13 @@ #define CODEC_NAME_SIZE 8 -static const struct snd_soc_dapm_widget sof_widgets[] = { - SND_SOC_DAPM_SPK("Speakers", NULL), -}; - -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) +int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { const char *dai_name = rtd->dai_link->codecs->dai_name; struct snd_soc_card *card = rtd->card; char codec_name[CODEC_NAME_SIZE]; char widget_name[16]; - struct snd_soc_dapm_route route = { "Speakers", NULL, widget_name }; + struct snd_soc_dapm_route route = { "Speaker", NULL, widget_name }; struct snd_soc_dai *codec_dai; int i, ret; @@ -35,13 +31,6 @@ int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) if (!card->components) return -ENOMEM; - ret = snd_soc_dapm_new_controls(&card->dapm, sof_widgets, - ARRAY_SIZE(sof_widgets)); - if (ret) { - dev_err(card->dev, "widgets addition failed: %d\n", ret); - return ret; - } - for_each_rtd_codec_dais(rtd, i, codec_dai) { if (!strstr(codec_dai->name, "cs35l56")) continue; @@ -57,7 +46,6 @@ int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) } int sof_sdw_cs_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) diff --git a/sound/soc/intel/boards/sof_sdw_maxim.c b/sound/soc/intel/boards/sof_sdw_maxim.c index 034730432671..b7f73177867f 100644 --- a/sound/soc/intel/boards/sof_sdw_maxim.c +++ b/sound/soc/intel/boards/sof_sdw_maxim.c @@ -11,23 +11,17 @@ #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_soc_dapm_route max_98373_dapm_routes[] = { + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, }; -static const struct snd_kcontrol_new maxim_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) +int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -41,20 +35,6 @@ int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) 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); @@ -139,7 +119,6 @@ static int mx8373_sdw_late_probe(struct snd_soc_card *card) } 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) diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c index 6b008a5a343b..96f193798540 100644 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ b/sound/soc/intel/boards/sof_sdw_rt5682.c @@ -15,14 +15,8 @@ #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include "sof_board_helpers.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), -}; - static const struct snd_soc_dapm_route rt5682_map[] = { /*Headphones*/ { "Headphone", NULL, "rt5682 HPOL" }, @@ -30,11 +24,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", @@ -50,7 +39,7 @@ static const char * const jack_codecs[] = { "rt5682" }; -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd) +int 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); @@ -70,20 +59,6 @@ int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd) 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, ARRAY_SIZE(rt5682_map)); diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c index 88e785a54b16..f9575db9d99c 100644 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ b/sound/soc/intel/boards/sof_sdw_rt700.c @@ -13,15 +13,8 @@ #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include "sof_board_helpers.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), -}; - static const struct snd_soc_dapm_route rt700_map[] = { /* Headphones */ { "Headphones", NULL, "rt700 HP" }, @@ -29,12 +22,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", @@ -50,7 +37,7 @@ static const char * const jack_codecs[] = { "rt700" }; -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd) +int 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); @@ -70,20 +57,6 @@ int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd) 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, ARRAY_SIZE(rt700_map)); diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c index cdd1587b246c..d49e5aa786c3 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -15,7 +15,6 @@ #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include "sof_board_helpers.h" #include "sof_sdw_common.h" /* @@ -43,22 +42,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", @@ -74,7 +63,7 @@ static const char * const jack_codecs[] = { "rt711" }; -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) +int 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); @@ -94,20 +83,6 @@ int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) 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, ARRAY_SIZE(rt711_map)); @@ -159,7 +134,6 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l } 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) diff --git a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c b/sound/soc/intel/boards/sof_sdw_rt712_sdca.c index ebb4b58c198b..788796461885 100644 --- a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c +++ b/sound/soc/intel/boards/sof_sdw_rt712_sdca.c @@ -13,13 +13,8 @@ #include <sound/soc.h> #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> -#include "sof_board_helpers.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 @@ -31,11 +26,7 @@ static const struct snd_soc_dapm_route rt712_spk_map[] = { { "Speaker", NULL, "rt712 SPOR" }, }; -static const struct snd_kcontrol_new rt712_spk_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) +int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -46,20 +37,6 @@ int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) 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); @@ -67,27 +44,3 @@ int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } -static const char * const dmics[] = { - "rt712-sdca-dmic" -}; - -int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - - codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:%s", - card->components, component->name_prefix); - if (!card->components) - return -ENOMEM; - - return 0; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); 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 b5a886cd595d..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt715.c +++ /dev/null @@ -1,26 +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" - -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; -} - 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 4b37a8a6dd2e..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c +++ /dev/null @@ -1,26 +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" - -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; -} - diff --git a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c index fe3a2bff95bc..083d281bd052 100644 --- a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c +++ b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c @@ -15,19 +15,11 @@ #include <sound/soc-dapm.h> #include "sof_sdw_common.h" -static const struct snd_soc_dapm_widget rt722_spk_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - static const struct snd_soc_dapm_route rt722_spk_map[] = { { "Speaker", NULL, "rt722 SPK" }, }; -static const struct snd_kcontrol_new rt722_spk_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd) +int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -38,20 +30,6 @@ static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd) if (!card->components) return -ENOMEM; - ret = snd_soc_add_card_controls(card, rt722_spk_controls, - ARRAY_SIZE(rt722_spk_controls)); - if (ret) { - dev_err(card->dev, "failed to add rt722 spk controls: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt722_spk_widgets, - ARRAY_SIZE(rt722_spk_widgets)); - if (ret) { - dev_err(card->dev, "failed to add rt722 spk widgets: %d\n", ret); - return ret; - } - ret = snd_soc_dapm_add_routes(&card->dapm, rt722_spk_map, ARRAY_SIZE(rt722_spk_map)); if (ret) dev_err(rtd->dev, "failed to add rt722 spk map: %d\n", ret); @@ -59,39 +37,3 @@ static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd) return ret; } -int sof_sdw_rt722_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 = rt722_spk_init; - - return 0; -} - -static int rt722_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:%s", - card->components, component->name_prefix); - if (!card->components) - return -ENOMEM; - - return 0; -} - -int sof_sdw_rt722_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 = rt722_sdca_dmic_rtd_init; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c index 202edab95000..797ea9ffa77a 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_amp.c +++ b/sound/soc/intel/boards/sof_sdw_rt_amp.c @@ -131,14 +131,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,15 +158,11 @@ 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 *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) @@ -185,16 +173,16 @@ static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_ return rt1318_map; } -int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) +int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; const struct snd_soc_dapm_route *rt_amp_map; char codec_name[CODEC_NAME_SIZE]; - struct snd_soc_dai *dai; + struct snd_soc_dai *codec_dai; int ret; int i; - rt_amp_map = get_codec_name_and_route(rtd, codec_name); + rt_amp_map = get_codec_name_and_route(dai, codec_name); card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s", @@ -202,24 +190,10 @@ int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) if (!card->components) return -ENOMEM; - 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; - } - - 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, dai) { - if (strstr(dai->component->name_prefix, "-1")) + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (strstr(codec_dai->component->name_prefix, "-1")) ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2); - else if (strstr(dai->component->name_prefix, "-2")) + else if (strstr(codec_dai->component->name_prefix, "-2")) ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map + 2, 2); } @@ -281,7 +255,6 @@ int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ } 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) diff --git a/sound/soc/intel/boards/sof_sdw_rt_dmic.c b/sound/soc/intel/boards/sof_sdw_rt_dmic.c new file mode 100644 index 000000000000..b8b493d5c6ec --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt_dmic.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2024 Intel Corporation + +/* + * sof_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 "sof_board_helpers.h" +#include "sof_sdw_common.h" + +static const char * const dmics[] = { + "rt715", + "rt715-sdca", + "rt712-sdca-dmic", + "rt722-sdca", +}; + +int 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; + struct snd_soc_dai *codec_dai; + char *mic_name; + + codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics)); + if (!codec_dai) + return -EINVAL; + + component = codec_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); + + 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; +} +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c index 5253d8332780..701b0372f59e 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c @@ -15,7 +15,6 @@ #include <sound/soc-acpi.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include "sof_board_helpers.h" #include "sof_sdw_common.h" /* @@ -44,11 +43,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" }, @@ -69,11 +63,6 @@ static const struct snd_soc_dapm_route rt722_sdca_map[] = { { "rt722 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 struct snd_soc_jack_pin rt_sdca_jack_pins[] = { { .pin = "Headphone", @@ -86,10 +75,19 @@ static struct snd_soc_jack_pin rt_sdca_jack_pins[] = { }; static const char * const jack_codecs[] = { - "rt711", "rt712", "rt713" + "rt711", "rt712", "rt713", "rt722" +}; + +/* + * 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 rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd) +int 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); @@ -97,6 +95,7 @@ int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; + int i; codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); if (!codec_dai) @@ -104,23 +103,20 @@ int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd) component = codec_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(codec_dai->name, 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")) { @@ -192,7 +188,6 @@ int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link } 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) diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index ee2e813bf4c0..f51f1008e016 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 @@ -20,34 +20,12 @@ #include "sof_board_helpers.h" #include "sof_realtek_common.h" #include "sof_cirrus_common.h" -#include "sof_ssp_common.h" - -/* 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_HDMI_CAPTURE_SSP_MASK_SHIFT 4 -#define SOF_HDMI_CAPTURE_SSP_MASK_MASK (GENMASK(9, 4)) -#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ - (((quirk) << SOF_HDMI_CAPTURE_SSP_MASK_SHIFT) & SOF_HDMI_CAPTURE_SSP_MASK_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) + +/* 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); +static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2); static const struct dmi_system_id chromebook_platforms[] = { { @@ -75,197 +53,107 @@ static struct snd_soc_card sof_ssp_amp_card = { #define HDMI_IN_BE_ID 0 #define SPK_BE_ID 2 #define DMIC01_BE_ID 3 -#define DMIC16K_BE_ID 4 #define INTEL_HDMI_BE_ID 5 - -static struct snd_soc_dai_link * -sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, - int ssp_amp, int dmic_be_num, int hdmi_num, - bool idisp_codec) +/* 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 snd_soc_dai_link *links; - int i; - int id = 0; int ret; - bool fixed_be = false; - int be_id; - unsigned long ssp_mask_hdmi_in; - - links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, - sizeof(struct snd_soc_dai_link), GFP_KERNEL); - if (!links) - return NULL; - - /* HDMI-In SSP */ - ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> - SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; - - if (ssp_mask_hdmi_in) { - int port = 0; - - /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ - fixed_be = true; - - be_id = HDMI_IN_BE_ID; - for_each_set_bit(port, &ssp_mask_hdmi_in, 32) { - ret = sof_intel_board_set_hdmi_in_link(dev, &links[id], - be_id, port); - if (ret) - return NULL; - - id++; - be_id++; - } - } - - /* codec SSP */ - if (amp_type != CODEC_NONE) { - be_id = fixed_be ? SPK_BE_ID : id; - ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id, - amp_type, ssp_amp); - if (ret) - return NULL; - - /* codec-specific fields */ - switch (amp_type) { - case CODEC_CS35L41: - cs35l41_set_dai_link(&links[id]); - break; - case CODEC_RT1308: - sof_rt1308_dai_link(&links[id]); - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return NULL; - } - id++; - } - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - be_id = fixed_be ? DMIC01_BE_ID : id; - ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id, - SOF_DMIC_01); - if (ret) - return NULL; - - id++; - } - - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - be_id = fixed_be ? DMIC16K_BE_ID : id; - ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id, - SOF_DMIC_16K); - if (ret) - return NULL; - - id++; - } + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; - /* HDMI playback */ - for (i = 1; i <= hdmi_num; i++) { - be_id = fixed_be ? (INTEL_HDMI_BE_ID + i - 1) : id; - ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], be_id, - i, idisp_codec); - if (ret) - return NULL; + if (ctx->amp_type == CODEC_NONE) + return 0; - 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; - - ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); - if (ret) - return NULL; - - 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; + return 0; } static int sof_ssp_amp_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + 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) - ctx->dmic_be_num = 2; - else - ctx->dmic_be_num = 0; - - /* port number/mask of peripherals attached to ssp interface */ - ctx->ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> - SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; - - ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; - - /* set number of dai links */ - sof_ssp_amp_card.num_links = ctx->dmic_be_num; - - if (ctx->amp_type != CODEC_NONE) - sof_ssp_amp_card.num_links++; + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk); + if (!ctx) + return -ENOMEM; - if (ctx->ssp_mask_hdmi_in) - sof_ssp_amp_card.num_links += hweight32(ctx->ssp_mask_hdmi_in); + 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) { - ctx->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 (!ctx->hdmi_num) - ctx->hdmi_num = 3; - if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - - sof_ssp_amp_card.num_links += ctx->hdmi_num; } else { ctx->hdmi_num = 0; } - if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - ctx->bt_offload_present = true; - sof_ssp_amp_card.num_links++; - } + ctx->link_order_overwrite = SSP_AMP_LINK_ORDER; - dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ctx->ssp_amp, ctx->dmic_be_num, - ctx->hdmi_num, - ctx->hdmi.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 */ switch (ctx->amp_type) { case CODEC_CS35L41: cs35l41_set_codec_conf(&sof_ssp_amp_card); break; - case CODEC_NONE: case CODEC_RT1308: + case CODEC_NONE: /* no codec conf required */ break; default: @@ -292,38 +180,35 @@ static const struct platform_device_id board_ids[] = { }, { .name = "tgl_rt1308_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | - SOF_HDMI_CAPTURE_SSP_MASK(0x22)), + .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_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "adl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "rpl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "mtl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | - /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_NO_OF_HDMI_PLAYBACK(3) | - SOF_HDMI_PLAYBACK_PRESENT), + .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), }, { } }; @@ -346,4 +231,3 @@ MODULE_LICENSE("GPL"); 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); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); diff --git a/sound/soc/intel/boards/sof_ssp_common.c b/sound/soc/intel/boards/sof_ssp_common.c deleted file mode 100644 index 96072790e9c0..000000000000 --- a/sound/soc/intel/boards/sof_ssp_common.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// -// Copyright(c) 2023 Intel Corporation. All rights reserved. - -#include <linux/device.h> -#include <sound/soc-acpi.h> -#include "sof_ssp_common.h" - -/* - * Codec probe function - */ -#define CODEC_MAP_ENTRY(n, h, t) \ - { \ - .name = n, \ - .acpi_hid = h, \ - .codec_type = t, \ - } - -struct codec_map { - const char *name; - const char *acpi_hid; - enum sof_ssp_codec codec_type; -}; - -static const struct codec_map codecs[] = { - /* Cirrus Logic */ - CODEC_MAP_ENTRY("CS42L42", CS42L42_ACPI_HID, CODEC_CS42L42), - - /* Dialog */ - CODEC_MAP_ENTRY("DA7219", DA7219_ACPI_HID, CODEC_DA7219), - - /* Everest */ - CODEC_MAP_ENTRY("ES8316", ES8316_ACPI_HID, CODEC_ES8316), - CODEC_MAP_ENTRY("ES8326", ES8326_ACPI_HID, CODEC_ES8326), - CODEC_MAP_ENTRY("ES8336", ES8336_ACPI_HID, CODEC_ES8336), - - /* Nuvoton */ - CODEC_MAP_ENTRY("NAU8825", NAU8825_ACPI_HID, CODEC_NAU8825), - - /* Realtek */ - CODEC_MAP_ENTRY("RT5650", RT5650_ACPI_HID, CODEC_RT5650), - CODEC_MAP_ENTRY("RT5682", RT5682_ACPI_HID, CODEC_RT5682), - CODEC_MAP_ENTRY("RT5682S", RT5682S_ACPI_HID, CODEC_RT5682S), -}; - -static const struct codec_map amps[] = { - /* Cirrus Logic */ - CODEC_MAP_ENTRY("CS35L41", CS35L41_ACPI_HID, CODEC_CS35L41), - - /* Maxim */ - CODEC_MAP_ENTRY("MAX98357A", MAX_98357A_ACPI_HID, CODEC_MAX98357A), - CODEC_MAP_ENTRY("MAX98360A", MAX_98360A_ACPI_HID, CODEC_MAX98360A), - CODEC_MAP_ENTRY("MAX98373", MAX_98373_ACPI_HID, CODEC_MAX98373), - CODEC_MAP_ENTRY("MAX98390", MAX_98390_ACPI_HID, CODEC_MAX98390), - - /* Nuvoton */ - CODEC_MAP_ENTRY("NAU8318", NAU8318_ACPI_HID, CODEC_NAU8318), - - /* Realtek */ - CODEC_MAP_ENTRY("RT1011", RT1011_ACPI_HID, CODEC_RT1011), - CODEC_MAP_ENTRY("RT1015", RT1015_ACPI_HID, CODEC_RT1015), - CODEC_MAP_ENTRY("RT1015P", RT1015P_ACPI_HID, CODEC_RT1015P), - CODEC_MAP_ENTRY("RT1019P", RT1019P_ACPI_HID, CODEC_RT1019P), - CODEC_MAP_ENTRY("RT1308", RT1308_ACPI_HID, CODEC_RT1308), -}; - -enum sof_ssp_codec sof_ssp_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(sof_ssp_detect_codec_type, SND_SOC_INTEL_SOF_SSP_COMMON); - -enum sof_ssp_codec sof_ssp_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(sof_ssp_detect_amp_type, SND_SOC_INTEL_SOF_SSP_COMMON); - -const char *sof_ssp_get_codec_name(enum sof_ssp_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(sof_ssp_get_codec_name, SND_SOC_INTEL_SOF_SSP_COMMON); - -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/boards/sof_ssp_common.h b/sound/soc/intel/boards/sof_ssp_common.h deleted file mode 100644 index d24888bc99fd..000000000000 --- a/sound/soc/intel/boards/sof_ssp_common.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2023 Intel Corporation. - */ - -#ifndef __SOF_SSP_COMMON_H -#define __SOF_SSP_COMMON_H - -/* Cirrus Logic */ -#define CS35L41_ACPI_HID "CSC3541" -#define CS42L42_ACPI_HID "10134242" - -/* Dialog */ -#define DA7219_ACPI_HID "DLGS7219" - -/* Everest */ -#define ES8316_ACPI_HID "ESSX8316" -#define ES8326_ACPI_HID "ESSX8326" -#define ES8336_ACPI_HID "ESSX8336" - -#define MAX_98357A_ACPI_HID "MX98357A" -#define MAX_98360A_ACPI_HID "MX98360A" -#define MAX_98373_ACPI_HID "MX98373" -#define MAX_98390_ACPI_HID "MX98390" - -/* Nuvoton */ -#define NAU8318_ACPI_HID "NVTN2012" -#define NAU8825_ACPI_HID "10508825" - -/* Realtek */ -#define RT1011_ACPI_HID "10EC1011" -#define RT1015_ACPI_HID "10EC1015" -#define RT1015P_ACPI_HID "RTL1015" -#define RT1019P_ACPI_HID "RTL1019" -#define RT1308_ACPI_HID "10EC1308" -#define RT5650_ACPI_HID "10EC5650" -#define RT5682_ACPI_HID "10EC5682" -#define RT5682S_ACPI_HID "RTL5682" - -enum sof_ssp_codec { - CODEC_NONE, - - /* headphone codec */ - CODEC_CS42L42, - CODEC_DA7219, - CODEC_ES8316, - CODEC_ES8326, - CODEC_ES8336, - CODEC_NAU8825, - CODEC_RT5650, - CODEC_RT5682, - CODEC_RT5682S, - - /* speaker amplifier */ - CODEC_CS35L41, - CODEC_MAX98357A, - CODEC_MAX98360A, - CODEC_MAX98373, - CODEC_MAX98390, - CODEC_NAU8318, - CODEC_RT1011, - CODEC_RT1015, - CODEC_RT1015P, - CODEC_RT1019P, - CODEC_RT1308, -}; - -enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev); -enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev); - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON) -const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type); -#else -static inline const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type) -{ - return NULL; -} -#endif - -#endif /* __SOF_SSP_COMMON_H */ 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..2e1fa79a04d4 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> // diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index 5454c6d9ab5b..5993819cc58a 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> // 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..696d84314eeb 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> // 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 3daf5eb37f7b..81a2f0339e05 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> // 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..936ac9d503ff 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> // 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 f7370e5b4e9e..40a74a19c508 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,7 +1,7 @@ # 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-sst-dsp-y := sst-dsp.o +snd-soc-sst-ipc-y := sst-ipc.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 \ @@ -15,5 +15,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hda-match.o \ soc-acpi-intel-sdw-mockup-match.o +snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.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 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 0da79a3ba1f0..4167b2e9bc6a 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, @@ -447,29 +448,14 @@ 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_codecs adl_max98357a_amp = { .num_codecs = 1, .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,49 +463,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"} -}; - -static struct snd_soc_acpi_codecs adl_rt5650_amp = { - .num_codecs = 1, - .codecs = {"10EC5650"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .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_rt5682_def", - .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, @@ -527,53 +484,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg", }, { - .id = "10508825", - .drv_name = "adl_nau8825_def", - .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_nau8825_def", - .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_rt5682_def", - .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_nau8825_def", - .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_nau8825_def", - .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_rt5682_def", - .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_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, @@ -581,18 +491,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg", }, { - .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .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", - }, - { .comp_ids = &essx_83x6, .drv_name = "adl_es83x6_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, @@ -607,19 +505,43 @@ 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 = "10EC5650", + .id = RT5650_ACPI_HID, .drv_name = "adl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_rt5650_amp, - .sof_tplg_filename = "sof-adl-rt5650.tplg", + .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 = "DLGS7219", - .drv_name = "adl_mx98360_da7219", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98360a_amp, - .sof_tplg_filename = "sof-adl-max98360a-da7219.tplg", + .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 */ { diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index e52797aae6e6..79d26e0f2c28 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -24,6 +24,15 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { } }; +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_link_adr arl_rvp[] = { { .mask = BIT(0), @@ -33,6 +42,15 @@ static const struct snd_soc_acpi_link_adr arl_rvp[] = { {} }; +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, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = { {}, }; @@ -46,6 +64,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .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", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines); 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-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 8911c90bbaf6..c82c8c93d200 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -33,7 +33,7 @@ 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, @@ -41,7 +41,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { }, { .comp_ids = &glk_rt5682_rt5682s_hp, - .drv_name = "glk_rt5682_mx98357a", + .drv_name = "glk_rt5682_def", .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, 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..39875d67dcd1 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -29,7 +29,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { }, { .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 a6ac2525df17..d4b397c53bcc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -52,14 +52,14 @@ 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 = "jsl_mx98373_da7219", + .drv_name = "jsl_da7219_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &mx98373_spk, .sof_tplg_filename = "sof-jsl-da7219.tplg", }, { .id = "DLGS7219", - .drv_name = "jsl_mx98360_da7219", + .drv_name = "jsl_da7219_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &mx98360a_spk, .sof_tplg_filename = "sof-jsl-da7219-mx98360a.tplg", 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 74d6dcd7471f..e6ffcd5be6c5 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -2,7 +2,7 @@ /* * 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 * */ @@ -76,6 +76,42 @@ static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { }, }; +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_sdca_0_adr[] = { { .adr = 0x000030025D071101ull, @@ -130,6 +166,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { } }; +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, @@ -139,6 +202,14 @@ static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { } }; +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_rvp[] = { { .mask = BIT(0), @@ -195,6 +266,25 @@ static const struct snd_soc_acpi_link_adr lnl_3_in_1_sdca[] = { {} }; +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, + }, + {} +}; + /* 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 */ @@ -224,6 +314,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { }, { .link_mask = BIT(0), + .links = lnl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l0.tplg", + }, + { + .link_mask = BIT(0), .links = lnl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt711.tplg", @@ -240,6 +336,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt722-l0.tplg", }, + { + .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" + }, {}, }; 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 e9a5da079089..48252fa9e39e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -8,26 +8,12 @@ #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 mtl_max98357a_amp = { - .num_codecs = 1, - .codecs = {"MX98357A"} -}; - -static const struct snd_soc_acpi_codecs mtl_max98360a_amp = { - .num_codecs = 1, - .codecs = {"MX98360A"} -}; - -static const struct snd_soc_acpi_codecs mtl_rt1019p_amp = { - .num_codecs = 1, - .codecs = {"RTL1019"} -}; - static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = { .num_codecs = 2, - .codecs = {"10EC5682", "RTL5682"}, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; static const struct snd_soc_acpi_codecs mtl_essx_83x6 = { @@ -40,34 +26,8 @@ static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = { .codecs = {"INTC10B0"} }; -static const struct snd_soc_acpi_codecs mtl_rt5650_amp = { - .num_codecs = 1, - .codecs = {"10EC5650"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { { - .comp_ids = &mtl_rt5682_rt5682s_hp, - .drv_name = "mtl_mx98357_rt5682", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_max98357a_amp, - .sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg", - }, - { - .comp_ids = &mtl_rt5682_rt5682s_hp, - .drv_name = "mtl_mx98360_rt5682", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_max98360a_amp, - .sof_tplg_filename = "sof-mtl-max98360a-rt5682.tplg", - }, - { - .comp_ids = &mtl_rt5682_rt5682s_hp, - .drv_name = "mtl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_rt1019p_amp, - .sof_tplg_filename = "sof-mtl-rt1019-rt5682.tplg", - }, - { .comp_ids = &mtl_essx_83x6, .drv_name = "mtl_es83x6_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, @@ -82,12 +42,43 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_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 = "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 = "10EC5650", + .id = RT5650_ACPI_HID, .drv_name = "mtl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_rt5650_amp, - .sof_tplg_filename = "sof-mtl-rt5650.tplg", + .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 */ { @@ -288,6 +279,24 @@ static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = { } }; +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 = 0x000130025D131801, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1318" + } +}; + static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = { { .adr = 0x000130025D131801ull, @@ -324,7 +333,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), @@ -338,11 +347,47 @@ 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_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 = 1, - .endpoints = &single_endpoint, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, .name_prefix = "cs42l43" } }; @@ -352,13 +397,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = { .adr = 0x00013701FA355601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, - .name_prefix = "AMP8" + .name_prefix = "AMP3" }, { .adr = 0x00013601FA355601ull, .num_endpoints = 1, .endpoints = &spk_3_endpoint, - .name_prefix = "AMP7" + .name_prefix = "AMP4" } }; @@ -508,6 +553,49 @@ static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12_rt1713_l3[] = {} }; +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), @@ -527,6 +615,20 @@ static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12[] = { {} }; +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, @@ -566,6 +668,14 @@ 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), @@ -633,6 +743,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .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", @@ -640,11 +762,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { }, { .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_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt712-l0.tplg", + }, + { .link_mask = GENMASK(2, 0), .links = mtl_sdw_rt1318_l12_rt714_l0, .drv_name = "sof_sdw", @@ -663,12 +791,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l12.tplg", }, { + .link_mask = BIT(0), + .links = mtl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs42l43-l0.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", 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 00a21af210fa..b0a49e28ab09 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, @@ -347,7 +348,7 @@ 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_essx_83x6 = { @@ -360,31 +361,11 @@ static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { .codecs = {"MX98357A"} }; -static const struct snd_soc_acpi_codecs rpl_max98360a_amp = { - .num_codecs = 1, - .codecs = {"MX98360A"}, -}; - -static const struct snd_soc_acpi_codecs rpl_max98373_amp = { - .num_codecs = 1, - .codecs = {"MX98373"} -}; - static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = { .num_codecs = 1, .codecs = {"INTC10B0"} }; -static const struct snd_soc_acpi_codecs rpl_nau8318_amp = { - .num_codecs = 1, - .codecs = {"NVTN2012"} -}; - -static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { - .num_codecs = 1, - .codecs = {"RTL1019"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -395,41 +376,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { }, { .comp_ids = &rpl_rt5682_hp, - .drv_name = "rpl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_max98360a_amp, - .sof_tplg_filename = "sof-rpl-max98360a-rt5682.tplg", - }, - { - .id = "10508825", - .drv_name = "rpl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_max98373_amp, - .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "rpl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_max98360a_amp, - .sof_tplg_filename = "sof-rpl-max98360a-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "rpl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_nau8318_amp, - .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg", - }, - { - .comp_ids = &rpl_rt5682_hp, - .drv_name = "rpl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_rt1019p_amp, - .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", - }, - { - .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_rt5682_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_lt6911_hdmi, @@ -450,6 +396,45 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_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 = "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", 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..75d0b931d895 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c @@ -0,0 +1,159 @@ +// 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), +}; + +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 0fba0a60d9c7..161ba532d270 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, @@ -414,11 +410,38 @@ static const struct snd_soc_acpi_link_adr tgl_712_only[] = { {} }; +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_3_adr[] = { { .adr = 0x00033001FA424301ull, - .num_endpoints = 1, - .endpoints = &single_endpoint, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, .name_prefix = "cs42l43" } }; @@ -443,13 +466,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = { .adr = 0x00013701FA355601ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, - .name_prefix = "AMP8" + .name_prefix = "AMP3" }, { .adr = 0x00013601FA355601ull, .num_endpoints = 1, .endpoints = &spk_2_endpoint, - .name_prefix = "AMP7" + .name_prefix = "AMP4" } }; @@ -472,19 +495,9 @@ static const struct snd_soc_acpi_link_adr tgl_cs42l43_cs35l56[] = { {} }; -static const struct snd_soc_acpi_codecs tgl_max98373_amp = { - .num_codecs = 1, - .codecs = {"MX98373"} -}; - -static const struct snd_soc_acpi_codecs tgl_rt1011_amp = { - .num_codecs = 1, - .codecs = {"10EC1011"} -}; - static const struct snd_soc_acpi_codecs tgl_rt5682_rt5682s_hp = { .num_codecs = 2, - .codecs = {"10EC5682", "RTL5682"}, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = { @@ -494,27 +507,6 @@ static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = { struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { - .comp_ids = &tgl_rt5682_rt5682s_hp, - .drv_name = "tgl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &tgl_codecs, - .sof_tplg_filename = "sof-tgl-max98357a-rt5682.tplg", - }, - { - .comp_ids = &tgl_rt5682_rt5682s_hp, - .drv_name = "tgl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &tgl_max98373_amp, - .sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg", - }, - { - .comp_ids = &tgl_rt5682_rt5682s_hp, - .drv_name = "tgl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &tgl_rt1011_amp, - .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg", - }, - { .comp_ids = &essx_83x6, .drv_name = "sof-essx8336", .sof_tplg_filename = "sof-tgl-es8336", /* the tplg suffix is added at run time */ @@ -522,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", diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index de2b44568feb..de32bb9afccb 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -2,7 +2,7 @@ /* * Intel Smart Sound Technology * - * Copyright (C) 2013, Intel Corporation. All rights reserved. + * Copyright (C) 2013, Intel Corporation */ #ifndef __SOUND_SOC_SST_DSP_PRIV_H diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index 229d09d61afb..cdd2f7cf50ae 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -2,7 +2,7 @@ /* * Intel Smart Sound Technology (SST) DSP Core Driver * - * Copyright (C) 2013, Intel Corporation. All rights reserved. + * Copyright (C) 2013, Intel Corporation */ #include <linux/slab.h> diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index f111fd3f334b..998b1a052281 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -2,7 +2,7 @@ /* * Intel Smart Sound Technology (SST) Core * - * Copyright (C) 2013, Intel Corporation. All rights reserved. + * Copyright (C) 2013, Intel Corporation */ #ifndef __SOUND_SOC_SST_DSP_H diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 89c10724d2a3..6b2c83f9f010 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -2,7 +2,7 @@ /* * Intel SST generic IPC Support * - * Copyright (C) 2015, Intel Corporation. All rights reserved. + * Copyright (C) 2015, Intel Corporation */ #include <linux/types.h> diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index 77d651e888f9..86d44ceadc92 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -2,7 +2,7 @@ /* * Intel SST generic IPC Support * - * Copyright (C) 2015, Intel Corporation. All rights reserved. + * Copyright (C) 2015, Intel Corporation */ #ifndef __SST_GENERIC_IPC_H 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/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 1c4649bccec5..ad9be6168428 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,15 +1,15 @@ # 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 \ +snd-soc-skl-y := 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 + snd-soc-skl-y += 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 +snd-soc-skl-ssp-clk-y := 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/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 96cfebded072..e27f0fc3d897 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2682,168 +2682,6 @@ static int skl_tplg_get_desc_blocks(struct device *dev, 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) { @@ -2877,13 +2715,6 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, 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); 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/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/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index dd2f806526c1..036b42058272 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -19,7 +19,7 @@ static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) { - struct snd_soc_pcm_runtime *soc_runtime = subs->private_data; + 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)); } @@ -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/loongson/Makefile b/sound/soc/loongson/Makefile index 601a905a4860..578030ad6563 100644 --- a/sound/soc/loongson/Makefile +++ b/sound/soc/loongson/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 #Platform Support -snd-soc-loongson-i2s-pci-objs := loongson_i2s_pci.o loongson_i2s.o loongson_dma.o +snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_i2s.o loongson_dma.o obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.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/loongson_card.c b/sound/soc/loongson/loongson_card.c index e8432d466f60..fae5e9312bf0 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -23,7 +23,7 @@ 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_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 loongson_card_data *ls_card = snd_soc_card_get_drvdata(rtd->card); diff --git a/sound/soc/loongson/loongson_dma.c b/sound/soc/loongson/loongson_dma.c index 8090662e8ff2..4fcc2868160b 100644 --- a/sound/soc/loongson/loongson_dma.c +++ b/sound/soc/loongson/loongson_dma.c @@ -226,7 +226,7 @@ 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; diff --git a/sound/soc/loongson/loongson_i2s_pci.c b/sound/soc/loongson/loongson_i2s_pci.c index fa90361865c6..ec18b122cd79 100644 --- a/sound/soc/loongson/loongson_i2s_pci.c +++ b/sound/soc/loongson/loongson_i2s_pci.c @@ -160,7 +160,6 @@ static struct pci_driver loongson_i2s_driver = { .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/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 296b434caf81..5a8476e1ecca 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -185,27 +185,11 @@ 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 @@ -215,8 +199,8 @@ config SND_SOC_MT8186_MT6366_RT1019_RT5682S 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". 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-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 32edcb6d5219..9b72b2a7ae91 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -126,10 +126,28 @@ int mtk_afe_pcm_new(struct snd_soc_component *component, } 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-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 7ec8965a70c0..bca758dca2c9 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++) { @@ -55,7 +55,6 @@ 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); - struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; /* Set stream_name to help sof bind widgets */ for_each_card_prelinks(card, i, dai_link) { @@ -63,7 +62,7 @@ int mtk_sof_card_probe(struct snd_soc_card *card) dai_link->stream_name = dai_link->name; } - INIT_LIST_HEAD(&sof_priv->dai_link_list); + INIT_LIST_HEAD(&soc_card_data->sof_dai_link_list); return 0; } @@ -73,7 +72,7 @@ static struct snd_soc_pcm_runtime *mtk_sof_find_tplg_be(struct snd_soc_pcm_runti { 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; struct snd_soc_pcm_runtime *fe; struct snd_soc_pcm_runtime *be; struct snd_soc_dpcm *dpcm; @@ -113,7 +112,7 @@ static int mtk_sof_check_tplg_be_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; struct snd_soc_pcm_runtime *sof_be; struct mtk_dai_link *dai_link; int ret = 0; @@ -125,7 +124,7 @@ static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, 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, &sof_priv->dai_link_list, list) { + 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); @@ -144,7 +143,7 @@ int mtk_sof_card_late_probe(struct snd_soc_card *card) 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; @@ -173,7 +172,7 @@ int mtk_sof_card_late_probe(struct snd_soc_card *card) 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, &sof_priv->dai_link_list); + list_add(&mtk_dai_link->list, &soc_card_data->sof_dai_link_list); } if (dai_link->no_pcm) diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.h b/sound/soc/mediatek/common/mtk-dsp-sof-common.h index 4bc5e1c0c8ed..8784ee471132 100644 --- a/sound/soc/mediatek/common/mtk-dsp-sof-common.h +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.h @@ -30,7 +30,6 @@ struct mtk_sof_priv { int num_streams; int (*sof_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); - struct list_head dai_link_list; }; int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h index eeda79370049..3f6e24dd22df 100644 --- a/sound/soc/mediatek/common/mtk-soc-card.h +++ b/sound/soc/mediatek/common/mtk-soc-card.h @@ -9,9 +9,14 @@ #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; 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..3bbf42c42805 100644 --- a/sound/soc/mediatek/common/mtk-soundcard-driver.c +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c @@ -10,6 +10,8 @@ #include <linux/of.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 +24,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; } @@ -132,3 +138,200 @@ 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; + 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_read_bool(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; + + 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_read_bool(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/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 da7267c684b1..c1dee119e93a 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -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"); 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/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile index fc4c82559b29..4b54bbe88683 100644 --- a/sound/soc/mediatek/mt7986/Makefile +++ b/sound/soc/mediatek/mt7986/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # platform driver -snd-soc-mt7986-afe-objs := \ +snd-soc-mt7986-afe-y := \ mt7986-afe-pcm.o \ mt7986-dai-etdm.o diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c index d497e1129889..572ded279b53 100644 --- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c +++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c @@ -106,7 +106,7 @@ static const struct snd_pcm_hardware mt7986_afe_hardware = { static int mt7986_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); @@ -116,7 +116,7 @@ static int mt7986_memif_fs(struct snd_pcm_substream *substream, static int mt7986_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); @@ -429,18 +429,6 @@ static int mt7986_afe_runtime_resume(struct device *dev) return 0; } -static int mt7986_afe_component_probe(struct snd_soc_component *component) -{ - return mtk_afe_add_sub_dai_control(component); -} - -static const struct snd_soc_component_driver mt7986_afe_component = { - .name = AFE_PCM_NAME, - .probe = mt7986_afe_component_probe, - .pointer = mtk_afe_pcm_pointer, - .pcm_construct = mtk_afe_pcm_new, -}; - static int mt7986_dai_memif_register(struct mtk_base_afe *afe) { struct mtk_base_afe_dai *dai; @@ -573,7 +561,7 @@ static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev) /* register component */ ret = devm_snd_soc_register_component(&pdev->dev, - &mt7986_afe_component, + &mtk_afe_pcm_platform, NULL, 0); if (ret) return dev_err_probe(dev, ret, "Cannot register AFE component\n"); 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 9e432ed9124b..25348fdf75fa 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -1042,18 +1042,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; @@ -1232,7 +1220,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) /* register component */ ret = devm_snd_soc_register_component(&pdev->dev, - &mt8183_afe_component, + &mtk_afe_pcm_platform, NULL, 0); if (ret) { dev_warn(dev, "err_platform\n"); diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c index 5b8a274419ed..be69bcea2a78 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), @@ -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/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-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c index bfcfc68ac64d..bafbef96a42d 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -40,7 +40,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; @@ -82,7 +82,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; @@ -104,7 +104,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; unsigned int channels = params_channels(params); @@ -153,7 +153,7 @@ 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; @@ -252,7 +252,7 @@ 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); @@ -269,7 +269,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,7 +290,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c index ad6d4b5cf697..dbd157d1a1ea 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), @@ -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-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c deleted file mode 100644 index d86dc45be30c..000000000000 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c +++ /dev/null @@ -1,1189 +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.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, - }, - { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, - }, -}; - -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 = - snd_soc_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 = snd_soc_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(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: %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 = snd_soc_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 = - 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_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 = snd_soc_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 = snd_soc_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_LINE("Line Out", 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("Line Out"), - 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 f78197c8e582..771d53611c2a 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c @@ -1,11 +1,14 @@ // 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/consumer.h> #include <linux/input.h> @@ -16,11 +19,13 @@ #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" @@ -32,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[] = { { @@ -158,17 +173,23 @@ 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 = 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; @@ -189,19 +210,94 @@ 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; + + 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 = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); @@ -257,7 +353,7 @@ static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rt 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"); @@ -266,13 +362,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_LINEOUT, 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, @@ -297,14 +393,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); } @@ -313,112 +409,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 = snd_soc_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_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 = snd_soc_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; + !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); } - 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")), @@ -639,7 +651,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .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), }, { @@ -673,7 +685,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .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), }, { @@ -740,7 +752,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .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), }, { @@ -762,7 +774,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .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), }, { @@ -879,7 +891,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .dpcm_playback = 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), }, { @@ -887,7 +898,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .no_pcm = 1, .dpcm_capture = 1, .ignore_suspend = 1, - .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, .ops = &mt8186_rt5682s_i2s_ops, SND_SOC_DAILINK_REG(i2s0), }, @@ -896,9 +906,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .no_pcm = 1, .dpcm_playback = 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), }, { @@ -906,7 +914,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .no_pcm = 1, .dpcm_capture = 1, .ignore_suspend = 1, - .be_hw_params_fixup = mt8186_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s2), }, { @@ -1029,6 +1036,19 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { }; 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), @@ -1081,6 +1101,14 @@ static const struct snd_soc_dapm_route mt8186_mt6366_rt5650_routes[] = { {"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"), @@ -1089,6 +1117,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, @@ -1134,187 +1177,222 @@ static struct snd_soc_card mt8186_mt6366_rt5650_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 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; + 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"); - 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 'playback-codecs' missing or invalid\n"); - goto err_playback_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"); - 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 playback_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; + + mach_priv = devm_kzalloc(card->dev, sizeof(*mach_priv), GFP_KERNEL); + if (!mach_priv) + return -ENOMEM; - snd_soc_card_set_drvdata(card, soc_card_data); + soc_card_data->mach_priv = mach_priv; - ret = mt8186_afe_gpio_init(&pdev->dev); - if (ret) { - dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__); - goto err_probe; + 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_soc_card, + .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..1178bce45c50 100644 --- a/sound/soc/mediatek/mt8188/Makefile +++ b/sound/soc/mediatek/mt8188/Makefile @@ -1,7 +1,7 @@ # 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 \ diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c index 46d6a5540403..ccb6c1f3adc7 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c @@ -91,7 +91,7 @@ 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; @@ -300,7 +300,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; @@ -334,7 +334,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[id]; @@ -358,7 +358,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[id]; @@ -3030,25 +3030,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; @@ -3350,7 +3331,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"); diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c index 7dc029f2b428..8a17d1935c48 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; @@ -440,7 +357,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 +391,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-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index a391066ab204..eba6f4c445ff 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -236,11 +236,11 @@ static const struct sof_conn_stream g_sof_conn_streams[] = { }, }; -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; +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[] = { @@ -268,11 +268,6 @@ static struct snd_soc_jack_pin nau8825_jack_pins[] = { }, }; -struct mt8188_card_data { - const char *name; - unsigned long quirk; -}; - static const struct snd_kcontrol_new mt8188_dumb_spk_controls[] = { SOC_DAPM_PIN_SWITCH("Ext Spk"), }; @@ -562,7 +557,7 @@ enum { 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; @@ -590,12 +585,12 @@ 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 mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); - struct mt8188_mt6359_priv *priv = soc_card_data->mach_priv; + 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_LINEOUT, jack, mt8188_hdmi_jack_pins, ARRAY_SIZE(mt8188_hdmi_jack_pins)); if (ret) { @@ -603,7 +598,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); @@ -616,19 +611,19 @@ 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 mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); - struct mt8188_mt6359_priv *priv = soc_card_data->mach_priv; + 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, + 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); @@ -663,7 +658,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai; @@ -736,10 +731,9 @@ static int mt8188_max98390_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 mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mt8188_mt6359_priv *priv = soc_card_data->mach_priv; + 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 snd_soc_jack *jack = &priv->headset_jack; int ret; ret = snd_soc_dapm_new_controls(&card->dapm, mt8188_nau8825_widgets, @@ -827,7 +821,7 @@ static const struct snd_soc_ops mt8188_nau8825_ops = { static int mt8188_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 = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); @@ -1224,11 +1218,10 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { static void mt8188_fixup_controls(struct snd_soc_card *card) { struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); - struct mt8188_mt6359_priv *priv = soc_card_data->mach_priv; - struct mt8188_card_data *card_data = (struct mt8188_card_data *)priv->private_data; + struct mtk_platform_card_data *card_data = soc_card_data->card_data; struct snd_kcontrol *kctl; - if (card_data->quirk & (NAU8825_HS_PRESENT | RT5682S_HS_PRESENT | ES8326_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) { @@ -1259,14 +1252,10 @@ static struct snd_soc_card mt8188_mt6359_soc_card = { .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 device_node *adsp_node; - struct mtk_soc_card_data *soc_card_data; - 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; @@ -1274,91 +1263,12 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev) 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; - - 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; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL); - if (!soc_card_data) - return -ENOMEM; - - soc_card_data->mach_priv = 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); - 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; - } - - 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", - mt8188_mt6359_dai_links, - ARRAY_SIZE(mt8188_mt6359_dai_links)); - if (ret) { - dev_err_probe(&pdev->dev, ret, "Parse dai-link fail\n"); - goto err_adsp_node; - } - } else { - if (!adsp_node) - card->num_links = DAI_LINK_REGULAR_NUM; - } - - platform_node = of_parse_phandle(pdev->dev.of_node, - "mediatek,platform", 0); - if (!platform_node) { - ret = dev_err_probe(&pdev->dev, -EINVAL, - "Property 'platform' missing or invalid\n"); - goto err_adsp_node; - - } + 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) { - if (!strncmp(dai_link->name, "AFE_SOF", strlen("AFE_SOF")) && adsp_node) - dai_link->platforms->of_node = adsp_node; - else - 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")) dai_link->init = mt8188_dptx_codec_init; @@ -1381,7 +1291,7 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev) * mt8188_max98390_ops. Two amps is I2S mode, * SOC and codec don't require TDM settings. */ - if (!(card_data->quirk & MAX98390_TWO_AMP)) { + if (!(card_data->flags & MAX98390_TWO_AMP)) { dai_link->ops = &mt8188_max98390_ops; } if (!init_max98390) { @@ -1420,40 +1330,55 @@ static int mt8188_mt6359_dev_probe(struct platform_device *pdev) } } - priv->private_data = card_data; - snd_soc_card_set_drvdata(card, soc_card_data); - - 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); - -err_adsp_node: - of_node_put(adsp_node); - - 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 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 struct mt8188_card_data mt8188_nau8825_card = { - .name = "mt8188_nau8825", - .quirk = NAU8825_HS_PRESENT, +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 struct mt8188_card_data mt8188_rt5682s_card = { - .name = "mt8188_rt5682s", - .quirk = RT5682S_HS_PRESENT | MAX98390_TWO_AMP, +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 struct mt8188_card_data mt8188_es8326_card = { - .name = "mt8188_es8326", - .quirk = ES8326_HS_PRESENT | MAX98390_TWO_AMP, +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[] = { @@ -1471,7 +1396,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/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-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c index bdd1e91824d9..424c5c68f78a 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -2125,22 +2125,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; @@ -2205,44 +2189,34 @@ 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(&pdev->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); 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); afe_priv->pm_runtime_bypass_reg_ctl = false; @@ -2254,10 +2228,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 +2243,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; @@ -2326,27 +2286,13 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev) /* 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, + &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) diff --git a/sound/soc/mediatek/mt8192/mt8192-dai-adda.c b/sound/soc/mediatek/mt8192/mt8192-dai-adda.c index 36d33032a37a..99de85b87643 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), @@ -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-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 bfcb2c486c39..8b323fb19925 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -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 */ @@ -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 = snd_soc_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; 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 = snd_soc_rtd_to_codec(rtd, 0)->component; - struct mt8192_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card); 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_LINEOUT, 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 = snd_soc_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 = snd_soc_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")), @@ -717,7 +626,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, .dpcm_playback = 1, - .ops = &mt8192_mt6359_rt5682_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(playback3), }, { @@ -781,7 +690,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8192_mt6359_capture1_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(capture1), }, { @@ -791,7 +700,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8192_mt6359_rt5682_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(capture2), }, { @@ -1136,71 +1045,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; - - 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"); + int i, ret = 0; - 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) { @@ -1211,52 +1102,122 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) if (dai_link->num_codecs && dai_link->codecs[0].dai_name && 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); + if (hdmi_codec) + 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 && dai_link->codecs[0].dai_name && + 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, }, {} }; @@ -1276,7 +1237,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-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 620d7ade1992..38891d1bd18a 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -84,7 +84,7 @@ 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); @@ -281,7 +281,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; @@ -310,7 +310,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; @@ -342,7 +342,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; @@ -380,7 +380,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[id]; @@ -2944,25 +2944,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; @@ -3164,7 +3145,7 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev) } /* register component */ - ret = devm_snd_soc_register_component(dev, &mt8195_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"); diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-adda.c b/sound/soc/mediatek/mt8195/mt8195-dai-adda.c index 0dd35255066b..8da1587128cc 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; @@ -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-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 53fd8a897b9d..ca8751190520 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -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[] = { { @@ -321,44 +328,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 = snd_soc_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,7 +338,7 @@ 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_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, @@ -382,33 +352,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 = 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_LINEOUT, 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 = 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_LINEOUT, 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,102 +391,10 @@ 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 = snd_soc_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 = snd_soc_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 = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); @@ -566,7 +442,7 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) 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); @@ -687,7 +563,7 @@ 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; int ret; @@ -707,6 +583,18 @@ static int mt8195_rt1019_init(struct snd_soc_pcm_runtime *rtd) return ret; } + return 0; +} + +static int mt8195_rt1019_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = mt8195_dumb_amp_init(rtd); + if (ret) + return ret; + ret = snd_soc_dapm_add_routes(&card->dapm, mt8195_rt1019_routes, ARRAY_SIZE(mt8195_rt1019_routes)); if (ret) @@ -1025,7 +913,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, - .ops = &mt8195_playback_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL2_FE), }, [DAI_LINK_DL3_FE] = { @@ -1037,7 +925,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, - .ops = &mt8195_playback_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL3_FE), }, [DAI_LINK_DL6_FE] = { @@ -1049,7 +937,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, - .ops = &mt8195_playback_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL6_FE), }, [DAI_LINK_DL7_FE] = { @@ -1072,7 +960,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, - .ops = &mt8195_playback_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL8_FE), }, [DAI_LINK_DL10_FE] = { @@ -1096,7 +984,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_playback = 1, - .ops = &mt8195_playback_ops, + .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL11_FE), }, [DAI_LINK_UL1_FE] = { @@ -1119,7 +1007,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL2_FE), }, [DAI_LINK_UL3_FE] = { @@ -1131,7 +1019,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL3_FE), }, [DAI_LINK_UL4_FE] = { @@ -1143,7 +1031,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL4_FE), }, [DAI_LINK_UL5_FE] = { @@ -1155,7 +1043,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL5_FE), }, [DAI_LINK_UL6_FE] = { @@ -1178,7 +1066,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL8_FE), }, [DAI_LINK_UL9_FE] = { @@ -1190,7 +1078,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL9_FE), }, [DAI_LINK_UL10_FE] = { @@ -1202,7 +1090,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { }, .dynamic = 1, .dpcm_capture = 1, - .ops = &mt8195_capture_ops, + .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL10_FE), }, /* BE */ @@ -1371,108 +1259,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, *codec_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; + struct device *dev = card->dev; + bool is5682s, init6359 = false; + int i; if (strstr(card->name, "_5682s")) { codec_node = of_find_compatible_node(NULL, NULL, "realtek,rt5682s"); - is5682s = 1; - } else - codec_node = of_find_compatible_node(NULL, NULL, "realtek,rt5682i"); - - 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; - } - - 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; - } + 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,7 +1292,7 @@ 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; @@ -1490,7 +1301,7 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) } } else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0) { if (!codec_node) { - dev_err(&pdev->dev, "Codec not found!\n"); + dev_err(dev, "Codec not found!\n"); } else { dai_link->codecs->of_node = codec_node; dai_link->codecs->name = NULL; @@ -1501,7 +1312,7 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) } } else if (strcmp(dai_link->name, "ETDM2_IN_BE") == 0) { if (!codec_node) { - dev_err(&pdev->dev, "Codec not found!\n"); + dev_err(dev, "Codec not found!\n"); } else { dai_link->codecs->of_node = codec_node; dai_link->codecs->name = NULL; @@ -1514,10 +1325,10 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) 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); @@ -1545,33 +1356,159 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev) } } - snd_soc_card_set_drvdata(card, soc_card_data); + return 0; +} - ret = devm_snd_soc_register_card(&pdev->dev, card); +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; - 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; + mach_priv = devm_kzalloc(card->dev, sizeof(*mach_priv), GFP_KERNEL); + if (!mach_priv) + return -ENOMEM; + + soc_card_data->mach_priv = mach_priv; + + if (legacy) + return mt8195_mt6359_legacy_probe(soc_card_data); + + for_each_card_prelinks(card, i, dai_link) { + if (strcmp(dai_link->name, "DPTX_BE") == 0) { + if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + dai_link->init = mt8195_dptx_codec_init; + } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { + if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + 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 (!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 (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) { + 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 of_device_id mt8195_mt6359_dt_match[] = { @@ -1597,7 +1534,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/meson/Kconfig b/sound/soc/meson/Kconfig index b93ea33739f2..6458d5dc4902 100644 --- a/sound/soc/meson/Kconfig +++ b/sound/soc/meson/Kconfig @@ -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-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c index 7d833500c799..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 | diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c index fa91f3c53fa4..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 | diff --git a/sound/soc/meson/aiu-fifo.c b/sound/soc/meson/aiu-fifo.c index 4041ff8e437f..b222bde1f61b 100644 --- a/sound/soc/meson/aiu-fifo.c +++ b/sound/soc/meson/aiu-fifo.c @@ -25,7 +25,7 @@ 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 snd_soc_rtd_to_cpu(rtd, 0); } diff --git a/sound/soc/meson/aiu-fifo.h b/sound/soc/meson/aiu-fifo.h index 42ce266677cc..84ab4577815a 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; diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 3180aa4d3a15..8c5605c1e34e 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -318,6 +318,7 @@ 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); if (ret) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index bebee0ca8e38..59abe0b3c59f 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -23,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 | @@ -46,7 +46,7 @@ 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 snd_soc_rtd_to_cpu(rtd, 0); } @@ -204,18 +204,26 @@ 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); + + /* Use the thread to call period elapsed on nonatomic links */ if (status & FIFO_INT_COUNT_REPEAT) - snd_pcm_period_elapsed(ss); - else - dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n", - status); + return IRQ_WAKE_THREAD; - /* Ack irqs */ - axg_fifo_ack_irq(fifo, status); + dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n", + status); + + return IRQ_NONE; +} + +static irqreturn_t axg_fifo_pcm_irq_block_thread(int irq, void *dev_id) +{ + struct snd_pcm_substream *ss = dev_id; + + snd_pcm_period_elapsed(ss); - return IRQ_RETVAL(status); + return IRQ_HANDLED; } int axg_fifo_pcm_open(struct snd_soc_component *component, @@ -243,8 +251,9 @@ 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); + ret = request_threaded_irq(fifo->irq, axg_fifo_pcm_irq_block, + axg_fifo_pcm_irq_block_thread, + IRQF_ONESHOT, dev_name(dev), ss); if (ret) return ret; diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 63333a2b0a9c..a6579efd3775 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -392,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 bf708717635b..62057c71f742 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -309,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) { @@ -346,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, @@ -354,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) @@ -412,8 +430,8 @@ static const struct snd_soc_dai_ops axg_tdm_iface_ops = { .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 */ diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h index 42f7470b9a7f..daaca10fec9e 100644 --- a/sound/soc/meson/axg-tdm.h +++ b/sound/soc/meson/axg-tdm.h @@ -58,12 +58,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/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/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/qcom/Makefile b/sound/soc/qcom/Makefile index 34f3fcb8ee9a..16db7b53ddac 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,17 +19,17 @@ 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-x1e80100-objs := x1e80100.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 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 4834a56eaa88..3023cf180a75 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -192,7 +192,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0); @@ -213,7 +213,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0); diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 747041fa7866..3d02aa3844f2 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -239,4 +239,6 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, return 0; } EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup); + +MODULE_DESCRIPTION("ASoC Qualcomm helper functions"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 3963bf234664..26b7c55c9c11 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 diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 00bbd291be5c..c7df8343b2dc 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -70,14 +70,10 @@ struct q6apm_dai_rtd { unsigned int bytes_received; unsigned int copied_total; uint16_t bits_per_sample; - uint16_t source; /* Encoding source bit mask */ - uint16_t session_id; bool next_track; enum stream_state state; struct q6apm_graph *graph; spinlock_t lock; - uint32_t initial_samples_drop; - uint32_t trailing_samples_drop; bool notify_on_drain; }; @@ -85,7 +81,7 @@ 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 | @@ -104,7 +100,7 @@ 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 | @@ -331,7 +327,7 @@ 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_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; @@ -720,14 +716,12 @@ static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component, switch (metadata->key) { case SNDRV_COMPRESS_ENCODER_PADDING: - prtd->trailing_samples_drop = metadata->value[0]; q6apm_remove_trailing_silence(component->dev, prtd->graph, - prtd->trailing_samples_drop); + metadata->value[0]); break; case SNDRV_COMPRESS_ENCODER_DELAY: - prtd->initial_samples_drop = metadata->value[0]; q6apm_remove_initial_silence(component->dev, prtd->graph, - prtd->initial_samples_drop); + metadata->value[0]); break; default: ret = -EINVAL; diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index aeb6a9d479ab..3913706ccdc5 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -103,7 +103,7 @@ 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 | 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/sc7180.c b/sound/soc/qcom/sc7180.c index 029780d6fe6d..bc030ce29680 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -200,7 +200,7 @@ static int sc7180_startup_realtek_codec(struct snd_soc_pcm_runtime *rtd) static int sc7180_snd_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 sc7180_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -234,7 +234,7 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) static int sc7180_qdsp_snd_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 sc7180_snd_data *data = snd_soc_card_get_drvdata(card); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -307,7 +307,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0); @@ -334,7 +334,7 @@ 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 = 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 = snd_soc_rtd_to_cpu(rtd, 0); @@ -389,7 +389,7 @@ 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_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; diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index d36f029b7888..207ac5da4dd4 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -205,7 +205,7 @@ 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_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -237,7 +237,7 @@ 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; + 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]; @@ -268,7 +268,7 @@ static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream) static int sc7280_snd_prepare(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); const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { @@ -287,7 +287,7 @@ 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 = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -312,7 +312,7 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream) 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 = snd_soc_rtd_to_cpu(rtd, 0); @@ -339,7 +339,7 @@ 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_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; diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index b7fd503a1666..06fd47c4178f 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -50,7 +50,7 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) static void sc8280xp_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_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id]; @@ -89,7 +89,7 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 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_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 *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -98,7 +98,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, static int sc8280xp_snd_prepare(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 *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]; @@ -109,7 +109,7 @@ static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) 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 = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -169,6 +169,8 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) } static const struct of_device_id snd_sc8280xp_dt_match[] = { + {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"}, + {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"}, {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, {.compatible = "qcom,sm8450-sndcard", "sm8450"}, {.compatible = "qcom,sm8550-sndcard", "sm8550"}, diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index 7f5089bbe022..eaa8bb016e50 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -21,7 +21,7 @@ */ int qcom_snd_sdw_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_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime; struct snd_soc_dai *codec_dai; @@ -54,7 +54,7 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream, struct sdw_stream_runtime *sruntime, bool *stream_prepared) { - 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 *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); int ret; @@ -105,7 +105,7 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct sdw_stream_runtime **psruntime) { - 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 = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime; @@ -135,7 +135,7 @@ EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params); int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, struct sdw_stream_runtime *sruntime, bool *stream_prepared) { - 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 *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index d70df72c0160..a15dafb99b33 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -50,7 +50,7 @@ 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_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); @@ -72,7 +72,7 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) static void sm2450_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_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]; @@ -84,7 +84,7 @@ static void sm2450_snd_shutdown(struct snd_pcm_substream *substream) 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_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 *pdata = snd_soc_card_get_drvdata(rtd->card); @@ -93,7 +93,7 @@ static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, static int sm8250_snd_prepare(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 *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]; @@ -104,7 +104,7 @@ static int sm8250_snd_prepare(struct snd_pcm_substream *substream) 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 = snd_soc_rtd_to_cpu(rtd, 0); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index c3c8bf7ffb5b..0e0773a85809 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -31,7 +31,7 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) static void x1e80100_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_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -67,7 +67,7 @@ static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int x1e80100_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_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); @@ -76,7 +76,7 @@ static int x1e80100_snd_hw_params(struct snd_pcm_substream *substream, static int x1e80100_snd_prepare(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 *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; @@ -87,7 +87,7 @@ static int x1e80100_snd_prepare(struct snd_pcm_substream *substream) static int x1e80100_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 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 sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 30c57c0d7660..2ee9c08131d1 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -1,19 +1,19 @@ # 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-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_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/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/i2s.c b/sound/soc/samsung/i2s.c index 9552748aea2e..1bcabb114e29 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1755,5 +1755,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/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index f31244156ff6..0841e2e6f8ce 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -127,7 +127,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" */ diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index f6fd79948f6a..f0e19cbd1581 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/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/rcar/Makefile b/sound/soc/sh/rcar/Makefile index d07eccfa3ac2..45eb875a912a 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o +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 diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 329e6ab1b222..8d9a1e345a22 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/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/sh/rcar/core.c index 0b1aa23c1189..6bc7027ed4db 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1512,7 +1512,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) continue; for_each_endpoint_of_node(ports, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + 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); @@ -1531,7 +1531,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) for_each_child_of_node(node, dai_np) { __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { + 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); diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index e39eb2ac7e95..a26ec7b780cd 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/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 @@ -323,10 +323,6 @@ int rsnd_ctu_probe(struct rsnd_priv *priv) 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 */ diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 1c494e521463..7b499eee5080 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -585,8 +585,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 +666,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/sh/rcar/dvc.c index 16befcbc312c..da91dd301aab 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/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 @@ -331,10 +331,6 @@ int rsnd_dvc_probe(struct rsnd_priv *priv) 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 */ diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 86bdecc24956..d1f20cde66be 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -178,8 +178,6 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, 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); @@ -216,69 +214,219 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, } /* + * (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) { - 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); + 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; } @@ -288,215 +436,17 @@ static int rsnd_gen4_probe(struct rsnd_priv *priv) */ 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; + /* + * 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; } /* @@ -505,30 +455,13 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) 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; + /* + * 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 0; + return ret_adg | ret_ssi; } /* diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 1de0e085804c..024d91cc8748 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/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 @@ -295,10 +295,6 @@ int rsnd_mix_probe(struct rsnd_priv *priv) 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 */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index da716b1f52e4..ff294aa2d640 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -20,20 +20,11 @@ #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 /* @@ -200,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, @@ -713,7 +703,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)) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3241a1bdc9ea..e7f86db0d94c 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -310,7 +310,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: @@ -606,13 +606,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 @@ -652,10 +652,6 @@ int rsnd_src_probe(struct rsnd_priv *priv) 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 */ diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0a46aa1975fa..8d2a86383ae0 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -1049,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 diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 17bd8cc86dd0..665e8b2db579 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/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 diff --git a/sound/soc/soc-card-test.c b/sound/soc/soc-card-test.c new file mode 100644 index 000000000000..e4a4b101d743 --- /dev/null +++ b/sound/soc/soc-card-test.c @@ -0,0 +1,186 @@ +// 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 void test_snd_soc_card_get_kcontrol_locked(struct kunit *test) +{ + struct soc_card_test_priv *priv = test->priv; + struct snd_soc_card *card = priv->card; + struct snd_kcontrol *kc, *kcw; + 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) { + down_read(&card->snd_card->controls_rwsem); + kc = snd_soc_card_get_kcontrol_locked(card, test_card_controls[i].name); + up_read(&card->snd_card->controls_rwsem); + 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); + + down_write(&card->snd_card->controls_rwsem); + kcw = snd_soc_card_get_kcontrol_locked(card, test_card_controls[i].name); + up_write(&card->snd_card->controls_rwsem); + KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, kcw, "Failed to find '%s'\n", + test_card_controls[i].name); + + KUNIT_EXPECT_PTR_EQ(test, kc, kcw); + } + + /* Test some names that should not be found */ + down_read(&card->snd_card->controls_rwsem); + kc = snd_soc_card_get_kcontrol_locked(card, "None"); + up_read(&card->snd_card->controls_rwsem); + KUNIT_EXPECT_NULL(test, kc); + + down_read(&card->snd_card->controls_rwsem); + kc = snd_soc_card_get_kcontrol_locked(card, "Left None"); + up_read(&card->snd_card->controls_rwsem); + KUNIT_EXPECT_NULL(test, kc); + + down_read(&card->snd_card->controls_rwsem); + kc = snd_soc_card_get_kcontrol_locked(card, "Left"); + up_read(&card->snd_card->controls_rwsem); + KUNIT_EXPECT_NULL(test, kc); + + down_read(&card->snd_card->controls_rwsem); + kc = snd_soc_card_get_kcontrol_locked(card, NULL); + up_read(&card->snd_card->controls_rwsem); + 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), + KUNIT_CASE(test_snd_soc_card_get_kcontrol_locked), + {} +}; + +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 8a2f163da6bc..0a3104d4ad23 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -32,33 +32,20 @@ static inline int _soc_card_ret(struct snd_soc_card *card, struct snd_kcontrol *snd_soc_card_get_kcontrol_locked(struct snd_soc_card *soc_card, const char *name) { - struct snd_card *card = soc_card->snd_card; - struct snd_kcontrol *kctl; - - /* must be held read or write */ - lockdep_assert_held(&card->controls_rwsem); - 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_locked(soc_card->snd_card, name); } EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol_locked); 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; - - down_read(&card->controls_rwsem); - kctl = snd_soc_card_get_kcontrol_locked(soc_card, name); - up_read(&card->controls_rwsem); + if (unlikely(!name)) + return NULL; - return kctl; + return snd_ctl_find_id_mixer(soc_card->snd_card, name); } EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ec13d1634b6..3ab6626ad680 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2796,10 +2796,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, &component->id); + if (!component->name) { + dev_err(dev, "ASoC: Failed to allocate name\n"); + return -ENOMEM; + } } component->dev = dev; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 6f8773a8fc05..fefe394dce72 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -45,7 +45,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. */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ad8ba8fbbaee..16dad4a45443 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2094,6 +2094,48 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) } #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) @@ -2104,6 +2146,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) @@ -2136,6 +2181,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) { @@ -2145,11 +2193,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); } } diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 092ca09f3631..ea3bc9318412 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -441,6 +441,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 +494,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 b2cc13b9c77b..63971396b708 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> @@ -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-ops.c b/sound/soc/soc-ops.c index 2d25748ca706..b27e89ff6a16 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -263,7 +263,7 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, int max = mc->max; int min = mc->min; int sign_bit = mc->sign_bit; - unsigned int mask = (1 << fls(max)) - 1; + unsigned int mask = (1ULL << fls(max)) - 1; unsigned int invert = mc->invert; int val; int ret; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 77ee103b7cd1..711b2f49ed88 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -315,23 +315,24 @@ 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; } /** @@ -723,7 +724,7 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd, } } - 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); diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c index 70cbccc42a42..d62a02ec5896 100644 --- a/sound/soc/soc-topology-test.c +++ b/sound/soc/soc-topology-test.c @@ -2,7 +2,7 @@ /* * 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> @@ -819,4 +819,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 ba4890991f0d..90ca37e008b3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1083,8 +1083,15 @@ 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) { + if (!dapm->card->disable_route_checks) { + dev_err(tplg->dev, "ASoC: dapm_add_routes failed: %d\n", ret); + break; + } + dev_info(tplg->dev, + "ASoC: disable_route_checks set, ignoring dapm_add_routes errors\n"); + } } return ret; @@ -1761,83 +1768,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); @@ -1845,8 +1782,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; @@ -1865,31 +1801,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); @@ -1966,49 +1889,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 @@ -2113,19 +1993,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; @@ -2140,30 +2018,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; @@ -2273,84 +2138,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; } diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 3624124575af..b0b22e6ebc03 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,44 +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\ +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_IPC4),) -snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\ +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_IPC4),) -snd-sof-probes-objs += sof-client-probes-ipc4.o +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/Makefile b/sound/soc/sof/amd/Makefile index ad25f4206177..63fe0d55fd0e 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -4,15 +4,15 @@ # # Copyright(c) 2021, 2023 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-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o -snd-sof-amd-renoir-objs := pci-rn.o renoir.o -snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o -snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o -snd-sof-amd-acp63-objs := pci-acp63.o acp63.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 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_VANGOGH) +=snd-sof-amd-vangogh.o -obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) +=snd-sof-amd-acp63.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 diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 0fc4e20ec673..b26fa471b431 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -193,7 +193,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, diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index aad904839b81..2d5e58846499 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -289,6 +289,8 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) 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, diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index be7dc1e02284..c12c7f820529 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -704,6 +704,10 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) goto unregister_dev; } + ret = acp_init(sdev); + if (ret < 0) + goto free_smn_dev; + sdev->ipc_irq = pci->irq; ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, IRQF_SHARED, "AudioDSP", sdev); @@ -713,10 +717,6 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) goto free_smn_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) { diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index e229bb6b849d..87e79d500865 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -310,7 +310,7 @@ 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); diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 75e13f4fd1eb..463d418e7200 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> // diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 9b00ede2a486..0a4917136ff9 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> // @@ -339,8 +339,7 @@ static int sof_init_environment(struct snd_sof_dev *sdev) ret = snd_sof_probe(sdev); if (ret < 0) { dev_err(sdev->dev, "failed to probe DSP %d\n", ret); - sof_ops_free(sdev); - return ret; + goto err_sof_probe; } /* check machine info */ @@ -351,22 +350,27 @@ static int sof_init_environment(struct snd_sof_dev *sdev) } ret = sof_select_ipc_and_paths(sdev); - if (!ret && plat_data->ipc_type != base_profile->ipc_type) { + 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: - if (ret) { - snd_sof_remove(sdev); - sof_ops_free(sdev); - } + snd_sof_remove(sdev); +err_sof_probe: + snd_sof_remove_late(sdev); + sof_ops_free(sdev); return ret; } diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 7c8aafca8fde..d0ffa1d71145 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 */ @@ -330,14 +311,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); diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c index b56b14232444..1c0eb13ae557 100644 --- a/sound/soc/sof/fw-file-profile.c +++ b/sound/soc/sof/fw-file-profile.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) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation // #include <linux/firmware.h> diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile index 798b43a415bf..be0bf0736dfa 100644 --- a/sound/soc/sof/imx/Makefile +++ b/sound/soc/sof/imx/Makefile @@ -1,9 +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-imx8m-y := imx8m.o +snd-sof-imx8ulp-y := imx8ulp.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 diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index 36e3d414a18f..2981aea123d9 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -74,28 +74,4 @@ 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) -{ - int ret; - - ret = devm_clk_bulk_get(sdev->dev, clks->num_dsp_clks, clks->dsp_clks); - if (ret) - dev_err(sdev->dev, "Failed to request DSP clocks\n"); - - return ret; -} -EXPORT_SYMBOL(imx8_parse_clocks); - -int imx8_enable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks) -{ - return clk_bulk_prepare_enable(clks->num_dsp_clks, clks->dsp_clks); -} -EXPORT_SYMBOL(imx8_enable_clocks); - -void imx8_disable_clocks(struct snd_sof_dev *sdev, struct imx_clocks *clks) -{ - clk_bulk_disable_unprepare(clks->num_dsp_clks, clks->dsp_clks); -} -EXPORT_SYMBOL(imx8_disable_clocks); - MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h index ec4b3a5c7496..13d7f3ef675e 100644 --- a/sound/soc/sof/imx/imx-common.h +++ b/sound/soc/sof/imx/imx-common.h @@ -15,13 +15,4 @@ 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); - #endif diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 07f51489d6c9..3021dc87ab5a 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -41,13 +41,6 @@ #define MBOX_OFFSET 0x800000 #define MBOX_SIZE 0x1000 -/* DSP clocks */ -static struct clk_bulk_data imx8_dsp_clks[] = { - { .id = "ipg" }, - { .id = "ocram" }, - { .id = "core" }, -}; - struct imx8_priv { struct device *dev; struct snd_sof_dev *sdev; @@ -64,7 +57,8 @@ struct imx8_priv { struct device **pd_dev; struct device_link **link; - struct imx_clocks *clks; + struct clk_bulk_data *clks; + int clk_num; }; static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) @@ -196,10 +190,6 @@ static int imx8_probe(struct snd_sof_dev *sdev) 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; @@ -313,17 +303,18 @@ static int imx8_probe(struct snd_sof_dev *sdev) /* set default mailbox offset for FW ready message */ sdev->dsp_box.offset = MBOX_OFFSET; - /* init clocks info */ - priv->clks->dsp_clks = imx8_dsp_clks; - priv->clks->num_dsp_clks = ARRAY_SIZE(imx8_dsp_clks); - - ret = imx8_parse_clocks(sdev, priv->clks); - if (ret < 0) + ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret); goto exit_pdev_unregister; + } + priv->clk_num = ret; - ret = imx8_enable_clocks(sdev, priv->clks); - if (ret < 0) + ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); goto exit_pdev_unregister; + } return 0; @@ -343,7 +334,7 @@ static void imx8_remove(struct snd_sof_dev *sdev) struct imx8_priv *priv = sdev->pdata->hw_pdata; int i; - imx8_disable_clocks(sdev, priv->clks); + clk_bulk_disable_unprepare(priv->clk_num, priv->clks); platform_device_unregister(priv->ipc_dev); for (i = 0; i < priv->num_domains; i++) { @@ -373,7 +364,7 @@ static void imx8_suspend(struct snd_sof_dev *sdev) for (i = 0; i < DSP_MU_CHAN_NUM; i++) imx_dsp_free_channel(priv->dsp_ipc, i); - imx8_disable_clocks(sdev, priv->clks); + clk_bulk_disable_unprepare(priv->clk_num, priv->clks); } static int imx8_resume(struct snd_sof_dev *sdev) @@ -382,9 +373,11 @@ static int imx8_resume(struct snd_sof_dev *sdev) int ret; int i; - ret = imx8_enable_clocks(sdev, priv->clks); - if (ret < 0) + ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); return ret; + } for (i = 0; i < DSP_MU_CHAN_NUM; i++) imx_dsp_request_channel(priv->dsp_ipc, i); @@ -485,7 +478,7 @@ static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev, } /* i.MX8 ops */ -static struct snd_sof_dsp_ops sof_imx8_ops = { +static const struct snd_sof_dsp_ops sof_imx8_ops = { /* probe and remove */ .probe = imx8_probe, .remove = imx8_remove, @@ -546,7 +539,7 @@ static struct snd_sof_dsp_ops sof_imx8_ops = { }; /* i.MX8X ops */ -static struct snd_sof_dsp_ops sof_imx8x_ops = { +static const struct snd_sof_dsp_ops sof_imx8x_ops = { /* probe and remove */ .probe = imx8_probe, .remove = imx8_remove, diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 222cd1467da6..4ed415f04345 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -26,12 +26,6 @@ #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) @@ -54,7 +48,8 @@ struct imx8m_priv { struct imx_dsp_ipc *dsp_ipc; struct platform_device *ipc_dev; - struct imx_clocks *clks; + struct clk_bulk_data *clks; + int clk_num; void __iomem *dap; struct regmap *regmap; @@ -163,10 +158,6 @@ static int imx8m_probe(struct snd_sof_dev *sdev) 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; @@ -250,17 +241,18 @@ static int imx8m_probe(struct snd_sof_dev *sdev) 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) + ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret); goto exit_pdev_unregister; + } + priv->clk_num = ret; - ret = imx8_enable_clocks(sdev, priv->clks); - if (ret < 0) + ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); goto exit_pdev_unregister; + } return 0; @@ -273,7 +265,7 @@ static void imx8m_remove(struct snd_sof_dev *sdev) { struct imx8m_priv *priv = sdev->pdata->hw_pdata; - imx8_disable_clocks(sdev, priv->clks); + clk_bulk_disable_unprepare(priv->clk_num, priv->clks); platform_device_unregister(priv->ipc_dev); } @@ -336,9 +328,11 @@ static int imx8m_resume(struct snd_sof_dev *sdev) int ret; int i; - ret = imx8_enable_clocks(sdev, priv->clks); - if (ret < 0) + ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); return ret; + } for (i = 0; i < DSP_MU_CHAN_NUM; i++) imx_dsp_request_channel(priv->dsp_ipc, i); @@ -354,7 +348,7 @@ static void imx8m_suspend(struct snd_sof_dev *sdev) for (i = 0; i < DSP_MU_CHAN_NUM; i++) imx_dsp_free_channel(priv->dsp_ipc, i); - imx8_disable_clocks(sdev, priv->clks); + clk_bulk_disable_unprepare(priv->clk_num, priv->clks); } static int imx8m_dsp_runtime_resume(struct snd_sof_dev *sdev) @@ -417,7 +411,7 @@ static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state } /* i.MX8 ops */ -static struct snd_sof_dsp_ops sof_imx8m_ops = { +static const struct snd_sof_dsp_ops sof_imx8m_ops = { /* probe and remove */ .probe = imx8m_probe, .remove = imx8m_remove, diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c index 7b527ffde488..8adfdd00413a 100644 --- a/sound/soc/sof/imx/imx8ulp.c +++ b/sound/soc/sof/imx/imx8ulp.c @@ -40,13 +40,6 @@ #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; @@ -56,7 +49,8 @@ struct imx8ulp_priv { struct platform_device *ipc_dev; struct regmap *regmap; - struct imx_clocks *clks; + struct clk_bulk_data *clks; + int clk_num; }; static void imx8ulp_sim_lpav_start(struct imx8ulp_priv *priv) @@ -175,10 +169,6 @@ static int imx8ulp_probe(struct snd_sof_dev *sdev) 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; @@ -259,16 +249,18 @@ static int imx8ulp_probe(struct snd_sof_dev *sdev) 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) + ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret); goto exit_pdev_unregister; + } + priv->clk_num = ret; - ret = imx8_enable_clocks(sdev, priv->clks); - if (ret < 0) + ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); goto exit_pdev_unregister; + } return 0; @@ -282,7 +274,7 @@ static void imx8ulp_remove(struct snd_sof_dev *sdev) { struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; - imx8_disable_clocks(sdev, priv->clks); + clk_bulk_disable_unprepare(priv->clk_num, priv->clks); platform_device_unregister(priv->ipc_dev); } @@ -303,7 +295,7 @@ static int imx8ulp_suspend(struct snd_sof_dev *sdev) for (i = 0; i < DSP_MU_CHAN_NUM; i++) imx_dsp_free_channel(priv->dsp_ipc, i); - imx8_disable_clocks(sdev, priv->clks); + clk_bulk_disable_unprepare(priv->clk_num, priv->clks); return 0; } @@ -311,9 +303,13 @@ static int imx8ulp_suspend(struct snd_sof_dev *sdev) static int imx8ulp_resume(struct snd_sof_dev *sdev) { struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata; - int i; + int i, ret; - imx8_enable_clocks(sdev, priv->clks); + ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); + return ret; + } for (i = 0; i < DSP_MU_CHAN_NUM; i++) imx_dsp_request_channel(priv->dsp_ipc, i); @@ -412,7 +408,7 @@ static int imx8ulp_dsp_set_power_state(struct snd_sof_dev *sdev, } /* i.MX8 ops */ -static struct snd_sof_dsp_ops sof_imx8ulp_ops = { +static const struct snd_sof_dsp_ops sof_imx8ulp_ops = { /* probe and remove */ .probe = imx8ulp_probe, .remove = imx8ulp_remove, diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 9de86aaa8d07..3396bd46b778 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -97,7 +97,7 @@ config SND_SOC_SOF_MERRIFIELD config SND_SOC_SOF_INTEL_SKL tristate - select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_HDA_GENERIC select SND_SOC_SOF_IPC4 config SND_SOC_SOF_SKYLAKE @@ -122,7 +122,7 @@ 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_IPC4 @@ -148,7 +148,7 @@ 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_IPC4 @@ -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_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_IPC4 + select SND_SOC_SOF_INTEL_CNL config SND_SOC_SOF_TIGERLAKE tristate "SOF support for Tigerlake" @@ -248,7 +250,7 @@ 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_IPC4 @@ -264,9 +266,10 @@ config SND_SOC_SOF_METEORLAKE config SND_SOC_SOF_INTEL_LNL 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_IPC4 + select SND_SOC_SOF_INTEL_MTL config SND_SOC_SOF_LUNARLAKE tristate "SOF support for Lunarlake" @@ -280,6 +283,10 @@ config SND_SOC_SOF_LUNARLAKE 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 @@ -296,7 +303,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)" @@ -316,7 +323,7 @@ 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_SOC_SOF_HDA_LINK_BASELINE tristate diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 6489d0660d58..b56fa5530b8b 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -1,38 +1,39 @@ # 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 lnl.o hda-common-ops.o \ - telemetry.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-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 -snd-sof-pci-intel-lnl-objs := pci-lnl.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 obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index dee6c7f73e80..76a92eaa1359 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) { @@ -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 */ @@ -121,4 +119,3 @@ const struct sof_intel_dsp_desc apl_chip_info = { .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS, }; -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..86af4e9a716e 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> // 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 e30ca086f3f8..3262286a9a9d 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> // @@ -567,7 +567,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, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 373527b206d7..d78d11d4cfbf 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> // @@ -214,7 +214,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, @@ -289,7 +289,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, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 85e1e4760d0e..6a8c7a108ef0 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) { @@ -331,6 +334,7 @@ int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) 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) { @@ -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 */ @@ -467,13 +473,13 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .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, }; -EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); /* * JasperLake is technically derived from IceLake, and should be in @@ -503,10 +509,11 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .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, }; -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..1989147aa6a4 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 9f84b0d287a5..da3db3ed379e 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> // @@ -79,18 +79,27 @@ 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); diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index 2b385cddc385..5fc28039a8e8 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,7 +14,7 @@ #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, @@ -57,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, @@ -102,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..262b482dc0a8 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) { 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) { @@ -221,7 +232,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 +266,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 +326,8 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) bus->chip_init = false; } + +MODULE_LICENSE("Dual BSD/GPL"); +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 c50ca9e72d37..484c76147885 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.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 <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> @@ -145,17 +146,9 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *dai; struct hdac_ext_stream *hext_stream; - /* only allocate a stream_tag for the first DAI in the dailink */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - if (dai == cpu_dai) - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); - else - hext_stream = snd_soc_dai_get_dma_data(dai, substream); - + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); if (!hext_stream) return NULL; @@ -168,14 +161,9 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *dai; - /* only release a stream_tag for the first DAI in the dailink */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - if (dai == cpu_dai) - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); + snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); } static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, @@ -362,6 +350,16 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_hdac_ext_stream_clear(hext_stream); + + /* + * Save the LLP registers in case the stream is + * restarting due PAUSE_RELEASE, or START without a pcm + * close/open since in this case the LLP register is not reset + * to 0 and the delay calculation will return with invalid + * results. + */ + hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL); + hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU); break; default: dev_err(sdev->dev, "unknown trigger command %d\n", cmd); @@ -435,28 +433,6 @@ out: return ret; } -static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev, - struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); - struct snd_sof_widget *swidget = w->dobj.private; - struct snd_sof_dai *dai = swidget->private; - struct sof_ipc4_copier *ipc4_copier = dai->private; - struct sof_ipc4_alh_configuration_blob *blob; - - blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; - - /* - * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using - * the multi-gateway firmware configuration. The DMA hardware can take care of - * multiple links without needing any firmware assistance - */ - blob->alh_cfg.device_count = 1; - - return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream); -} - static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { .get_hext_stream = hda_ipc4_get_hext_stream, .assign_hext_stream = hda_assign_hext_stream, @@ -498,7 +474,7 @@ static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = { }; static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = { - .get_hext_stream = sdw_hda_ipc4_get_hext_stream, + .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, diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index c1682bcdb5a6..ce675c22a5ab 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.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> // @@ -29,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) { @@ -62,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) @@ -221,15 +214,15 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream, return hda_link_dma_cleanup(substream, hext_stream, cpu_dai); } -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; @@ -249,9 +242,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); + 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_hw_params_data(substream, params, dai, &data, flags); } /* @@ -341,11 +344,14 @@ static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w) return ipc4_copier; } -static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) +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; @@ -353,6 +359,8 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, 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; @@ -363,9 +371,9 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, } /* use HDaudio stream handling */ - ret = hda_dai_hw_params(substream, params, cpu_dai); + 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 failed: %d\n", __func__, ret); + dev_err(cpu_dai->dev, "%s: hda_dai_hw_params_data failed: %d\n", __func__, ret); return ret; } @@ -392,7 +400,12 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, /* configure TLV */ ipc4_copier = widget_to_copier(w); - dma_config_tlv = &ipc4_copier->dma_config_tlv; + 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); @@ -403,13 +416,27 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, dma_config->pre_allocated_by_host = 1; dma_config->dma_channel_id = stream_id - 1; dma_config->stream_id = stream_id; - dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ + /* + * 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; skip_tlv: 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) { @@ -436,15 +463,29 @@ static const struct snd_soc_dai_ops dmic_dai_ops = { 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 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; - ret = non_hda_dai_hw_params(substream, params, cpu_dai); + 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; @@ -457,9 +498,25 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, if (!hext_stream) return -ENODEV; - /* in the case of SoundWire we need to program the PCMSyCM registers */ + /* + * 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, - GENMASK(params_channels(params) - 1, 0), + ch_mask, hdac_stream(hext_stream)->stream_tag, substream->stream); if (ret < 0) { @@ -468,8 +525,25 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, return ret; } + 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); + 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, @@ -498,12 +572,14 @@ int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, 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) { @@ -618,6 +694,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 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) { @@ -783,6 +860,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 31ffa1a8f2ac..1315f5bc3e31 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,85 @@ 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: + 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 +215,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 +241,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 +269,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 +321,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 +369,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 +410,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 +429,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 +447,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 +731,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 +743,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 +780,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; @@ -843,6 +952,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) { @@ -858,6 +968,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) { @@ -871,6 +982,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) { @@ -892,6 +1004,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) { @@ -952,6 +1065,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) { @@ -1024,12 +1138,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) { @@ -1042,6 +1158,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) { @@ -1068,6 +1185,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) { @@ -1108,6 +1226,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) { @@ -1116,3 +1343,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..9feaaa2d166a 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) { @@ -92,6 +99,7 @@ void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev, mod_delayed_work(system_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 b81f231abee3..b8b914eaf7e0 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> @@ -43,13 +43,13 @@ 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, + 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); @@ -62,7 +62,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned hstream->substream = NULL; /* allocate DMA buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); if (ret < 0) { dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret); goto out_put; @@ -72,7 +72,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned 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); @@ -95,6 +95,7 @@ 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 +219,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 +252,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, +int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, 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; @@ -277,20 +286,40 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, 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) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; + struct sof_intel_hda_stream *hda_stream; + unsigned long time_left; unsigned int reg; int ret, status; - ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START); + hda_stream = container_of(hext_stream, struct sof_intel_hda_stream, + hext_stream); + + 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; } + /* Wait for completion of transfer */ + time_left = wait_for_completion_timeout(&hda_stream->ioc, + msecs_to_jiffies(HDA_CL_DMA_IOC_TIMEOUT_MS)); + + if (!time_left) { + dev_err(sdev->dev, "Code loader DMA did not complete\n"); + return -ETIMEDOUT; + } + dev_dbg(sdev->dev, "Code loader DMA done, 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 +335,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; @@ -333,8 +366,8 @@ 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, + &dmab_bdl, 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 +379,7 @@ 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, &dmab_bdl, iccmax_stream); if (ret1 < 0) { dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); @@ -361,6 +394,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) { @@ -418,9 +452,9 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) 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); + hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, + stripped_firmware.size, + &dmab, 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); @@ -493,7 +527,7 @@ 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, &dmab, hext_stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); @@ -514,6 +548,7 @@ cleanup: 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) @@ -535,9 +570,9 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset; /* 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, + &dmab, 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); @@ -580,7 +615,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, 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; @@ -597,7 +632,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); /* Stop the DMA channel */ - ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); + 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) @@ -606,7 +641,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, cleanup: /* clean up even in case of error and return the first error */ - ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream); + ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream); if (ret1 < 0) { dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); @@ -617,41 +652,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_IPC_TYPE_4)) - 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) @@ -690,3 +691,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 b592e687a87a..04bbc5c9904c 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 // /* diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 18f07364d219..9fb8521b896b 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> @@ -142,6 +142,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 +165,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,6 +175,7 @@ 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) @@ -204,6 +207,7 @@ 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) @@ -259,10 +263,40 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, 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 make sure that userspace allocate large enough ALSA buffer we need + * to place a constraint on the buffer time. + * + * On capture the DMA will transfer 1ms chunks. + * + * Exact dsp_max_burst_size_in_ms constraint is racy, so set the + * constraint to a minimum of 2x dsp_max_burst_size_in_ms. + */ + if (spcm->stream[direction].dsp_max_burst_size_in_ms) + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_BUFFER_TIME, + spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2, + 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 +316,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..3e33101f0521 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: @@ -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); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index b387b1a69d7e..8213debde497 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> @@ -24,6 +24,11 @@ #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) @@ -709,6 +714,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) { @@ -731,6 +737,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) @@ -765,12 +772,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) { @@ -812,6 +834,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) { @@ -880,6 +903,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; @@ -948,6 +972,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) 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) { @@ -977,6 +1002,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) @@ -1063,3 +1089,76 @@ 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 hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + u32 llp_l, llp_u; + + /* + * 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..351eb2eb184b 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 ecfdb8f882d2..e6a38de0a0aa 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,21 +19,22 @@ #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/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 "hda.h" -#include "telemetry.h" -#define CREATE_TRACE_POINTS #include <trace/events/sof_intel.h> #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) @@ -43,86 +44,6 @@ /* platform specific devices */ #include "shim.h" -#define EXCEPT_MAX_HDR_SIZE 0x400 -#define HDA_EXT_ROM_STATUS_SIZE 8 - -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: - 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; - } -} - -static 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]; -} - -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; - } -} - #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) /* @@ -144,12 +65,37 @@ static int sdw_params_stream(struct device *dev, 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, }; static int sdw_ace2x_params_stream(struct device *dev, @@ -158,7 +104,8 @@ static int sdw_ace2x_params_stream(struct device *dev, return sdw_hda_dai_hw_params(params_data->substream, params_data->hw_params, params_data->dai, - params_data->link_id); + params_data->link_id, + params_data->alh_stream_id); } static int sdw_ace2x_free_stream(struct device *dev, @@ -180,33 +127,6 @@ static struct sdw_intel_ops sdw_ace2x_callback = { .trigger = sdw_ace2x_trigger, }; -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); -} - -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); -} - static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); @@ -298,65 +218,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; @@ -377,6 +238,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) { @@ -418,6 +280,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) { @@ -451,6 +314,7 @@ bool hda_sdw_check_wakeen_irq_common(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) { @@ -467,7 +331,7 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *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; @@ -481,6 +345,7 @@ 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); #else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */ static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) @@ -515,15 +380,50 @@ static inline bool hda_sdw_check_wakeen_irq(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); @@ -532,10 +432,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."); @@ -548,321 +444,6 @@ 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_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); - } -} - -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); -} - -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 hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; @@ -1226,6 +807,7 @@ int hda_dsp_probe_early(struct snd_sof_dev *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) { @@ -1382,6 +964,7 @@ hdac_bus_unmap: return ret; } +EXPORT_SYMBOL_NS(hda_dsp_probe, SND_SOC_SOF_INTEL_HDA_GENERIC); void hda_dsp_remove(struct snd_sof_dev *sdev) { @@ -1435,6 +1018,7 @@ 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); void hda_dsp_remove_late(struct snd_sof_dev *sdev) { @@ -1450,6 +1034,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, @@ -1556,6 +1141,7 @@ 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; + struct sdw_extended_slave_id *ids; struct snd_soc_acpi_mach *mach; struct sof_intel_hda_dev *hdev; u32 link_mask; @@ -1564,92 +1150,109 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev 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->num_slaves) { + 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; - - /* 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 (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, - hdev->sdw->ids, - hdev->sdw->num_slaves)) - break; - } - /* Found if all Slaves are checked */ - if (i == hdev->info.count || !link->num_adr) - break; - } - if (mach && mach->link_mask) { - int dmic_num = 0; - bool tplg_fixup; - const char *tplg_filename; + 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; - mach->mach_params.links = mach->links; - mach->mach_params.link_mask = mach->link_mask; - mach->mach_params.platform = dev_name(sdev->dev); - - if (pdata->tplg_filename) { - tplg_fixup = false; - } else { - tplg_fixup = true; - tplg_filename = mach->sof_tplg_filename; - } + /* 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++) { /* - * 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 + * Try next machine if any expected Slaves + * are not found on this link. */ - if (hweight_long(mach->link_mask) <= 2) { - int ret; - - 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; + if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, + hdev->sdw->ids, + hdev->sdw->num_slaves)) + break; + } + /* Found if all Slaves are checked */ + if (i == hdev->info.count || !link->num_adr) + break; + } + if (mach && mach->link_mask) { + int dmic_num = 0; + bool tplg_fixup; + const char *tplg_filename; + + mach->mach_params.links = mach->links; + mach->mach_params.link_mask = mach->link_mask; + mach->mach_params.platform = dev_name(sdev->dev); + + if (pdata->tplg_filename) { + tplg_fixup = false; + } else { + tplg_fixup = true; + tplg_filename = mach->sof_tplg_filename; + } - dev_dbg(sdev->dev, - "SoundWire machine driver %s topology %s\n", - mach->drv_name, - pdata->tplg_filename); + /* + * 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; - return mach; + 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; + + dev_dbg(sdev->dev, + "SoundWire machine driver %s topology %s\n", + mach->drv_name, + pdata->tplg_filename); - dev_info(sdev->dev, "No SoundWire machine driver found\n"); + return mach; } + dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n"); + ids = hdev->sdw->ids; + for (i = 0; i < hdev->sdw->num_slaves; i++) + dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n", + ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version); + return NULL; } #else @@ -1676,13 +1279,37 @@ 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; +} + 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; const char *tplg_filename; + const char *tplg_suffix; /* Try I2S or DMIC if it is supported */ if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) @@ -1701,6 +1328,17 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) 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); @@ -1775,6 +1413,52 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) } } + codec_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev); + + if (tplg_fixup && + mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME && + codec_type != CODEC_NONE) { + tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(codec_type); + if (!tplg_suffix) { + dev_err(sdev->dev, "no tplg suffix found, amp %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; + add_extension = true; + } + + codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev); + + 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; + add_extension = true; + } + if (tplg_fixup && add_extension) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s", @@ -1794,8 +1478,12 @@ 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))) + /* + * 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); /* @@ -1821,7 +1509,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) { @@ -1842,3 +1530,5 @@ 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_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 b36eb7c78913..3c9e1d59e1ab 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> @@ -453,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)) @@ -559,6 +562,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) \ @@ -615,6 +619,8 @@ 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. @@ -662,6 +668,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); @@ -689,16 +701,23 @@ 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 *hda_cl_prepare(struct device *dev, unsigned int format, + unsigned int size, struct snd_dma_buffer *dmab, + 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, 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 @@ -793,10 +812,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); @@ -812,6 +833,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; @@ -830,6 +856,10 @@ 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) { } @@ -844,7 +874,8 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev) 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 link_id, + int intel_alh_id); int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, @@ -860,7 +891,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); @@ -999,4 +1030,12 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream, struct snd_soc_dai *cpu_dai); +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 040698591992..dad6bc72ad37 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) { @@ -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 */ @@ -189,10 +187,10 @@ const struct sof_intel_dsp_desc icl_chip_info = { .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, }; -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 index 7ae017a00184..4b5665f82170 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// 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> @@ -16,28 +17,31 @@ #include "hda-ipc.h" #include "../sof-audio.h" #include "mtl.h" +#include "lnl.h" #include <sound/hda-mlink.h> /* LunarLake ops */ struct snd_sof_dsp_ops sof_lnl_ops; -EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"fw_regs", HDA_DSP_BAR, MTL_SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY}, }; /* this helps allows the DSP to setup DMIC/SSP */ -static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus) +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, true); + 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, true); + ret = hdac_bus_eml_enable_offload(bus, true, + AZX_REG_ML_LEPTR_ID_INTEL_DMIC, enable); if (ret < 0) return ret; @@ -52,7 +56,19 @@ static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev) if (ret < 0) return ret; - return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); + 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) @@ -63,7 +79,7 @@ static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev) if (ret < 0) return ret; - return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true); } static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev) @@ -74,7 +90,7 @@ static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev) if (ret < 0) return ret; - return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev)); + return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true); } static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev) @@ -83,8 +99,12 @@ static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev) 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)) + 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; @@ -97,9 +117,11 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) /* common defaults */ memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); - /* probe */ - if (!sdev->dspless_mode_selected) + /* probe/remove */ + if (!sdev->dspless_mode_selected) { sof_lnl_ops.probe = lnl_hda_dsp_probe; + sof_lnl_ops.remove = lnl_hda_dsp_remove; + } /* shutdown */ sof_lnl_ops.shutdown = hda_dsp_shutdown; @@ -134,8 +156,6 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume; } - sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; - /* dsp core get/put */ sof_lnl_ops.core_get = mtl_dsp_core_get; sof_lnl_ops.core_put = mtl_dsp_core_put; @@ -161,7 +181,6 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) return 0; }; -EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); /* Check if an SDW IRQ occurred */ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) @@ -185,6 +204,23 @@ static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } +static 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); +} + const struct sof_intel_dsp_desc lnl_chip_info = { .cores_num = 5, .init_core_mask = BIT(0), @@ -194,17 +230,18 @@ const struct sof_intel_dsp_desc lnl_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 = 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, .enable_sdw_irq = lnl_enable_sdw_irq, .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, }; -EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/lnl.h b/sound/soc/sof/intel/lnl.h new file mode 100644 index 000000000000..79101af84b2e --- /dev/null +++ b/sound/soc/sof/intel/lnl.h @@ -0,0 +1,15 @@ +/* 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 */ + +#endif /* __SOF_INTEL_LNL_H */ diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index df05dc77b8d5..1bf274509ee6 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,6 +9,7 @@ * Hardware interface for audio DSP on Meteorlake. */ +#include <linux/debugfs.h> #include <linux/firmware.h> #include <sound/sof/ipc4/header.h> #include <trace/events/sof_intel.h> @@ -24,6 +25,7 @@ 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) @@ -75,6 +77,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) @@ -118,6 +121,7 @@ int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } +EXPORT_SYMBOL_NS(mtl_ipc_send_msg, SND_SOC_SOF_INTEL_MTL); void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev) { @@ -145,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) { @@ -229,6 +234,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) return ret; } +EXPORT_SYMBOL_NS(mtl_enable_interrupts, SND_SOC_SOF_INTEL_MTL); /* pre fw run operations */ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) @@ -279,6 +285,7 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) return ret; } +EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, SND_SOC_SOF_INTEL_MTL); int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) { @@ -294,36 +301,36 @@ 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); return 0; } +EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, SND_SOC_SOF_INTEL_MTL); void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { 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); } +EXPORT_SYMBOL_NS(mtl_dsp_dump, SND_SOC_SOF_INTEL_MTL); static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev) { @@ -434,12 +441,13 @@ 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; + unsigned int status, target_status; u32 ipc_hdr, flags; char *dump_msg; int ret; @@ -485,13 +493,40 @@ 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: flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; @@ -503,11 +538,13 @@ err: 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); irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { @@ -591,16 +628,19 @@ irqreturn_t mtl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } +EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, SND_SOC_SOF_INTEL_MTL); int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return MTL_DSP_MBOX_UPLINK_OFFSET; } +EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, SND_SOC_SOF_INTEL_MTL); int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MTL_SRAM_WINDOW_OFFSET(id); } +EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, SND_SOC_SOF_INTEL_MTL); void mtl_ipc_dump(struct snd_sof_dev *sdev) { @@ -618,6 +658,7 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev) "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n", hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl); } +EXPORT_SYMBOL_NS(mtl_ipc_dump, SND_SOC_SOF_INTEL_MTL); static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { @@ -626,18 +667,6 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } -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; -} - int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; @@ -650,6 +679,7 @@ int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) return 0; } +EXPORT_SYMBOL_NS(mtl_dsp_core_get, SND_SOC_SOF_INTEL_MTL); int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) { @@ -667,10 +697,10 @@ int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) return 0; } +EXPORT_SYMBOL_NS(mtl_dsp_core_put, SND_SOC_SOF_INTEL_MTL); /* Meteorlake ops */ struct snd_sof_dsp_ops sof_mtl_ops; -EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); int sof_mtl_ops_init(struct snd_sof_dev *sdev) { @@ -707,8 +737,6 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) 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; - sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) return -ENOMEM; @@ -730,7 +758,6 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) return 0; }; -EXPORT_SYMBOL_NS(sof_mtl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc mtl_chip_info = { .cores_num = 3, @@ -741,7 +768,7 @@ 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, @@ -752,13 +779,13 @@ const struct sof_intel_dsp_desc mtl_chip_info = { .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, }; -EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc arl_s_chip_info = { .cores_num = 2, @@ -769,7 +796,7 @@ const struct sof_intel_dsp_desc arl_s_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, @@ -780,10 +807,10 @@ const struct sof_intel_dsp_desc arl_s_chip_info = { .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, }; -EXPORT_SYMBOL_NS(arl_s_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 cc5a1f46fd09..7acaa7e724f4 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -3,15 +3,9 @@ * 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) @@ -76,8 +70,52 @@ #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) @@ -103,9 +141,5 @@ int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); void mtl_ipc_dump(struct snd_sof_dev *sdev); -u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream); - int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core); int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core); diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 4b287b5e9077..df6d897da290 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> // @@ -105,5 +105,6 @@ static struct pci_driver snd_sof_pci_intel_apl_driver = { module_pci_driver(snd_sof_pci_intel_apl_driver); MODULE_LICENSE("Dual BSD/GPL"); +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 9fa0cd2eae79..a39fa3657d55 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> // @@ -143,5 +143,6 @@ static struct pci_driver snd_sof_pci_intel_cnl_driver = { module_pci_driver(snd_sof_pci_intel_cnl_driver); MODULE_LICENSE("Dual BSD/GPL"); +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 b99c7c9aad7d..9f1fe47475fb 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> // @@ -108,5 +108,7 @@ static struct pci_driver snd_sof_pci_intel_icl_driver = { module_pci_driver(snd_sof_pci_intel_icl_driver); MODULE_LICENSE("Dual BSD/GPL"); +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 index b26ffe767fab..68e5c90151b2 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.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) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation // // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> // @@ -35,6 +35,9 @@ static const struct sof_dev_desc lnl_desc = { .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", }, @@ -67,5 +70,8 @@ static struct pci_driver snd_sof_pci_intel_lnl_driver = { module_pci_driver(snd_sof_pci_intel_lnl_driver); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_MTL); +MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index cacc985d80f4..c685cb8d6171 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> // @@ -133,5 +133,6 @@ static struct pci_driver snd_sof_pci_intel_mtl_driver = { module_pci_driver(snd_sof_pci_intel_mtl_driver); MODULE_LICENSE("Dual BSD/GPL"); +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 9dde439a0b0f..862da8009543 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> @@ -89,5 +89,6 @@ static struct pci_driver snd_sof_pci_intel_skl_driver = { module_pci_driver(snd_sof_pci_intel_skl_driver); MODULE_LICENSE("Dual BSD/GPL"); +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 a361ee9d1107..f73bb47cd79e 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> // @@ -317,5 +317,7 @@ static struct pci_driver snd_sof_pci_intel_tgl_driver = { module_pci_driver(snd_sof_pci_intel_tgl_driver); MODULE_LICENSE("Dual BSD/GPL"); +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 c90173003c2b..5c3069588bb7 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, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 9515d753c816..9328d2bbfd03 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> */ @@ -190,13 +190,14 @@ struct sof_intel_dsp_desc { 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); 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 93824e6ce573..9a002811e9ff 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 // /* diff --git a/sound/soc/sof/intel/telemetry.c b/sound/soc/sof/intel/telemetry.c index 1a3b5c28a6f0..2d2f96548310 100644 --- a/sound/soc/sof/intel/telemetry.c +++ b/sound/soc/sof/intel/telemetry.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) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation /* telemetry data queried from debug window */ @@ -93,3 +93,4 @@ free_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 index 3c2b23c75f5d..e4e91943a41a 100644 --- a/sound/soc/sof/intel/telemetry.h +++ b/sound/soc/sof/intel/telemetry.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) 2023 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation * * telemetry data in debug windows */ diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index c2bb04c89b9d..df2d26b78ddc 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) { @@ -75,6 +81,8 @@ 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; } @@ -105,6 +113,8 @@ 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; } @@ -112,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; @@ -128,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 */ @@ -151,13 +156,13 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .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, }; -EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc tglh_chip_info = { /* Tigerlake-H */ @@ -180,13 +185,13 @@ const struct sof_intel_dsp_desc tglh_chip_info = { .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, }; -EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc ehl_chip_info = { /* Elkhartlake */ @@ -209,13 +214,13 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .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, }; -EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc adls_chip_info = { /* Alderlake-S */ @@ -238,10 +243,10 @@ const struct sof_intel_dsp_desc adls_chip_info = { .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, }; -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..cd9cb54e7b23 100644 --- a/sound/soc/sof/iomem-utils.c +++ b/sound/soc/sof/iomem-utils.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: Keyon Jie <yang.jie@linux.intel.com> // diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index febe372f9aa8..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> // 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 0dca139322f3..744a91a150bc 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> diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c index 6e3ef0672110..35b89c2b9d4c 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" diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 35769dd7905e..1c1b8f595367 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 // // @@ -434,4 +434,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 ab7f46a162da..32c7d1f3b528 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 // // diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index c03dd513fbff..83c22d4a4830 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 // // diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c index 1be9519de909..576f407cd456 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 // // 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 c79479afa8d0..bcdb33d03682 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) diff --git a/sound/soc/sof/ipc4-mtrace.c b/sound/soc/sof/ipc4-mtrace.c index 9f1e33ee8826..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" @@ -412,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) @@ -424,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); diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0f332c8cdbe6..307bee63756b 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,6 +15,47 @@ #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) + * @stream_end_offset: reported by fw in memory window (converted to frames) + * @llp_offset: llp offset in memory window + * @boundary: wrap boundary should be used for the LLP frame counter + * @delay: Calculated and stored in pointer callback. The stored value is + * returned in the delay callback. + */ +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; + + u64 boundary; + 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; +}; + +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 int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state, struct ipc4_pipeline_set_state_data *trigger_list) { @@ -231,14 +272,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, - int direction, + 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 */ @@ -259,6 +303,11 @@ 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; @@ -316,7 +365,12 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, 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, @@ -356,7 +410,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, * trigger function that handles the rest for the substream. */ if (pipeline->use_chain_dma) - return sof_ipc4_chain_dma_trigger(sdev, substream->stream, + return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, pipeline_list, state, cmd); /* allocate memory for the pipeline data */ @@ -423,8 +477,19 @@ 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); @@ -464,14 +529,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; @@ -675,12 +738,16 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, 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; } @@ -690,7 +757,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; @@ -703,6 +771,10 @@ 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; @@ -714,33 +786,41 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm return -ENOMEM; } + 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; + if (!support_info) 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) @@ -760,44 +840,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)); + 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) - info->llp_offset = 0; + time_info->llp_offset = 0; } static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, @@ -814,7 +894,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, if (!spcm) return -EINVAL; - time_info = spcm->stream[substream->stream].private; + 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; @@ -829,13 +909,12 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, 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; @@ -852,38 +931,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); + + /* + * Calculate the wrap boundary need to be used for delay calculation + * The host counter is in bytes, it will wrap earlier than the frames + * based link counter. + */ + time_info->boundary = div64_u64(~((u64)0), + frames_to_bytes(substream->runtime, 1)); + /* 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 = 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 @@ -891,47 +983,116 @@ 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); + 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; } + dai_cnt += time_info->stream_end_offset; - /* In two cases dai dma position is not accurate + /* 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; + } + + /* Wrap the dai counter at the boundary where the host counter wraps */ + div64_u64_rem(dai_cnt, time_info->boundary, &dai_cnt); + 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_cnt < tail_cnt) { + time_info->delay = time_info->boundary - tail_cnt + head_cnt; + goto out; } - if (head_ptr < tail_ptr) - return substream->runtime->boundary - tail_ptr + head_ptr; + time_info->delay = head_cnt - tail_cnt; + +out: + /* + * 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 = { @@ -941,6 +1102,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 f3b908b093f9..ea3323b90343 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 @@ -92,27 +92,13 @@ struct sof_ipc4_fw_data { 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_query_fw_configuration(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/ipc4-telemetry.c b/sound/soc/sof/ipc4-telemetry.c index ec4ae9674364..ddc3bc494ffe 100644 --- a/sound/soc/sof/ipc4-telemetry.c +++ b/sound/soc/sof/ipc4-telemetry.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-2023 Intel Corporation. All rights reserved. +// Copyright(c) 2018-2023 Intel Corporation // #include <linux/debugfs.h> diff --git a/sound/soc/sof/ipc4-telemetry.h b/sound/soc/sof/ipc4-telemetry.h index ab3599e3d87d..9298f8acc648 100644 --- a/sound/soc/sof/ipc4-telemetry.h +++ b/sound/soc/sof/ipc4-telemetry.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) 2023 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation */ #ifndef __SOUND_SOC_SOF_IPC4_TELEMETRY_H diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index da4a83afb87a..beff10989324 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-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) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022 Intel Corporation // // #include <linux/bitfield.h> @@ -407,13 +407,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) @@ -447,6 +494,29 @@ 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) + sps->dsp_max_burst_size_in_ms = 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) { @@ -566,7 +636,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; @@ -1050,42 +1119,50 @@ static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, /* 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); + snd_pcm_format_t snd_fmt; + struct snd_mask *m; + + 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; + } + + 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; } @@ -1277,7 +1354,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) } 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; @@ -1287,9 +1363,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; } } @@ -1347,23 +1420,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_format, + 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_format) { + 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; @@ -1371,36 +1457,82 @@ 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) { + 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; + + 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 we have loaded 32-bit blob + * instead of the 16-bit. + * 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); + 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_format, + struct snd_pcm_hw_params *params, u32 dai_index, + u32 linktype, u8 dir, u32 **dst, u32 *len) { return 0; } @@ -1432,6 +1564,68 @@ bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev, } 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_copier *ipc4_copier; + bool single_format; + int ret; + + ipc4_copier = dai->private; + copier_data = &ipc4_copier->data; + available_fmt = &ipc4_copier->available_fmt; + + /* + * If the copier on the DAI side supports only single bit depth then + * this depth (format) should be used to look for the NHLT blob (if + * needed) and in case of capture this should be used for the input + * format lookup + */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + single_format = sof_ipc4_copier_is_single_format(sdev, + available_fmt->output_pin_fmts, + available_fmt->num_output_formats); + + /* Update the dai_params with the only supported format */ + if (single_format) { + ret = sof_ipc4_update_hw_params(sdev, &dai_params, + &available_fmt->output_pin_fmts[0].audio_fmt, + BIT(SNDRV_PCM_HW_PARAM_FORMAT)); + if (ret) + return ret; + } + } else { + single_format = sof_ipc4_copier_is_single_format(sdev, + available_fmt->input_pin_fmts, + available_fmt->num_input_formats); + + /* Update the dai_params with the only supported format */ + if (single_format) { + ret = sof_ipc4_update_hw_params(sdev, &dai_params, + &available_fmt->input_pin_fmts[0].audio_fmt, + BIT(SNDRV_PCM_HW_PARAM_FORMAT)); + if (ret) + return ret; + } + } + + ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_format, + &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, @@ -1441,7 +1635,7 @@ 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; + struct snd_pcm_hw_params ref_params; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_dai *dai; u32 gtw_cfg_config_length; @@ -1454,6 +1648,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, u32 deep_buffer_dma_ms = 0; int output_fmt_index; bool single_output_format; + int i; dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); @@ -1518,9 +1713,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * for capture. */ if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ref_params = fe_params; + ref_params = *fe_params; else - ref_params = pipeline_params; + ref_params = *pipeline_params; copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; copier_data->gtw_cfg.node_id |= @@ -1546,23 +1741,25 @@ 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; - - 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); + ref_params = *fe_params; + 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) + ref_params = *pipeline_params; + break; } case snd_soc_dapm_buffer: @@ -1570,7 +1767,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 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 = *pipeline_params; break; } @@ -1581,8 +1778,8 @@ 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); + ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, + &ref_params, available_fmt); if (ret < 0) return ret; @@ -1671,6 +1868,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; @@ -1679,7 +1877,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; @@ -1703,6 +1900,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, */ i = 0; list_for_each_entry(w, &sdev->widget_list, list) { + u32 node_type; + if (w->widget->sname && strcmp(w->widget->sname, swidget->widget->sname)) continue; @@ -1710,7 +1909,22 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, dai = w->private; 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 @@ -1748,7 +1962,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* modify the input params for the next widget */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format); + 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; @@ -1789,19 +2007,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 */ @@ -1974,7 +2191,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, src->data.sink_rate = out_audio_fmt->sampling_frequency; /* update pipeline_params for sink widgets */ - return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt); + 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 @@ -2098,7 +2318,11 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, sizeof(struct sof_ipc4_audio_format)); /* modify the pipeline params with the pin 0 output format */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->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; } @@ -2813,17 +3037,24 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * case SOF_DAI_INTEL_HDA: gtw_attr = ipc4_copier->gtw_attr; gtw_attr->lp_buffer_alloc = pipeline->lp_mode; - fallthrough; + if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { + copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; + copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); + } + break; case SOF_DAI_INTEL_ALH: /* * Do not clear the node ID when this op is invoked with * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during - * unprepare. + * unprepare. The node_id for multi-gateway DAI's will be overwritten with the + * group_id during copier's ipc_prepare op. */ if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { + ipc4_copier->dai_index = data->dai_node_id; copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; - copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); + copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_node_id); } + break; case SOF_DAI_INTEL_DMIC: case SOF_DAI_INTEL_SSP: diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index dce174a190dd..4488762f6a71 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.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 __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__ @@ -45,6 +45,7 @@ #define SOF_IPC4_NODE_INDEX_MASK 0xFF #define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK) #define SOF_IPC4_NODE_TYPE(x) ((x) << 8) +#define SOF_IPC4_GET_NODE_TYPE(node_id) ((node_id) >> 8) /* Node ID for SSP type DAI copiers */ #define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4) @@ -313,7 +314,7 @@ struct sof_ipc4_copier { struct sof_ipc4_gtw_attributes *gtw_attr; u32 dai_type; int dai_index; - struct sof_ipc4_dma_config_tlv dma_config_tlv; + struct sof_ipc4_dma_config_tlv dma_config_tlv[SOF_IPC4_DMA_DEVICE_MAX_COUNT]; }; /** diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index ac5c6bc66d2a..4386cbae16d4 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.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 // // Authors: Rander Wang <rander.wang@linux.intel.com> // Peter Ujfalusi <peter.ujfalusi@linux.intel.com> diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 2f8555f11c03..0baf316b0064 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/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 // // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // diff --git a/sound/soc/sof/mediatek/mt8186/Makefile b/sound/soc/sof/mediatek/mt8186/Makefile index c1f5fc4e2495..022f415afac9 100644 --- a/sound/soc/sof/mediatek/mt8186/Makefile +++ b/sound/soc/sof/mediatek/mt8186/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-mt8186-objs := mt8186.o mt8186-clk.o mt8186-loader.o +snd-sof-mt8186-y := mt8186.o mt8186-clk.o mt8186-loader.o obj-$(CONFIG_SND_SOC_SOF_MT8186) += snd-sof-mt8186.o diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 0d2d7d697de0..c63e0d2f4b96 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -481,7 +481,7 @@ static struct snd_soc_dai_driver mt8186_dai[] = { }; /* mt8186 ops */ -static struct snd_sof_dsp_ops sof_mt8186_ops = { +static const struct snd_sof_dsp_ops sof_mt8186_ops = { /* probe and remove */ .probe = mt8186_dsp_probe, .remove = mt8186_dsp_remove, diff --git a/sound/soc/sof/mediatek/mt8195/Makefile b/sound/soc/sof/mediatek/mt8195/Makefile index afc4f21fccc5..f5eeda380b50 100644 --- a/sound/soc/sof/mediatek/mt8195/Makefile +++ b/sound/soc/sof/mediatek/mt8195/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-mt8195-objs := mt8195.o mt8195-clk.o mt8195-loader.o +snd-sof-mt8195-y := mt8195.o mt8195-clk.o mt8195-loader.o obj-$(CONFIG_SND_SOC_SOF_MT8195) += snd-sof-mt8195.o diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 8ee7ee246344..fc1c016104ae 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -505,7 +505,7 @@ static struct snd_soc_dai_driver mt8195_dai[] = { }; /* mt8195 ops */ -static struct snd_sof_dsp_ops sof_mt8195_ops = { +static const struct snd_sof_dsp_ops sof_mt8195_ops = { /* probe and remove */ .probe = mt8195_dsp_probe, .remove = mt8195_dsp_remove, diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 34aa8a7cfc7d..fdcbe33d3dcf 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.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> // diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index ff066de4ceb9..bd52e7ec6883 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/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) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018 Intel Corporation // // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 6cf21e829e07..2584621c3b2d 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.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) 2018 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> */ @@ -523,12 +523,26 @@ static inline int snd_sof_pcm_platform_ack(struct snd_sof_dev *sdev, return 0; } -static inline u64 snd_sof_pcm_get_stream_position(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream) +static inline u64 +snd_sof_pcm_get_dai_frame_counter(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) { - if (sof_ops(sdev) && sof_ops(sdev)->get_stream_position) - return sof_ops(sdev)->get_stream_position(sdev, component, substream); + if (sof_ops(sdev) && sof_ops(sdev)->get_dai_frame_counter) + return sof_ops(sdev)->get_dai_frame_counter(sdev, component, + substream); + + return 0; +} + +static inline u64 +snd_sof_pcm_get_host_byte_counter(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->get_host_byte_counter) + return sof_ops(sdev)->get_host_byte_counter(sdev, component, + substream); return 0; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 33d576b17647..baad4c1445aa 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/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 // // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // @@ -196,9 +196,8 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; - int ret, err = 0; + int ret; /* nothing to do for BE */ if (rtd->dai_link->no_pcm) @@ -211,42 +210,18 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, dev_dbg(component->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - if (spcm->prepared[substream->stream]) { - /* stop DMA first if needed */ - if (pcm_ops && pcm_ops->platform_stop_during_hw_free) - snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP); - - /* free PCM in the DSP */ - if (pcm_ops && pcm_ops->hw_free) { - ret = pcm_ops->hw_free(component, substream); - if (ret < 0) - err = ret; - } - - spcm->prepared[substream->stream] = false; - } - - /* reset DMA */ - ret = snd_sof_pcm_platform_hw_free(sdev, substream); - if (ret < 0) { - dev_err(component->dev, "error: platform hw free failed\n"); - err = ret; - } - - /* free the DAPM widget list */ - ret = sof_widget_list_free(sdev, spcm, substream->stream); - if (ret < 0) - err = ret; + ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); - return err; + return ret; } static int sof_pcm_prepare(struct snd_soc_component *component, struct snd_pcm_substream *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 snd_sof_pcm *spcm; int ret; @@ -258,8 +233,18 @@ static int sof_pcm_prepare(struct snd_soc_component *component, if (!spcm) return -EINVAL; - if (spcm->prepared[substream->stream]) - return 0; + if (spcm->prepared[substream->stream]) { + if (!spcm->pending_stop[substream->stream]) + return 0; + + /* + * this case should be reached in case of xruns where we absolutely + * want to free-up and reset all PCM/DMA resources + */ + ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); + if (ret < 0) + return ret; + } dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -302,6 +287,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n", spcm->pcm.pcm_id, substream->stream, cmd); + spcm->pending_stop[substream->stream] = false; + switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ipc_first = true; @@ -325,14 +312,13 @@ static int sof_pcm_trigger(struct snd_soc_component *component, ipc_first = true; break; case SNDRV_PCM_TRIGGER_SUSPEND: - if (sdev->system_suspend_target == SOF_SUSPEND_S0IX && + /* + * If DSP D0I3 is allowed during S0iX, set the suspend_ignored flag for + * D0I3-compatible streams to keep the firmware pipeline running + */ + if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix && + sdev->system_suspend_target == SOF_SUSPEND_S0IX && spcm->stream[substream->stream].d0i3_compatible) { - /* - * trap the event, not sending trigger stop to - * prevent the FW pipelines from being stopped, - * and mark the flag to ignore the upcoming DAPM - * PM events. - */ spcm->stream[substream->stream].suspend_ignored = true; return 0; } @@ -371,6 +357,15 @@ static int sof_pcm_trigger(struct snd_soc_component *component, /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */ if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free) snd_sof_pcm_platform_trigger(sdev, substream, cmd); + + /* + * set the pending_stop flag to indicate that pipeline stop has been delayed. + * This will be used later to stop the pipelines during prepare when recovering + * from xruns. + */ + if (pcm_ops && pcm_ops->platform_stop_during_hw_free && + cmd == SNDRV_PCM_TRIGGER_STOP) + spcm->pending_stop[substream->stream] = true; break; default: break; @@ -388,13 +383,21 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; snd_pcm_uframes_t host, dai; + int ret = -EOPNOTSUPP; /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; + if (pcm_ops && pcm_ops->pointer) + ret = pcm_ops->pointer(component, substream, &host); + + if (ret != -EOPNOTSUPP) + return ret ? ret : host; + /* use dsp ops pointer callback directly if set */ if (sof_ops(sdev)->pcm_pointer) return sof_ops(sdev)->pcm_pointer(sdev, substream); @@ -420,7 +423,7 @@ static int sof_pcm_open(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_dsp_ops *ops = sof_ops(sdev); + const struct snd_sof_dsp_ops *ops = sof_ops(sdev); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 704b21413c71..8e3bcf602beb 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.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> // diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 2977f0a63fba..2d96d00f1c44 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.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> // diff --git a/sound/soc/sof/sof-acpi-dev.h b/sound/soc/sof/sof-acpi-dev.h index 9bf8f75ceaae..89adfa507035 100644 --- a/sound/soc/sof/sof-acpi-dev.h +++ b/sound/soc/sof/sof-acpi-dev.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_ACPI_H diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e693dcb475e4..b3ac040811e7 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.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 Intel Corporation. All rights reserved. +// Copyright(c) 2019 Intel Corporation // // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> // @@ -834,35 +834,48 @@ int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *subs { const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); int ret; + int err = 0; if (spcm->prepared[substream->stream]) { /* stop DMA first if needed */ if (pcm_ops && pcm_ops->platform_stop_during_hw_free) snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP); - /* Send PCM_FREE IPC to reset pipeline */ + /* free PCM in the DSP */ if (pcm_ops && pcm_ops->hw_free) { ret = pcm_ops->hw_free(sdev->component, substream); - if (ret < 0) - return ret; + if (ret < 0) { + dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n", + __func__, ret); + err = ret; + } } spcm->prepared[substream->stream] = false; + spcm->pending_stop[substream->stream] = false; } /* reset the DMA */ ret = snd_sof_pcm_platform_hw_free(sdev, substream); - if (ret < 0) - return ret; + if (ret < 0) { + dev_err(sdev->dev, "%s: platform hw free failed %d\n", + __func__, ret); + if (!err) + err = ret; + } /* free widget list */ if (free_widget_list) { ret = sof_widget_list_free(sdev, spcm, dir); - if (ret < 0) - dev_err(sdev->dev, "failed to free widgets during suspend\n"); + if (ret < 0) { + dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n", + __func__, ret); + if (!err) + err = ret; + } } - return ret; + return err; } /* diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 9ea2ac5adac7..ec2a3bb644d2 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.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: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> */ @@ -91,6 +91,7 @@ struct snd_sof_pcm; struct snd_sof_dai_config_data { int dai_index; int dai_data; /* contains DAI-specific information */ + int dai_node_id; /* contains DAI-specific information for Gateway configuration */ }; /** @@ -103,7 +104,10 @@ struct snd_sof_dai_config_data { * additional memory in the SOF PCM stream structure * @pcm_free: Function pointer for PCM free that can be used for freeing any * additional memory in the SOF PCM stream structure - * @delay: Function pointer for pcm delay calculation + * @pointer: Function pointer for pcm pointer + * Note: the @pointer callback may return -EOPNOTSUPP which should be + * handled in a same way as if the callback is not provided + * @delay: Function pointer for pcm delay reporting * @reset_hw_params_during_stop: Flag indicating whether the hw_params should be reset during the * STOP pcm trigger * @ipc_first_on_start: Send IPC before invoking platform trigger during @@ -113,6 +117,7 @@ struct snd_sof_dai_config_data { * triggers. The FW keeps the host DMA running in this case and * therefore the host must do the same and should stop the DMA during * hw_free. + * @d0i3_supported_in_s0ix: Allow DSP D0I3 during S0iX */ struct sof_ipc_pcm_ops { int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, @@ -124,11 +129,15 @@ struct sof_ipc_pcm_ops { int (*dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); int (*pcm_setup)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); void (*pcm_free)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); + int (*pointer)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + snd_pcm_uframes_t *pointer); snd_pcm_sframes_t (*delay)(struct snd_soc_component *component, struct snd_pcm_substream *substream); bool reset_hw_params_during_stop; bool ipc_first_on_start; bool platform_stop_during_hw_free; + bool d0i3_supported_in_s0ix; }; /** @@ -322,6 +331,7 @@ struct snd_sof_pcm_stream { struct work_struct period_elapsed_work; struct snd_soc_dapm_widget_list *list; /* list of connected DAPM widgets */ bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ + unsigned int dsp_max_burst_size_in_ms; /* The maximum size of the host DMA burst in ms */ /* * flag to indicate that the DSP pipelines should be kept * active or not while suspending the stream @@ -341,6 +351,7 @@ struct snd_sof_pcm { struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; bool prepared[2]; /* PCM_PARAMS set successfully */ + bool pending_stop[2]; /* only used if (!pcm_ops->platform_stop_during_hw_free) */ }; struct snd_sof_led_control { diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c index c0d6723aed59..435614926092 100644 --- a/sound/soc/sof/sof-client-ipc-flood-test.c +++ b/sound/soc/sof/sof-client-ipc-flood-test.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: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> // Peter Ujfalusi <peter.ujfalusi@linux.intel.com> @@ -160,15 +160,20 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf unsigned long ipc_count = 0; struct dentry *dentry; int err; - size_t size; char *string; int ret; + if (*ppos != 0) + return -EINVAL; + string = kzalloc(count + 1, GFP_KERNEL); if (!string) return -ENOMEM; - size = simple_write_to_buffer(string, count, ppos, buffer, count); + if (copy_from_user(string, buffer, count)) { + ret = -EFAULT; + goto out; + } /* * write op is only supported for ipc_flood_count or @@ -198,7 +203,7 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf /* limit max duration/ipc count for flood test */ if (flood_duration_test) { if (!ipc_duration_ms) { - ret = size; + ret = count; goto out; } @@ -207,7 +212,7 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS; } else { if (!ipc_count) { - ret = size; + ret = count; goto out; } @@ -231,9 +236,9 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf if (err < 0) dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err); - /* return size if test is successful */ + /* return count if test is successful */ if (ret >= 0) - ret = size; + ret = count; out: kfree(string); return ret; diff --git a/sound/soc/sof/sof-client-ipc-kernel-injector.c b/sound/soc/sof/sof-client-ipc-kernel-injector.c index ad0ed2d570a9..6973b6690df4 100644 --- a/sound/soc/sof/sof-client-ipc-kernel-injector.c +++ b/sound/soc/sof/sof-client-ipc-kernel-injector.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2023 Google Inc. All rights reserved. +// Copyright(c) 2023 Google Inc // // Author: Curtis Malainey <cujomalainey@chromium.org> // diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c index e249d3a9afb5..af22e6421029 100644 --- a/sound/soc/sof/sof-client-ipc-msg-injector.c +++ b/sound/soc/sof/sof-client-ipc-msg-injector.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: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> // diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c index 5e8eb19582a8..816df745c9af 100644 --- a/sound/soc/sof/sof-client-probes-ipc3.c +++ b/sound/soc/sof/sof-client-probes-ipc3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2019-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2019-2022 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index c56a85854d92..796eac0a2e74 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2019-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2019-2022 Intel Corporation // // Author: Jyri Sarha <jyri.sarha@intel.com> // diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index 30f771ac7bbf..b8f297307565 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2019-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2019-2022 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 54dca91255a0..99f74def4ab6 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.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: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> // Peter Ujfalusi <peter.ujfalusi@linux.intel.com> diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index aab5c900cecf..4365405783e6 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.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> // diff --git a/sound/soc/sof/sof-pci-dev.h b/sound/soc/sof/sof-pci-dev.h index 81155a59e63a..c90e6276c83b 100644 --- a/sound/soc/sof/sof-pci-dev.h +++ b/sound/soc/sof/sof-pci-dev.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_PCI_H diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d453a4ce3b21..4d6a1517f9b3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-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) 2018 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> */ @@ -262,13 +262,25 @@ struct snd_sof_dsp_ops { int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ /* - * optional callback to retrieve the link DMA position for the substream - * when the position is not reported in the shared SRAM windows but - * instead from a host-accessible hardware counter. + * optional callback to retrieve the number of frames left/arrived from/to + * the DSP on the DAI side (link/codec/DMIC/etc). + * + * The callback is used when the firmware does not provide this information + * via the shared SRAM window and it can be retrieved by host. */ - u64 (*get_stream_position)(struct snd_sof_dev *sdev, - struct snd_soc_component *component, - struct snd_pcm_substream *substream); /* optional */ + u64 (*get_dai_frame_counter)(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream); /* optional */ + + /* + * Optional callback to retrieve the number of bytes left/arrived from/to + * the DSP on the host side (bytes between host ALSA buffer and DSP). + * + * The callback is needed for ALSA delay reporting. + */ + u64 (*get_host_byte_counter)(struct snd_sof_dev *sdev, + struct snd_soc_component *component, + struct snd_pcm_substream *substream); /* optional */ /* host read DSP stream data */ int (*ipc_msg_data)(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/sof-utils.c b/sound/soc/sof/sof-utils.c index b6345a7345af..cad041bf56cc 100644 --- a/sound/soc/sof/sof-utils.c +++ b/sound/soc/sof/sof-utils.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: Keyon Jie <yang.jie@linux.intel.com> // diff --git a/sound/soc/sof/sof-utils.h b/sound/soc/sof/sof-utils.h index 6f902893807e..9ac6de9a6d6a 100644 --- a/sound/soc/sof/sof-utils.h +++ b/sound/soc/sof/sof-utils.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 __SOC_SOF_UTILS_H diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c index 216b454f6b94..eb71303aa24c 100644 --- a/sound/soc/sof/stream-ipc.c +++ b/sound/soc/sof/stream-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) 2019 Intel Corporation. All rights reserved. +// Copyright(c) 2019 Intel Corporation // // Authors: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bcdb499c96a0..da182314aa87 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/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) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018 Intel Corporation // // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> // @@ -1531,10 +1531,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, /* check token parsing reply */ if (ret < 0) { dev_err(scomp->dev, - "error: failed to add widget id %d type %d name : %s stream %s\n", - tw->shift, swidget->id, tw->name, - strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 - ? tw->sname : "none"); + "failed to add widget type %d name : %s stream %s\n", + swidget->id, tw->name, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 + ? tw->sname : "none"); goto widget_free; } diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index b2ab51e5214a..fe6c67c01b0d 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.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 #include "sof-priv.h" diff --git a/sound/soc/sof/xtensa/Makefile b/sound/soc/sof/xtensa/Makefile index b8376ea04bcf..b9e6e8f5a7f6 100644 --- a/sound/soc/sof/xtensa/Makefile +++ b/sound/soc/sof/xtensa/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-xtensa-dsp-objs := core.o +snd-sof-xtensa-dsp-y := core.o obj-$(CONFIG_SND_SOC_SOF_XTENSA) += snd-sof-xtensa-dsp.o diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 7c91a919eadc..ccbc3fcdadd5 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/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: Pan Xiuli <xiuli.pan@linux.intel.com> // diff --git a/sound/soc/spear/Makefile b/sound/soc/spear/Makefile index 31d9dae280e7..61569d2e7606 100644 --- a/sound/soc/spear/Makefile +++ b/sound/soc/spear/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # SPEAR Platform Support -snd-soc-spear-pcm-objs := spear_pcm.o -snd-soc-spear-spdif-in-objs := spdif_in.o -snd-soc-spear-spdif-out-objs := spdif_out.o +snd-soc-spear-pcm-y := spear_pcm.o +snd-soc-spear-spdif-in-y := spdif_in.o +snd-soc-spear-spdif-out-y := spdif_out.o obj-$(CONFIG_SND_SPEAR_SOC) += snd-soc-spear-pcm.o obj-$(CONFIG_SND_SPEAR_SPDIF_IN) += snd-soc-spear-spdif-in.o diff --git a/sound/soc/sprd/Makefile b/sound/soc/sprd/Makefile index a95fa56cd000..c36399414862 100644 --- a/sound/soc/sprd/Makefile +++ b/sound/soc/sprd/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Spreadtrum Audio Support -snd-soc-sprd-platform-objs := sprd-pcm-dma.o sprd-pcm-compress.o +snd-soc-sprd-platform-y := sprd-pcm-dma.o sprd-pcm-compress.o obj-$(CONFIG_SND_SOC_SPRD) += snd-soc-sprd-platform.o diff --git a/sound/soc/sti/Makefile b/sound/soc/sti/Makefile index 787ccb521298..dfd4f4dd36fc 100644 --- a/sound/soc/sti/Makefile +++ b/sound/soc/sti/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only # STI platform support -snd-soc-sti-objs := sti_uniperif.o uniperif_player.o uniperif_reader.o +snd-soc-sti-y := sti_uniperif.o uniperif_player.o uniperif_reader.o obj-$(CONFIG_SND_SOC_STI) += snd-soc-sti.o diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 3143c0b47042..3372432faa09 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -1,17 +1,17 @@ # SPDX-License-Identifier: GPL-2.0 # SAI -snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o +snd-soc-stm32-sai-sub-y := stm32_sai_sub.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o -snd-soc-stm32-sai-objs := stm32_sai.o +snd-soc-stm32-sai-y := stm32_sai.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o # I2S -snd-soc-stm32-i2s-objs := stm32_i2s.o +snd-soc-stm32-i2s-y := stm32_i2s.o obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o # SPDIFRX -snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o +snd-soc-stm32-spdifrx-y := stm32_spdifrx.o obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o #DFSDM diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index a736f632bf0b..5f8d979585b6 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -156,6 +156,7 @@ struct sun4i_i2s; /** * struct sun4i_i2s_quirks - Differences between SoC variants. * @has_reset: SoC needs reset deasserted. + * @pcm_formats: available PCM formats. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. * @field_clkdiv_mclk_en: regmap field to enable mclk output. @@ -175,6 +176,7 @@ struct sun4i_i2s; */ struct sun4i_i2s_quirks { bool has_reset; + u64 pcm_formats; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; @@ -1092,8 +1094,18 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static int sun4i_i2s_dai_startup(struct snd_pcm_substream *sub, struct snd_soc_dai *dai) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *runtime = sub->runtime; + + return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, + i2s->variant->pcm_formats); +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .probe = sun4i_i2s_dai_probe, + .startup = sun4i_i2s_dai_startup, .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk, @@ -1101,9 +1113,10 @@ static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .trigger = sun4i_i2s_trigger, }; -#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_LE | \ - SNDRV_PCM_FMTBIT_S24_LE) +#define SUN4I_FORMATS_ALL (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver sun4i_i2s_dai = { .capture = { @@ -1111,14 +1124,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SUN4I_FORMATS, + .formats = SUN4I_FORMATS_ALL, }, .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SUN4I_FORMATS, + .formats = SUN4I_FORMATS_ALL, }, .ops = &sun4i_i2s_dai_ops, .symmetric_rate = 1, @@ -1340,8 +1353,12 @@ static int sun4i_i2s_runtime_suspend(struct device *dev) return 0; } +#define SUN4I_FORMATS_A10 (SUN4I_FORMATS_ALL & ~SNDRV_PCM_FMTBIT_S32_LE) +#define SUN4I_FORMATS_H3 SUN4I_FORMATS_ALL + static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .has_reset = false, + .pcm_formats = SUN4I_FORMATS_A10, .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), @@ -1360,6 +1377,7 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .has_reset = true, + .pcm_formats = SUN4I_FORMATS_A10, .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), @@ -1383,6 +1401,7 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { */ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, + .pcm_formats = SUN4I_FORMATS_A10, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), @@ -1401,6 +1420,7 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .has_reset = true, + .pcm_formats = SUN4I_FORMATS_H3, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), @@ -1419,6 +1439,7 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, + .pcm_formats = SUN4I_FORMATS_H3, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), @@ -1437,6 +1458,7 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { .has_reset = true, + .pcm_formats = SUN4I_FORMATS_H3, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), @@ -1455,6 +1477,7 @@ static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { static const struct sun4i_i2s_quirks sun50i_r329_i2s_quirks = { .has_reset = true, + .pcm_formats = SUN4I_FORMATS_H3, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index 8a32d05e23e1..2dcdf113b66e 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -115,9 +115,16 @@ #define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7 +#define SUN50I_ADDA_MDET_CTRL 0x1c +#define SUN50I_ADDA_MDET_CTRL_SELDETADC_FS 4 +#define SUN50I_ADDA_MDET_CTRL_SELDETADC_DB 2 +#define SUN50I_ADDA_MDET_CTRL_SELDETADC_BF 0 + #define SUN50I_ADDA_JACK_MIC_CTRL 0x1d +#define SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN 7 #define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN 6 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5 +#define SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN 4 /* mixer controls */ static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = { @@ -296,6 +303,19 @@ static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = { SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0), }; +static int sun50i_codec_hbias_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); + u32 value = !!SND_SOC_DAPM_EVENT_ON(event); + + regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL, + BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN), + value << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN); + + return 0; +} + static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { /* DAC */ SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL, @@ -367,7 +387,8 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { /* Microphone Bias */ SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL, SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN, - 0, NULL, 0), + 0, sun50i_codec_hbias_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* Mic input path */ SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL, @@ -471,17 +492,37 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { { "EARPIECE", NULL, "Earpiece Amp" }, }; -static int sun50i_a64_codec_suspend(struct snd_soc_component *component) +static int sun50i_a64_codec_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) { - return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL, - BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), - BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); -} + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int hbias; + + switch (level) { + case SND_SOC_BIAS_OFF: + regmap_clear_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL, + BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) | + BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN)); + + regmap_set_bits(component->regmap, SUN50I_ADDA_HP_CTRL, + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); + break; + case SND_SOC_BIAS_STANDBY: + regmap_clear_bits(component->regmap, SUN50I_ADDA_HP_CTRL, + BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE)); + + hbias = snd_soc_dapm_get_pin_status(dapm, "HBIAS"); + regmap_update_bits(component->regmap, SUN50I_ADDA_JACK_MIC_CTRL, + BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) | + BIT(SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN), + BIT(SUN50I_ADDA_JACK_MIC_CTRL_JACKDETEN) | + hbias << SUN50I_ADDA_JACK_MIC_CTRL_MICADCEN); + break; + default: + break; + } -static int sun50i_a64_codec_resume(struct snd_soc_component *component) -{ - return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL, - BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0); + return 0; } static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { @@ -491,8 +532,9 @@ static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = { .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets), .dapm_routes = sun50i_a64_codec_routes, .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes), - .suspend = sun50i_a64_codec_suspend, - .resume = sun50i_a64_codec_resume, + .set_bias_level = sun50i_a64_codec_set_bias_level, + .idle_bias_on = true, + .suspend_bias_off = true, }; static const struct of_device_id sun50i_codec_analog_of_match[] = { @@ -527,6 +569,13 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev) BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN), enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN); + /* Select sample interval of the ADC sample to 16ms */ + regmap_update_bits(regmap, SUN50I_ADDA_MDET_CTRL, + 0x7 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS | + 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF, + 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_FS | + 0x3 << SUN50I_ADDA_MDET_CTRL_SELDETADC_BF); + return devm_snd_soc_register_component(&pdev->dev, &sun50i_codec_analog_cmpnt_drv, NULL, 0); diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index c76628bc86c6..884394ddaf86 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -14,6 +14,7 @@ #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/tlv.h> #define SUN50I_DMIC_EN_CTL (0x00) #define SUN50I_DMIC_EN_CTL_GLOBE BIT(8) @@ -43,6 +44,17 @@ #define SUN50I_DMIC_CH_NUM_N_MASK GENMASK(2, 0) #define SUN50I_DMIC_CNT (0x2c) #define SUN50I_DMIC_CNT_N (1 << 0) +#define SUN50I_DMIC_D0D1_VOL_CTR (0x30) + #define SUN50I_DMIC_D0D1_VOL_CTR_0R (0) + #define SUN50I_DMIC_D0D1_VOL_CTR_0L (8) + #define SUN50I_DMIC_D0D1_VOL_CTR_1R (16) + #define SUN50I_DMIC_D0D1_VOL_CTR_1L (24) +#define SUN50I_DMIC_D2D3_VOL_CTR (0x34) + #define SUN50I_DMIC_D2D3_VOL_CTR_2R (0) + #define SUN50I_DMIC_D2D3_VOL_CTR_2L (8) + #define SUN50I_DMIC_D2D3_VOL_CTR_3R (16) + #define SUN50I_DMIC_D2D3_VOL_CTR_3L (24) + #define SUN50I_DMIC_HPF_CTRL (0x38) #define SUN50I_DMIC_VERSION (0x50) @@ -74,7 +86,7 @@ static const struct dmic_rate dmic_rate_s[] = { static int sun50i_dmic_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0)); /* only support capture */ @@ -273,8 +285,30 @@ static const struct of_device_id sun50i_dmic_of_match[] = { }; MODULE_DEVICE_TABLE(of, sun50i_dmic_of_match); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(sun50i_dmic_vol_scale, -12000, 75, 1); + +static const struct snd_kcontrol_new sun50i_dmic_controls[] = { + + SOC_DOUBLE_TLV("DMIC Channel 0 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR, + SUN50I_DMIC_D0D1_VOL_CTR_0L, SUN50I_DMIC_D0D1_VOL_CTR_0R, + 0xFF, 0, sun50i_dmic_vol_scale), + SOC_DOUBLE_TLV("DMIC Channel 1 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR, + SUN50I_DMIC_D0D1_VOL_CTR_1L, SUN50I_DMIC_D0D1_VOL_CTR_1R, + 0xFF, 0, sun50i_dmic_vol_scale), + SOC_DOUBLE_TLV("DMIC Channel 2 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR, + SUN50I_DMIC_D2D3_VOL_CTR_2L, SUN50I_DMIC_D2D3_VOL_CTR_2R, + 0xFF, 0, sun50i_dmic_vol_scale), + SOC_DOUBLE_TLV("DMIC Channel 3 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR, + SUN50I_DMIC_D2D3_VOL_CTR_3L, SUN50I_DMIC_D2D3_VOL_CTR_3R, + 0xFF, 0, sun50i_dmic_vol_scale), + + +}; + static const struct snd_soc_component_driver sun50i_dmic_component = { .name = "sun50i-dmic", + .controls = sun50i_dmic_controls, + .num_controls = ARRAY_SIZE(sun50i_dmic_controls), }; static int sun50i_dmic_runtime_suspend(struct device *dev) diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 7b45ddffe990..b5dafb749c3f 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -12,12 +12,16 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/clk.h> +#include <linux/input.h> #include <linux/io.h> +#include <linux/irq.h> +#include <linux/mutex.h> #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/log2.h> +#include <sound/jack.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-dapm.h> @@ -118,6 +122,23 @@ #define SUN8I_ADC_VOL_CTRL 0x104 #define SUN8I_ADC_VOL_CTRL_ADCL_VOL 8 #define SUN8I_ADC_VOL_CTRL_ADCR_VOL 0 +#define SUN8I_HMIC_CTRL1 0x110 +#define SUN8I_HMIC_CTRL1_HMIC_M 12 +#define SUN8I_HMIC_CTRL1_HMIC_N 8 +#define SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB 5 +#define SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN 4 +#define SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN 3 +#define SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN 0 +#define SUN8I_HMIC_CTRL2 0x114 +#define SUN8I_HMIC_CTRL2_HMIC_SAMPLE 14 +#define SUN8I_HMIC_CTRL2_HMIC_MDATA_THRESHOLD 8 +#define SUN8I_HMIC_CTRL2_HMIC_SF 6 +#define SUN8I_HMIC_STS 0x118 +#define SUN8I_HMIC_STS_MDATA_DISCARD 13 +#define SUN8I_HMIC_STS_HMIC_DATA 8 +#define SUN8I_HMIC_STS_JACK_OUT_IRQ_ST 4 +#define SUN8I_HMIC_STS_JACK_IN_IRQ_ST 3 +#define SUN8I_HMIC_STS_HMIC_DATA_IRQ_ST 0 #define SUN8I_DAC_DIG_CTRL 0x120 #define SUN8I_DAC_DIG_CTRL_ENDA 15 #define SUN8I_DAC_VOL_CTRL 0x124 @@ -143,6 +164,17 @@ #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4) #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2) #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK GENMASK(1, 0) +#define SUN8I_HMIC_CTRL1_HMIC_M_MASK GENMASK(15, 12) +#define SUN8I_HMIC_CTRL1_HMIC_N_MASK GENMASK(11, 8) +#define SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB_MASK GENMASK(6, 5) +#define SUN8I_HMIC_CTRL2_HMIC_SAMPLE_MASK GENMASK(15, 14) +#define SUN8I_HMIC_CTRL2_HMIC_SF_MASK GENMASK(7, 6) +#define SUN8I_HMIC_STS_HMIC_DATA_MASK GENMASK(12, 8) + +#define SUN8I_CODEC_BUTTONS (SND_JACK_BTN_0|\ + SND_JACK_BTN_1|\ + SND_JACK_BTN_2|\ + SND_JACK_BTN_3) #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000 @@ -177,15 +209,34 @@ struct sun8i_codec_aif { }; struct sun8i_codec_quirks { - bool legacy_widgets : 1; - bool lrck_inversion : 1; + bool bus_clock : 1; + bool jack_detection : 1; + bool legacy_widgets : 1; + bool lrck_inversion : 1; +}; + +enum { + SUN8I_JACK_STATUS_DISCONNECTED, + SUN8I_JACK_STATUS_WAITING_HBIAS, + SUN8I_JACK_STATUS_CONNECTED, }; struct sun8i_codec { + struct snd_soc_component *component; struct regmap *regmap; + struct clk *clk_bus; struct clk *clk_module; const struct sun8i_codec_quirks *quirks; struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS]; + struct snd_soc_jack *jack; + struct delayed_work jack_work; + int jack_irq; + int jack_status; + int jack_type; + int jack_last_sample; + ktime_t jack_hbias_ready; + struct mutex jack_mutex; + int last_hmic_irq; unsigned int sysclk_rate; int sysclk_refcnt; }; @@ -197,6 +248,14 @@ static int sun8i_codec_runtime_resume(struct device *dev) struct sun8i_codec *scodec = dev_get_drvdata(dev); int ret; + if (scodec->clk_bus) { + ret = clk_prepare_enable(scodec->clk_bus); + if (ret) { + dev_err(dev, "Failed to enable the bus clock\n"); + return ret; + } + } + regcache_cache_only(scodec->regmap, false); ret = regcache_sync(scodec->regmap); @@ -215,6 +274,9 @@ static int sun8i_codec_runtime_suspend(struct device *dev) regcache_cache_only(scodec->regmap, true); regcache_mark_dirty(scodec->regmap); + if (scodec->clk_bus) + clk_disable_unprepare(scodec->clk_bus); + return 0; } @@ -1232,6 +1294,8 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component) struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); int ret; + scodec->component = component; + /* Add widgets for backward compatibility with old device trees. */ if (scodec->quirks->legacy_widgets) { ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets, @@ -1268,6 +1332,250 @@ static int sun8i_codec_component_probe(struct snd_soc_component *component) return 0; } +static void sun8i_codec_set_hmic_bias(struct sun8i_codec *scodec, bool enable) +{ + struct snd_soc_dapm_context *dapm = &scodec->component->card->dapm; + int irq_mask = BIT(SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN); + + if (enable) + snd_soc_dapm_force_enable_pin(dapm, "HBIAS"); + else + snd_soc_dapm_disable_pin(dapm, "HBIAS"); + + snd_soc_dapm_sync(dapm); + + regmap_update_bits(scodec->regmap, SUN8I_HMIC_CTRL1, + irq_mask, enable ? irq_mask : 0); +} + +static void sun8i_codec_jack_work(struct work_struct *work) +{ + struct sun8i_codec *scodec = container_of(work, struct sun8i_codec, + jack_work.work); + unsigned int mdata; + int type; + + guard(mutex)(&scodec->jack_mutex); + + if (scodec->jack_status == SUN8I_JACK_STATUS_DISCONNECTED) { + if (scodec->last_hmic_irq != SUN8I_HMIC_STS_JACK_IN_IRQ_ST) + return; + + scodec->jack_last_sample = -1; + + if (scodec->jack_type & SND_JACK_MICROPHONE) { + /* + * If we were in disconnected state, we enable HBIAS and + * wait 600ms before reading initial HDATA value. + */ + scodec->jack_hbias_ready = ktime_add_ms(ktime_get(), 600); + sun8i_codec_set_hmic_bias(scodec, true); + queue_delayed_work(system_power_efficient_wq, + &scodec->jack_work, + msecs_to_jiffies(610)); + scodec->jack_status = SUN8I_JACK_STATUS_WAITING_HBIAS; + } else { + snd_soc_jack_report(scodec->jack, SND_JACK_HEADPHONE, + scodec->jack_type); + scodec->jack_status = SUN8I_JACK_STATUS_CONNECTED; + } + } else if (scodec->jack_status == SUN8I_JACK_STATUS_WAITING_HBIAS) { + /* + * If we're waiting for HBIAS to stabilize, and we get plug-out + * interrupt and nothing more for > 100ms, just cancel the + * initialization. + */ + if (scodec->last_hmic_irq == SUN8I_HMIC_STS_JACK_OUT_IRQ_ST) { + scodec->jack_status = SUN8I_JACK_STATUS_DISCONNECTED; + sun8i_codec_set_hmic_bias(scodec, false); + return; + } + + /* + * If we're not done waiting for HBIAS to stabilize, wait more. + */ + if (!ktime_after(ktime_get(), scodec->jack_hbias_ready)) { + s64 msecs = ktime_ms_delta(scodec->jack_hbias_ready, + ktime_get()); + + queue_delayed_work(system_power_efficient_wq, + &scodec->jack_work, + msecs_to_jiffies(msecs + 10)); + return; + } + + /* + * Everything is stabilized, determine jack type and report it. + */ + regmap_read(scodec->regmap, SUN8I_HMIC_STS, &mdata); + mdata &= SUN8I_HMIC_STS_HMIC_DATA_MASK; + mdata >>= SUN8I_HMIC_STS_HMIC_DATA; + + regmap_write(scodec->regmap, SUN8I_HMIC_STS, 0); + + type = mdata < 16 ? SND_JACK_HEADPHONE : SND_JACK_HEADSET; + if (type == SND_JACK_HEADPHONE) + sun8i_codec_set_hmic_bias(scodec, false); + + snd_soc_jack_report(scodec->jack, type, scodec->jack_type); + scodec->jack_status = SUN8I_JACK_STATUS_CONNECTED; + } else if (scodec->jack_status == SUN8I_JACK_STATUS_CONNECTED) { + if (scodec->last_hmic_irq != SUN8I_HMIC_STS_JACK_OUT_IRQ_ST) + return; + + scodec->jack_status = SUN8I_JACK_STATUS_DISCONNECTED; + if (scodec->jack_type & SND_JACK_MICROPHONE) + sun8i_codec_set_hmic_bias(scodec, false); + + snd_soc_jack_report(scodec->jack, 0, scodec->jack_type); + } +} + +static irqreturn_t sun8i_codec_jack_irq(int irq, void *dev_id) +{ + struct sun8i_codec *scodec = dev_id; + int type = SND_JACK_HEADSET; + unsigned int status, value; + + guard(mutex)(&scodec->jack_mutex); + + regmap_read(scodec->regmap, SUN8I_HMIC_STS, &status); + regmap_write(scodec->regmap, SUN8I_HMIC_STS, status); + + /* + * De-bounce in/out interrupts via a delayed work re-scheduling to + * 100ms after each interrupt.. + */ + if (status & BIT(SUN8I_HMIC_STS_JACK_OUT_IRQ_ST)) { + /* + * Out interrupt has priority over in interrupt so that if + * we get both, we assume the disconnected state, which is + * safer. + */ + scodec->last_hmic_irq = SUN8I_HMIC_STS_JACK_OUT_IRQ_ST; + mod_delayed_work(system_power_efficient_wq, &scodec->jack_work, + msecs_to_jiffies(100)); + } else if (status & BIT(SUN8I_HMIC_STS_JACK_IN_IRQ_ST)) { + scodec->last_hmic_irq = SUN8I_HMIC_STS_JACK_IN_IRQ_ST; + mod_delayed_work(system_power_efficient_wq, &scodec->jack_work, + msecs_to_jiffies(100)); + } else if (status & BIT(SUN8I_HMIC_STS_HMIC_DATA_IRQ_ST)) { + /* + * Ignore data interrupts until jack status turns to connected + * state, which is after HMIC enable stabilization is completed. + * Until then tha data are bogus. + */ + if (scodec->jack_status != SUN8I_JACK_STATUS_CONNECTED) + return IRQ_HANDLED; + + value = (status & SUN8I_HMIC_STS_HMIC_DATA_MASK) >> + SUN8I_HMIC_STS_HMIC_DATA; + + /* + * Assumes 60 mV per ADC LSB increment, 2V bias voltage, 2.2kOhm + * bias resistor. + */ + if (value == 0) + type |= SND_JACK_BTN_0; + else if (value == 1) + type |= SND_JACK_BTN_3; + else if (value <= 3) + type |= SND_JACK_BTN_1; + else if (value <= 8) + type |= SND_JACK_BTN_2; + + /* + * De-bounce. Only report button after two consecutive A/D + * samples are identical. + */ + if (scodec->jack_last_sample >= 0 && + scodec->jack_last_sample == value) + snd_soc_jack_report(scodec->jack, type, + scodec->jack_type); + + scodec->jack_last_sample = value; + } + + return IRQ_HANDLED; +} + +static int sun8i_codec_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); + struct platform_device *pdev = to_platform_device(component->dev); + int ret; + + if (!scodec->quirks->jack_detection) + return 0; + + scodec->jack = jack; + + scodec->jack_irq = platform_get_irq(pdev, 0); + if (scodec->jack_irq < 0) + return scodec->jack_irq; + + /* Reserved value required for jack IRQs to trigger. */ + regmap_write(scodec->regmap, SUN8I_HMIC_CTRL1, + 0xf << SUN8I_HMIC_CTRL1_HMIC_N | + 0x0 << SUN8I_HMIC_CTRL1_MDATA_THRESHOLD_DB | + 0x4 << SUN8I_HMIC_CTRL1_HMIC_M); + + /* Sample the ADC at 128 Hz; bypass smooth filter. */ + regmap_write(scodec->regmap, SUN8I_HMIC_CTRL2, + 0x0 << SUN8I_HMIC_CTRL2_HMIC_SAMPLE | + 0x17 << SUN8I_HMIC_CTRL2_HMIC_MDATA_THRESHOLD | + 0x0 << SUN8I_HMIC_CTRL2_HMIC_SF); + + /* Do not discard any MDATA, enable user written MDATA threshold. */ + regmap_write(scodec->regmap, SUN8I_HMIC_STS, 0); + + regmap_set_bits(scodec->regmap, SUN8I_HMIC_CTRL1, + BIT(SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN) | + BIT(SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN)); + + ret = devm_request_threaded_irq(&pdev->dev, scodec->jack_irq, + NULL, sun8i_codec_jack_irq, + IRQF_ONESHOT, + dev_name(&pdev->dev), scodec); + if (ret) + return ret; + + return 0; +} + +static void sun8i_codec_disable_jack_detect(struct snd_soc_component *component) +{ + struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component); + + if (!scodec->quirks->jack_detection) + return; + + devm_free_irq(component->dev, scodec->jack_irq, scodec); + + cancel_delayed_work_sync(&scodec->jack_work); + + regmap_clear_bits(scodec->regmap, SUN8I_HMIC_CTRL1, + BIT(SUN8I_HMIC_CTRL1_JACK_OUT_IRQ_EN) | + BIT(SUN8I_HMIC_CTRL1_JACK_IN_IRQ_EN) | + BIT(SUN8I_HMIC_CTRL1_HMIC_DATA_IRQ_EN)); + + scodec->jack = NULL; +} + +static int sun8i_codec_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + int ret = 0; + + if (jack) + ret = sun8i_codec_enable_jack_detect(component, jack, data); + else + sun8i_codec_disable_jack_detect(component); + + return ret; +} + static const struct snd_soc_component_driver sun8i_soc_component = { .controls = sun8i_codec_controls, .num_controls = ARRAY_SIZE(sun8i_codec_controls), @@ -1275,15 +1583,23 @@ static const struct snd_soc_component_driver sun8i_soc_component = { .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), .dapm_routes = sun8i_codec_dapm_routes, .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes), + .set_jack = sun8i_codec_component_set_jack, .probe = sun8i_codec_component_probe, .idle_bias_on = 1, + .suspend_bias_off = 1, .endianness = 1, }; +static bool sun8i_codec_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == SUN8I_HMIC_STS; +} + static const struct regmap_config sun8i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, + .volatile_reg = sun8i_codec_volatile_reg, .max_register = SUN8I_DAC_MXR_SRC, .cache_type = REGCACHE_FLAT, @@ -1299,6 +1615,20 @@ static int sun8i_codec_probe(struct platform_device *pdev) if (!scodec) return -ENOMEM; + scodec->quirks = of_device_get_match_data(&pdev->dev); + INIT_DELAYED_WORK(&scodec->jack_work, sun8i_codec_jack_work); + mutex_init(&scodec->jack_mutex); + + platform_set_drvdata(pdev, scodec); + + if (scodec->quirks->bus_clock) { + scodec->clk_bus = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(scodec->clk_bus)) { + dev_err(&pdev->dev, "Failed to get the bus clock\n"); + return PTR_ERR(scodec->clk_bus); + } + } + scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(scodec->clk_module)) { dev_err(&pdev->dev, "Failed to get the module clock\n"); @@ -1311,17 +1641,14 @@ static int sun8i_codec_probe(struct platform_device *pdev) return PTR_ERR(base); } - scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, - &sun8i_codec_regmap_config); + scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &sun8i_codec_regmap_config); if (IS_ERR(scodec->regmap)) { dev_err(&pdev->dev, "Failed to create our regmap\n"); return PTR_ERR(scodec->regmap); } - scodec->quirks = of_device_get_match_data(&pdev->dev); - - platform_set_drvdata(pdev, scodec); - + regcache_cache_only(scodec->regmap, true); pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = sun8i_codec_runtime_resume(&pdev->dev); @@ -1357,11 +1684,14 @@ static void sun8i_codec_remove(struct platform_device *pdev) } static const struct sun8i_codec_quirks sun8i_a33_quirks = { + .bus_clock = true, .legacy_widgets = true, .lrck_inversion = true, }; static const struct sun8i_codec_quirks sun50i_a64_quirks = { + .bus_clock = true, + .jack_detection = true, }; static const struct of_device_id sun8i_codec_of_match[] = { diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index b723c78e665d..cea4b0d54378 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -1,25 +1,25 @@ # SPDX-License-Identifier: GPL-2.0 # Tegra platform Support -snd-soc-tegra-pcm-objs := tegra_pcm.o -snd-soc-tegra-utils-objs += tegra_asoc_utils.o -snd-soc-tegra20-ac97-objs := tegra20_ac97.o -snd-soc-tegra20-das-objs := tegra20_das.o -snd-soc-tegra20-i2s-objs := tegra20_i2s.o -snd-soc-tegra20-spdif-objs := tegra20_spdif.o -snd-soc-tegra30-ahub-objs := tegra30_ahub.o -snd-soc-tegra30-i2s-objs := tegra30_i2s.o -snd-soc-tegra210-ahub-objs := tegra210_ahub.o -snd-soc-tegra210-dmic-objs := tegra210_dmic.o -snd-soc-tegra210-i2s-objs := tegra210_i2s.o -snd-soc-tegra186-asrc-objs := tegra186_asrc.o -snd-soc-tegra186-dspk-objs := tegra186_dspk.o -snd-soc-tegra210-admaif-objs := tegra210_admaif.o -snd-soc-tegra210-mvc-objs := tegra210_mvc.o -snd-soc-tegra210-sfc-objs := tegra210_sfc.o -snd-soc-tegra210-amx-objs := tegra210_amx.o -snd-soc-tegra210-adx-objs := tegra210_adx.o -snd-soc-tegra210-mixer-objs := tegra210_mixer.o -snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o +snd-soc-tegra-pcm-y := tegra_pcm.o +snd-soc-tegra-utils-y += tegra_asoc_utils.o +snd-soc-tegra20-ac97-y := tegra20_ac97.o +snd-soc-tegra20-das-y := tegra20_das.o +snd-soc-tegra20-i2s-y := tegra20_i2s.o +snd-soc-tegra20-spdif-y := tegra20_spdif.o +snd-soc-tegra30-ahub-y := tegra30_ahub.o +snd-soc-tegra30-i2s-y := tegra30_i2s.o +snd-soc-tegra210-ahub-y := tegra210_ahub.o +snd-soc-tegra210-dmic-y := tegra210_dmic.o +snd-soc-tegra210-i2s-y := tegra210_i2s.o +snd-soc-tegra186-asrc-y := tegra186_asrc.o +snd-soc-tegra186-dspk-y := tegra186_dspk.o +snd-soc-tegra210-admaif-y := tegra210_admaif.o +snd-soc-tegra210-mvc-y := tegra210_mvc.o +snd-soc-tegra210-sfc-y := tegra210_sfc.o +snd-soc-tegra210-amx-y := tegra210_amx.o +snd-soc-tegra210-adx-y := tegra210_adx.o +snd-soc-tegra210-mixer-y := tegra210_mixer.o +snd-soc-tegra210-ope-y := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -42,9 +42,9 @@ obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o # Tegra machine Support -snd-soc-tegra-wm8903-objs := tegra_wm8903.o -snd-soc-tegra-machine-objs := tegra_asoc_machine.o -snd-soc-tegra-audio-graph-card-objs := tegra_audio_graph_card.o +snd-soc-tegra-wm8903-y := tegra_wm8903.o +snd-soc-tegra-machine-y := tegra_asoc_machine.o +snd-soc-tegra-audio-graph-card-y := tegra_audio_graph_card.o obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o obj-$(CONFIG_SND_SOC_TEGRA_MACHINE_DRV) += snd-soc-tegra-machine.o diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index aa37c4ab0adb..21cd41fec7a9 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // tegra186_dspk.c - Tegra186 DSPK driver -// -// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. #include <linux/clk.h> #include <linux/device.h> @@ -241,14 +240,14 @@ static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - cif_conf.client_bits = TEGRA_ACIF_BITS_24; - switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_16; + cif_conf.client_bits = TEGRA_ACIF_BITS_16; break; case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + cif_conf.client_bits = TEGRA_ACIF_BITS_24; break; default: dev_err(dev, "unsupported format!\n"); diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c index 192e9692bdf2..775ce433fdbf 100644 --- a/sound/soc/tegra/tegra_asoc_machine.c +++ b/sound/soc/tegra/tegra_asoc_machine.c @@ -290,7 +290,7 @@ static unsigned int tegra_machine_mclk_rate_6mhz(unsigned int srate) static int tegra_machine_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 = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_card *card = rtd->card; struct tegra_machine *machine = snd_soc_card_get_drvdata(card); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 42acb56543db..4bdbcd2635ef 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -76,7 +76,7 @@ EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister); int tegra_pcm_open(struct snd_soc_component *component, 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_dmaengine_dai_dma_data *dmap; struct dma_chan *chan; struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -127,7 +127,7 @@ EXPORT_SYMBOL_GPL(tegra_pcm_open); int tegra_pcm_close(struct snd_soc_component *component, 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); if (rtd->dai_link->no_pcm) return 0; @@ -142,7 +142,7 @@ int tegra_pcm_hw_params(struct snd_soc_component *component, 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_dmaengine_dai_dma_data *dmap; struct dma_slave_config slave_config; struct dma_chan *chan; diff --git a/sound/soc/ti/Makefile b/sound/soc/ti/Makefile index 41cdcaec770d..421e13bc04db 100644 --- a/sound/soc/ti/Makefile +++ b/sound/soc/ti/Makefile @@ -1,20 +1,20 @@ # SPDX-License-Identifier: GPL-2.0 # Platform drivers -snd-soc-ti-edma-objs := edma-pcm.o -snd-soc-ti-sdma-objs := sdma-pcm.o -snd-soc-ti-udma-objs := udma-pcm.o +snd-soc-ti-edma-y := edma-pcm.o +snd-soc-ti-sdma-y := sdma-pcm.o +snd-soc-ti-udma-y := udma-pcm.o obj-$(CONFIG_SND_SOC_TI_EDMA_PCM) += snd-soc-ti-edma.o obj-$(CONFIG_SND_SOC_TI_SDMA_PCM) += snd-soc-ti-sdma.o obj-$(CONFIG_SND_SOC_TI_UDMA_PCM) += snd-soc-ti-udma.o # CPU DAI drivers -snd-soc-davinci-asp-objs := davinci-i2s.o -snd-soc-davinci-mcasp-objs := davinci-mcasp.o -snd-soc-omap-dmic-objs := omap-dmic.o -snd-soc-omap-mcbsp-objs := omap-mcbsp.o omap-mcbsp-st.o -snd-soc-omap-mcpdm-objs := omap-mcpdm.o +snd-soc-davinci-asp-y := davinci-i2s.o +snd-soc-davinci-mcasp-y := davinci-mcasp.o +snd-soc-omap-dmic-y := omap-dmic.o +snd-soc-omap-mcbsp-y := omap-mcbsp.o omap-mcbsp-st.o +snd-soc-omap-mcpdm-y := omap-mcpdm.o obj-$(CONFIG_SND_SOC_DAVINCI_ASP) += snd-soc-davinci-asp.o obj-$(CONFIG_SND_SOC_DAVINCI_MCASP) += snd-soc-davinci-mcasp.o @@ -23,16 +23,16 @@ obj-$(CONFIG_SND_SOC_OMAP_MCBSP) += snd-soc-omap-mcbsp.o obj-$(CONFIG_SND_SOC_OMAP_MCPDM) += snd-soc-omap-mcpdm.o # Machine drivers -snd-soc-davinci-evm-objs := davinci-evm.o -snd-soc-n810-objs := n810.o -snd-soc-rx51-objs := rx51.o -snd-soc-omap3pandora-objs := omap3pandora.o -snd-soc-omap-twl4030-objs := omap-twl4030.o -snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o -snd-soc-ams-delta-objs := ams-delta.o -snd-soc-omap-hdmi-objs := omap-hdmi.o -snd-soc-osk5912-objs := osk5912.o -snd-soc-j721e-evm-objs := j721e-evm.o +snd-soc-davinci-evm-y := davinci-evm.o +snd-soc-n810-y := n810.o +snd-soc-rx51-y := rx51.o +snd-soc-omap3pandora-y := omap3pandora.o +snd-soc-omap-twl4030-y := omap-twl4030.o +snd-soc-omap-abe-twl6040-y := omap-abe-twl6040.o +snd-soc-ams-delta-y := ams-delta.o +snd-soc-omap-hdmi-y := omap-hdmi.o +snd-soc-osk5912-y := osk5912.o +snd-soc-j721e-evm-y := j721e-evm.o obj-$(CONFIG_SND_SOC_DAVINCI_EVM) += snd-soc-davinci-evm.o obj-$(CONFIG_SND_SOC_NOKIA_N810) += snd-soc-n810.o diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 07c8b2259208..0f15a743c798 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -19,7 +19,6 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/clk.h> -#include <linux/platform_data/davinci_asp.h> #include <sound/core.h> #include <sound/pcm.h> @@ -62,6 +61,9 @@ #define DAVINCI_MCBSP_SPCR_RRST (1 << 0) #define DAVINCI_MCBSP_SPCR_RINTM(v) ((v) << 4) +#define DAVINCI_MCBSP_SPCR_RJUST(v) ((v) << 13) +#define DAVINCI_MCBSP_SPCR_RJUST_Z_LE DAVINCI_MCBSP_SPCR_RJUST(0) +#define DAVINCI_MCBSP_SPCR_RJUST_S_LE DAVINCI_MCBSP_SPCR_RJUST(1) #define DAVINCI_MCBSP_SPCR_XRST (1 << 16) #define DAVINCI_MCBSP_SPCR_XINTM(v) ((v) << 20) #define DAVINCI_MCBSP_SPCR_GRST (1 << 22) @@ -108,15 +110,10 @@ enum { DAVINCI_MCBSP_WORD_32, }; -static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = { - [SNDRV_PCM_FORMAT_S8] = 1, - [SNDRV_PCM_FORMAT_S16_LE] = 2, - [SNDRV_PCM_FORMAT_S32_LE] = 4, -}; - static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = { [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8, [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16, + [SNDRV_PCM_FORMAT_S24_LE] = DAVINCI_MCBSP_WORD_24, [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32, }; @@ -135,6 +132,7 @@ struct davinci_mcbsp_dev { int mode; u32 pcr; struct clk *clk; + struct clk *ext_clk; /* * Combining both channels into 1 element will at least double the * amount of time between servicing the dma channel, increase @@ -159,8 +157,13 @@ struct davinci_mcbsp_dev { unsigned int fmt; int clk_div; - int clk_input_pin; bool i2s_accurate_sck; + + int tdm_slots; + int slot_width; + + bool tx_framing_bit; + bool rx_framing_bit; }; static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, @@ -214,6 +217,63 @@ static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback) toggle_clock(dev, playback); } +static int davinci_i2s_tdm_word_length(int tdm_slot_width) +{ + switch (tdm_slot_width) { + case 8: + return DAVINCI_MCBSP_WORD_8; + case 12: + return DAVINCI_MCBSP_WORD_12; + case 16: + return DAVINCI_MCBSP_WORD_16; + case 20: + return DAVINCI_MCBSP_WORD_20; + case 24: + return DAVINCI_MCBSP_WORD_24; + case 32: + return DAVINCI_MCBSP_WORD_32; + default: + return -EINVAL; + } +} + +static int davinci_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, int slot_width) +{ + struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); + + dev_dbg(dev->dev, "slots %d, slot_width %d\n", slots, slot_width); + + if (slots > 128 || !slots) { + dev_err(dev->dev, "Invalid number of slots\n"); + return -EINVAL; + } + + if (rx_mask != (1 << slots) - 1) { + dev_err(dev->dev, "Invalid RX mask (0x%08x) : all slots must be used by McBSP\n", + rx_mask); + return -EINVAL; + } + + if (tx_mask != (1 << slots) - 1) { + dev_err(dev->dev, "Invalid TX mask (0x%08x) : all slots must be used by McBSP\n", + tx_mask); + return -EINVAL; + } + + if (davinci_i2s_tdm_word_length(slot_width) < 0) { + dev_err(dev->dev, "%s: Unsupported slot_width %d\n", __func__, slot_width); + return -EINVAL; + } + + dev->tdm_slots = slots; + dev->slot_width = slot_width; + + return 0; +} + #define DEFAULT_BITPERSAMPLE 16 static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, @@ -221,6 +281,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, { struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); unsigned int pcr; + unsigned int spcr; unsigned int srgr; bool inv_fs = false; /* Attention srgr is updated by hw_params! */ @@ -229,6 +290,23 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); dev->fmt = fmt; + + spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CONT: + spcr |= DAVINCI_MCBSP_SPCR_FREE; + dev_dbg(dev->dev, "Free-running mode ON\n"); + break; + case SND_SOC_DAIFMT_GATED: + spcr &= ~DAVINCI_MCBSP_SPCR_FREE; + dev_dbg(dev->dev, "Free-running mode OFF\n"); + break; + default: + dev_err(dev->dev, "Invalid clock gating\n"); + return -EINVAL; + } + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); + /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { case SND_SOC_DAIFMT_BP_FP: @@ -239,28 +317,30 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, DAVINCI_MCBSP_PCR_CLKRM; break; case SND_SOC_DAIFMT_BC_FP: - pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; - /* - * Selection of the clock input pin that is the - * input for the Sample Rate Generator. - * McBSP FSR and FSX are driven by the Sample Rate - * Generator. - */ - switch (dev->clk_input_pin) { - case MCBSP_CLKS: - pcr |= DAVINCI_MCBSP_PCR_CLKXM | - DAVINCI_MCBSP_PCR_CLKRM; - break; - case MCBSP_CLKR: - pcr |= DAVINCI_MCBSP_PCR_SCLKME; - break; - default: - dev_err(dev->dev, "bad clk_input_pin\n"); + if (dev->tdm_slots || dev->slot_width) { + dev_err(dev->dev, "TDM is not supported for BC_FP format\n"); return -EINVAL; } + /* + * McBSP CLKR pin is the input for the Sample Rate Generator. + * McBSP FSR and FSX are driven by the Sample Rate Generator. + */ + pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM; + pcr |= DAVINCI_MCBSP_PCR_SCLKME; + break; + case SND_SOC_DAIFMT_BP_FC: + /* cpu is bitclock provider */ + pcr = DAVINCI_MCBSP_PCR_CLKXM | + DAVINCI_MCBSP_PCR_CLKRM; break; + case SND_SOC_DAIFMT_BC_FC: + if (dev->tdm_slots || dev->slot_width) { + dev_err(dev->dev, "TDM is not supported for BC_FC format\n"); + return -EINVAL; + } + /* codec is master */ pcr = 0; break; @@ -380,30 +460,58 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai); struct snd_interval *i = NULL; int mcbsp_word_length, master; - unsigned int rcr, xcr, srgr, clk_div, freq, framesize; + unsigned int clk_div, freq, framesize; + unsigned int srgr = 0; + unsigned int rcr = 0; + unsigned int xcr = 0; u32 spcr; snd_pcm_format_t fmt; unsigned element_cnt = 1; - /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + + /* Determine xfer data type */ + fmt = params_format(params); + switch (fmt) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S32_LE: + break; + case SNDRV_PCM_FORMAT_S24_LE: + spcr |= DAVINCI_MCBSP_SPCR_RJUST_S_LE; + break; + default: + dev_warn(dev->dev, "davinci-i2s: unsupported PCM format\n"); + return -EINVAL; + } + + /* general line settings */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - spcr |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + spcr |= DAVINCI_MCBSP_SPCR_RINTM(3); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } else { - spcr |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + spcr |= DAVINCI_MCBSP_SPCR_XINTM(3); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } master = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; fmt = params_format(params); - mcbsp_word_length = asp_word_length[fmt]; + if (dev->slot_width) + mcbsp_word_length = davinci_i2s_tdm_word_length(dev->slot_width); + else + mcbsp_word_length = asp_word_length[fmt]; + + if (mcbsp_word_length < 0) + return mcbsp_word_length; switch (master) { case SND_SOC_DAIFMT_BP_FP: - freq = clk_get_rate(dev->clk); - srgr = DAVINCI_MCBSP_SRGR_FSGM | - DAVINCI_MCBSP_SRGR_CLKSM; + if (dev->ext_clk) { + freq = clk_get_rate(dev->ext_clk); + } else { + freq = clk_get_rate(dev->clk); + srgr = DAVINCI_MCBSP_SRGR_CLKSM; + } + srgr |= DAVINCI_MCBSP_SRGR_FSGM; srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); if (dev->i2s_accurate_sck) { @@ -434,6 +542,23 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, clk_div &= 0xFF; srgr |= clk_div; break; + case SND_SOC_DAIFMT_BP_FC: + if (dev->ext_clk) { + freq = clk_get_rate(dev->ext_clk); + } else { + freq = clk_get_rate(dev->clk); + srgr = DAVINCI_MCBSP_SRGR_CLKSM; + } + if (dev->tdm_slots && dev->slot_width) { + clk_div = freq / (params->rate_num * params->rate_den) + / (dev->tdm_slots * dev->slot_width) - 1; + } else { + clk_div = freq / (mcbsp_word_length * 16) / + params->rate_num * params->rate_den; + } + clk_div &= 0xFF; + srgr |= clk_div; + break; case SND_SOC_DAIFMT_BC_FC: /* Clock and frame sync given from external sources */ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); @@ -450,8 +575,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); - rcr = DAVINCI_MCBSP_RCR_RFIG; - xcr = DAVINCI_MCBSP_XCR_XFIG; if (dev->mode == MOD_DSP_B) { rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0); @@ -459,11 +582,14 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); } - /* Determine xfer data type */ - fmt = params_format(params); - if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) { - printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); - return -EINVAL; + + if (dev->tx_framing_bit) { + xcr &= ~DAVINCI_MCBSP_XCR_XDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(2); + } + if (dev->rx_framing_bit) { + rcr &= ~DAVINCI_MCBSP_RCR_RDATDLY(1); + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(2); } if (params_channels(params) == 2) { @@ -489,13 +615,17 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } } - mcbsp_word_length = asp_word_length[fmt]; switch (master) { case SND_SOC_DAIFMT_BP_FP: case SND_SOC_DAIFMT_BP_FC: - rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); - xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); + if (dev->tdm_slots > 0) { + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(dev->tdm_slots - 1); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(dev->tdm_slots - 1); + } else { + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); + } break; case SND_SOC_DAIFMT_BC_FC: case SND_SOC_DAIFMT_BC_FP: @@ -599,6 +729,7 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 #define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) static int davinci_i2s_dai_probe(struct snd_soc_dai *dai) @@ -620,19 +751,20 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, .set_clkdiv = davinci_i2s_dai_set_clkdiv, + .set_tdm_slot = davinci_i2s_set_tdm_slot, }; static struct snd_soc_dai_driver davinci_i2s_dai = { .playback = { .channels_min = 2, - .channels_max = 2, + .channels_max = 128, .rates = DAVINCI_I2S_RATES, .formats = DAVINCI_I2S_FORMATS, }, .capture = { .channels_min = 2, - .channels_max = 2, + .channels_max = 128, .rates = DAVINCI_I2S_RATES, .formats = DAVINCI_I2S_FORMATS, }, @@ -676,6 +808,9 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->base = io_base; + dev->tx_framing_bit = of_property_read_bool(pdev->dev.of_node, "ti,T1-framing-tx"); + dev->rx_framing_bit = of_property_read_bool(pdev->dev.of_node, "ti,T1-framing-rx"); + /* setup DMA, first TX, then RX */ dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); @@ -707,12 +842,36 @@ static int davinci_i2s_probe(struct platform_device *pdev) return -ENODEV; } - dev->clk = clk_get(&pdev->dev, NULL); + /* + * The optional is there for backward compatibility. + * If 'fck' is not present, the clk_get(dev, NULL) that follows may find something + */ + dev->clk = devm_clk_get_optional(&pdev->dev, "fck"); if (IS_ERR(dev->clk)) - return -ENODEV; - ret = clk_enable(dev->clk); + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk), "Invalid functional clock\n"); + if (!dev->clk) { + dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk), + "Missing functional clock\n"); + } + + dev->ext_clk = devm_clk_get_optional(&pdev->dev, "clks"); + if (IS_ERR(dev->ext_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dev->ext_clk), "Invalid external clock\n"); + + ret = clk_prepare_enable(dev->clk); if (ret) - goto err_put_clk; + return ret; + + if (dev->ext_clk) { + dev_dbg(&pdev->dev, "External clock used for sample rate generator\n"); + ret = clk_prepare_enable(dev->ext_clk); + if (ret) { + dev_err_probe(&pdev->dev, ret, "Failed to enable external clock\n"); + goto err_disable_clk; + } + } dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); @@ -720,11 +879,11 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component, &davinci_i2s_dai, 1); if (ret != 0) - goto err_release_clk; + goto err_disable_ext_clk; ret = edma_pcm_platform_register(&pdev->dev); if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + dev_err_probe(&pdev->dev, ret, "register PCM failed\n"); goto err_unregister_component; } @@ -732,10 +891,12 @@ static int davinci_i2s_probe(struct platform_device *pdev) err_unregister_component: snd_soc_unregister_component(&pdev->dev); -err_release_clk: - clk_disable(dev->clk); -err_put_clk: - clk_put(dev->clk); +err_disable_ext_clk: + if (dev->ext_clk) + clk_disable_unprepare(dev->ext_clk); +err_disable_clk: + clk_disable_unprepare(dev->clk); + return ret; } @@ -745,9 +906,10 @@ static void davinci_i2s_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - clk_disable(dev->clk); - clk_put(dev->clk); - dev->clk = NULL; + clk_disable_unprepare(dev->clk); + + if (dev->ext_clk) + clk_disable_unprepare(dev->ext_clk); } static const struct of_device_id davinci_i2s_match[] __maybe_unused = { diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index b892d66f7847..1e760c315521 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2417,12 +2417,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp_reparent_fck(pdev); - ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, - &davinci_mcasp_dai[mcasp->op_mode], 1); - - if (ret != 0) - goto err; - ret = davinci_mcasp_get_dma_type(mcasp); switch (ret) { case PCM_EDMA: @@ -2449,6 +2443,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) goto err; } + ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, + &davinci_mcasp_dai[mcasp->op_mode], 1); + + if (ret != 0) + goto err; + no_audio: ret = davinci_mcasp_init_gpiochip(mcasp); if (ret) { diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index 4513b527ab97..639bc83f4263 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -40,7 +40,7 @@ struct hdmi_audio_data { static struct hdmi_audio_data *card_drvdata_substream(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 snd_soc_card_get_drvdata(rtd->card); } diff --git a/sound/soc/uniphier/Makefile b/sound/soc/uniphier/Makefile index 88169395f68a..5fee21b6074c 100644 --- a/sound/soc/uniphier/Makefile +++ b/sound/soc/uniphier/Makefile @@ -1,11 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-uniphier-aio-cpu-objs := aio-core.o aio-dma.o aio-cpu.o aio-compress.o -snd-soc-uniphier-aio-ld11-objs := aio-ld11.o -snd-soc-uniphier-aio-pxs2-objs := aio-pxs2.o +snd-soc-uniphier-aio-cpu-y := aio-core.o aio-dma.o aio-cpu.o aio-compress.o +snd-soc-uniphier-aio-ld11-y := aio-ld11.o +snd-soc-uniphier-aio-pxs2-y := aio-pxs2.o obj-$(CONFIG_SND_SOC_UNIPHIER_AIO) += snd-soc-uniphier-aio-cpu.o obj-$(CONFIG_SND_SOC_UNIPHIER_LD11) += snd-soc-uniphier-aio-ld11.o obj-$(CONFIG_SND_SOC_UNIPHIER_PXS2) += snd-soc-uniphier-aio-pxs2.o -snd-soc-uniphier-evea-objs := evea.o +snd-soc-uniphier-evea-y := evea.o obj-$(CONFIG_SND_SOC_UNIPHIER_EVEA_CODEC) += snd-soc-uniphier-evea.o diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c index fe272befd967..265d61723e99 100644 --- a/sound/soc/uniphier/aio-dma.c +++ b/sound/soc/uniphier/aio-dma.c @@ -14,7 +14,7 @@ #include "aio.h" -static struct snd_pcm_hardware uniphier_aiodma_hw = { +static const struct snd_pcm_hardware uniphier_aiodma_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED, diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile index e7d6de51b32b..a63787d9d664 100644 --- a/sound/soc/ux500/Makefile +++ b/sound/soc/ux500/Makefile @@ -1,11 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 # Ux500 Platform Support -snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o +snd-soc-ux500-plat-msp-i2s-y := ux500_msp_dai.o ux500_msp_i2s.o obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o -snd-soc-ux500-plat-dma-objs := ux500_pcm.o +snd-soc-ux500-plat-dma-y := ux500_pcm.o obj-$(CONFIG_SND_SOC_UX500_PLAT_DMA) += snd-soc-ux500-plat-dma.o -snd-soc-ux500-mach-mop500-objs := mop500.o mop500_ab8500.o +snd-soc-ux500-mach-mop500-y := mop500.o mop500_ab8500.o obj-$(CONFIG_SND_SOC_UX500_MACH_MOP500) += snd-soc-ux500-mach-mop500.o diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index cde0dd8e2569..3fd13e8dd110 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -820,4 +820,5 @@ static struct platform_driver msp_i2s_driver = { }; module_platform_driver(msp_i2s_driver); +MODULE_DESCRIPTION("ASoC Ux500 I2S driver"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile index be7652ce7c13..61cb47cf74dc 100644 --- a/sound/soc/xilinx/Makefile +++ b/sound/soc/xilinx/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-xlnx-i2s-objs := xlnx_i2s.o +snd-soc-xlnx-i2s-y := xlnx_i2s.o obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o -snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o +snd-soc-xlnx-formatter-pcm-y := xlnx_formatter_pcm.o obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o -snd-soc-xlnx-spdif-objs := xlnx_spdif.o +snd-soc-xlnx-spdif-y := xlnx_spdif.o obj-$(CONFIG_SND_SOC_XILINX_SPDIF) += snd-soc-xlnx-spdif.o diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index 299cfb5e2022..158fc21a86c1 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -721,5 +721,7 @@ static struct platform_driver xlnx_formatter_pcm_driver = { }; module_platform_driver(xlnx_formatter_pcm_driver); + +MODULE_DESCRIPTION("ASoC driver for Xilinx audio formatter"); MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c index 9de92d35e30e..ca915a001ad5 100644 --- a/sound/soc/xilinx/xlnx_i2s.c +++ b/sound/soc/xilinx/xlnx_i2s.c @@ -253,6 +253,7 @@ static struct platform_driver xlnx_i2s_aud_driver = { module_platform_driver(xlnx_i2s_aud_driver); +MODULE_DESCRIPTION("ASoC driver for Xilinx I2S audio"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Praveen Vuppala <praveenv@xilinx.com>"); MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>"); diff --git a/sound/soc/xtensa/Makefile b/sound/soc/xtensa/Makefile index b8707f63c4ae..be4e847d1b20 100644 --- a/sound/soc/xtensa/Makefile +++ b/sound/soc/xtensa/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-xtfpga-i2s-objs := xtfpga-i2s.o +snd-soc-xtfpga-i2s-y := xtfpga-i2s.o obj-$(CONFIG_SND_SOC_XTFPGA_I2S) += snd-soc-xtfpga-i2s.o diff --git a/sound/sparc/Makefile b/sound/sparc/Makefile index e1f596571d7f..0a03123933c6 100644 --- a/sound/sparc/Makefile +++ b/sound/sparc/Makefile @@ -4,9 +4,9 @@ # Copyright (c) 2002 by David S. Miller <davem@redhat.com> # -snd-sun-amd7930-objs := amd7930.o -snd-sun-cs4231-objs := cs4231.o -snd-sun-dbri-objs := dbri.o +snd-sun-amd7930-y := amd7930.o +snd-sun-cs4231-y := cs4231.o +snd-sun-dbri-y := dbri.o obj-$(CONFIG_SND_SUN_AMD7930) += snd-sun-amd7930.o obj-$(CONFIG_SND_SUN_CS4231) += snd-sun-cs4231.o diff --git a/sound/spi/Makefile b/sound/spi/Makefile index a3834919b0f6..d6a198a44917 100644 --- a/sound/spi/Makefile +++ b/sound/spi/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for SPI drivers -snd-at73c213-objs := at73c213.o +snd-at73c213-y := at73c213.o obj-$(CONFIG_SND_AT73C213) += snd-at73c213.o diff --git a/sound/synth/Makefile b/sound/synth/Makefile index b9f71d5dbc8c..369f3be2cd17 100644 --- a/sound/synth/Makefile +++ b/sound/synth/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-util-mem-objs := util_mem.o +snd-util-mem-y := util_mem.o # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o diff --git a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile index ed28c81ac12e..59357da6d1ef 100644 --- a/sound/synth/emux/Makefile +++ b/sound/synth/emux/Makefile @@ -4,7 +4,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ +snd-emux-synth-y := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ emux_effect.o emux_hwdep.o soundfont.o snd-emux-synth-$(CONFIG_SND_PROC_FS) += emux_proc.o ifneq ($(CONFIG_SND_SEQUENCER_OSS),) diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index a82af9374852..01444fc960d0 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -94,10 +94,8 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch /* create soundfont list */ memset(&sf_cb, 0, sizeof(sf_cb)); sf_cb.private_data = emu; - if (emu->ops.sample_new) - sf_cb.sample_new = sf_sample_new; - if (emu->ops.sample_free) - sf_cb.sample_free = sf_sample_free; + sf_cb.sample_new = sf_sample_new; + sf_cb.sample_free = sf_sample_free; if (emu->ops.sample_reset) sf_cb.sample_reset = sf_sample_reset; emu->sflist = snd_sf_new(&sf_cb, emu->memhdr); diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index 81719bfb8ed7..fd8f978cde1c 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -27,8 +27,7 @@ snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg) if (patch.key == GUS_PATCH) return snd_soundfont_load_guspatch(emu->sflist, arg, - patch.len + sizeof(patch), - TMP_CLIENT_ID); + patch.len + sizeof(patch)); if (patch.type >= SNDRV_SFNT_LOAD_INFO && patch.type <= SNDRV_SFNT_PROBE_DATA) { diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index d8d32671f703..04df46b269d3 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -205,8 +205,7 @@ snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, return -ENXIO; if (format == GUS_PATCH) - rc = snd_soundfont_load_guspatch(emu->sflist, buf, count, - SF_CLIENT_NO(p->chset.port)); + rc = snd_soundfont_load_guspatch(emu->sflist, buf, count); else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { struct soundfont_patch_info patch; if (count < (int)sizeof(patch)) diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 7993e6a01e54..820351f52551 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c @@ -102,6 +102,7 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = emu; entry->c.text.read = snd_emux_proc_info_read; + emu->proc = entry; } void snd_emux_proc_free(struct snd_emux *emu) diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index b227c7e0bc2a..1adaa75df2f6 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c @@ -65,11 +65,11 @@ snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index) return -ENODEV; } - if (emu->num_ports < 0) { + if (emu->num_ports <= 0) { snd_printk(KERN_WARNING "seqports must be greater than zero\n"); emu->num_ports = 1; - } else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) { - snd_printk(KERN_WARNING "too many ports." + } else if (emu->num_ports > SNDRV_EMUX_MAX_PORTS) { + snd_printk(KERN_WARNING "too many ports. " "limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS); emu->num_ports = SNDRV_EMUX_MAX_PORTS; } diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 16f00097cb95..2373ed580bf8 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -689,6 +689,21 @@ find_sample(struct snd_soundfont *sf, int sample_id) } +static int +validate_sample_info(struct soundfont_sample_info *si) +{ + if (si->end < 0 || si->end > si->size) + return -EINVAL; + if (si->loopstart < 0 || si->loopstart > si->end) + return -EINVAL; + if (si->loopend < 0 || si->loopend > si->end) + return -EINVAL; + /* be sure loop points start < end */ + if (si->loopstart > si->loopend) + swap(si->loopstart, si->loopend); + return 0; +} + /* * Load sample information, this can include data to be loaded onto * the soundcard. It can also just be a pointer into soundcard ROM. @@ -701,7 +716,6 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) struct snd_soundfont *sf; struct soundfont_sample_info sample_info; struct snd_sf_sample *sp; - long off; /* patch must be opened */ sf = sflist->currsf; @@ -711,12 +725,16 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) if (is_special_type(sf->type)) return -EINVAL; + if (count < (long)sizeof(sample_info)) { + return -EINVAL; + } if (copy_from_user(&sample_info, data, sizeof(sample_info))) return -EFAULT; + data += sizeof(sample_info); + count -= sizeof(sample_info); - off = sizeof(sample_info); - - if (sample_info.size != (count-off)/2) + // SoundFont uses S16LE samples. + if (sample_info.size * 2 != count) return -EINVAL; /* Check for dup */ @@ -727,6 +745,21 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) return -EINVAL; } + if (sample_info.size > 0) { + if (sample_info.start < 0) + return -EINVAL; + + // Here we "rebase out" the start address, because the + // real start is the start of the provided sample data. + sample_info.end -= sample_info.start; + sample_info.loopstart -= sample_info.start; + sample_info.loopend -= sample_info.start; + sample_info.start = 0; + + if (validate_sample_info(&sample_info) < 0) + return -EINVAL; + } + /* Allocate a new sample structure */ sp = sf_sample_new(sflist, sf); if (!sp) @@ -735,7 +768,7 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) sp->v = sample_info; sp->v.sf_id = sf->id; sp->v.dummy = 0; - sp->v.truesize = sp->v.size; + sp->v.truesize = 0; /* * If there is wave data then load it. @@ -744,7 +777,7 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count) int rc; rc = sflist->callback.sample_new (sflist->callback.private_data, sp, sflist->memhdr, - data + off, count - off); + data, count); if (rc < 0) { sf_sample_delete(sflist, sf, sp); return rc; @@ -941,8 +974,7 @@ int snd_sf_vol_table[128] = { /* load GUS patch */ static int -load_guspatch(struct snd_sf_list *sflist, const char __user *data, - long count, int client) +load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count) { struct patch_info patch; struct snd_soundfont *sf; @@ -957,10 +989,12 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, } if (copy_from_user(&patch, data, sizeof(patch))) return -EFAULT; - count -= sizeof(patch); data += sizeof(patch); + if ((patch.len << (patch.mode & WAVE_16_BITS ? 1 : 0)) != count) + return -EINVAL; + sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_GUS|SNDRV_SFNT_PAT_SHARED, NULL); if (sf == NULL) return -ENOMEM; @@ -975,6 +1009,11 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, smp->v.loopend = patch.loop_end; smp->v.size = patch.len; + if (validate_sample_info(&smp->v) < 0) { + sf_sample_delete(sflist, sf, smp); + return -EINVAL; + } + /* set up mode flags */ smp->v.mode_flags = 0; if (!(patch.mode & WAVE_16_BITS)) @@ -1012,7 +1051,7 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, /* * load wave data */ - if (sflist->callback.sample_new) { + if (smp->v.size > 0) { rc = sflist->callback.sample_new (sflist->callback.private_data, smp, sflist->memhdr, data, count); @@ -1122,11 +1161,11 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, /* load GUS patch */ int snd_soundfont_load_guspatch(struct snd_sf_list *sflist, const char __user *data, - long count, int client) + long count) { int rc; lock_preset(sflist); - rc = load_guspatch(sflist, data, count, client); + rc = load_guspatch(sflist, data, count); unlock_preset(sflist); return rc; } @@ -1377,9 +1416,8 @@ snd_sf_clear(struct snd_sf_list *sflist) } for (sp = sf->samples; sp; sp = nextsp) { nextsp = sp->next; - if (sflist->callback.sample_free) - sflist->callback.sample_free(sflist->callback.private_data, - sp, sflist->memhdr); + sflist->callback.sample_free(sflist->callback.private_data, + sp, sflist->memhdr); kfree(sp); } kfree(sf); @@ -1481,9 +1519,8 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist) nextsp = sp->next; sf->samples = nextsp; sflist->mem_used -= sp->v.truesize; - if (sflist->callback.sample_free) - sflist->callback.sample_free(sflist->callback.private_data, - sp, sflist->memhdr); + sflist->callback.sample_free(sflist->callback.private_data, + sp, sflist->memhdr); kfree(sp); } } diff --git a/sound/usb/6fire/Makefile b/sound/usb/6fire/Makefile index 7d353bbf7493..587f25c64e56 100644 --- a/sound/usb/6fire/Makefile +++ b/sound/usb/6fire/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-usb-6fire-objs += chip.o comm.o midi.o control.o firmware.o pcm.o +snd-usb-6fire-y += chip.o comm.o midi.o control.o firmware.o pcm.o obj-$(CONFIG_SND_USB_6FIRE) += snd-usb-6fire.o diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 8c657c2753c8..0532499dbc6d 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -3,7 +3,7 @@ # Makefile for ALSA # -snd-usb-audio-objs := card.o \ +snd-usb-audio-y := card.o \ clock.o \ endpoint.o \ format.o \ @@ -25,7 +25,7 @@ snd-usb-audio-objs := card.o \ snd-usb-audio-$(CONFIG_SND_USB_AUDIO_MIDI_V2) += midi2.o snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o -snd-usbmidi-lib-objs := midi.o +snd-usbmidi-lib-y := midi.o # Toplevel Module Dependency obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usbmidi-lib.o diff --git a/sound/usb/card.c b/sound/usb/card.c index 1b2edc0fd2e9..bdb04fa37a71 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -425,6 +425,10 @@ static const struct usb_audio_device_name usb_audio_names[] = { DEVICE_NAME(0x0fd9, 0x0008, "Hauppauge", "HVR-950Q"), + /* Dock/Stand for HP Engage Go */ + PROFILE_NAME(0x103c, 0x830a, "HP", "HP Engage Go Dock", + "HP-Engage-Go-Dock"), + /* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"), DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"), diff --git a/sound/usb/hiface/Makefile b/sound/usb/hiface/Makefile index 8f3b24e7d6c2..997c1558d0cb 100644 --- a/sound/usb/hiface/Makefile +++ b/sound/usb/hiface/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-usb-hiface-objs := chip.o pcm.o +snd-usb-hiface-y := chip.o pcm.o obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index b67617b68e50..f4437015d43a 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -202,7 +202,7 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, struct urb *urb; /* create message: */ - msg = kmalloc(sizeof(struct message), GFP_ATOMIC); + msg = kzalloc(sizeof(struct message), GFP_ATOMIC); if (msg == NULL) return -ENOMEM; @@ -688,7 +688,7 @@ static int line6_init_cap_control(struct usb_line6 *line6) int ret; /* initialize USB buffers: */ - line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); + line6->buffer_listen = kzalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); if (!line6->buffer_listen) return -ENOMEM; @@ -697,7 +697,7 @@ static int line6_init_cap_control(struct usb_line6 *line6) return -ENOMEM; if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) { - line6->buffer_message = kmalloc(LINE6_MIDI_MESSAGE_MAXLEN, GFP_KERNEL); + line6->buffer_message = kzalloc(LINE6_MIDI_MESSAGE_MAXLEN, GFP_KERNEL); if (!line6->buffer_message) return -ENOMEM; diff --git a/sound/usb/misc/Makefile b/sound/usb/misc/Makefile index 068ecd7bc043..3e9f4adc28de 100644 --- a/sound/usb/misc/Makefile +++ b/sound/usb/misc/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-ua101-objs := ua101.o +snd-ua101-y := ua101.o obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 065a4be0d771..212b5e6443d8 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3447,6 +3447,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ + case USB_ID(0x1235, 0x8216): /* Focusrite Vocaster One */ + case USB_ID(0x1235, 0x8217): /* Focusrite Vocaster Two */ case USB_ID(0x1235, 0x8218): /* Focusrite Scarlett Solo 4th Gen */ case USB_ID(0x1235, 0x8219): /* Focusrite Scarlett 2i2 4th Gen */ case USB_ID(0x1235, 0x821a): /* Focusrite Scarlett 4i4 4th Gen */ diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index bd114be537d7..1150cf104985 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -85,8 +85,10 @@ * controls * - disable/enable MSD mode * - disable/enable standalone mode - * - input gain, autogain, safe mode + * - input mute, gain, autogain, safe mode * - direct monitor mixes + * - compressor and EQ + * - Bluetooth volume * * <ditaa> * /--------------\ 18chn 20chn /--------------\ @@ -174,22 +176,24 @@ /* some gui mixers can't handle negative ctl values */ #define SCARLETT2_VOLUME_BIAS 127 -/* maximum preamp input gain and value - * values are from 0 to 70, preamp gain is from 0 to 69 dB +/* maximum preamp input gain value + * (the corresponding value in dB is per-device) */ #define SCARLETT2_MAX_GAIN_VALUE 70 -#define SCARLETT2_MAX_GAIN_DB 69 -/* mixer range from -80dB to +6dB in 0.5dB steps */ +/* maximum Bluetooth volume value */ +#define SCARLETT2_MAX_BLUETOOTH_VOLUME 30 + +/* mixer range from -80dB to +12dB in 0.5dB steps */ #define SCARLETT2_MIXER_MIN_DB -80 #define SCARLETT2_MIXER_BIAS (-SCARLETT2_MIXER_MIN_DB * 2) -#define SCARLETT2_MIXER_MAX_DB 6 +#define SCARLETT2_MIXER_MAX_DB 12 #define SCARLETT2_MIXER_MAX_VALUE \ ((SCARLETT2_MIXER_MAX_DB - SCARLETT2_MIXER_MIN_DB) * 2) #define SCARLETT2_MIXER_VALUE_COUNT (SCARLETT2_MIXER_MAX_VALUE + 1) /* map from (dB + 80) * 2 to mixer value - * for dB in 0 .. 172: int(8192 * pow(10, ((dB - 160) / 2 / 20))) + * for dB in 0 .. 184: int(8192 * pow(10, ((dB - 160) / 2 / 20))) */ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, @@ -205,7 +209,8 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 3078, 3261, 3454, 3659, 3876, 4105, 4349, 4606, 4879, 5168, 5475, 5799, 6143, 6507, 6892, 7301, 7733, 8192, 8677, 9191, 9736, 10313, 10924, 11571, 12257, 12983, 13752, 14567, 15430, - 16345 + 16345, 17313, 18339, 19426, 20577, 21796, 23088, 24456, 25905, + 27440, 29066, 30788, 32612 }; /* Maximum number of analogue outputs */ @@ -215,6 +220,8 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { #define SCARLETT2_LEVEL_SWITCH_MAX 2 #define SCARLETT2_PAD_SWITCH_MAX 8 #define SCARLETT2_AIR_SWITCH_MAX 8 +#define SCARLETT2_DSP_SWITCH_MAX 2 +#define SCARLETT2_INPUT_MUTE_SWITCH_MAX 2 #define SCARLETT2_PHANTOM_SWITCH_MAX 2 #define SCARLETT2_INPUT_GAIN_MAX 2 @@ -245,6 +252,59 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { /* Maximum number of meters (sum of output port counts) */ #define SCARLETT2_MAX_METERS 65 +/* Compressor parameter data + * + * The compressor parameters are 32-bit fixed point values with 24 + * bits of fraction. Integer values are sufficient for the parameters + * except for ratio which we can set in 0.5:1 steps. + */ +struct compressor_param { + const char *name; + snd_ctl_elem_type_t type; + s32 min; + s32 max; + int scale_bits; +}; + +/* The available compressor parameters on the Vocaster: + * - Enable: Off, On + * - Threshold: -40dB to 0dB + * - Ratio: 1:1 to 50:1 in 0.5:1 steps + * - Knee Width: 0dB to 10dB + * - Attack: 30ms to 127ms + * - Release: 30ms to 127ms + * - Makeup Gain: 0dB to 24dB + */ +static const struct compressor_param compressor_params[] = { + { "Enable", SNDRV_CTL_ELEM_TYPE_BOOLEAN, 0, 1, 0 }, + { "Threshold", SNDRV_CTL_ELEM_TYPE_INTEGER, -40, 0, 24 }, + { "Ratio", SNDRV_CTL_ELEM_TYPE_INTEGER, 2, 100, 23 }, + { "Knee Width", SNDRV_CTL_ELEM_TYPE_INTEGER, 0, 10, 24 }, + { "Attack", SNDRV_CTL_ELEM_TYPE_INTEGER, 30, 127, 24 }, + { "Release", SNDRV_CTL_ELEM_TYPE_INTEGER, 30, 127, 24 }, + { "Makeup Gain", SNDRV_CTL_ELEM_TYPE_INTEGER, 0, 24, 24 }, +}; + +#define SCARLETT2_COMPRESSOR_PARAM_COUNT ARRAY_SIZE(compressor_params) +#define SCARLETT2_COMPRESSOR_CTLS_MAX \ + (SCARLETT2_COMPRESSOR_PARAM_COUNT * SCARLETT2_DSP_SWITCH_MAX) + +/* Maximum number of filter controls */ +#define SCARLETT2_PRECOMP_FLT_CTLS_MAX (2 * SCARLETT2_DSP_SWITCH_MAX) +#define SCARLETT2_PEQ_FLT_CTLS_MAX (3 * SCARLETT2_DSP_SWITCH_MAX) + +/* Number of biquad filter coefficients */ +#define SCARLETT2_BIQUAD_COEFFS 5 + +/* Maximum number of filter coefficient values */ +#define SCARLETT2_PRECOMP_FLT_VALUES_MAX \ + (SCARLETT2_PRECOMP_FLT_CTLS_MAX * SCARLETT2_BIQUAD_COEFFS) +#define SCARLETT2_PEQ_FLT_VALUES_MAX \ + (SCARLETT2_PEQ_FLT_CTLS_MAX * SCARLETT2_BIQUAD_COEFFS) + +/* Maximum number of PEQ filter slots */ +#define SCARLETT2_PEQ_FLT_SLOTS_MAX 4 + /* Hardware port types: * - None (no input to mux) * - Analogue I/O @@ -277,6 +337,17 @@ enum { SCARLETT2_DIM_MUTE_COUNT }; +/* Autogain target values */ + +#define SCARLETT2_AG_TARGET_MIN (-30) + +enum { + SCARLETT2_AG_HOT_TARGET, + SCARLETT2_AG_MEAN_TARGET, + SCARLETT2_AG_PEAK_TARGET, + SCARLETT2_AG_TARGET_COUNT +}; + /* Flash Write State */ enum { SCARLETT2_FLASH_WRITE_STATE_IDLE, @@ -295,7 +366,7 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { * If autogain_switch is set, autogain_status is set to 0 (Running). * The other status values are from the raw_autogain_status value + 1. */ -static const char *const scarlett2_autogain_status_texts[] = { +static const char *const scarlett2_autogain_status_gen4[] = { "Running", "Success", "SuccessDRover", @@ -304,7 +375,20 @@ static const char *const scarlett2_autogain_status_texts[] = { "FailMaxGainLimit", "FailClipped", "Cancelled", - "Invalid" + "Invalid", + NULL +}; + +static const char *const scarlett2_autogain_status_vocaster[] = { + "Running", + "Success", + "FailPG", + "FailRange", + "WarnMaxCap", + "WarnMinCap", + "Cancelled", + "Invalid", + NULL }; /* Power Status Values */ @@ -321,6 +405,7 @@ struct scarlett2_notification { void (*func)(struct usb_mixer_interface *mixer); }; +static void scarlett2_notify_ack(struct usb_mixer_interface *mixer); static void scarlett2_notify_sync(struct usb_mixer_interface *mixer); static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer); static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer); @@ -328,6 +413,8 @@ static void scarlett2_notify_volume(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_level(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_pad(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_air(struct usb_mixer_interface *mixer); +static void scarlett2_notify_input_dsp(struct usb_mixer_interface *mixer); +static void scarlett2_notify_input_mute(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_phantom(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_other(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer); @@ -339,11 +426,12 @@ static void scarlett2_notify_direct_monitor(struct usb_mixer_interface *mixer); static void scarlett2_notify_power_status(struct usb_mixer_interface *mixer); static void scarlett2_notify_pcm_input_switch( struct usb_mixer_interface *mixer); +static void scarlett2_notify_bluetooth(struct usb_mixer_interface *mixer); /* Arrays of notification callback functions */ static const struct scarlett2_notification scarlett2_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00200000, scarlett2_notify_dim_mute }, { 0x00400000, scarlett2_notify_monitor }, @@ -353,14 +441,26 @@ static const struct scarlett2_notification scarlett2_notifications[] = { }; static const struct scarlett2_notification scarlett3a_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00800000, scarlett2_notify_input_other }, { 0x01000000, scarlett2_notify_direct_monitor }, { 0, NULL } }; +static const struct scarlett2_notification vocaster_notifications[] = { + { 0x00000001, scarlett2_notify_ack }, + { 0x00000008, scarlett2_notify_sync }, + { 0x00200000, scarlett2_notify_input_mute }, + { 0x00400000, scarlett2_notify_autogain }, + { 0x04000000, scarlett2_notify_input_dsp }, + { 0x08000000, scarlett2_notify_input_gain }, + { 0x10000000, scarlett2_notify_input_phantom }, + { 0x20000000, scarlett2_notify_bluetooth }, + { 0, NULL } +}; + static const struct scarlett2_notification scarlett4_solo_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00400000, scarlett2_notify_input_air }, { 0x00800000, scarlett2_notify_direct_monitor }, @@ -371,7 +471,7 @@ static const struct scarlett2_notification scarlett4_solo_notifications[] = { }; static const struct scarlett2_notification scarlett4_2i2_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00200000, scarlett2_notify_input_safe }, { 0x00400000, scarlett2_notify_autogain }, @@ -387,7 +487,7 @@ static const struct scarlett2_notification scarlett4_2i2_notifications[] = { }; static const struct scarlett2_notification scarlett4_4i4_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00200000, scarlett2_notify_input_safe }, { 0x00400000, scarlett2_notify_autogain }, @@ -414,6 +514,13 @@ enum { SCARLETT2_CONFIG_PAD_SWITCH, SCARLETT2_CONFIG_MSD_SWITCH, SCARLETT2_CONFIG_AIR_SWITCH, + SCARLETT2_CONFIG_DSP_SWITCH, + SCARLETT2_CONFIG_COMPRESSOR_PARAMS, + SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, + SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, + SCARLETT2_CONFIG_PEQ_FLT_SWITCH, + SCARLETT2_CONFIG_PEQ_FLT_PARAMS, + SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, SCARLETT2_CONFIG_STANDALONE_SWITCH, SCARLETT2_CONFIG_PHANTOM_SWITCH, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, @@ -423,6 +530,9 @@ enum { SCARLETT2_CONFIG_TALKBACK_MAP, SCARLETT2_CONFIG_AUTOGAIN_SWITCH, SCARLETT2_CONFIG_AUTOGAIN_STATUS, + SCARLETT2_CONFIG_AG_HOT_TARGET, + SCARLETT2_CONFIG_AG_MEAN_TARGET, + SCARLETT2_CONFIG_AG_PEAK_TARGET, SCARLETT2_CONFIG_INPUT_GAIN, SCARLETT2_CONFIG_SAFE_SWITCH, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, @@ -431,15 +541,30 @@ enum { SCARLETT2_CONFIG_POWER_LOW, SCARLETT2_CONFIG_PCM_INPUT_SWITCH, SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, + SCARLETT2_CONFIG_BLUETOOTH_VOLUME, + SCARLETT2_CONFIG_SPDIF_MODE, SCARLETT2_CONFIG_COUNT }; +/* Autogain target configuration parameters and names */ + +static const int scarlett2_ag_target_configs[] = { + [SCARLETT2_AG_HOT_TARGET] = SCARLETT2_CONFIG_AG_HOT_TARGET, + [SCARLETT2_AG_MEAN_TARGET] = SCARLETT2_CONFIG_AG_MEAN_TARGET, + [SCARLETT2_AG_PEAK_TARGET] = SCARLETT2_CONFIG_AG_PEAK_TARGET +}; + +static const char *const scarlett2_ag_target_names[] = { + "Hot", "Mean", "Peak" +}; + /* Location, size, and activation command number for the configuration - * parameters. Size is in bits and may be 0, 1, 8, or 16. + * parameters. Size is in bits and may be 1, 8, 16, or 32. * - * A size of 0 indicates that the parameter is a byte-sized Scarlett - * Gen 4 configuration which is written through the gen4_write_addr - * location (but still read through the given offset location). + * Vocaster and 4th Gen devices have a parameter buffer to set certain + * configuration parameters. When pbuf is set, rather than writing to + * the given offset, the channel and value are written to the + * parameter buffer and the activate command is sent to the device. * * Some Gen 4 configuration parameters are written with 0x02 for a * desired value of 0x01, and 0x03 for 0x00. These are indicated with @@ -451,15 +576,28 @@ struct scarlett2_config { u16 offset; u8 size; u8 activate; + u8 pbuf; u8 mute; }; struct scarlett2_config_set { const struct scarlett2_notification *notifications; - u16 gen4_write_addr; + u16 param_buf_addr; + const unsigned int *input_gain_tlv; + const char *const *autogain_status_texts; const struct scarlett2_config items[SCARLETT2_CONFIG_COUNT]; }; +/* Input gain TLV dB ranges */ + +static const DECLARE_TLV_DB_MINMAX( + db_scale_vocaster_gain, 0, 70 * 100 +); + +static const DECLARE_TLV_DB_MINMAX( + db_scale_gen4_gain, 0, 69 * 100 +); + /* Gen 2 devices without SW/HW volume switch: 6i6, 18i8 */ static const struct scarlett2_config_set scarlett2_config_set_gen2a = { @@ -618,31 +756,87 @@ static const struct scarlett2_config_set scarlett2_config_set_gen3c = { [SCARLETT2_CONFIG_TALKBACK_MAP] = { .offset = 0xb0, .size = 16, .activate = 10 }, + + [SCARLETT2_CONFIG_SPDIF_MODE] = { + .offset = 0x94, .size = 8, .activate = 6 }, + } +}; + +/* Vocaster */ +static const struct scarlett2_config_set scarlett2_config_set_vocaster = { + .notifications = vocaster_notifications, + .param_buf_addr = 0x1bc, + .input_gain_tlv = db_scale_vocaster_gain, + .autogain_status_texts = scarlett2_autogain_status_vocaster, + .items = { + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x9d, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { + .offset = 0x1c0, .size = 8, .activate = 19, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { + .offset = 0x1c2, .size = 8, }, + + [SCARLETT2_CONFIG_AG_HOT_TARGET] = { + .offset = 0xc1, .size = 8, .activate = 29, .pbuf = 1 }, + + [SCARLETT2_CONFIG_INPUT_GAIN] = { + .offset = 0x9f, .size = 8, .activate = 21, .pbuf = 1 }, + + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x9c, .size = 1, .activate = 20, .pbuf = 1 }, + + [SCARLETT2_CONFIG_DSP_SWITCH] = { + .offset = 0x1c4, .size = 8, .activate = 22, .pbuf = 1 }, + + [SCARLETT2_CONFIG_COMPRESSOR_PARAMS] = { + .offset = 0x1c8, .size = 32, .activate = 23 }, + + [SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH] = { + .offset = 0x7c, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS] = { + .offset = 0x200, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_PEQ_FLT_SWITCH] = { + .offset = 0x84, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_PEQ_FLT_PARAMS] = { + .offset = 0x250, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_INPUT_MUTE_SWITCH] = { + .offset = 0x1be, .size = 8, .activate = 17, .pbuf = 1 }, + + [SCARLETT2_CONFIG_BLUETOOTH_VOLUME] = { + .offset = 0xbf, .size = 8, .activate = 28 }, } }; /* Solo Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_solo = { .notifications = scarlett4_solo_notifications, - .gen4_write_addr = 0xd8, + .param_buf_addr = 0xd8, .items = { [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x47, .size = 8, .activate = 4 }, [SCARLETT2_CONFIG_DIRECT_MONITOR] = { - .offset = 0x108, .activate = 12 }, + .offset = 0x108, .size = 8, .activate = 12, .pbuf = 1 }, [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { - .offset = 0x46, .activate = 9, .mute = 1 }, + .offset = 0x46, .size = 8, .activate = 9, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x3d, .activate = 10, .mute = 1 }, + .offset = 0x3d, .size = 8, .activate = 10, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_AIR_SWITCH] = { - .offset = 0x3e, .activate = 11 }, + .offset = 0x3e, .size = 8, .activate = 11, .pbuf = 1 }, [SCARLETT2_CONFIG_PCM_INPUT_SWITCH] = { - .offset = 0x206, .activate = 25 }, + .offset = 0x206, .size = 8, .activate = 25, .pbuf = 1 }, [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = { .offset = 0x232, .size = 16, .activate = 26 } @@ -652,40 +846,50 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_solo = { /* 2i2 Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = { .notifications = scarlett4_2i2_notifications, - .gen4_write_addr = 0xfc, + .param_buf_addr = 0xfc, + .input_gain_tlv = db_scale_gen4_gain, + .autogain_status_texts = scarlett2_autogain_status_gen4, .items = { [SCARLETT2_CONFIG_MSD_SWITCH] = { - .offset = 0x49, .size = 8, .activate = 4 }, // 0x41 ?? + .offset = 0x49, .size = 8, .activate = 4 }, [SCARLETT2_CONFIG_DIRECT_MONITOR] = { - .offset = 0x14a, .activate = 16 }, + .offset = 0x14a, .size = 8, .activate = 16, .pbuf = 1 }, [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { - .offset = 0x135, .activate = 10 }, + .offset = 0x135, .size = 8, .activate = 10, .pbuf = 1 }, [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { - .offset = 0x137 }, + .offset = 0x137, .size = 8 }, + + [SCARLETT2_CONFIG_AG_MEAN_TARGET] = { + .offset = 0x131, .size = 8, .activate = 29, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AG_PEAK_TARGET] = { + .offset = 0x132, .size = 8, .activate = 30, .pbuf = 1 }, [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { - .offset = 0x48, .activate = 11, .mute = 1 }, + .offset = 0x48, .size = 8, .activate = 11, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_INPUT_GAIN] = { - .offset = 0x4b, .activate = 12 }, + .offset = 0x4b, .size = 8, .activate = 12, .pbuf = 1 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x3c, .activate = 13, .mute = 1 }, + .offset = 0x3c, .size = 8, .activate = 13, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_SAFE_SWITCH] = { - .offset = 0x147, .activate = 14 }, + .offset = 0x147, .size = 8, .activate = 14, .pbuf = 1 }, [SCARLETT2_CONFIG_AIR_SWITCH] = { - .offset = 0x3e, .activate = 15 }, + .offset = 0x3e, .size = 8, .activate = 15, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = { - .offset = 0x14b, .activate = 17 }, + .offset = 0x14b, .size = 8, .activate = 17, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = { - .offset = 0x14e, .activate = 18 }, + .offset = 0x14e, .size = 8, .activate = 18, .pbuf = 1 }, [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = { .offset = 0x2a0, .size = 16, .activate = 36 } @@ -695,37 +899,47 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = { /* 4i4 Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = { .notifications = scarlett4_4i4_notifications, - .gen4_write_addr = 0x130, + .param_buf_addr = 0x130, + .input_gain_tlv = db_scale_gen4_gain, + .autogain_status_texts = scarlett2_autogain_status_gen4, .items = { [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x5c, .size = 8, .activate = 4 }, [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { - .offset = 0x13e, .activate = 10 }, + .offset = 0x13e, .size = 8, .activate = 10, .pbuf = 1 }, [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { - .offset = 0x140 }, + .offset = 0x140, .size = 8 }, + + [SCARLETT2_CONFIG_AG_MEAN_TARGET] = { + .offset = 0x13a, .size = 8, .activate = 23, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AG_PEAK_TARGET] = { + .offset = 0x13b, .size = 8, .activate = 24, .pbuf = 1 }, [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { - .offset = 0x5a, .activate = 11, .mute = 1 }, + .offset = 0x5a, .size = 8, .activate = 11, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_INPUT_GAIN] = { - .offset = 0x5e, .activate = 12 }, + .offset = 0x5e, .size = 8, .activate = 12, .pbuf = 1 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x4e, .activate = 13, .mute = 1 }, + .offset = 0x4e, .size = 8, .activate = 13, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_SAFE_SWITCH] = { - .offset = 0x150, .activate = 14 }, + .offset = 0x150, .size = 8, .activate = 14, .pbuf = 1 }, [SCARLETT2_CONFIG_AIR_SWITCH] = { - .offset = 0x50, .activate = 15 }, + .offset = 0x50, .size = 8, .activate = 15, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = { - .offset = 0x153, .activate = 16 }, + .offset = 0x153, .size = 8, .activate = 16, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = { - .offset = 0x156, .activate = 17 }, + .offset = 0x156, .size = 8, .activate = 17, .pbuf = 1 }, [SCARLETT2_CONFIG_MASTER_VOLUME] = { .offset = 0x32, .size = 16 }, @@ -734,10 +948,10 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = { .offset = 0x3a, .size = 16 }, [SCARLETT2_CONFIG_POWER_EXT] = { - .offset = 0x168 }, + .offset = 0x168, .size = 8 }, [SCARLETT2_CONFIG_POWER_LOW] = { - .offset = 0x16d } + .offset = 0x16d, .size = 8 } } }; @@ -768,6 +982,9 @@ static const struct scarlett2_config_set scarlett2_config_set_clarett = { [SCARLETT2_CONFIG_STANDALONE_SWITCH] = { .offset = 0x8d, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_SPDIF_MODE] = { + .offset = 0x9e, .size = 8, .activate = 4 }, } }; @@ -895,6 +1112,23 @@ struct scarlett2_device_info { */ u8 air_option; + /* the number of analogue inputs with DSP control */ + u8 dsp_input_count; + + /* number of pre-compressor filters */ + u8 precomp_flt_count; + + /* number of parametric EQ filters */ + u8 peq_flt_count; + + /* number of PEQ filters plus unused slots */ + u8 peq_flt_total_count; + + /* the number of analogue inputs with a software switchable + * mute control + */ + u8 mute_input_count; + /* the number of phantom (48V) software switchable controls */ u8 phantom_count; @@ -907,6 +1141,9 @@ struct scarlett2_device_info { /* the number of inputs with software-controllable gain */ u8 gain_input_count; + /* the number of inputs with safe mode */ + u8 safe_input_count; + /* the number of direct monitor options * (0 = none, 1 = mono only, 2 = mono/stereo) */ @@ -915,6 +1152,14 @@ struct scarlett2_device_info { /* the number of DSP channels */ u8 dsp_count; + /* has a Bluetooth module with volume control */ + u8 has_bluetooth; + + /* S/PDIF Source/Digital I/O mode control */ + const char * const spdif_mode_control_name; + const u8 *spdif_mode_values; + const char * const *spdif_mode_texts; + /* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected * internally to the analogue 7/8 outputs */ @@ -942,7 +1187,9 @@ struct scarlett2_device_info { struct scarlett2_data { struct usb_mixer_interface *mixer; struct mutex usb_mutex; /* prevent sending concurrent USB requests */ + struct completion cmd_done; struct mutex data_mutex; /* lock access to this data */ + u8 running; u8 hwdep_in_use; u8 selected_flash_segment_id; u8 flash_write_state; @@ -960,6 +1207,7 @@ struct scarlett2_data { u8 num_mix_out; u8 num_line_out; u8 num_monitor_mix_ctls; + u8 num_autogain_status_texts; u32 firmware_version; u8 flash_segment_nums[SCARLETT2_SEGMENT_ID_COUNT]; u8 flash_segment_blocks[SCARLETT2_SEGMENT_ID_COUNT]; @@ -970,6 +1218,8 @@ struct scarlett2_data { u8 input_level_updated; u8 input_pad_updated; u8 input_air_updated; + u8 input_dsp_updated; + u8 input_mute_updated; u8 input_phantom_updated; u8 input_select_updated; u8 input_gain_updated; @@ -982,6 +1232,7 @@ struct scarlett2_data { u8 mix_updated; u8 speaker_switching_switched; u8 power_status_updated; + u8 bluetooth_updated; u8 sync; u8 master_vol; u8 headphone_vol; @@ -992,6 +1243,13 @@ struct scarlett2_data { u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; + u8 dsp_switch[SCARLETT2_DSP_SWITCH_MAX]; + s32 compressor_values[SCARLETT2_COMPRESSOR_CTLS_MAX]; + s32 precomp_flt_values[SCARLETT2_PRECOMP_FLT_VALUES_MAX]; + s32 peq_flt_values[SCARLETT2_PEQ_FLT_VALUES_MAX]; + u8 precomp_flt_switch[SCARLETT2_DSP_SWITCH_MAX]; + u8 peq_flt_switch[SCARLETT2_DSP_SWITCH_MAX]; + u8 input_mute_switch[SCARLETT2_INPUT_MUTE_SWITCH_MAX]; u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 phantom_persistence; u8 input_select_switch; @@ -999,6 +1257,7 @@ struct scarlett2_data { u8 gain[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_status[SCARLETT2_INPUT_GAIN_MAX]; + s8 ag_targets[SCARLETT2_AG_TARGET_COUNT]; u8 safe_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 pcm_input_switch; u8 direct_monitor_switch; @@ -1008,6 +1267,8 @@ struct scarlett2_data { u8 msd_switch; u8 standalone_switch; u8 power_status; + u8 bluetooth_volume; + u8 spdif_mode; u8 meter_level_map[SCARLETT2_MAX_METERS]; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -1019,20 +1280,29 @@ struct scarlett2_data { struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; + struct snd_kcontrol *dsp_ctls[SCARLETT2_DSP_SWITCH_MAX]; + struct snd_kcontrol *input_mute_ctls[SCARLETT2_INPUT_MUTE_SWITCH_MAX]; struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; struct snd_kcontrol *input_select_ctl; struct snd_kcontrol *input_link_ctls[SCARLETT2_INPUT_GAIN_MAX / 2]; struct snd_kcontrol *input_gain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_status_ctls[SCARLETT2_INPUT_GAIN_MAX]; + struct snd_kcontrol *ag_target_ctls[SCARLETT2_AG_TARGET_COUNT]; struct snd_kcontrol *safe_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *pcm_input_switch_ctl; struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX]; struct snd_kcontrol *mix_ctls[SCARLETT2_MIX_MAX]; + struct snd_kcontrol *compressor_ctls[SCARLETT2_COMPRESSOR_CTLS_MAX]; + struct snd_kcontrol *precomp_flt_ctls[SCARLETT2_PRECOMP_FLT_CTLS_MAX]; + struct snd_kcontrol *peq_flt_ctls[SCARLETT2_PEQ_FLT_CTLS_MAX]; + struct snd_kcontrol *precomp_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX]; + struct snd_kcontrol *peq_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX]; struct snd_kcontrol *direct_monitor_ctl; struct snd_kcontrol *speaker_switching_ctl; struct snd_kcontrol *talkback_ctl; struct snd_kcontrol *power_status_ctl; + struct snd_kcontrol *bluetooth_volume_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_MIX_MAX]; u8 monitor_mix[SCARLETT2_MONITOR_MIX_MAX]; @@ -1326,6 +1596,14 @@ static const struct scarlett2_device_info s8i6_gen3_info = { } }; +static const u8 scarlett2_spdif_s18i8_gen3_values[] = { 0, 2, 0xff }; + +static const char * const scarlett2_spdif_s18i8_gen3_texts[] = { + "RCA", + "Optical", + NULL +}; + static const struct scarlett2_device_info s18i8_gen3_info = { .config_set = &scarlett2_config_set_gen3c, .has_speaker_switching = 1, @@ -1335,6 +1613,10 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .phantom_count = 2, .inputs_per_phantom = 2, + .spdif_mode_control_name = "S/PDIF Mode Capture Enum", + .spdif_mode_values = scarlett2_spdif_s18i8_gen3_values, + .spdif_mode_texts = scarlett2_spdif_s18i8_gen3_texts, + .line_out_remap_enable = 1, .line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 }, .line_out_unmap = { 0, 1, 4, 5, 6, 7, 2, 3 }, @@ -1405,6 +1687,15 @@ static const struct scarlett2_device_info s18i8_gen3_info = { } }; +static const u8 scarlett2_spdif_s18i20_gen3_values[] = { 0, 6, 1, 0xff }; + +static const char * const scarlett2_spdif_s18i20_gen3_texts[] = { + "S/PDIF RCA", + "S/PDIF Optical", + "Dual ADAT", + NULL +}; + static const struct scarlett2_device_info s18i20_gen3_info = { .config_set = &scarlett2_config_set_gen3c, .has_speaker_switching = 1, @@ -1415,6 +1706,10 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .phantom_count = 2, .inputs_per_phantom = 4, + .spdif_mode_control_name = "Digital I/O Mode Capture Enum", + .spdif_mode_values = scarlett2_spdif_s18i20_gen3_values, + .spdif_mode_texts = scarlett2_spdif_s18i20_gen3_texts, + .line_out_descrs = { "Monitor 1 L", "Monitor 1 R", @@ -1475,6 +1770,91 @@ static const struct scarlett2_device_info s18i20_gen3_info = { } }; +static const struct scarlett2_device_info vocaster_one_info = { + .config_set = &scarlett2_config_set_vocaster, + .min_firmware_version = 1769, + + .phantom_count = 1, + .inputs_per_phantom = 1, + .dsp_count = 1, + .dsp_input_count = 1, + .precomp_flt_count = 2, + .peq_flt_count = 3, + .peq_flt_total_count = 4, + .mute_input_count = 1, + .gain_input_count = 1, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 2, 4 }, + [SCARLETT2_PORT_TYPE_MIX] = { 9, 9 }, + [SCARLETT2_PORT_TYPE_PCM] = { 4, 10 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_MIX, 8, 1 }, + { SCARLETT2_PORT_TYPE_PCM, 5, 5 }, + { SCARLETT2_PORT_TYPE_MIX, 6, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 0, 5 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { 0, 0, 0 }, + } }, + + .meter_map = { + { 12, 1 }, + { 18, 5 }, + { 10, 2 }, + { 13, 5 }, + { 4, 6 }, + { 0, 4 }, + { 0, 0 } + } +}; + +static const struct scarlett2_device_info vocaster_two_info = { + .config_set = &scarlett2_config_set_vocaster, + .min_firmware_version = 1769, + + .phantom_count = 2, + .inputs_per_phantom = 1, + .dsp_count = 2, + .dsp_input_count = 2, + .precomp_flt_count = 2, + .peq_flt_count = 3, + .peq_flt_total_count = 4, + .mute_input_count = 2, + .gain_input_count = 2, + .has_bluetooth = 1, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 6, 6 }, + [SCARLETT2_PORT_TYPE_MIX] = { 12, 14 }, + [SCARLETT2_PORT_TYPE_PCM] = { 4, 14 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_MIX, 12, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 6, 8 }, + { SCARLETT2_PORT_TYPE_MIX, 10, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 6 }, + { 0, 0, 0 }, + } }, + + .meter_map = { + { 18, 2 }, + { 26, 8 }, + { 16, 2 }, + { 20, 6 }, + { 6, 10 }, + { 0, 6 }, + { 0, 0 } + } +}; + static const struct scarlett2_device_info solo_gen4_info = { .config_set = &scarlett2_config_set_gen4_solo, .min_firmware_version = 2115, @@ -1539,6 +1919,7 @@ static const struct scarlett2_device_info s2i2_gen4_info = { .phantom_count = 1, .inputs_per_phantom = 2, .gain_input_count = 2, + .safe_input_count = 2, .direct_monitor = 2, .dsp_count = 2, @@ -1592,6 +1973,7 @@ static const struct scarlett2_device_info s4i4_gen4_info = { .phantom_count = 2, .inputs_per_phantom = 1, .gain_input_count = 2, + .safe_input_count = 2, .dsp_count = 2, .port_count = { @@ -1676,11 +2058,24 @@ static const struct scarlett2_device_info clarett_2pre_info = { } }; +static const u8 scarlett2_spdif_clarett_values[] = { 0, 1, 2, 0xff }; + +static const char * const scarlett2_spdif_clarett_texts[] = { + "None", + "Optical", + "RCA", + NULL +}; + static const struct scarlett2_device_info clarett_4pre_info = { .config_set = &scarlett2_config_set_clarett, .level_input_count = 2, .air_input_count = 4, + .spdif_mode_control_name = "S/PDIF Source Capture Enum", + .spdif_mode_values = scarlett2_spdif_clarett_values, + .spdif_mode_texts = scarlett2_spdif_clarett_texts, + .line_out_descrs = { "Monitor L", "Monitor R", @@ -1733,6 +2128,10 @@ static const struct scarlett2_device_info clarett_8pre_info = { .level_input_count = 2, .air_input_count = 8, + .spdif_mode_control_name = "S/PDIF Source Capture Enum", + .spdif_mode_values = scarlett2_spdif_clarett_values, + .spdif_mode_texts = scarlett2_spdif_clarett_texts, + .line_out_descrs = { "Monitor L", "Monitor R", @@ -1806,6 +2205,10 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { { USB_ID(0x1235, 0x8214), &s18i8_gen3_info, "Scarlett Gen 3" }, { USB_ID(0x1235, 0x8215), &s18i20_gen3_info, "Scarlett Gen 3" }, + /* Supported Vocaster devices */ + { USB_ID(0x1235, 0x8216), &vocaster_one_info, "Vocaster" }, + { USB_ID(0x1235, 0x8217), &vocaster_two_info, "Vocaster" }, + /* Supported Gen 4 devices */ { USB_ID(0x1235, 0x8218), &solo_gen4_info, "Scarlett Gen 4" }, { USB_ID(0x1235, 0x8219), &s2i2_gen4_info, "Scarlett Gen 4" }, @@ -1856,6 +2259,7 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_ERASE_SEGMENT 0x00004002 #define SCARLETT2_USB_GET_ERASE 0x00004003 #define SCARLETT2_USB_WRITE_SEGMENT 0x00004004 +#define SCARLETT2_USB_READ_SEGMENT 0x00004005 #define SCARLETT2_USB_GET_SYNC 0x00006004 #define SCARLETT2_USB_GET_DATA 0x00800000 #define SCARLETT2_USB_SET_DATA 0x00800001 @@ -1866,7 +2270,7 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 #define SCARLETT2_FLASH_BLOCK_SIZE 4096 -#define SCARLETT2_FLASH_WRITE_MAX 1024 +#define SCARLETT2_FLASH_RW_MAX 1024 #define SCARLETT2_SEGMENT_NUM_MIN 1 #define SCARLETT2_SEGMENT_NUM_MAX 4 @@ -1960,6 +2364,17 @@ static int scarlett2_usb( goto unlock; } + if (!wait_for_completion_timeout(&private->cmd_done, + msecs_to_jiffies(1000))) { + usb_audio_err( + mixer->chip, + "%s USB request timed out, cmd %x\n", + private->series_name, cmd); + + err = -ETIMEDOUT; + goto unlock; + } + /* send a second message to get the response */ err = scarlett2_usb_rx(dev, private->bInterfaceNumber, @@ -2065,7 +2480,7 @@ static int scarlett2_usb_get_config( if (!config_item->offset) return -EFAULT; - /* Gen 4 style parameters are always 1 byte */ + /* Writes to the parameter buffer are always 1 byte */ size = config_item->size ? config_item->size : 8; /* For byte-sized parameters, retrieve directly into buf */ @@ -2079,6 +2494,11 @@ static int scarlett2_usb_get_config( for (i = 0; i < count; i++, buf_16++) *buf_16 = le16_to_cpu(*(__le16 *)buf_16); + } else if (size == 4) { + u32 *buf_32 = buf; + + for (i = 0; i < count; i++, buf_32++) + *buf_32 = le32_to_cpu(*(__le32 *)buf_32); } return 0; } @@ -2118,6 +2538,54 @@ static int scarlett2_usb_set_data( &req, sizeof(u32) * 2 + size, NULL, 0); } +/* Send a SCARLETT2_USB_SET_DATA command with multiple values. + * offset: location in the device's data space + * size: size in bytes of each value (1, 2, 4) + * count: number of values + */ +static int scarlett2_usb_set_data_buf( + struct usb_mixer_interface *mixer, + int offset, int size, int count, void *buf) +{ + struct scarlett2_data *private = mixer->private_data; + int bytes = size * count; + struct { + __le32 offset; + __le32 size; + u8 data[]; + } __packed *req; + int err; + int buf_size = struct_size(req, data, bytes); + + req = kmalloc(buf_size, GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->offset = cpu_to_le32(offset); + req->size = cpu_to_le32(bytes); + if (size == 1) { + memcpy(req->data, buf, count); + } else if (size == 2) { + u16 *buf_16 = buf; + int i; + + for (i = 0; i < count; i++) + ((__le16 *)req->data)[i] = cpu_to_le16(buf_16[i]); + } else { + u32 *buf_32 = buf; + int i; + + for (i = 0; i < count; i++) + ((__le32 *)req->data)[i] = cpu_to_le32(buf_32[i]); + } + + err = scarlett2_usb(private->mixer, SCARLETT2_USB_SET_DATA, + req, buf_size, NULL, 0); + + kfree(req); + return err; +} + /* Send a SCARLETT2_USB_DATA_CMD command. * Configuration changes require activation with this after they have * been uploaded by a previous SCARLETT2_USB_SET_DATA. @@ -2152,34 +2620,30 @@ static int scarlett2_usb_set_config( if (!config_item->offset) return -EFAULT; - /* Gen 4 style writes are selected with size = 0; - * these are only byte-sized values written through a shared - * location, different to the read address - */ - if (!config_item->size) { - if (!config_set->gen4_write_addr) + /* Write via the parameter buffer? */ + if (config_item->pbuf) { + if (!config_set->param_buf_addr) return -EFAULT; - /* Place index in gen4_write_addr + 1 */ + /* Place index in param_buf_addr + 1 */ err = scarlett2_usb_set_data( - mixer, config_set->gen4_write_addr + 1, 1, index); + mixer, config_set->param_buf_addr + 1, 1, index); if (err < 0) return err; - /* Place value in gen4_write_addr */ + /* Place value in param_buf_addr */ err = scarlett2_usb_set_data( - mixer, config_set->gen4_write_addr, 1, value); + mixer, config_set->param_buf_addr, 1, value); if (err < 0) return err; - /* Request the interface do the write */ + /* Activate the write through the parameter buffer */ return scarlett2_usb_activate_config( mixer, config_item->activate); } - /* Not-Gen 4 style needs NVRAM save, supports - * bit-modification, and writing is done to the same place - * that the value can be read from + /* Direct writes (not via the parameter buffer) need NVRAM + * save and support bit-modification */ /* Cancel any pending NVRAM save */ @@ -2213,7 +2677,7 @@ static int scarlett2_usb_set_config( value = tmp; } - /* Send the configuration parameter data */ + /* Write the new value */ err = scarlett2_usb_set_data(mixer, offset, size, value); if (err < 0) return err; @@ -2223,8 +2687,10 @@ static int scarlett2_usb_set_config( if (err < 0) return err; - /* Gen 2 style writes to Gen 4 devices don't need saving */ - if (config_set->gen4_write_addr) + /* Interfaces with parameter buffer writes don't need a + * separate save step + */ + if (config_set->param_buf_addr) return 0; /* Schedule the change to be written to NVRAM */ @@ -2234,6 +2700,47 @@ static int scarlett2_usb_set_config( return 0; } +/* Send USB messages to set a SCARLETT2_CONFIG_* parameter with + * multiple values + */ +static int scarlett2_usb_set_config_buf( + struct usb_mixer_interface *mixer, + int config_item_num, int index, int count, void *buf) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_config_set *config_set = private->config_set; + const struct scarlett2_config *config_item = + &config_set->items[config_item_num]; + int offset, size; + int err; + + /* Check that the configuration item is present in the + * configuration set used by this device + */ + if (!config_item->offset) + return -EFAULT; + + /* Convert config_item->size in bits to size in bytes and + * calculate offset + */ + if (config_item->size >= 8) { + size = config_item->size / 8; + offset = config_item->offset + index * size; + + /* Bit updates not supported */ + } else { + return -EFAULT; + } + + /* Write the new values */ + err = scarlett2_usb_set_data_buf(mixer, offset, size, count, buf); + if (err < 0) + return err; + + /* Activate the change */ + return scarlett2_usb_activate_config(mixer, config_item->activate); +} + /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ static void scarlett2_config_save(struct usb_mixer_interface *mixer) { @@ -2862,6 +3369,7 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int err, i; u8 raw_autogain_status[SCARLETT2_INPUT_GAIN_MAX]; + s8 ag_target_values[SCARLETT2_AG_TARGET_COUNT]; private->autogain_updated = 0; @@ -2893,12 +3401,27 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) if (private->autogain_switch[i]) private->autogain_status[i] = 0; else if (raw_autogain_status[i] < - ARRAY_SIZE(scarlett2_autogain_status_texts) - 1) + private->num_autogain_status_texts - 1) private->autogain_status[i] = raw_autogain_status[i] + 1; else private->autogain_status[i] = - ARRAY_SIZE(scarlett2_autogain_status_texts) - 1; + private->num_autogain_status_texts - 1; + + + for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) { + err = scarlett2_usb_get_config( + mixer, scarlett2_ag_target_configs[i], + 1, &ag_target_values[i]); + if (err < 0) + return err; + } + + /* convert from negative dBFS as used by the device */ + for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + private->ag_targets[i] = -ag_target_values[i]; return 0; } @@ -2911,19 +3434,34 @@ static void scarlett2_autogain_update_access(struct usb_mixer_interface *mixer) int val = !scarlett2_autogain_is_running(private); int i; - scarlett2_set_ctl_access(private->input_select_ctl, val); - for (i = 0; i < info->gain_input_count / 2; i++) - scarlett2_set_ctl_access(private->input_link_ctls[i], val); - for (i = 0; i < info->gain_input_count; i++) { + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) + scarlett2_set_ctl_access(private->input_select_ctl, val); + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) + for (i = 0; i < info->gain_input_count / 2; i++) + scarlett2_set_ctl_access(private->input_link_ctls[i], + val); + for (i = 0; i < info->gain_input_count; i++) scarlett2_set_ctl_access(private->input_gain_ctls[i], val); + for (i = 0; i < info->safe_input_count; i++) scarlett2_set_ctl_access(private->safe_ctls[i], val); - } for (i = 0; i < info->level_input_count; i++) scarlett2_set_ctl_access(private->level_ctls[i], val); for (i = 0; i < info->air_input_count; i++) scarlett2_set_ctl_access(private->air_ctls[i], val); + for (i = 0; i < info->mute_input_count; i++) + scarlett2_set_ctl_access(private->input_mute_ctls[i], val); for (i = 0; i < info->phantom_count; i++) scarlett2_set_ctl_access(private->phantom_ctls[i], val); + for (i = 0; i < info->dsp_input_count; i++) + scarlett2_set_ctl_access(private->dsp_ctls[i], val); + + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) + scarlett2_set_ctl_access( + private->ag_target_ctls[i], val); } /* Notify of access mode change for all controls read-only while @@ -2936,26 +3474,42 @@ static void scarlett2_autogain_notify_access(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int i; - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, - &private->input_select_ctl->id); - for (i = 0; i < info->gain_input_count / 2; i++) + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, - &private->input_link_ctls[i]->id); - for (i = 0; i < info->gain_input_count; i++) { + &private->input_select_ctl->id); + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) + for (i = 0; i < info->gain_input_count / 2; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->input_link_ctls[i]->id); + for (i = 0; i < info->gain_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->input_gain_ctls[i]->id); + for (i = 0; i < info->safe_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->safe_ctls[i]->id); - } for (i = 0; i < info->level_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->level_ctls[i]->id); for (i = 0; i < info->air_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->air_ctls[i]->id); + for (i = 0; i < info->dsp_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->dsp_ctls[i]->id); + for (i = 0; i < info->mute_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->input_mute_ctls[i]->id); for (i = 0; i < info->phantom_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->phantom_ctls[i]->id); + + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->ag_target_ctls[i]->id); } /* Call scarlett2_update_autogain() and @@ -3124,10 +3678,13 @@ unlock: static int scarlett2_autogain_status_ctl_info( struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + return snd_ctl_enum_info( uinfo, 1, - ARRAY_SIZE(scarlett2_autogain_status_texts), - scarlett2_autogain_status_texts); + private->num_autogain_status_texts, + private->config_set->autogain_status_texts); } static const struct snd_kcontrol_new scarlett2_autogain_switch_ctl = { @@ -3146,6 +3703,122 @@ static const struct snd_kcontrol_new scarlett2_autogain_status_ctl = { .get = scarlett2_autogain_status_ctl_get, }; +/*** Autogain Target Controls ***/ + +static int scarlett2_ag_target_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_autogain_updated(mixer); + if (err < 0) + goto unlock; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = SCARLETT2_AG_TARGET_MIN; + uinfo->value.integer.max = 0; + uinfo->value.integer.step = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_ag_target_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->autogain_updated) { + err = scarlett2_update_autogain(mixer); + if (err < 0) + goto unlock; + } + + ucontrol->value.integer.value[0] = private->ag_targets[elem->control]; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_ag_target_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->ag_targets[index]; + val = clamp(ucontrol->value.integer.value[0], + (long)SCARLETT2_AG_TARGET_MIN, 0L); + + if (oval == val) + goto unlock; + + private->ag_targets[index] = val; + + /* Send new value to the device */ + err = scarlett2_usb_set_config( + mixer, scarlett2_ag_target_configs[index], 1, -val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const DECLARE_TLV_DB_MINMAX( + db_scale_ag_target, SCARLETT2_AG_TARGET_MIN * 100, 0 +); + +static const struct snd_kcontrol_new scarlett2_ag_target_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett2_ag_target_ctl_info, + .get = scarlett2_ag_target_ctl_get, + .put = scarlett2_ag_target_ctl_put, + .tlv = { .p = db_scale_ag_target } +}; + /*** Input Select Control ***/ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) @@ -3157,7 +3830,9 @@ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) private->input_select_updated = 0; - if (!link_count) + if (!scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH) || + !link_count) return 0; err = scarlett2_usb_get_config( @@ -3545,10 +4220,6 @@ unlock: return err; } -static const DECLARE_TLV_DB_MINMAX( - db_scale_scarlett2_gain, 0, SCARLETT2_MAX_GAIN_DB * 100 -); - static const struct snd_kcontrol_new scarlett2_input_gain_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -3558,7 +4229,6 @@ static const struct snd_kcontrol_new scarlett2_input_gain_ctl = { .get = scarlett2_input_gain_ctl_get, .put = scarlett2_input_gain_ctl_put, .private_value = 0, /* max value */ - .tlv = { .p = db_scale_scarlett2_gain } }; /*** Safe Controls ***/ @@ -3570,12 +4240,12 @@ static int scarlett2_update_input_safe(struct usb_mixer_interface *mixer) private->input_safe_updated = 0; - if (!info->gain_input_count) + if (!info->safe_input_count) return 0; return scarlett2_usb_get_config( mixer, SCARLETT2_CONFIG_SAFE_SWITCH, - info->gain_input_count, private->safe_switch); + info->safe_input_count, private->safe_switch); } static int scarlett2_safe_ctl_get(struct snd_kcontrol *kctl, @@ -4567,6 +5237,670 @@ static const struct snd_kcontrol_new scarlett2_air_ctl[2] = { } }; +/*** DSP Switch Control ***/ + +static int scarlett2_update_input_dsp(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->input_dsp_updated = 0; + + if (!info->dsp_input_count) + return 0; + + return scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_DSP_SWITCH, + info->dsp_input_count, private->dsp_switch); +} + +static int scarlett2_dsp_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->input_dsp_updated) { + err = scarlett2_update_input_dsp(mixer); + if (err < 0) + goto unlock; + } + ucontrol->value.integer.value[0] = private->dsp_switch[elem->control]; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_dsp_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->dsp_switch[index]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->dsp_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_DSP_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_dsp_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_autogain_disables_ctl_info, + .get = scarlett2_dsp_ctl_get, + .put = scarlett2_dsp_ctl_put, +}; + +/*** DSP Compressor Parameter Controls ***/ + +static int scarlett2_update_compressor_values(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i, j; + + if (!info->dsp_input_count) + return 0; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_COMPRESSOR_PARAMS, + SCARLETT2_COMPRESSOR_PARAM_COUNT * info->dsp_input_count, + private->compressor_values); + + if (err < 0) + return err; + + for (i = 0; i < SCARLETT2_COMPRESSOR_PARAM_COUNT; i++) { + const struct compressor_param *param = &compressor_params[i]; + + for (j = 0; j < info->dsp_input_count; j++) { + int idx = i + j * SCARLETT2_COMPRESSOR_PARAM_COUNT; + int val = private->compressor_values[idx]; + + val >>= param->scale_bits; + val = clamp(val, param->min, param->max); + private->compressor_values[idx] = val; + } + } + + return 0; +} + +static int scarlett2_compressor_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = + private->compressor_values[elem->control]; + return 0; +} + +static int scarlett2_compressor_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int channel = index / SCARLETT2_COMPRESSOR_PARAM_COUNT; + int param_index = index % SCARLETT2_COMPRESSOR_PARAM_COUNT; + int oval, val, err; + s32 scaled_val; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->compressor_values[index]; + val = ucontrol->value.integer.value[0]; + if (oval == val) + goto unlock; + + private->compressor_values[index] = val; + + const struct compressor_param *param = &compressor_params[param_index]; + + scaled_val = val << param->scale_bits; + + /* Send change to the device */ + + /* The channel needs to be put in the parameter buffer index + * field (param_buf_addr + 1); the value field isn't used in + * this case. + */ + err = scarlett2_usb_set_data( + mixer, private->config_set->param_buf_addr + 1, 1, channel); + if (err < 0) + goto unlock; + + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_COMPRESSOR_PARAMS, index, scaled_val); + if (err < 0) + goto unlock; + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_compressor_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + int control = elem->control % SCARLETT2_COMPRESSOR_PARAM_COUNT; + + uinfo->type = compressor_params[control].type; + uinfo->count = 1; + uinfo->value.integer.min = compressor_params[control].min; + uinfo->value.integer.max = compressor_params[control].max; + uinfo->value.integer.step = 1; + return 0; +} + +static const struct snd_kcontrol_new scarlett2_compressor_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = scarlett2_compressor_ctl_info, + .get = scarlett2_compressor_ctl_get, + .put = scarlett2_compressor_ctl_put, +}; + +/*** DSP Pre-Compressor and PEQ Filter Controls ***/ + +static int scarlett2_precomp_flt_switch_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->precomp_flt_switch[elem->control]; + + return 0; +} + +static int scarlett2_peq_flt_switch_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = + private->peq_flt_switch[elem->control]; + + return 0; +} + +static int scarlett2_precomp_flt_switch_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + oval = private->precomp_flt_switch[elem->control]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->precomp_flt_switch[elem->control] = val; + + /* Send change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, + elem->control, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_peq_flt_switch_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + oval = private->peq_flt_switch[elem->control]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->peq_flt_switch[elem->control] = val; + + /* Send change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_PEQ_FLT_SWITCH, + elem->control, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_precomp_flt_switch_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_precomp_flt_switch_ctl_get, + .put = scarlett2_precomp_flt_switch_ctl_put, +}; + +static const struct snd_kcontrol_new scarlett2_peq_flt_switch_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_peq_flt_switch_ctl_get, + .put = scarlett2_peq_flt_switch_ctl_put, +}; + +static int scarlett2_update_filter_values(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i, j, k, src_idx, dst_idx; + s32 peq_flt_values[SCARLETT2_DSP_SWITCH_MAX * + SCARLETT2_PEQ_FLT_SLOTS_MAX * + SCARLETT2_BIQUAD_COEFFS]; + + if (!info->dsp_input_count) + return 0; + + /* Get filter switch values */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, + info->dsp_input_count, private->precomp_flt_switch); + if (err < 0) + return err; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PEQ_FLT_SWITCH, + info->dsp_input_count * info->peq_flt_count, + private->peq_flt_switch); + if (err < 0) + return err; + + /* Get pre-compressor filter values directly */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, + info->dsp_input_count * + info->precomp_flt_count * + SCARLETT2_BIQUAD_COEFFS, + private->precomp_flt_values); + + if (err < 0) + return err; + + /* PEQ filter values need to be copied via buffer because of + * padding after peq_flt_count up to peq_flt_total_count + */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PEQ_FLT_PARAMS, + info->dsp_input_count * + info->peq_flt_total_count * + SCARLETT2_BIQUAD_COEFFS, + peq_flt_values); + + for (i = 0, dst_idx = 0; i < info->dsp_input_count; i++) { + src_idx = i * + info->peq_flt_total_count * + SCARLETT2_BIQUAD_COEFFS; + for (j = 0; j < info->peq_flt_count; j++) + for (k = 0; + k < SCARLETT2_BIQUAD_COEFFS; + k++, src_idx++, dst_idx++) + private->peq_flt_values[dst_idx] = + peq_flt_values[src_idx]; + } + + return 0; +} + +static int scarlett2_precomp_flt_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + int i, idx; + + for (i = 0, idx = elem->control * SCARLETT2_BIQUAD_COEFFS; + i < SCARLETT2_BIQUAD_COEFFS; + i++, idx++) + ucontrol->value.integer.value[i] = + private->precomp_flt_values[idx]; + + return 0; +} + +static int scarlett2_peq_flt_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + int i, idx; + + for (i = 0, idx = elem->control * SCARLETT2_BIQUAD_COEFFS; + i < SCARLETT2_BIQUAD_COEFFS; + i++, idx++) + ucontrol->value.integer.value[i] = + private->peq_flt_values[idx]; + + return 0; +} + +static int scarlett2_precomp_flt_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control * SCARLETT2_BIQUAD_COEFFS; + int i, oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + /* Check if any of the values have changed; if not, return */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) { + oval = private->precomp_flt_values[index + i]; + val = ucontrol->value.integer.value[i]; + if (oval != val) + break; + } + + if (i == SCARLETT2_BIQUAD_COEFFS) + goto unlock; + + /* Update the values */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) + private->precomp_flt_values[index + i] = + ucontrol->value.integer.value[i]; + + /* Send change to the device */ + err = scarlett2_usb_set_data( + mixer, private->config_set->param_buf_addr, 1, index); + if (err < 0) + goto unlock; + + err = scarlett2_usb_set_config_buf( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, + index, SCARLETT2_BIQUAD_COEFFS, + &private->precomp_flt_values[index]); + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_peq_flt_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + int src_index = elem->control * SCARLETT2_BIQUAD_COEFFS; + int dst_index = ( + elem->control / + info->peq_flt_count * + info->peq_flt_total_count + + elem->control % info->peq_flt_count + ) * SCARLETT2_BIQUAD_COEFFS; + int i, oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + /* Check if any of the values have changed; if not, return */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) { + oval = private->peq_flt_values[src_index + i]; + val = ucontrol->value.integer.value[i]; + if (oval != val) + break; + } + + if (i == SCARLETT2_BIQUAD_COEFFS) + goto unlock; + + /* Update the values */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) + private->peq_flt_values[src_index + i] = + ucontrol->value.integer.value[i]; + + /* Send change to the device */ + err = scarlett2_usb_set_data( + mixer, private->config_set->param_buf_addr, 1, dst_index); + if (err < 0) + goto unlock; + + err = scarlett2_usb_set_config_buf( + mixer, SCARLETT2_CONFIG_PEQ_FLT_PARAMS, + dst_index, SCARLETT2_BIQUAD_COEFFS, + &private->peq_flt_values[src_index]); + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_flt_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = SCARLETT2_BIQUAD_COEFFS; + uinfo->value.integer.min = INT_MIN; + uinfo->value.integer.max = INT_MAX; + uinfo->value.integer.step = 1; + return 0; +} + +static const struct snd_kcontrol_new scarlett2_precomp_flt_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = scarlett2_flt_ctl_info, + .get = scarlett2_precomp_flt_ctl_get, + .put = scarlett2_precomp_flt_ctl_put, +}; + +static const struct snd_kcontrol_new scarlett2_peq_flt_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = scarlett2_flt_ctl_info, + .get = scarlett2_peq_flt_ctl_get, + .put = scarlett2_peq_flt_ctl_put, +}; + +/*** Input Mute Switch Controls ***/ + +static int scarlett2_update_input_mute(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->input_mute_updated = 0; + + if (!info->mute_input_count) + return 0; + + return scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, + info->mute_input_count, private->input_mute_switch); +} + +static int scarlett2_input_mute_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->input_mute_updated) { + err = scarlett2_update_input_mute(mixer); + if (err < 0) + goto unlock; + } + ucontrol->value.integer.value[0] = + private->input_mute_switch[elem->control]; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_input_mute_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->input_mute_switch[index]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->input_mute_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_input_mute_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_autogain_disables_ctl_info, + .get = scarlett2_input_mute_ctl_get, + .put = scarlett2_input_mute_ctl_put, +}; + /*** Phantom Switch Controls ***/ static int scarlett2_update_input_phantom(struct usb_mixer_interface *mixer) @@ -5406,6 +6740,69 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) /*** Create the analogue input controls ***/ +static int scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int j, err; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *compr_fmt = "Line In %d Compressor %s"; + const char *flt_switch_fmt = "Line In %d %s Filter Enable"; + const char *flt_fmt = "Line In %d %s Coefficients %d"; + + /* Add compressor controls */ + for (j = 0; j < SCARLETT2_COMPRESSOR_PARAM_COUNT; j++) { + const struct compressor_param *param = &compressor_params[j]; + int idx = i * SCARLETT2_COMPRESSOR_PARAM_COUNT + j; + + scnprintf(s, sizeof(s), compr_fmt, i + 1, param->name); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_compressor_ctl, + i * SCARLETT2_COMPRESSOR_PARAM_COUNT + j, + 1, s, &private->compressor_ctls[idx]); + if (err < 0) + return err; + } + + /* Add filter enable controls */ + scnprintf(s, sizeof(s), flt_switch_fmt, i + 1, "Pre-Comp"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_precomp_flt_switch_ctl, + i, 1, s, &private->precomp_flt_switch_ctls[i]); + if (err < 0) + return err; + + scnprintf(s, sizeof(s), flt_switch_fmt, i + 1, "PEQ"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_peq_flt_switch_ctl, + i, 1, s, &private->peq_flt_switch_ctls[i]); + if (err < 0) + return err; + + /* Add filter coefficient controls */ + for (j = 0; j < info->precomp_flt_count; j++) { + scnprintf(s, sizeof(s), flt_fmt, i + 1, "Pre-Comp", j + 1); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_precomp_flt_ctl, + i * info->precomp_flt_count + j, + 1, s, &private->precomp_flt_switch_ctls[j]); + if (err < 0) + return err; + } + + for (j = 0; j < info->peq_flt_count; j++) { + scnprintf(s, sizeof(s), flt_fmt, i + 1, "PEQ", j + 1); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_peq_flt_ctl, + i * info->peq_flt_count + j, + 1, s, &private->peq_flt_switch_ctls[j]); + if (err < 0) + return err; + } + + return 0; +} + static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; @@ -5445,6 +6842,29 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) return err; } + /* Add input DSP controls */ + for (i = 0; i < info->dsp_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, "DSP", "Switch"); + err = scarlett2_add_new_ctl(mixer, &scarlett2_dsp_ctl, + i, 1, s, &private->dsp_ctls[i]); + if (err < 0) + return err; + + err = scarlett2_add_dsp_ctls(mixer, i); + if (err < 0) + return err; + } + + /* Add input mute controls */ + for (i = 0; i < info->mute_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, "Mute", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_input_mute_ctl, + i, 1, s, &private->input_mute_ctls[i]); + if (err < 0) + return err; + } + /* Add input phantom controls */ if (info->inputs_per_phantom == 1) { for (i = 0; i < info->phantom_count; i++) { @@ -5481,58 +6901,81 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) return err; } - /* Add software-controllable input gain controls */ - if (info->gain_input_count) { + /* Add input select/link controls */ + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) { err = scarlett2_add_new_ctl( mixer, &scarlett2_input_select_ctl, 0, 1, "Input Select Capture Enum", &private->input_select_ctl); if (err < 0) return err; + } - for (i = 0; i < info->gain_input_count; i++) { - if (i % 2) { - scnprintf(s, sizeof(s), - "Line In %d-%d Link Capture Switch", - i, i + 1); - err = scarlett2_add_new_ctl( - mixer, &scarlett2_input_link_ctl, - i / 2, 1, s, - &private->input_link_ctls[i / 2]); - if (err < 0) - return err; - } - - scnprintf(s, sizeof(s), fmt, i + 1, - "Gain", "Volume"); + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) { + for (i = 0; i < info->gain_input_count / 2; i++) { + scnprintf(s, sizeof(s), + "Line In %d-%d Link Capture Switch", + (i * 2) + 1, (i * 2) + 2); err = scarlett2_add_new_ctl( - mixer, &scarlett2_input_gain_ctl, - i, 1, s, &private->input_gain_ctls[i]); + mixer, &scarlett2_input_link_ctl, + i, 1, s, &private->input_link_ctls[i]); if (err < 0) return err; + } + } - scnprintf(s, sizeof(s), fmt, i + 1, - "Autogain", "Switch"); - err = scarlett2_add_new_ctl( - mixer, &scarlett2_autogain_switch_ctl, - i, 1, s, &private->autogain_ctls[i]); - if (err < 0) - return err; + /* Add software-controllable input gain controls */ + for (i = 0; i < info->gain_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, + "Gain", "Volume"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_input_gain_ctl, + i, 1, s, &private->input_gain_ctls[i]); + if (err < 0) + return err; + private->input_gain_ctls[i]->tlv.p = + private->config_set->input_gain_tlv; - scnprintf(s, sizeof(s), fmt, i + 1, - "Autogain Status", "Enum"); - err = scarlett2_add_new_ctl( - mixer, &scarlett2_autogain_status_ctl, - i, 1, s, &private->autogain_status_ctls[i]); + scnprintf(s, sizeof(s), fmt, i + 1, + "Autogain", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_switch_ctl, + i, 1, s, &private->autogain_ctls[i]); + if (err < 0) + return err; + + scnprintf(s, sizeof(s), fmt, i + 1, + "Autogain Status", "Enum"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_status_ctl, + i, 1, s, &private->autogain_status_ctls[i]); + } + + /* Add autogain target controls */ + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) { - scnprintf(s, sizeof(s), fmt, i + 1, - "Safe", "Switch"); + scnprintf(s, sizeof(s), "Autogain %s Target", + scarlett2_ag_target_names[i]); err = scarlett2_add_new_ctl( - mixer, &scarlett2_safe_ctl, - i, 1, s, &private->safe_ctls[i]); + mixer, &scarlett2_ag_target_ctl, + i, 1, s, &private->ag_target_ctls[i]); if (err < 0) return err; } + + /* Add safe-mode input switch controls */ + for (i = 0; i < info->safe_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, + "Safe", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_safe_ctl, + i, 1, s, &private->safe_ctls[i]); + if (err < 0) + return err; } /* Add PCM Input Switch control */ @@ -6383,413 +7826,238 @@ static int scarlett2_add_power_status_ctl(struct usb_mixer_interface *mixer) &private->power_status_ctl); } -/*** Cleanup/Suspend Callbacks ***/ +/*** Bluetooth Volume ***/ -static void scarlett2_private_free(struct usb_mixer_interface *mixer) -{ - struct scarlett2_data *private = mixer->private_data; - - cancel_delayed_work_sync(&private->work); - kfree(private); - mixer->private_data = NULL; -} - -static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) +static int scarlett2_update_bluetooth_volume(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; + int err; - if (cancel_delayed_work_sync(&private->work)) - scarlett2_config_save(private->mixer); -} - -/*** Initialisation ***/ - -static void scarlett2_count_io(struct scarlett2_data *private) -{ - const struct scarlett2_device_info *info = private->info; - const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; - int port_type, srcs = 0, dsts = 0; - - /* Count the number of mux sources and destinations */ - for (port_type = 0; - port_type < SCARLETT2_PORT_TYPE_COUNT; - port_type++) { - srcs += port_count[port_type][SCARLETT2_PORT_IN]; - dsts += port_count[port_type][SCARLETT2_PORT_OUT]; - } - - private->num_mux_srcs = srcs; - private->num_mux_dsts = dsts; - - /* Mixer inputs are mux outputs and vice versa. - * Scarlett Gen 4 DSP I/O uses SCARLETT2_PORT_TYPE_MIX but - * doesn't have mixer controls. - */ - private->num_mix_in = - port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT] - - info->dsp_count; + private->bluetooth_updated = 0; - private->num_mix_out = - port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN] - - info->dsp_count; + if (!private->info->has_bluetooth) + return 0; - /* Number of analogue line outputs */ - private->num_line_out = - port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + err = scarlett2_usb_get_config(mixer, + SCARLETT2_CONFIG_BLUETOOTH_VOLUME, + 1, &private->bluetooth_volume); + if (err < 0) + return err; - /* Number of monitor mix controls */ - private->num_monitor_mix_ctls = - info->direct_monitor * 2 * private->num_mix_in; + return 0; } -/* Look through the interface descriptors for the Focusrite Control - * interface (bInterfaceClass = 255 Vendor Specific Class) and set - * bInterfaceNumber, bEndpointAddress, wMaxPacketSize, and bInterval - * in private - */ -static int scarlett2_find_fc_interface(struct usb_device *dev, - struct scarlett2_data *private) +static int scarlett2_bluetooth_volume_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) { - struct usb_host_config *config = dev->actconfig; - int i; + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int err = 0; - for (i = 0; i < config->desc.bNumInterfaces; i++) { - struct usb_interface *intf = config->interface[i]; - struct usb_interface_descriptor *desc = - &intf->altsetting[0].desc; - struct usb_endpoint_descriptor *epd; + mutex_lock(&private->data_mutex); - if (desc->bInterfaceClass != 255) - continue; + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } - epd = get_endpoint(intf->altsetting, 0); - private->bInterfaceNumber = desc->bInterfaceNumber; - private->bEndpointAddress = epd->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize); - private->bInterval = epd->bInterval; - return 0; + if (private->bluetooth_updated) { + err = scarlett2_update_bluetooth_volume(mixer); + if (err < 0) + goto unlock; } + ucontrol->value.integer.value[0] = private->bluetooth_volume; - return -EINVAL; +unlock: + mutex_unlock(&private->data_mutex); + return err; } -/* Initialise private data */ -static int scarlett2_init_private(struct usb_mixer_interface *mixer, - const struct scarlett2_device_entry *entry) +static int scarlett2_bluetooth_volume_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) { - struct scarlett2_data *private = - kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL); + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int oval, val, err = 0; - if (!private) - return -ENOMEM; + mutex_lock(&private->data_mutex); - mutex_init(&private->usb_mutex); - mutex_init(&private->data_mutex); - INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } - mixer->private_data = private; - mixer->private_free = scarlett2_private_free; - mixer->private_suspend = scarlett2_private_suspend; + oval = private->bluetooth_volume; + val = clamp(ucontrol->value.integer.value[0], + 0L, (long)SCARLETT2_MAX_BLUETOOTH_VOLUME); - private->info = entry->info; - private->config_set = entry->info->config_set; - private->series_name = entry->series_name; - scarlett2_count_io(private); - private->scarlett2_seq = 0; - private->mixer = mixer; + if (oval == val) + goto unlock; - return scarlett2_find_fc_interface(mixer->chip->dev, private); + private->bluetooth_volume = val; + err = scarlett2_usb_set_config(mixer, + SCARLETT2_CONFIG_BLUETOOTH_VOLUME, + 0, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; } -/* Cargo cult proprietary initialisation sequence */ -static int scarlett2_usb_init(struct usb_mixer_interface *mixer) +static int scarlett2_bluetooth_volume_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { - struct usb_device *dev = mixer->chip->dev; - struct scarlett2_data *private = mixer->private_data; - u8 step0_buf[24]; - u8 step2_buf[84]; - int err; - - if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; - - /* step 0 */ - err = scarlett2_usb_rx(dev, private->bInterfaceNumber, - SCARLETT2_USB_CMD_INIT, - step0_buf, sizeof(step0_buf)); - if (err < 0) - return err; - - /* step 1 */ - private->scarlett2_seq = 1; - err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_1, NULL, 0, NULL, 0); - if (err < 0) - return err; - - /* step 2 */ - private->scarlett2_seq = 1; - err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_2, - NULL, 0, - step2_buf, sizeof(step2_buf)); - if (err < 0) - return err; - - /* extract 4-byte firmware version from step2_buf[8] */ - private->firmware_version = le32_to_cpu(*(__le32 *)(step2_buf + 8)); - usb_audio_info(mixer->chip, - "Firmware version %d\n", - private->firmware_version); - + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SCARLETT2_MAX_BLUETOOTH_VOLUME; + uinfo->value.integer.step = 1; return 0; } -/* Get the flash segment numbers for the App_Settings and App_Upgrade - * segments and put them in the private data - */ -static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer) +static const struct snd_kcontrol_new scarlett2_bluetooth_volume_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_bluetooth_volume_ctl_info, + .get = scarlett2_bluetooth_volume_ctl_get, + .put = scarlett2_bluetooth_volume_ctl_put, +}; + +static int scarlett2_add_bluetooth_volume_ctl( + struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; - int err, count, i; - - struct { - __le32 size; - __le32 count; - u8 unknown[8]; - } __packed flash_info; - - struct { - __le32 size; - __le32 flags; - char name[16]; - } __packed segment_info; - err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH, - NULL, 0, - &flash_info, sizeof(flash_info)); - if (err < 0) - return err; - - count = le32_to_cpu(flash_info.count); - - /* sanity check count */ - if (count < SCARLETT2_SEGMENT_NUM_MIN || - count > SCARLETT2_SEGMENT_NUM_MAX + 1) { - usb_audio_err(mixer->chip, - "invalid flash segment count: %d\n", count); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - __le32 segment_num_req = cpu_to_le32(i); - int flash_segment_id; - - err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT, - &segment_num_req, sizeof(segment_num_req), - &segment_info, sizeof(segment_info)); - if (err < 0) { - usb_audio_err(mixer->chip, - "failed to get flash segment info %d: %d\n", - i, err); - return err; - } - - if (!strncmp(segment_info.name, - SCARLETT2_SEGMENT_SETTINGS_NAME, 16)) - flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS; - else if (!strncmp(segment_info.name, - SCARLETT2_SEGMENT_FIRMWARE_NAME, 16)) - flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE; - else - continue; - - private->flash_segment_nums[flash_segment_id] = i; - private->flash_segment_blocks[flash_segment_id] = - le32_to_cpu(segment_info.size) / - SCARLETT2_FLASH_BLOCK_SIZE; - } - - /* segment 0 is App_Gold and we never want to touch that, so - * use 0 as the "not-found" value - */ - if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) { - usb_audio_err(mixer->chip, - "failed to find flash segment %s\n", - SCARLETT2_SEGMENT_SETTINGS_NAME); - return -EINVAL; - } - if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) { - usb_audio_err(mixer->chip, - "failed to find flash segment %s\n", - SCARLETT2_SEGMENT_FIRMWARE_NAME); - return -EINVAL; - } + if (!private->info->has_bluetooth) + return 0; - return 0; + /* Add Bluetooth volume control */ + return scarlett2_add_new_ctl(mixer, &scarlett2_bluetooth_volume_ctl, + 0, 1, "Bluetooth Capture Volume", + &private->bluetooth_volume_ctl); } -/* Read configuration from the interface on start */ -static int scarlett2_read_configs(struct usb_mixer_interface *mixer) +/*** S/PDIF Mode Controls ***/ + +static int scarlett2_update_spdif_mode(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; - const struct scarlett2_device_info *info = private->info; int err, i; + u8 mode; + const u8 *mode_values = private->info->spdif_mode_values; - if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) { - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_MSD_SWITCH, - 1, &private->msd_switch); - if (err < 0) - return err; - } - - if (private->firmware_version < info->min_firmware_version) { - usb_audio_err(mixer->chip, - "Focusrite %s firmware version %d is too old; " - "need %d", - private->series_name, - private->firmware_version, - info->min_firmware_version); - return 0; - } - - /* no other controls are created if MSD mode is on */ - if (private->msd_switch) + if (!private->info->spdif_mode_control_name) return 0; - err = scarlett2_update_input_level(mixer); - if (err < 0) - return err; - - err = scarlett2_update_input_pad(mixer); + err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_SPDIF_MODE, + 1, &mode); if (err < 0) return err; - err = scarlett2_update_input_air(mixer); - if (err < 0) - return err; + private->spdif_mode = 0; - err = scarlett2_update_input_phantom(mixer); - if (err < 0) - return err; - - err = scarlett2_update_direct_monitor(mixer); - if (err < 0) - return err; - - /* the rest of the configuration is for devices with a mixer */ - if (!scarlett2_has_mixer(private)) - return 0; - - err = scarlett2_update_monitor_mix(mixer); - if (err < 0) - return err; - - err = scarlett2_update_monitor_other(mixer); - if (err < 0) - return err; + for (i = 0; *mode_values != 0xff; i++, mode_values++) + if (*mode_values == mode) { + private->spdif_mode = i; + break; + } - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_STANDALONE_SWITCH)) { - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH, - 1, &private->standalone_switch); - if (err < 0) - return err; - } + return 0; +} - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_POWER_EXT)) { - err = scarlett2_update_power_status(mixer); - if (err < 0) - return err; - } +static int scarlett2_spdif_mode_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + const char * const *mode_texts = private->info->spdif_mode_texts; + int count = 0; - err = scarlett2_update_sync(mixer); - if (err < 0) - return err; + while (*mode_texts++) + count++; - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_LINE_OUT_VOLUME)) { - s16 sw_vol[SCARLETT2_ANALOGUE_MAX]; + return snd_ctl_enum_info(uinfo, 1, count, + private->info->spdif_mode_texts); +} - /* read SW line out volume */ - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, - private->num_line_out, &sw_vol); - if (err < 0) - return err; +static int scarlett2_spdif_mode_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; - for (i = 0; i < private->num_line_out; i++) - private->vol[i] = clamp( - sw_vol[i] + SCARLETT2_VOLUME_BIAS, - 0, SCARLETT2_VOLUME_BIAS); + ucontrol->value.enumerated.item[0] = private->spdif_mode; + return 0; +} - /* read SW mute */ - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_MUTE_SWITCH, - private->num_line_out, &private->mute_switch); - if (err < 0) - return err; +static int scarlett2_spdif_mode_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int oval, val, err = 0; + int i; - for (i = 0; i < private->num_line_out; i++) - private->mute_switch[i] = - !!private->mute_switch[i]; + mutex_lock(&private->data_mutex); - /* read SW/HW switches */ - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_SW_HW_SWITCH)) { - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, - private->num_line_out, - &private->vol_sw_hw_switch); - if (err < 0) - return err; + oval = private->spdif_mode; + val = ucontrol->value.enumerated.item[0]; - for (i = 0; i < private->num_line_out; i++) - private->vol_sw_hw_switch[i] = - !!private->vol_sw_hw_switch[i]; - } + if (val < 0) { + err = -EINVAL; + goto unlock; } - err = scarlett2_update_volumes(mixer); - if (err < 0) - return err; + for (i = 0; i <= val; i++) + if (private->info->spdif_mode_values[i] == 0xff) { + err = -EINVAL; + goto unlock; + } - err = scarlett2_update_dim_mute(mixer); - if (err < 0) - return err; + if (oval == val) + goto unlock; - err = scarlett2_update_input_select(mixer); - if (err < 0) - return err; + private->spdif_mode = val; - err = scarlett2_update_input_gain(mixer); - if (err < 0) - return err; + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_SPDIF_MODE, 0, + private->info->spdif_mode_values[val]); + if (!err) + err = 1; - err = scarlett2_update_autogain(mixer); - if (err < 0) - return err; +unlock: + mutex_unlock(&private->data_mutex); + return err; +} - err = scarlett2_update_input_safe(mixer); - if (err < 0) - return err; +static const struct snd_kcontrol_new scarlett2_spdif_mode_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_spdif_mode_ctl_info, + .get = scarlett2_spdif_mode_ctl_get, + .put = scarlett2_spdif_mode_ctl_put, +}; - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_PCM_INPUT_SWITCH)) { - err = scarlett2_update_pcm_input_switch(mixer); - if (err < 0) - return err; - } +static int scarlett2_add_spdif_mode_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; - err = scarlett2_update_mix(mixer); - if (err < 0) - return err; + if (!private->info->spdif_mode_control_name) + return 0; - return scarlett2_usb_get_mux(mixer); + return scarlett2_add_new_ctl(mixer, &scarlett2_spdif_mode_ctl, + 0, 1, + private->info->spdif_mode_control_name, + NULL); } +/*** Notification Handlers ***/ + /* Notify on sync change */ static void scarlett2_notify_sync(struct usb_mixer_interface *mixer) { @@ -6902,6 +8170,36 @@ static void scarlett2_notify_input_air(struct usb_mixer_interface *mixer) &private->air_ctls[i]->id); } +/* Notify on input DSP switch change */ +static void scarlett2_notify_input_dsp(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int i; + + private->input_dsp_updated = 1; + + for (i = 0; i < info->dsp_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->dsp_ctls[i]->id); +} + +/* Notify on input mute switch change */ +static void scarlett2_notify_input_mute(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int i; + + private->input_mute_updated = 1; + + for (i = 0; i < info->mute_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->input_mute_ctls[i]->id); +} + /* Notify on input phantom switch change */ static void scarlett2_notify_input_phantom(struct usb_mixer_interface *mixer) { @@ -6936,7 +8234,8 @@ static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int i; - if (!info->gain_input_count) + if (!scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) return; private->input_select_updated = 1; @@ -6988,6 +8287,12 @@ static void scarlett2_notify_autogain(struct usb_mixer_interface *mixer) &private->autogain_status_ctls[i]->id); } + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->ag_target_ctls[i]->id); + scarlett2_autogain_notify_access(mixer); } @@ -6999,12 +8304,12 @@ static void scarlett2_notify_input_safe(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int i; - if (!info->gain_input_count) + if (!info->safe_input_count) return; private->input_safe_updated = 1; - for (i = 0; i < info->gain_input_count; i++) + for (i = 0; i < info->safe_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->safe_ctls[i]->id); } @@ -7107,6 +8412,33 @@ static void scarlett2_notify_pcm_input_switch(struct usb_mixer_interface *mixer) scarlett2_notify_mux(mixer); } +/* Notify on Bluetooth change */ +static void scarlett2_notify_bluetooth(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + + if (!private->info->has_bluetooth) + return; + + private->bluetooth_updated = 1; + + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->bluetooth_volume_ctl->id); +} + +/* Handle acknowledgement that a command was received; let + * scarlett2_usb() know that it can proceed + */ +static void scarlett2_notify_ack(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + /* if running == 0, ignore ACKs */ + if (private->running) + complete(&private->cmd_done); +} + /* Interrupt callback */ static void scarlett2_notify(struct urb *urb) { @@ -7123,6 +8455,12 @@ static void scarlett2_notify(struct urb *urb) data = le32_to_cpu(*(__le32 *)urb->transfer_buffer); + /* Ignore notifications except ACK during initialisation. + * ACK is 0x00000001 on every device. + */ + if (private->running < 2) + data &= 1; + while (data && notifications->mask) { if (data & notifications->mask) { data &= ~notifications->mask; @@ -7143,9 +8481,141 @@ requeue: ustatus != -ESHUTDOWN) { urb->dev = mixer->chip->dev; usb_submit_urb(urb, GFP_ATOMIC); + } else { + complete(&private->cmd_done); } } +/*** Cleanup/Suspend Callbacks ***/ + +static void scarlett2_private_free(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + cancel_delayed_work_sync(&private->work); + kfree(private); + mixer->private_data = NULL; +} + +static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + if (cancel_delayed_work_sync(&private->work)) + scarlett2_config_save(private->mixer); +} + +/*** Initialisation ***/ + +static void scarlett2_count_io(struct scarlett2_data *private) +{ + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_config_set *config_set = info->config_set; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int port_type, srcs = 0, dsts = 0, i; + + /* Count the number of mux sources and destinations */ + for (port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) { + srcs += port_count[port_type][SCARLETT2_PORT_IN]; + dsts += port_count[port_type][SCARLETT2_PORT_OUT]; + } + + private->num_mux_srcs = srcs; + private->num_mux_dsts = dsts; + + /* Mixer inputs are mux outputs and vice versa. + * Scarlett Gen 4 DSP I/O uses SCARLETT2_PORT_TYPE_MIX but + * doesn't have mixer controls. + */ + private->num_mix_in = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT] - + info->dsp_count; + + private->num_mix_out = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN] - + info->dsp_count; + + /* Number of analogue line outputs */ + private->num_line_out = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + + /* Number of monitor mix controls */ + private->num_monitor_mix_ctls = + info->direct_monitor * 2 * private->num_mix_in; + + /* Number of autogain status texts */ + if (config_set->autogain_status_texts) { + const char * const *texts = config_set->autogain_status_texts; + + for (i = 0; texts[i]; i++) + ; + private->num_autogain_status_texts = i; + } +} + +/* Look through the interface descriptors for the Focusrite Control + * interface (bInterfaceClass = 255 Vendor Specific Class) and set + * bInterfaceNumber, bEndpointAddress, wMaxPacketSize, and bInterval + * in private + */ +static int scarlett2_find_fc_interface(struct usb_device *dev, + struct scarlett2_data *private) +{ + struct usb_host_config *config = dev->actconfig; + int i; + + for (i = 0; i < config->desc.bNumInterfaces; i++) { + struct usb_interface *intf = config->interface[i]; + struct usb_interface_descriptor *desc = + &intf->altsetting[0].desc; + struct usb_endpoint_descriptor *epd; + + if (desc->bInterfaceClass != 255) + continue; + + epd = get_endpoint(intf->altsetting, 0); + private->bInterfaceNumber = desc->bInterfaceNumber; + private->bEndpointAddress = epd->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize); + private->bInterval = epd->bInterval; + return 0; + } + + return -EINVAL; +} + +/* Initialise private data */ +static int scarlett2_init_private(struct usb_mixer_interface *mixer, + const struct scarlett2_device_entry *entry) +{ + struct scarlett2_data *private = + kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL); + + if (!private) + return -ENOMEM; + + mutex_init(&private->usb_mutex); + mutex_init(&private->data_mutex); + INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); + + mixer->private_data = private; + mixer->private_free = scarlett2_private_free; + mixer->private_suspend = scarlett2_private_suspend; + + private->info = entry->info; + private->config_set = entry->info->config_set; + private->series_name = entry->series_name; + scarlett2_count_io(private); + private->scarlett2_seq = 0; + private->mixer = mixer; + + return scarlett2_find_fc_interface(mixer->chip->dev, private); +} + +/* Submit a URB to receive notifications from the device */ static int scarlett2_init_notify(struct usb_mixer_interface *mixer) { struct usb_device *dev = mixer->chip->dev; @@ -7174,9 +8644,341 @@ static int scarlett2_init_notify(struct usb_mixer_interface *mixer) transfer_buffer, private->wMaxPacketSize, scarlett2_notify, mixer, private->bInterval); + init_completion(&private->cmd_done); + return usb_submit_urb(mixer->urb, GFP_KERNEL); } +/* Cargo cult proprietary initialisation sequence */ +static int scarlett2_usb_init(struct usb_mixer_interface *mixer) +{ + struct usb_device *dev = mixer->chip->dev; + struct scarlett2_data *private = mixer->private_data; + u8 step0_buf[24]; + u8 step2_buf[84]; + int err; + + if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0))) + return -EINVAL; + + /* step 0 */ + err = scarlett2_usb_rx(dev, private->bInterfaceNumber, + SCARLETT2_USB_CMD_INIT, + step0_buf, sizeof(step0_buf)); + if (err < 0) + return err; + + /* Set up the interrupt polling for notifications. + * When running is: + * 0: all notifications are ignored + * 1: only ACKs are handled + * 2: all notifications are handled + */ + err = scarlett2_init_notify(mixer); + if (err < 0) + return err; + + /* sleep for a moment in case of an outstanding ACK */ + msleep(20); + + /* start handling ACKs, but no other notifications until the + * ALSA controls have been created + */ + private->running = 1; + + /* step 1 */ + private->scarlett2_seq = 1; + err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_1, NULL, 0, NULL, 0); + if (err < 0) + return err; + + /* step 2 */ + private->scarlett2_seq = 1; + err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_2, + NULL, 0, + step2_buf, sizeof(step2_buf)); + if (err < 0) + return err; + + /* extract 4-byte firmware version from step2_buf[8] */ + private->firmware_version = le32_to_cpu(*(__le32 *)(step2_buf + 8)); + usb_audio_info(mixer->chip, + "Firmware version %d\n", + private->firmware_version); + + return 0; +} + +/* Get the flash segment numbers for the App_Settings and App_Upgrade + * segments and put them in the private data + */ +static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + int err, count, i; + + struct { + __le32 size; + __le32 count; + u8 unknown[8]; + } __packed flash_info; + + struct { + __le32 size; + __le32 flags; + char name[16]; + } __packed segment_info; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH, + NULL, 0, + &flash_info, sizeof(flash_info)); + if (err < 0) + return err; + + count = le32_to_cpu(flash_info.count); + + /* sanity check count */ + if (count < SCARLETT2_SEGMENT_NUM_MIN || + count > SCARLETT2_SEGMENT_NUM_MAX + 1) { + usb_audio_err(mixer->chip, + "invalid flash segment count: %d\n", count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + __le32 segment_num_req = cpu_to_le32(i); + int flash_segment_id; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT, + &segment_num_req, sizeof(segment_num_req), + &segment_info, sizeof(segment_info)); + if (err < 0) { + usb_audio_err(mixer->chip, + "failed to get flash segment info %d: %d\n", + i, err); + return err; + } + + if (!strncmp(segment_info.name, + SCARLETT2_SEGMENT_SETTINGS_NAME, 16)) + flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS; + else if (!strncmp(segment_info.name, + SCARLETT2_SEGMENT_FIRMWARE_NAME, 16)) + flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE; + else + continue; + + private->flash_segment_nums[flash_segment_id] = i; + private->flash_segment_blocks[flash_segment_id] = + le32_to_cpu(segment_info.size) / + SCARLETT2_FLASH_BLOCK_SIZE; + } + + /* segment 0 is App_Gold and we never want to touch that, so + * use 0 as the "not-found" value + */ + if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) { + usb_audio_err(mixer->chip, + "failed to find flash segment %s\n", + SCARLETT2_SEGMENT_SETTINGS_NAME); + return -EINVAL; + } + if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) { + usb_audio_err(mixer->chip, + "failed to find flash segment %s\n", + SCARLETT2_SEGMENT_FIRMWARE_NAME); + return -EINVAL; + } + + return 0; +} + +/* Read configuration from the interface on start */ +static int scarlett2_read_configs(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i; + + if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MSD_SWITCH, + 1, &private->msd_switch); + if (err < 0) + return err; + } + + if (private->firmware_version < info->min_firmware_version) { + usb_audio_err(mixer->chip, + "Focusrite %s firmware version %d is too old; " + "need %d", + private->series_name, + private->firmware_version, + info->min_firmware_version); + return 0; + } + + /* no other controls are created if MSD mode is on */ + if (private->msd_switch) + return 0; + + err = scarlett2_update_input_level(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_pad(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_air(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_dsp(mixer); + if (err < 0) + return err; + + err = scarlett2_update_compressor_values(mixer); + if (err < 0) + return err; + + err = scarlett2_update_filter_values(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_mute(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_phantom(mixer); + if (err < 0) + return err; + + err = scarlett2_update_direct_monitor(mixer); + if (err < 0) + return err; + + /* the rest of the configuration is for devices with a mixer */ + if (!scarlett2_has_mixer(private)) + return 0; + + err = scarlett2_update_monitor_mix(mixer); + if (err < 0) + return err; + + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + return err; + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_STANDALONE_SWITCH)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH, + 1, &private->standalone_switch); + if (err < 0) + return err; + } + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_POWER_EXT)) { + err = scarlett2_update_power_status(mixer); + if (err < 0) + return err; + } + + err = scarlett2_update_sync(mixer); + if (err < 0) + return err; + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_LINE_OUT_VOLUME)) { + s16 sw_vol[SCARLETT2_ANALOGUE_MAX]; + + /* read SW line out volume */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, + private->num_line_out, &sw_vol); + if (err < 0) + return err; + + for (i = 0; i < private->num_line_out; i++) + private->vol[i] = clamp( + sw_vol[i] + SCARLETT2_VOLUME_BIAS, + 0, SCARLETT2_VOLUME_BIAS); + + /* read SW mute */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MUTE_SWITCH, + private->num_line_out, &private->mute_switch); + if (err < 0) + return err; + + for (i = 0; i < private->num_line_out; i++) + private->mute_switch[i] = + !!private->mute_switch[i]; + + /* read SW/HW switches */ + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_SW_HW_SWITCH)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, + private->num_line_out, + &private->vol_sw_hw_switch); + if (err < 0) + return err; + + for (i = 0; i < private->num_line_out; i++) + private->vol_sw_hw_switch[i] = + !!private->vol_sw_hw_switch[i]; + } + } + + err = scarlett2_update_volumes(mixer); + if (err < 0) + return err; + + err = scarlett2_update_dim_mute(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_select(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_gain(mixer); + if (err < 0) + return err; + + err = scarlett2_update_autogain(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_safe(mixer); + if (err < 0) + return err; + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_PCM_INPUT_SWITCH)) { + err = scarlett2_update_pcm_input_switch(mixer); + if (err < 0) + return err; + } + + err = scarlett2_update_bluetooth_volume(mixer); + if (err < 0) + return err; + + err = scarlett2_update_spdif_mode(mixer); + if (err < 0) + return err; + + err = scarlett2_update_mix(mixer); + if (err < 0) + return err; + + return scarlett2_usb_get_mux(mixer); +} + static const struct scarlett2_device_entry *get_scarlett2_device_entry( struct usb_mixer_interface *mixer) { @@ -7297,6 +9099,16 @@ static int snd_scarlett2_controls_create( if (err < 0) return err; + /* Create the Bluetooth volume control */ + err = scarlett2_add_bluetooth_volume_ctl(mixer); + if (err < 0) + return err; + + /* Create the S/PDIF mode control */ + err = scarlett2_add_spdif_mode_ctl(mixer); + if (err < 0) + return err; + /* Set the access mode of controls disabled during * autogain/phantom power switching. */ @@ -7305,10 +9117,8 @@ static int snd_scarlett2_controls_create( scarlett2_phantom_update_access(mixer); } - /* Set up the interrupt polling */ - err = scarlett2_init_notify(mixer); - if (err < 0) - return err; + /* Start handling all notifications */ + private->running = 2; return 0; } @@ -7397,7 +9207,7 @@ static int scarlett2_reboot(struct usb_mixer_interface *mixer) return scarlett2_usb(mixer, SCARLETT2_USB_REBOOT, NULL, 0, NULL, 0); } -/* Select a flash segment for erasing (and possibly writing to) */ +/* Select a flash segment for reading/erasing/writing */ static int scarlett2_ioctl_select_flash_segment( struct usb_mixer_interface *mixer, unsigned long arg) @@ -7578,6 +9388,84 @@ static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, } } +static long scarlett2_hwdep_read(struct snd_hwdep *hw, + char __user *buf, + long count, loff_t *offset) +{ + struct usb_mixer_interface *mixer = hw->private_data; + struct scarlett2_data *private = mixer->private_data; + int segment_id, segment_num, err; + int flash_size; + + /* SCARLETT2_USB_READ_SEGMENT request data */ + struct { + __le32 segment_num; + __le32 offset; + __le32 len; + } __packed req; + + u8 *resp; + + /* Flash segment must first be selected */ + if (private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_SELECTED) + return -EINVAL; + + /* Get the selected flash segment number */ + segment_id = private->selected_flash_segment_id; + if (segment_id < 0 || segment_id >= SCARLETT2_SEGMENT_ID_COUNT) + return -EINVAL; + + segment_num = private->flash_segment_nums[segment_id]; + if (segment_num < 0 || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) + return -EFAULT; + + /* Validate the offset and count */ + if (count < 0 || *offset < 0) + return -EINVAL; + + /* Reached EOF? */ + flash_size = private->flash_segment_blocks[segment_id] * + SCARLETT2_FLASH_BLOCK_SIZE; + if (!count || *offset >= flash_size) + return 0; + + /* Limit the numbers of bytes read to SCARLETT2_FLASH_RW_MAX */ + if (count > SCARLETT2_FLASH_RW_MAX) + count = SCARLETT2_FLASH_RW_MAX; + + /* Limit read to EOF */ + if (*offset + count >= flash_size) + count = flash_size - *offset; + + /* Create and send the request */ + req.segment_num = cpu_to_le32(segment_num); + req.offset = cpu_to_le32(*offset); + req.len = cpu_to_le32(count); + + resp = kzalloc(count, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + err = scarlett2_usb(mixer, SCARLETT2_USB_READ_SEGMENT, + &req, sizeof(req), resp, count); + if (err < 0) + goto error; + + /* Copy the response to userspace */ + if (copy_to_user(buf, resp, count)) { + err = -EFAULT; + goto error; + } + + *offset += count; + err = count; + +error: + kfree(resp); + return err; +} + static long scarlett2_hwdep_write(struct snd_hwdep *hw, const char __user *buf, long count, loff_t *offset) @@ -7596,7 +9484,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, } __packed *req; /* Calculate the maximum permitted in data[] */ - const size_t max_data_size = SCARLETT2_FLASH_WRITE_MAX - + const size_t max_data_size = SCARLETT2_FLASH_RW_MAX - offsetof(typeof(*req), data); /* If erasing, wait for it to complete */ @@ -7633,7 +9521,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, if (!count) return 0; - /* Limit the *req size to SCARLETT2_FLASH_WRITE_MAX */ + /* Limit the *req size to SCARLETT2_FLASH_RW_MAX */ if (count > max_data_size) count = max_data_size; @@ -7694,6 +9582,7 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) hw->exclusive = 1; hw->ops.open = scarlett2_hwdep_open; hw->ops.ioctl = scarlett2_hwdep_ioctl; + hw->ops.read = scarlett2_hwdep_read; hw->ops.write = scarlett2_hwdep_write; hw->ops.release = scarlett2_hwdep_release; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 5d72dc8441cb..73abc38a5400 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3013,21 +3013,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .fmt_bits = 24, .channels = 4, .iface = 2, .altsetting = 1, .altset_idx = 1, .attributes = 0x00, - .endpoint = 0x01, + .endpoint = USB_RECIP_INTERFACE | USB_DIR_OUT, .ep_attr = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .nr_rates = 1, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, .rate_table = (unsigned int[]) { - 48000 - } + 44100, 48000, 88200, 96000 + }, + .sync_ep = USB_RECIP_INTERFACE | USB_DIR_IN, + .sync_iface = 3, + .sync_altsetting = 1, + .sync_ep_idx = 1, + .implicit_fb = 1, } }, { @@ -3035,22 +3042,25 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .fmt_bits = 24, .channels = 4, .iface = 3, .altsetting = 1, .altset_idx = 1, - .endpoint = 0x81, .attributes = 0x00, + .endpoint = USB_RECIP_INTERFACE | USB_DIR_IN, .ep_attr = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, .maxpacksize = 0x009c, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .nr_rates = 1, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, .rate_table = (unsigned int[]) { - 48000 - } + 44100, 48000, 88200, 96000 + }, + .implicit_fb = 0, } }, { diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 09712e61c606..2f961f0e9378 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -984,21 +984,13 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) return 0; } -static void mbox3_setup_48_24_magic(struct usb_device *dev) +static void mbox3_setup_defaults(struct usb_device *dev) { /* The Mbox 3 is "little endian" */ /* max volume is: 0x0000. */ /* min volume is: 0x0080 (shown in little endian form) */ - - /* Load 48000Hz rate into buffer */ - u8 com_buff[4] = {0x80, 0xbb, 0x00, 0x00}; - - /* Set 48000Hz sample rate */ - snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x21, 0x0100, 0x0001, &com_buff, 4); //Is this really needed? - snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x21, 0x0100, 0x8101, &com_buff, 4); + u8 com_buff[2]; /* Deactivate Tuner */ /* on = 0x01*/ @@ -1008,6 +1000,8 @@ static void mbox3_setup_48_24_magic(struct usb_device *dev) 0x01, 0x21, 0x0003, 0x2001, &com_buff, 1); /* Set clock source to Internal (as opposed to S/PDIF) */ + /* Internal = 0x01*/ + /* S/PDIF = 0x02*/ com_buff[0] = 0x01; snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 1, 0x21, 0x0100, 0x8001, &com_buff, 1); @@ -1113,9 +1107,11 @@ static void mbox3_setup_48_24_magic(struct usb_device *dev) 1, 0x21, 0x0107, 0x4201, &com_buff, 2); /* Toggle allowing host control */ + /* Not needed com_buff[0] = 0x02; snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 3, 0x21, 0x0000, 0x2001, &com_buff, 1); + */ /* Do not dim fx returns */ com_buff[0] = 0x00; @@ -1259,26 +1255,27 @@ static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) descriptor_size = le16_to_cpu(get_cfg_desc(config)->wTotalLength); if (descriptor_size != MBOX3_DESCRIPTOR_SIZE) { - dev_err(&dev->dev, "Invalid descriptor size=%d.\n", descriptor_size); + dev_err(&dev->dev, "MBOX3: Invalid descriptor size=%d.\n", descriptor_size); return -ENODEV; } - dev_dbg(&dev->dev, "device initialised!\n"); + dev_dbg(&dev->dev, "MBOX3: device initialised!\n"); err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); config = dev->actconfig; if (err < 0) - dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err); + dev_dbg(&dev->dev, "MBOX3: error usb_get_descriptor: %d\n", err); err = usb_reset_configuration(dev); if (err < 0) - dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err); - dev_dbg(&dev->dev, "mbox3_boot: new boot length = %d\n", + dev_dbg(&dev->dev, "MBOX3: error usb_reset_configuration: %d\n", err); + + dev_dbg(&dev->dev, "MBOX3: new boot length = %d\n", le16_to_cpu(get_cfg_desc(config)->wTotalLength)); - mbox3_setup_48_24_magic(dev); - dev_info(&dev->dev, "Digidesign Mbox 3: 24bit 48kHz"); + mbox3_setup_defaults(dev); + dev_info(&dev->dev, "MBOX3: Initialized."); return 0; /* Successful boot */ } @@ -1734,6 +1731,46 @@ static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs, return 0; } +static void mbox3_set_format_quirk(struct snd_usb_substream *subs, + const struct audioformat *fmt) +{ + __le32 buff4 = 0; + u8 buff1 = 0x01; + u32 new_rate = subs->data_endpoint->cur_rate; + u32 current_rate; + + // Get current rate from card and check if changing it is needed + snd_usb_ctl_msg(subs->dev, usb_sndctrlpipe(subs->dev, 0), + 0x01, 0x21 | USB_DIR_IN, 0x0100, 0x8101, &buff4, 4); + current_rate = le32_to_cpu(buff4); + dev_dbg(&subs->dev->dev, + "MBOX3: Current configured sample rate: %d", current_rate); + if (current_rate == new_rate) { + dev_dbg(&subs->dev->dev, + "MBOX3: No change needed (current rate:%d == new rate:%d)", + current_rate, new_rate); + return; + } + + // Set new rate + dev_info(&subs->dev->dev, + "MBOX3: Changing sample rate to: %d", new_rate); + buff4 = cpu_to_le32(new_rate); + snd_usb_ctl_msg(subs->dev, usb_sndctrlpipe(subs->dev, 0), + 0x01, 0x21, 0x0100, 0x8101, &buff4, 4); + + // Set clock source to Internal + snd_usb_ctl_msg(subs->dev, usb_sndctrlpipe(subs->dev, 0), + 0x01, 0x21, 0x0100, 0x8001, &buff1, 1); + + // Check whether the change was successful + buff4 = 0; + snd_usb_ctl_msg(subs->dev, usb_sndctrlpipe(subs->dev, 0), + 0x01, 0x21 | USB_DIR_IN, 0x0100, 0x8101, &buff4, 4); + if (new_rate != le32_to_cpu(buff4)) + dev_warn(&subs->dev->dev, "MBOX3: Couldn't set the sample rate"); +} + void snd_usb_set_format_quirk(struct snd_usb_substream *subs, const struct audioformat *fmt) { @@ -1755,6 +1792,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */ pioneer_djm_set_format_quirk(subs, 0x0086); break; + case USB_ID(0x0dba, 0x5000): + mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */ + break; } } diff --git a/sound/usb/usx2y/Makefile b/sound/usb/usx2y/Makefile index cc4c2f1efab2..fc033aba03a4 100644 --- a/sound/usb/usx2y/Makefile +++ b/sound/usb/usx2y/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -snd-usb-usx2y-objs := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o -snd-usb-us122l-objs := us122l.o +snd-usb-usx2y-y := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o +snd-usb-us122l-y := us122l.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o obj-$(CONFIG_SND_USB_US122L) += snd-usb-us122l.o diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index a839f8c8b5e6..3ca41b3c8b95 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o -virtio_snd-objs := \ +virtio_snd-y := \ virtio_card.o \ virtio_chmap.o \ virtio_ctl_msg.o \ diff --git a/sound/x86/Makefile b/sound/x86/Makefile index 6b5ffb329d47..44d2a339615d 100644 --- a/sound/x86/Makefile +++ b/sound/x86/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-hdmi-lpe-audio-objs += \ +snd-hdmi-lpe-audio-y += \ intel_hdmi_audio.o obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/xen/Makefile b/sound/xen/Makefile index 24031775b715..5dab1616eac0 100644 --- a/sound/xen/Makefile +++ b/sound/xen/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 OR MIT -snd_xen_front-objs := xen_snd_front.o \ +snd_xen_front-y := xen_snd_front.o \ xen_snd_front_cfg.o \ xen_snd_front_evtchnl.o \ xen_snd_front_alsa.o |