From aa80272171c48491bf5b1246ccd8b6b2c057f15d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 13 Mar 2020 16:56:59 -0500 Subject: [PATCH 1/6] ALSA: core: sysfs: show components string Add attribute and show the components string. This is useful to see what is provided to userspace and e.g. used by UCM to understand the card configuration: root@plb:~# more /sys/class/sound/card0/components HDA:8086280b,80860101,00100000 cfg-spk:2 hs:rt711 spk:rt1308 mic:rt715 Note that the style uses what's recommended by checkpatch.pl and is slightly different from other sysfs attributes. Signed-off-by: Pierre-Louis Bossart --- sound/core/init.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/core/init.c b/sound/core/init.c index b02a99766351d7..decaf944a8ad43 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -695,9 +695,21 @@ card_number_show_attr(struct device *dev, static DEVICE_ATTR(number, 0444, card_number_show_attr, NULL); +static ssize_t +components_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_card *card = container_of(dev, struct snd_card, card_dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", card->components); +} + +static DEVICE_ATTR_RO(components); + static struct attribute *card_dev_attrs[] = { &dev_attr_id.attr, &dev_attr_number.attr, + &dev_attr_components.attr, NULL }; From 45125d2151d78444a85566bdb43d7e3b20121ea5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Mar 2020 18:37:38 -0500 Subject: [PATCH 2/6] ASoC: Intel: soc-acpi: transition to generic SoundWire machine driver Use generic SoundWire machine driver instead of platform-specific ones. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cml-match.c | 6 +++--- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 6 +++--- sound/soc/intel/common/soc-acpi-intel-tgl-match.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) 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 3525da79c68ac3..50a9e2e6896cdd 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -175,7 +175,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { { .link_mask = 0xF, /* 4 active links required */ .links = cml_3_in_1_default, - .drv_name = "sdw_rt711_rt1308_rt715", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt711-rt1308-rt715.tplg", }, @@ -187,13 +187,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { */ .link_mask = 0xF, .links = cml_3_in_1_mono_amp, - .drv_name = "sdw_rt711_rt1308_rt715", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt711-rt1308-mono-rt715.tplg", }, { .link_mask = 0x2, /* RT700 connected on Link1 */ - .drv_name = "sdw_rt700", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt700.tplg", }, 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 a05fc083829e34..ef8500349f2f2f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -166,21 +166,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[] = { { .link_mask = 0xF, /* 4 active links required */ .links = icl_3_in_1_default, - .drv_name = "sdw_rt711_rt1308_rt715", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt711-rt1308-rt715.tplg", }, { .link_mask = 0xB, /* 3 active links required */ .links = icl_3_in_1_mono_amp, - .drv_name = "sdw_rt711_rt1308_rt715", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt711-rt1308-rt715-mono.tplg", }, { .link_mask = 0x1, /* rt700 connected on link0 */ .links = icl_rvp, - .drv_name = "sdw_rt700", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt700.tplg", }, 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 d05cae41ddf85d..12f30d5e8c2f03 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -82,7 +82,7 @@ static const struct snd_soc_acpi_link_adr tgl_rvp[] = { struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC1308", - .drv_name = "sdw_rt711_rt1308_rt715", + .drv_name = "sof_sdw", .link_mask = 0x1, /* RT711 on SoundWire link0 */ .links = tgl_i2s_rt1308, .sof_fw_filename = "sof-tgl.ri", @@ -105,7 +105,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { { .link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */ .links = tgl_rvp, - .drv_name = "sdw_rt711_rt1308_rt715", + .drv_name = "sof_sdw", .sof_fw_filename = "sof-tgl.ri", .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", }, From 6522c3f2d5bddc1fab0130e56617bb5963358e6e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 17 Mar 2020 17:43:00 -0500 Subject: [PATCH 3/6] ASoC: Intel: soc-acpi: fix CML RVP Need to have links information, not just link mask Signed-off-by: Pierre-Louis Bossart --- .../intel/common/soc-acpi-intel-cml-match.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 50a9e2e6896cdd..bcedec6c6117cb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -80,6 +80,23 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_adr_device rt700_1_adr[] = { + { + .adr = 0x000110025D070000, + .num_endpoints = 1, + .endpoints = &single_endpoint, + } +}; + +static const struct snd_soc_acpi_link_adr cml_rvp[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt700_1_adr), + .adr_d = rt700_1_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000010025D071100, @@ -193,6 +210,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { }, { .link_mask = 0x2, /* RT700 connected on Link1 */ + .links = cml_rvp, .drv_name = "sof_sdw", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt700.tplg", From aaac218d17228bb2620747d81a9ab5998e833a7f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Mar 2020 17:33:39 -0500 Subject: [PATCH 4/6] ASoC: Intel: transition to generic SoundWire machine driver No need to maintain multiple drivers when we have everything we need to generate dailinks dynamically. Tested on CML w/ RT700 and CML with RT711/RT1308x1/RT715 Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 22 +- sound/soc/intel/boards/Makefile | 10 +- sound/soc/intel/boards/sdw_rt700.c | 386 ------------ .../{sdw_rt711_rt1308_rt715.c => sof_sdw.c} | 580 +++--------------- sound/soc/intel/boards/sof_sdw_common.h | 108 ++++ sound/soc/intel/boards/sof_sdw_dmic.c | 42 ++ sound/soc/intel/boards/sof_sdw_hdmi.c | 97 +++ sound/soc/intel/boards/sof_sdw_rt1308.c | 151 +++++ sound/soc/intel/boards/sof_sdw_rt700.c | 125 ++++ sound/soc/intel/boards/sof_sdw_rt711.c | 156 +++++ sound/soc/intel/boards/sof_sdw_rt715.c | 42 ++ 11 files changed, 809 insertions(+), 910 deletions(-) delete mode 100644 sound/soc/intel/boards/sdw_rt700.c rename sound/soc/intel/boards/{sdw_rt711_rt1308_rt715.c => sof_sdw.c} (60%) create mode 100644 sound/soc/intel/boards/sof_sdw_common.h create mode 100644 sound/soc/intel/boards/sof_sdw_dmic.c create mode 100644 sound/soc/intel/boards/sof_sdw_hdmi.c create mode 100644 sound/soc/intel/boards/sof_sdw_rt1308.c create mode 100644 sound/soc/intel/boards/sof_sdw_rt700.c create mode 100644 sound/soc/intel/boards/sof_sdw_rt711.c create mode 100644 sound/soc/intel/boards/sof_sdw_rt715.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index db3ab995df8b2e..be17a161bd50f4 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -542,30 +542,22 @@ endif ## SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_INTEL_SOUNDWIRE -config SND_SOC_INTEL_SOUNDWIRE_RT700_MACH - tristate "SoundWire with RT700 codec" - depends on SOUNDWIRE && ACPI - depends on SND_HDA_CODEC_HDMI - select SND_SOC_RT700_SDW - select SND_SOC_DMIC - help - Add support for Intel SoundWire-based platforms connected to RT700 - on link 0 or 1 - If unsure select "N" - -config SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH - tristate "SoundWire with RT711, RT1308 and RT715" +config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH + tristate "SoundWire generic machine driver" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST + depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE depends on SND_HDA_CODEC_HDMI + select SND_SOC_RT700_SDW select SND_SOC_RT711_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 select SND_SOC_RT715_SDW + select SND_SOC_DMIC help - Add support for Intel SoundWire-based platforms connected to RT711, - RT1308 and RT715 + Add support for Intel SoundWire-based platforms connected to + RT700, RT711, RT1308 and RT715 If unsure select "N". endif diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 23226160abc436..6a887d39130b83 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -32,9 +32,10 @@ snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_c snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o -snd-soc-sdw-rt700-objs := sdw_rt700.o hda_dsp_common.o -snd-soc-sdw-rt711-rt1308-rt715-objs := sdw_rt711_rt1308_rt715.o hda_dsp_common.o - +snd-soc-sof-sdw-objs += sof_sdw.o \ + sof_sdw_rt711.o sof_sdw_rt700.o \ + sof_sdw_rt1308.o sof_sdw_rt715.o \ + sof_sdw_dmic.o sof_sdw_hdmi.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o @@ -68,5 +69,4 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max9 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o -obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH) += snd-soc-sdw-rt700.o -obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH) += snd-soc-sdw-rt711-rt1308-rt715.o +obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o diff --git a/sound/soc/intel/boards/sdw_rt700.c b/sound/soc/intel/boards/sdw_rt700.c deleted file mode 100644 index 11a2f33afbb12a..00000000000000 --- a/sound/soc/intel/boards/sdw_rt700.c +++ /dev/null @@ -1,386 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2016-19 Intel Corporation - -/* - * sdw_rt700 - ASOC Machine driver for Intel SoundWire platforms - * connected to ALC700 device - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../codecs/hdac_hdmi.h" -#include "hda_dsp_common.h" - -struct mc_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; - struct snd_soc_jack sdw_headset; -}; - -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) -static struct snd_soc_jack hdmi[3]; - -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -static int hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = rtd->codec_dai; - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - /* dai_link id is 1:1 mapped to the PCM device */ - pcm->device = rtd->dai_link->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -#define NAME_SIZE 32 -static int card_late_probe(struct snd_soc_card *card) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - component = pcm->codec_dai->component; - - if (ctx->common_hdmi_codec_drv) - 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, &hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} -#else -static int card_late_probe(struct snd_soc_card *card) -{ - return 0; -} -#endif - -static struct snd_soc_jack_pin sdw_jack_pins[] = { - { - .pin = "Headphones", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "AMIC", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int headset_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = rtd->codec_dai->component; - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_jack *jack; - int ret; - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - sdw_jack_pins, - ARRAY_SIZE(sdw_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - - ret = snd_soc_component_set_jack(component, jack, NULL); - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -/* these wrappers are only needed to avoid typecast compilation errors */ -static int sdw_startup(struct snd_pcm_substream *substream) -{ - return sdw_startup_stream(substream); -} - -static void sdw_shutdown(struct snd_pcm_substream *substream) -{ - sdw_shutdown_stream(substream); -} - -static const struct snd_soc_ops sdw_ops = { - .startup = sdw_startup, - .shutdown = sdw_shutdown, -}; - -static const struct snd_soc_dapm_widget 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 map[] = { - /*Headphones*/ - { "Headphones", NULL, "HP" }, - { "Speaker", NULL, "SPK" }, - { "MIC2", NULL, "AMIC" }, -}; - -static const struct snd_kcontrol_new controls[] = { - SOC_DAPM_PIN_SWITCH("Headphones"), - SOC_DAPM_PIN_SWITCH("AMIC"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -SND_SOC_DAILINK_DEF(sdw0_pin2, - DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin2"))); -SND_SOC_DAILINK_DEF(sdw0_pin3, - DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin3"))); -SND_SOC_DAILINK_DEF(sdw0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("sdw:0:25d:700:0", "rt700-aif1"))); - -SND_SOC_DAILINK_DEF(sdw1_pin2, - DAILINK_COMP_ARRAY(COMP_CPU("SDW1 Pin2"))); -SND_SOC_DAILINK_DEF(sdw1_pin3, - DAILINK_COMP_ARRAY(COMP_CPU("SDW1 Pin3"))); -SND_SOC_DAILINK_DEF(sdw1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("sdw:1:25d:700:0", "rt700-aif1"))); - -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"))); - -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) -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"))); -#endif - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -static struct snd_soc_dai_link dailink[] = { - { - .name = "SDW0-Playback", - .id = 0, - .init = headset_init, - .no_pcm = 1, - .dpcm_playback = 1, - .nonatomic = true, - .ops = &sdw_ops, - SND_SOC_DAILINK_REG(sdw0_pin2, sdw0_codec, platform), - }, - { - .name = "SDW0-Capture", - .id = 1, - .no_pcm = 1, - .dpcm_capture = 1, - .nonatomic = true, - .ops = &sdw_ops, - SND_SOC_DAILINK_REG(sdw0_pin3, sdw0_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 = "dmic16k", - .id = 3, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - }, -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) - { - .name = "iDisp1", - .id = 4, - .init = hdmi_init, - .no_pcm = 1, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 5, - .init = hdmi_init, - .no_pcm = 1, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 6, - .init = hdmi_init, - .no_pcm = 1, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -#endif -}; - -/* SoC card */ -static struct snd_soc_card card_sdw_rt700 = { - .name = "sdw-rt700", - .dai_link = dailink, - .num_links = ARRAY_SIZE(dailink), - .controls = controls, - .num_controls = ARRAY_SIZE(controls), - .dapm_widgets = widgets, - .num_dapm_widgets = ARRAY_SIZE(widgets), - .dapm_routes = map, - .num_dapm_routes = ARRAY_SIZE(map), - .late_probe = card_late_probe, -}; - -static int mc_probe(struct platform_device *pdev) -{ - struct mc_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - struct snd_soc_card *card = &card_sdw_rt700; - const char *board; - int ret; - - dev_dbg(&pdev->dev, "Entry %s\n", __func__); - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); -#endif - - board = dmi_get_system_info(DMI_BOARD_NAME); - if (strstr(board, "CometLake U DDR4 HR")) { - dailink[0].name = "SDW1-Playback"; - dailink[0].codecs = sdw1_codec; - dailink[0].num_codecs = ARRAY_SIZE(sdw1_codec); - dailink[0].cpus = sdw1_pin2; - dailink[0].num_cpus = ARRAY_SIZE(sdw1_pin2); - - dailink[1].name = "SDW1-Capture"; - dailink[1].codecs = sdw1_codec; - dailink[1].num_codecs = ARRAY_SIZE(sdw1_codec); - dailink[1].cpus = sdw1_pin3; - dailink[1].num_cpus = ARRAY_SIZE(sdw1_pin3); - } - - card->dev = &pdev->dev; - - /* 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; - - snd_soc_card_set_drvdata(card, ctx); - - /* Register the card */ - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); - return ret; - } - - platform_set_drvdata(pdev, card); - - return ret; -} - -static struct platform_driver sdw_rt700_driver = { - .driver = { - .name = "sdw_rt700", - .pm = &snd_soc_pm_ops, - }, - .probe = mc_probe, -}; - -module_platform_driver(sdw_rt700_driver); - -MODULE_DESCRIPTION("ASoC SoundWire RT700 Machine driver"); -MODULE_AUTHOR("Bard Liao "); -MODULE_AUTHOR("Pierre-Louis Bossart "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sdw_rt700"); diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sof_sdw.c similarity index 60% rename from sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c rename to sound/soc/intel/boards/sof_sdw.c index 1f987b747bf472..c0a829ab692974 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1,233 +1,32 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2019 Intel Corporation +// Copyright (c) 2020 Intel Corporation /* - * sdw_rt711_rt1308_rt715 - ASOC Machine driver for Intel SoundWire platforms - * connected to 3 Realtek devices + * sof_sdw - ASOC Machine driver for Intel SoundWire platforms */ -#include -#include -#include #include -#include -#include -#include -#include #include #include -#include #include #include -#include -#include -#include #include #include -#include -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt1308.h" -#include "hda_dsp_common.h" - -/* comment out this define for mono configurations */ - -#define MAX_NO_PROPS 2 -#define MAX_HDMI_NUM 4 -#define SDW_DMIC_DAI_ID 4 -#define SDW_MAX_CPU_DAIS 16 -#define SDW_INTEL_BIDIR_PDI_BASE 2 - -/* 8 combinations with 4 links + unused group 0 */ -#define SDW_MAX_GROUPS 9 - -enum { - SOF_RT711_JD_SRC_JD1 = 1, - SOF_RT711_JD_SRC_JD2 = 2, -}; +#include "sof_sdw_common.h" -enum { - SOF_PRE_TGL_HDMI_COUNT = 3, - SOF_TGL_HDMI_COUNT = 4, -}; - -enum { - SOF_I2S_SSP0 = BIT(0), - SOF_I2S_SSP1 = BIT(1), - SOF_I2S_SSP2 = BIT(2), - SOF_I2S_SSP3 = BIT(3), - SOF_I2S_SSP4 = BIT(4), - SOF_I2S_SSP5 = BIT(5), -}; - -#define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) -#define SOF_SDW_MONO_SPK BIT(2) -#define SOF_SDW_TGL_HDMI BIT(3) -#define SOF_SDW_PCH_DMIC BIT(4) -#define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 5) -#define SOF_SSP_GET_PORT(quirk) (((quirk) >> 5) & GENMASK(5, 0)) -#define SOF_RT715_DAI_ID_FIX BIT(11) -#define SOF_SDW_NO_AGGREGATED BIT(12) - -static unsigned long sof_rt711_rt1308_rt715_quirk = SOF_RT711_JD_SRC_JD1; +unsigned long sof_sdw_quirk = SOF_RT711_JD_SRC_JD1; #define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0) -struct mc_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; - struct snd_soc_jack sdw_headset; -}; - -struct codec_info { - const int id; - int amp_num; - const u8 acpi_id[ACPI_ID_LEN]; - const bool direction[2]; // playback & capture support - const char *dai_name; - const struct snd_soc_ops *ops; - - void (*init)(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct codec_info *info, - bool playback); -}; - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) -static struct snd_soc_jack hdmi[MAX_HDMI_NUM]; - -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -static int hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = rtd->codec_dai; - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - /* dai_link id is 1:1 mapped to the PCM device */ - pcm->device = rtd->dai_link->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -#define NAME_SIZE 32 -static int card_late_probe(struct snd_soc_card *card) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - component = pcm->codec_dai->component; - - if (ctx->common_hdmi_codec_drv) - 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, &hdmi[i], - NULL, 0); - - if (err) - return err; - - err = snd_jack_add_new_kctl(hdmi[i].jack, - jack_name, SND_JACK_AVOUT); - if (err) - dev_warn(component->dev, "failed creating Jack kctl\n"); - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} -#else -static int card_late_probe(struct snd_soc_card *card) -{ - return 0; -} -#endif - -static struct snd_soc_jack_pin sdw_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int headset_init(struct snd_soc_pcm_runtime *rtd) +static int sof_sdw_quirk_cb(const struct dmi_system_id *id) { - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = rtd->codec_dai->component; - struct snd_soc_jack *jack; - int ret; - - ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - sdw_jack_pins, - ARRAY_SIZE(sdw_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -static int sof_rt711_rt1308_rt715_quirk_cb(const struct dmi_system_id *id) -{ - sof_rt711_rt1308_rt715_quirk = (unsigned long)id->driver_data; + sof_sdw_quirk = (unsigned long)id->driver_data; return 1; } -static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { +static const struct dmi_system_id sof_sdw_quirk_table[] = { { - .callback = sof_rt711_rt1308_rt715_quirk_cb, + .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), @@ -237,17 +36,17 @@ static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { SOF_RT715_DAI_ID_FIX), }, { - .callback = sof_rt711_rt1308_rt715_quirk_cb, + .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_MATCH(DMI_PRODUCT_NAME, "XPS"), }, .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | SOF_RT715_DAI_ID_FIX | - SOF_SDW_NO_AGGREGATED), + SOF_SDW_NO_AGGREGATION), }, { - .callback = sof_rt711_rt1308_rt715_quirk_cb, + .callback = sof_sdw_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, @@ -257,160 +56,26 @@ static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | SOF_SSP_PORT(SOF_I2S_SSP2)), }, - {} -}; - -/* - * Note this MUST be called before snd_soc_register_card(), so that the props - * are in place before the codec component driver's probe function parses them. - */ -static int sof_rt711_add_codec_device_props(const char *sdw_dev_name) -{ - struct property_entry props[MAX_NO_PROPS] = {}; - struct device *sdw_dev; - int ret; - - sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_dev_name); - if (!sdw_dev) - return -EPROBE_DEFER; - - if (SOF_RT711_JDSRC(sof_rt711_rt1308_rt715_quirk)) { - int cnt = 0; - props[cnt++] = PROPERTY_ENTRY_U32( - "realtek,jd-src", - SOF_RT711_JDSRC(sof_rt711_rt1308_rt715_quirk)); - } - - ret = device_add_properties(sdw_dev, props); - put_device(sdw_dev); - - return ret; -} - -static const struct snd_soc_dapm_widget widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_soc_dapm_route map[] = { - /* Headphones */ - { "Headphone", NULL, "rt711 HP" }, - { "rt711 MIC2", NULL, "Headset Mic" }, -}; - -/* - * dapm routes for rt1308 will be registered dynamically according - * to the number of rt1308 used. The first two entries will be registered - * for one codec case, and the last two entries are also registered - * if two 1308s are used. - */ -static const struct snd_soc_dapm_route rt1308_speaker_map[] = { - { "Speaker", NULL, "rt1308-1 SPOL" }, - { "Speaker", NULL, "rt1308-1 SPOR" }, - { "Speaker", NULL, "rt1308-2 SPOL" }, - { "Speaker", NULL, "rt1308-2 SPOR" }, -}; - -static const struct snd_kcontrol_new controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static int set_amp_tdm_slots(struct snd_soc_pcm_runtime *rtd, bool tdm_mode) -{ - struct snd_soc_dai *codec_dai; - int ret; - int i; - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (tdm_mode) - /* tx_mask 0, rx_mask with only one bit, single slot) */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, BIT(i), 1, 0); - else - /* tx_mask 0, rx_mask 0x3, 2 slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 0x3, 2, 0); - if (ret < 0) - return ret; - } - - return 0; -} - -static int first_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_speaker_map, 2); - if (ret) { - dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); - return ret; - } - - return set_amp_tdm_slots(rtd, false); -} - -static int second_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_speaker_map + 2, 2); - if (ret) { - dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret); - return ret; - } - - return set_amp_tdm_slots(rtd, false); -} - -static int all_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_speaker_map, 4); - if (ret) { - dev_err(rtd->dev, "failed to add all SPK map: %d\n", ret); - return ret; - } - - return set_amp_tdm_slots(rtd, true); -} - -static const struct snd_soc_dapm_widget dmic_widgets[] = { - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), + }, + .driver_data = (void *)SOF_SDW_PCH_DMIC, + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), + }, + .driver_data = (void *)SOF_SDW_PCH_DMIC, + }, -static const struct snd_soc_dapm_route dmic_map[] = { - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, + {} }; -static int dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, - ARRAY_SIZE(dmic_widgets)); - if (ret) { - dev_err(card->dev, "DMic widget addition failed: %d\n", ret); - /* Don't need to add routes if widget addition failed */ - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, - ARRAY_SIZE(dmic_map)); - - if (ret) - dev_err(card->dev, "DMic map addition failed: %d\n", ret); - - return ret; -} - static struct snd_soc_codec_conf codec_conf[] = { { .dlc = COMP_CODEC_CONF("sdw:0:25d:711:0"), @@ -460,43 +125,6 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; -static int rt1308_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_card *card = rtd->card; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int clk_id, clk_freq, pll_out; - int err; - - clk_id = RT1308_PLL_S_MCLK; - clk_freq = 38400000; - - pll_out = params_rate(params) * 512; - - /* Set rt1308 pll */ - err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); - if (err < 0) { - dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err); - return err; - } - - /* Set rt1308 sysclk */ - err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err); - return err; - } - - return 0; -} - -/* machine stream operations */ -static struct snd_soc_ops rt1308_i2s_ops = { - .hw_params = rt1308_i2s_hw_params, -}; - /* these wrappers are only needed to avoid typecast compilation errors */ static int sdw_startup(struct snd_pcm_substream *substream) { @@ -513,77 +141,32 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = sdw_shutdown, }; -static void rt711_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct codec_info *info, - bool playback) -{ - /* - * headset should be initialized once. - * Do it with dai link for playback. - */ - if (!playback) - return; - - dai_links->init = headset_init; -} - -static void rt1308_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct codec_info *info, - bool playback) -{ - info->amp_num++; - if (info->amp_num == 1) - dai_links->init = first_spk_init; - - if (info->amp_num == 2) { - /* - * if two 1308s are in one dai link, the init function - * in this dai link will be first set for the first speaker, - * and it should be reset to initialize all speakers when - * the second speaker is found. - */ - if (dai_links->init) - dai_links->init = all_spk_init; - else - dai_links->init = second_spk_init; - } -} - -static void rt715_init(const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct codec_info *info, - bool playback) -{ - /* - * DAI ID is fixed at SDW_DMIC_DAI_ID for 715 to - * keep sdw DMIC and HDMI setting static in UCM - */ - if (sof_rt711_rt1308_rt715_quirk & SOF_RT715_DAI_ID_FIX) - dai_links->id = SDW_DMIC_DAI_ID; -} - -static struct codec_info codec_info_list[] = { +static struct sof_sdw_codec_info codec_info_list[] = { + { + .id = 0x700, + .direction = {true, true}, + .dai_name = "rt700-aif1", + .init = sof_sdw_rt700_init, + }, { .id = 0x711, .direction = {true, true}, .dai_name = "rt711-aif1", - .init = rt711_init, + .init = sof_sdw_rt711_init, }, { .id = 0x1308, .acpi_id = "10EC1308", .direction = {true, false}, .dai_name = "rt1308-aif", - .ops = &rt1308_i2s_ops, - .init = rt1308_init, + .ops = &sof_sdw_rt1308_i2s_ops, + .init = sof_sdw_rt1308_init, }, { .id = 0x715, .direction = {false, true}, .dai_name = "rt715-aif2", - .init = rt715_init, + .init = sof_sdw_rt715_init, }, }; @@ -629,10 +212,10 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, { const struct snd_soc_acpi_link_adr *link; bool group_visited[SDW_MAX_GROUPS]; - bool no_aggregated; + bool no_aggregation; int i; - no_aggregated = sof_rt711_rt1308_rt715_quirk & SOF_SDW_NO_AGGREGATED; + no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; *sdw_cpu_dai_num = 0; *sdw_be_num = 0; @@ -664,7 +247,7 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, (*sdw_cpu_dai_num)++; /* count BE for each non-aggregated slave or group */ - if (!endpoint->aggregated || no_aggregated || + if (!endpoint->aggregated || no_aggregation || !group_visited[endpoint->group_id]) (*sdw_be_num)++; } @@ -835,10 +418,10 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, { const struct snd_soc_acpi_adr_device *adr_d; const struct snd_soc_acpi_link_adr *adr_next; - bool no_aggregated; + bool no_aggregation; int index = 0; - no_aggregated = sof_rt711_rt1308_rt715_quirk & SOF_SDW_NO_AGGREGATED; + no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; *codec_num = adr_link->num_adr; adr_d = adr_link->adr_d; @@ -847,7 +430,7 @@ static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, return -EINVAL; cpu_dai_id[index++] = ffs(adr_link->mask) - 1; - if (!adr_d->endpoints->aggregated || no_aggregated) { + if (!adr_d->endpoints->aggregated || no_aggregation) { *cpu_dai_num = 1; *group_id = 0; return 0; @@ -1056,11 +639,11 @@ static int sof_card_dai_links_create(struct device *dev, codec_info_list[i].amp_num = 0; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - hdmi_num = sof_rt711_rt1308_rt715_quirk & SOF_SDW_TGL_HDMI ? + hdmi_num = sof_sdw_quirk & SOF_SDW_TGL_HDMI ? SOF_TGL_HDMI_COUNT : SOF_PRE_TGL_HDMI_COUNT; #endif - ssp_mask = SOF_SSP_GET_PORT(sof_rt711_rt1308_rt715_quirk); + ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); /* * on generic tgl platform, I2S or sdw mode is supported * based on board rework. A ACPI device is registered in @@ -1080,7 +663,7 @@ static int sof_card_dai_links_create(struct device *dev, } /* enable dmic01 & dmic16k */ - dmic_num = (sof_rt711_rt1308_rt715_quirk & SOF_SDW_PCH_DMIC) ? 2 : 0; + dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC) ? 2 : 0; comp_num += dmic_num; dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num, @@ -1151,7 +734,7 @@ static int sof_card_dai_links_create(struct device *dev, goto DMIC; for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) { - struct codec_info *info; + struct sof_sdw_codec_info *info; int playback, capture; char *codec_name; @@ -1190,7 +773,10 @@ static int sof_card_dai_links_create(struct device *dev, ssp_components, 1, NULL, info->ops); - info->init(NULL, links + link_id, info, 0); + ret = info->init(NULL, links + link_id, info, 0); + if (ret < 0) + return ret; + INC_ID(be_id, cpu_id, link_id); } @@ -1202,7 +788,7 @@ static int sof_card_dai_links_create(struct device *dev, 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, - dmic_init, NULL); + sof_sdw_dmic_init, NULL); INC_ID(be_id, cpu_id, link_id); cpus[cpu_id].dai_name = "DMIC16k Pin"; @@ -1210,7 +796,7 @@ static int sof_card_dai_links_create(struct device *dev, 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, - dmic_init, NULL); + sof_sdw_dmic_init, NULL); INC_ID(be_id, cpu_id, link_id); } @@ -1248,7 +834,7 @@ static int sof_card_dai_links_create(struct device *dev, 1, 0, // HDMI only supports playback cpus + cpu_id, 1, idisp_components + i, 1, - hdmi_init, NULL); + sof_sdw_hdmi_init, NULL); INC_ID(be_id, cpu_id, link_id); } #endif @@ -1260,28 +846,18 @@ static int sof_card_dai_links_create(struct device *dev, } /* SoC card */ -static char components_string[] = "cfg-spk:2"; /* cfg-spk:%d */ -#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) -/* Can also be sof-sdw-rt711-mono-rt1308-rt715 */ -static char sdw_card_long_name[] = "sof-sdw-rt711-stereo-rt1308-rt715"; -#endif -static struct snd_soc_card card_rt700_rt1308_rt715 = { - .name = "sdw-rt711-1308-715", - .controls = controls, - .num_controls = ARRAY_SIZE(controls), - .dapm_widgets = widgets, - .num_dapm_widgets = ARRAY_SIZE(widgets), - .dapm_routes = map, - .num_dapm_routes = ARRAY_SIZE(map), - .late_probe = card_late_probe, +static const char sdw_card_long_name[] = "Intel Soundwire SOF"; + +static struct snd_soc_card card_sof_sdw = { + .name = "soundwire", + .late_probe = sof_sdw_hdmi_card_late_probe, .codec_conf = codec_conf, .num_configs = ARRAY_SIZE(codec_conf), - .components = components_string, }; static int mc_probe(struct platform_device *pdev) { - struct snd_soc_card *card = &card_rt700_rt1308_rt715; + struct snd_soc_card *card = &card_sof_sdw; struct snd_soc_acpi_mach *mach; struct mc_private *ctx; int ret; @@ -1292,7 +868,7 @@ static int mc_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - dmi_check_system(sof_sdw_rt711_rt1308_rt715_quirk_table); + dmi_check_system(sof_sdw_quirk_table); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); @@ -1302,7 +878,7 @@ static int mc_probe(struct platform_device *pdev) mach = pdev->dev.platform_data; ret = sof_card_dai_links_create(&pdev->dev, mach, - &card_rt700_rt1308_rt715); + card); if (ret < 0) return ret; @@ -1310,19 +886,14 @@ static int mc_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, ctx); - sof_rt711_add_codec_device_props("sdw:0:25d:711:0"); + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "cfg-spk:%d", + (sof_sdw_quirk & SOF_SDW_MONO_SPK) ? 2 : 4); + if (!card->components) + return -ENOMEM; + card->long_name = sdw_card_long_name; - snprintf(components_string, sizeof(components_string), - "cfg-spk:%d", - (sof_rt711_rt1308_rt715_quirk & SOF_SDW_MONO_SPK) ? 2 : 4); -#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) - snprintf(sdw_card_long_name, sizeof(sdw_card_long_name), - "sof-sdw-rt711-%s-rt1308-rt715", - (sof_rt711_rt1308_rt715_quirk & SOF_SDW_MONO_SPK) ? - "mono" : "stereo"); - card_rt700_rt1308_rt715.long_name = sdw_card_long_name; -#endif /* Register the card */ ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { @@ -1335,18 +906,19 @@ static int mc_probe(struct platform_device *pdev) return ret; } -static struct platform_driver sdw_rt711_rt1308_rt715_driver = { +static struct platform_driver sof_sdw_driver = { .driver = { - .name = "sdw_rt711_rt1308_rt715", + .name = "sof_sdw", .pm = &snd_soc_pm_ops, }, .probe = mc_probe, }; -module_platform_driver(sdw_rt711_rt1308_rt715_driver); +module_platform_driver(sof_sdw_driver); -MODULE_DESCRIPTION("ASoC SoundWire RT711/1308/715 Machine driver"); +MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver"); MODULE_AUTHOR("Bard Liao "); +MODULE_AUTHOR("Rander Wang "); MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sdw_rt711_rt1308_rt715"); +MODULE_ALIAS("platform:sof_sdw"); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h new file mode 100644 index 00000000000000..893c4f9e10df72 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2020 Intel Corporation + */ + +/* + * sof_sdw_common.h - prototypes for common helpers + */ + +#ifndef SND_SOC_SOF_SDW_COMMON_H +#define SND_SOC_SOF_SDW_COMMON_H + +#include +#include + +#define MAX_NO_PROPS 2 +#define MAX_HDMI_NUM 4 +#define SDW_DMIC_DAI_ID 4 +#define SDW_MAX_CPU_DAIS 16 +#define SDW_INTEL_BIDIR_PDI_BASE 2 + +/* 8 combinations with 4 links + unused group 0 */ +#define SDW_MAX_GROUPS 9 + +enum { + SOF_RT711_JD_SRC_JD1 = 1, + SOF_RT711_JD_SRC_JD2 = 2, +}; + +enum { + SOF_PRE_TGL_HDMI_COUNT = 3, + SOF_TGL_HDMI_COUNT = 4, +}; + +enum { + SOF_I2S_SSP0 = BIT(0), + SOF_I2S_SSP1 = BIT(1), + SOF_I2S_SSP2 = BIT(2), + SOF_I2S_SSP3 = BIT(3), + SOF_I2S_SSP4 = BIT(4), + SOF_I2S_SSP5 = BIT(5), +}; + +#define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) +#define SOF_SDW_MONO_SPK BIT(2) +#define SOF_SDW_TGL_HDMI BIT(3) +#define SOF_SDW_PCH_DMIC BIT(4) +#define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 5) +#define SOF_SSP_GET_PORT(quirk) (((quirk) >> 5) & GENMASK(5, 0)) +#define SOF_RT715_DAI_ID_FIX BIT(11) +#define SOF_SDW_NO_AGGREGATION BIT(12) + +struct sof_sdw_codec_info { + const int id; + int amp_num; + const u8 acpi_id[ACPI_ID_LEN]; + const bool direction[2]; // playback & capture support + const char *dai_name; + const struct snd_soc_ops *ops; + + int (*init)(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); +}; + +struct mc_private { + struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; + struct snd_soc_jack sdw_headset; +}; + +extern unsigned long sof_sdw_quirk; + +/* generic HDMI support */ +int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd); + +int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card); + +/* DMIC support */ +int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); + +/* RT711 support */ +int sof_sdw_rt711_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + +/* RT700 support */ +int sof_sdw_rt700_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + +/* RT1308 support */ +extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops; + +int sof_sdw_rt1308_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + +/* RT715 support */ +int sof_sdw_rt715_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback); + +#endif diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/intel/boards/sof_sdw_dmic.c new file mode 100644 index 00000000000000..e92176bf0ad40f --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_dmic.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_dmic - Helpers to handle dmic from generic machine driver + */ + +#include +#include +#include "sof_sdw_common.h" + +static const struct snd_soc_dapm_widget dmic_widgets[] = { + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route dmic_map[] = { + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, +}; + +int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ARRAY_SIZE(dmic_widgets)); + if (ret) { + dev_err(card->dev, "DMic widget addition failed: %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ARRAY_SIZE(dmic_map)); + + if (ret) + dev_err(card->dev, "DMic map addition failed: %d\n", ret); + + return ret; +} + diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c new file mode 100644 index 00000000000000..c7b5612a39e6a1 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_hdmi - Helpers to handle HDMI from generic machine driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sof_sdw_common.h" +#include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +static struct snd_soc_jack hdmi[MAX_HDMI_NUM]; + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +#define NAME_SIZE 32 +int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + 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, &hdmi[i], + NULL, 0); + + if (err) + return err; + + err = snd_jack_add_new_kctl(hdmi[i].jack, + jack_name, SND_JACK_AVOUT); + if (err) + dev_warn(component->dev, "failed creating Jack kctl\n"); + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} +#else +int hdmi_card_late_probe(struct snd_soc_card *card) +{ + return 0; +} +#endif diff --git a/sound/soc/intel/boards/sof_sdw_rt1308.c b/sound/soc/intel/boards/sof_sdw_rt1308.c new file mode 100644 index 00000000000000..321768e54d08a0 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt1308.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver + */ + +#include +#include +#include +#include +#include "sof_sdw_common.h" +#include "../../codecs/rt1308.h" + +static const struct snd_soc_dapm_widget rt1308_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +/* + * dapm routes for rt1308 will be registered dynamically according + * to the number of rt1308 used. The first two entries will be registered + * for one codec case, and the last two entries are also registered + * if two 1308s are used. + */ +static const struct snd_soc_dapm_route rt1308_map[] = { + { "Speaker", NULL, "rt1308-1 SPOL" }, + { "Speaker", NULL, "rt1308-1 SPOR" }, + { "Speaker", NULL, "rt1308-2 SPOL" }, + { "Speaker", NULL, "rt1308-2 SPOR" }, +}; + +static const struct snd_kcontrol_new rt1308_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int first_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:rt1308", + card->components); + if (!card->components) + return -ENOMEM; + + ret = snd_soc_add_card_controls(card, rt1308_controls, + ARRAY_SIZE(rt1308_controls)); + if (ret) { + dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets, + ARRAY_SIZE(rt1308_widgets)); + if (ret) { + dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2); + if (ret) + dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); + + return ret; +} + +static int second_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2); + if (ret) + dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret); + + return ret; +} + +static int all_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + + ret = first_spk_init(rtd); + if (ret) + return ret; + + return second_spk_init(rtd); +} + +static int rt1308_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_card *card = rtd->card; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int clk_id, clk_freq, pll_out; + int err; + + clk_id = RT1308_PLL_S_MCLK; + clk_freq = 38400000; + + pll_out = params_rate(params) * 512; + + /* Set rt1308 pll */ + err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (err < 0) { + dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err); + return err; + } + + /* Set rt1308 sysclk */ + err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err); + return err; + } + + return 0; +} + +/* machine stream operations */ +struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { + .hw_params = rt1308_i2s_hw_params, +}; + +int sof_sdw_rt1308_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + info->amp_num++; + if (info->amp_num == 1) + dai_links->init = first_spk_init; + + if (info->amp_num == 2) { + /* + * if two 1308s are in one dai link, the init function + * in this dai link will be first set for the first speaker, + * and it should be reset to initialize all speakers when + * the second speaker is found. + */ + if (dai_links->init) + dai_links->init = all_spk_init; + else + dai_links->init = second_spk_init; + } + + return 0; +} diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c new file mode 100644 index 00000000000000..2ee4e6910d7f97 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt700.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt700 - Helpers to handle RT700 from generic machine driver + */ + +#include +#include +#include +#include +#include +#include +#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, "HP" }, + { "Speaker", NULL, "SPK" }, + { "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", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "AMIC", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s hs:rt700", + card->components); + if (!card->components) + return -ENOMEM; + + ret = snd_soc_add_card_controls(card, rt700_controls, + ARRAY_SIZE(rt700_controls)); + if (ret) { + dev_err(card->dev, "rt700 controls addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(&card->dapm, rt700_widgets, + ARRAY_SIZE(rt700_widgets)); + if (ret) { + dev_err(card->dev, "rt700 widgets addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt700_map, + ARRAY_SIZE(rt700_map)); + + if (ret) { + dev_err(card->dev, "rt700 map addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt700_jack_pins, + ARRAY_SIZE(rt700_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", + ret); + return ret; + } + + jack = &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} + +int sof_sdw_rt700_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* + * headset should be initialized once. + * Do it with dai link for playback. + */ + if (!playback) + return 0; + + dai_links->init = rt700_rtd_init; + + return 0; +} diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c new file mode 100644 index 00000000000000..2a4917e3d56148 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt711.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt711 - Helpers to handle RT711 from generic machine driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof_sdw_common.h" + +/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int rt711_add_codec_device_props(const char *sdw_dev_name) +{ + struct property_entry props[MAX_NO_PROPS] = {}; + struct device *sdw_dev; + int ret; + + sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_dev_name); + if (!sdw_dev) + return -EPROBE_DEFER; + + if (SOF_RT711_JDSRC(sof_sdw_quirk)) { + props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", + SOF_RT711_JDSRC(sof_sdw_quirk)); + } + + ret = device_add_properties(sdw_dev, props); + put_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", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s hs:rt711", + card->components); + if (!card->components) + return -ENOMEM; + + ret = snd_soc_add_card_controls(card, rt711_controls, + ARRAY_SIZE(rt711_controls)); + if (ret) { + dev_err(card->dev, "rt711 controls addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(&card->dapm, rt711_widgets, + ARRAY_SIZE(rt711_widgets)); + if (ret) { + dev_err(card->dev, "rt711 widgets addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt711_map, + ARRAY_SIZE(rt711_map)); + + if (ret) { + dev_err(card->dev, "rt711 map addition failed: %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + rt711_jack_pins, + ARRAY_SIZE(rt711_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", + ret); + return ret; + } + + jack = &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} + +int sof_sdw_rt711_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + int ret; + + /* + * headset should be initialized once. + * Do it with dai link for playback. + */ + if (!playback) + return 0; + + ret = rt711_add_codec_device_props("sdw:0:25d:711:0"); + if (ret < 0) + return ret; + + dai_links->init = rt711_rtd_init; + + return 0; +} diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c new file mode 100644 index 00000000000000..321e1cbc03ed72 --- /dev/null +++ b/sound/soc/intel/boards/sof_sdw_rt715.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation + +/* + * sof_sdw_rt715 - Helpers to handle RT715 from generic machine driver + */ + +#include +#include +#include +#include +#include "sof_sdw_common.h" + +static int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:rt715", + card->components); + if (!card->components) + return -ENOMEM; + + return 0; +} + +int sof_sdw_rt715_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* + * DAI ID is fixed at SDW_DMIC_DAI_ID for 715 to + * keep sdw DMIC and HDMI setting static in UCM + */ + if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX) + dai_links->id = SDW_DMIC_DAI_ID; + + dai_links->init = rt715_rtd_init; + + return 0; +} From df287ca112548a078329cc52835e7c004e216536 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Mar 2020 14:43:15 -0500 Subject: [PATCH 5/6] ASoC: Intel: boards: sof_sdw: redefined MONO_SPK quirk Flip the definition for this quirk. By default let's assume 2 speakers and add 4 speakers configurations as needed for some devices. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/sof_sdw.c | 4 ++-- sound/soc/intel/boards/sof_sdw_common.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index c0a829ab692974..a5bd13d3f7e80d 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -32,7 +32,6 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), }, .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | - SOF_SDW_MONO_SPK | SOF_RT715_DAI_ID_FIX), }, { @@ -43,6 +42,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | SOF_RT715_DAI_ID_FIX | + SOF_SDW_FOUR_SPK | SOF_SDW_NO_AGGREGATION), }, { @@ -888,7 +888,7 @@ static int mc_probe(struct platform_device *pdev) card->components = devm_kasprintf(card->dev, GFP_KERNEL, "cfg-spk:%d", - (sof_sdw_quirk & SOF_SDW_MONO_SPK) ? 2 : 4); + (sof_sdw_quirk & SOF_SDW_FOUR_SPK) ? 4 : 2); if (!card->components) return -ENOMEM; diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 893c4f9e10df72..0d738e234bc5b1 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -41,7 +41,7 @@ enum { }; #define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) -#define SOF_SDW_MONO_SPK BIT(2) +#define SOF_SDW_FOUR_SPK BIT(2) #define SOF_SDW_TGL_HDMI BIT(3) #define SOF_SDW_PCH_DMIC BIT(4) #define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 5) From a27eabc671eb753c2297f9c50fd4ff5f16970238 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Mar 2020 15:50:03 -0500 Subject: [PATCH 6/6] ASoC: Intel: sof_sdw: only init DMICs once Avoid the following warning when using the same init function for the two DMIC dailinks [ 2.224651] debugfs: File 'SoC DMIC' in directory 'dapm' already present! Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/sof_sdw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index a5bd13d3f7e80d..64e3a98bef6951 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -796,7 +796,8 @@ static int sof_card_dai_links_create(struct device *dev, 0, 1, // DMIC only supports capture cpus + cpu_id, 1, dmic_component, 1, - sof_sdw_dmic_init, NULL); + /* don't call sof_sdw_dmic_init() twice */ + NULL, NULL); INC_ID(be_id, cpu_id, link_id); }