diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 38ccec4e3fcd95..b6d301946244e6 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -70,6 +70,7 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode * @subsystem_vendor: optional PCI SSID vendor value * @subsystem_device: optional PCI SSID device value + * @subsystem_rev: optional PCI SSID revision value * @subsystem_id_set: true if a value has been written to * subsystem_vendor and subsystem_device. */ @@ -86,6 +87,7 @@ struct snd_soc_acpi_mach_params { struct snd_soc_dai_driver *dai_drivers; unsigned short subsystem_vendor; unsigned short subsystem_device; + unsigned short subsystem_rev; bool subsystem_id_set; }; diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h new file mode 100644 index 00000000000000..e366b7968c2d02 --- /dev/null +++ b/include/sound/soc_sdw_utils.h @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * This file incorporates work covered by the following copyright notice: + * Copyright (c) 2020 Intel Corporation + * Copyright(c) 2024 Advanced Micro Devices, Inc. + * + */ + +#ifndef SOC_SDW_UTILS_H +#define SOC_SDW_UTILS_H + +#include +#include + +#define SOC_SDW_MAX_DAI_NUM 8 +#define SOC_SDW_MAX_NO_PROPS 2 +#define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) + +/* If a CODEC has an optional speaker output, this quirk will enable it */ +#define SOC_SDW_CODEC_SPKR BIT(15) +/* + * If the CODEC has additional devices attached directly to it. + * + * For the cs42l43: + * - 0 - No speaker output + * - SOC_SDW_CODEC_SPKR - CODEC internal speaker + * - SOC_SDW_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker + * - SOC_SDW_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported + */ +#define SOC_SDW_SIDECAR_AMPS BIT(16) + +#define SOC_SDW_UNUSED_DAI_ID -1 +#define SOC_SDW_JACK_OUT_DAI_ID 0 +#define SOC_SDW_JACK_IN_DAI_ID 1 +#define SOC_SDW_AMP_OUT_DAI_ID 2 +#define SOC_SDW_AMP_IN_DAI_ID 3 +#define SOC_SDW_DMIC_DAI_ID 4 + +#define SOC_SDW_DAI_TYPE_JACK 0 +#define SOC_SDW_DAI_TYPE_AMP 1 +#define SOC_SDW_DAI_TYPE_MIC 2 + +struct asoc_sdw_codec_info; + +struct asoc_sdw_dai_info { + const bool direction[2]; /* playback & capture support */ + const char *dai_name; + const int dai_type; + const int dailink[2]; /* dailink id for each direction */ + 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, + struct snd_soc_dai_link *dai_links, + struct asoc_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, struct snd_soc_dai *dai); + bool rtd_init_done; /* Indicate that the rtd_init callback is done */ + unsigned long quirk; +}; + +struct asoc_sdw_codec_info { + const int part_id; + const int version_id; + const char *codec_name; + int amp_num; + const u8 acpi_id[ACPI_ID_LEN]; + const bool ignore_internal_dmic; + const struct snd_soc_ops *ops; + struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM]; + 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 asoc_sdw_mc_private { + struct snd_soc_card card; + struct snd_soc_jack sdw_headset; + struct device *headset_codec_dev; /* only one headset per card */ + struct device *amp_dev1, *amp_dev2; + bool append_dai_type; + bool ignore_internal_dmic; + void *private; + unsigned long mc_quirk; + int codec_info_list_count; +}; + +extern struct asoc_sdw_codec_info codec_info_list[]; +int asoc_sdw_get_codec_info_list_count(void); + +int asoc_sdw_startup(struct snd_pcm_substream *substream); +int asoc_sdw_prepare(struct snd_pcm_substream *substream); +int asoc_sdw_prepare(struct snd_pcm_substream *substream); +int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd); +int asoc_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int asoc_sdw_hw_free(struct snd_pcm_substream *substream); +void asoc_sdw_shutdown(struct snd_pcm_substream *substream); + +const char *asoc_sdw_get_codec_name(struct device *dev, + const struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, + int *dai_index); + +struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, + const char *dai_name); + +void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card); + +int asoc_sdw_card_late_probe(struct snd_soc_card *card); + +void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + struct snd_soc_dai_link_component *cpus, int cpus_num, + struct snd_soc_dai_link_component *platform_component, + int num_platforms, struct snd_soc_dai_link_component *codecs, + int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops); + +int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + const char *cpu_dai_name, const char *platform_comp_name, + int num_platforms, const char *codec_name, + const char *codec_dai_name, + int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops); + +int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd); + +/* DMIC support */ +int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); + +/* RT711 support */ +int asoc_sdw_rt711_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); +int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + +/* RT711-SDCA support */ +int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); +int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + +/* RT1308 I2S support */ +extern const struct snd_soc_ops soc_sdw_rt1308_i2s_ops; + +/* generic amp support */ +int asoc_sdw_rt_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); +int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); + +/* CS42L43 support */ +int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +/* CS AMP support */ +int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, + int *num_dais, int *num_devs); +int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf); +int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +int asoc_sdw_cs_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +/* MAXIM codec support */ +int asoc_sdw_maxim_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback); + +/* dai_link init callbacks */ +int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); + +#endif diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index a52afb423b46bf..e87bd15a8b4393 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -126,6 +126,8 @@ source "sound/soc/xtensa/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" +source "sound/soc/sdw_utils/Kconfig" + # generic frame-work source "sound/soc/generic/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index fd61847dd1eb67..775bb38c2ed447 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_SND_SOC) += uniphier/ obj-$(CONFIG_SND_SOC) += ux500/ obj-$(CONFIG_SND_SOC) += xilinx/ obj-$(CONFIG_SND_SOC) += xtensa/ +obj-$(CONFIG_SND_SOC) += sdw_utils/ diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 30590a23ad63b4..88391e4c17e3c6 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -13,6 +13,10 @@ config SND_SOC_AMD_ACP_COMMON This option enables common modules for Audio-Coprocessor i.e. ACP IP block on AMD platforms. +config SND_SOC_ACPI_AMD_MATCH + tristate + select SND_SOC_ACPI if ACPI + if SND_SOC_AMD_ACP_COMMON config SND_SOC_AMD_ACP_PDM @@ -115,6 +119,24 @@ config SND_SOC_AMD_SOF_MACH help This option enables SOF sound card support for ACP audio. +config SND_SOC_AMD_SOF_SDW_MACH + tristate "AMD SOF Soundwire Machine Driver Support" + depends on X86 && PCI && ACPI + depends on SOUNDWIRE + select SND_SOC_SDW_UTILS + select SND_SOC_DMIC + select SND_SOC_RT711_SDW + select SND_SOC_RT711_SDCA_SDW + select SND_SOC_RT1316_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW + help + This option enables SOF sound card support for SoundWire enabled + AMD platforms along with ACP PDM controller. + Say Y if you want to enable SoundWire based machine driver support + on AMD platform. + If unsure select "N". + endif # SND_SOC_AMD_ACP_COMMON config SND_AMD_SOUNDWIRE_ACPI diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index b068bf1f920ede..82cf5d180b3a14 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -22,6 +22,8 @@ snd-acp70-y := acp70.o snd-acp-mach-y := acp-mach-common.o snd-acp-legacy-mach-y := acp-legacy-mach.o acp3x-es83xx/acp3x-es83xx.o snd-acp-sof-mach-y := acp-sof-mach.o +snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o +snd-acp-sdw-sof-mach-y += acp-sdw-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 @@ -38,3 +40,5 @@ obj-$(CONFIG_SND_AMD_SOUNDWIRE_ACPI) += snd-amd-sdw-acpi.o obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o +obj-$(CONFIG_SND_SOC_ACPI_AMD_MATCH) += snd-soc-acpi-amd-match.o +obj-$(CONFIG_SND_SOC_AMD_SOF_SDW_MACH) += snd-acp-sdw-sof-mach.o diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c new file mode 100644 index 00000000000000..3419675e45a986 --- /dev/null +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -0,0 +1,742 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Advanced Micro Devices, Inc. + +/* + * acp-sdw-sof-mach - ASoC Machine driver for AMD SoundWire platforms + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "soc_amd_sdw_common.h" +#include "../../codecs/rt711.h" + +static unsigned long sof_sdw_quirk = RT711_JD1; +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (SOC_JACK_JDSRC(sof_sdw_quirk)) + dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", + SOC_JACK_JDSRC(sof_sdw_quirk)); + if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC) + dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n"); +} + +static int sof_sdw_quirk_cb(const struct dmi_system_id *id) +{ + sof_sdw_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id sof_sdw_quirk_table[] = { + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AMD"), + DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"), + }, + .driver_data = (void *)RT711_JD2, + }, + {} +}; + +static struct snd_soc_dai_link_component platform_component[] = { + { + /* name might be overridden during probe */ + .name = "0000:04:00.5", + } +}; + +static const struct snd_soc_ops sdw_ops = { + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, +}; + +/* + * 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) +{ + bool group_visited[AMD_SDW_MAX_GROUPS]; + int i; + int j; + + *sdw_be_num = 0; + + if (!adr_link) + return -EINVAL; + + for (i = 0; i < AMD_SDW_MAX_GROUPS; i++) + group_visited[i] = false; + + for (; adr_link->num_adr; adr_link++) { + const struct snd_soc_acpi_endpoint *endpoint; + struct asoc_sdw_codec_info *codec_info; + 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_info = asoc_sdw_find_codec_info_part(adr); + if (!codec_info) + return -EINVAL; + + *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; + + /* count BE for each non-aggregated slave or group */ + if (!endpoint->aggregated || + !group_visited[endpoint->group_id]) + (*sdw_be_num)++; + } + } + + if (endpoint->aggregated) + group_visited[endpoint->group_id] = true; + } + } + return 0; +} + +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) +{ + u64 adr = adr_link->adr_d[adr_index].adr; + struct asoc_sdw_codec_info *codec_info; + + codec_info = asoc_sdw_find_codec_info_part(adr); + if (!codec_info) + return -EINVAL; + + codec->name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, adr_index); + if (!codec->name) + return -ENOMEM; + + codec->dai_name = codec_info->dais[dai_index].dai_name; + dev_err(dev, "codec->dai_name:%s\n", codec->dai_name); + return 0; +} + +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) +{ + int i = adr_index; + + 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) + */ + for ( ; i < adr_link->num_adr; i++) { + struct asoc_sdw_codec_info *codec_info; + + codec_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[i].adr); + if (!codec_info) + return -EINVAL; + + /* The group_id is > 0 iff the codec is aggregated */ + if (adr_link->adr_d[i].endpoints->group_id != group_id) + continue; + if (codec_info->dais[dai_index].init) + codec_info->dais[dai_index].init(card, + dai_links, + codec_info, + playback); + + if (!group_id) + return 0; + } + + i = 0; + adr_link++; + } while (adr_link->mask); + + 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 = 1 + * one sdw BE DAI <---> one-cpu DAI <---> multi-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) +{ + int i; + + if (!adr_link->adr_d[adr_index].endpoints->aggregated) { + cpu_dai_id[0] = ffs(adr_link->mask) - 1; + *cpu_dai_num = 1; + *codec_num = 1; + *group_id = 0; + return 0; + } + + *codec_num = 0; + *cpu_dai_num = 0; + *group_id = adr_link->adr_d[adr_index].endpoints->group_id; + + /* 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; + + 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++; + } + + if (link_codecs) { + *codec_num += link_codecs; + + if (*cpu_dai_num >= ACP63_SDW_MAX_CPU_DAIS) { + dev_err(dev, "cpu_dai_id array overflowed\n"); + return -EINVAL; + } + + cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; + } + } + + return 0; +} + +static int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev) +{ + switch (sdw_link_id) { + case AMD_SDW0: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO0_RX; + break; + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO1_TX; + break; + case SOC_SDW_AMP_IN_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO1_RX; + break; + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO2_RX; + break; + default: + dev_err(dev, "Invalid be id:%d\n", be_id); + return -EINVAL; + } + break; + case AMD_SDW1: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW1_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + case SOC_SDW_AMP_IN_DAI_ID: + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP63_SW1_AUDIO0_RX; + break; + default: + dev_err(dev, "invalid be_id:%d\n", be_id); + return -EINVAL; + } + break; + default: + dev_err(dev, "Invalid link id:%d\n", sdw_link_id); + return -EINVAL; + } + return 0; +} + +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; + +static int create_sdw_dailink(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + const struct snd_soc_acpi_link_adr *adr_link, + struct snd_soc_codec_conf **codec_conf, + int *be_id, int adr_index, int dai_index) +{ + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private; + struct device *dev = card->dev; + const struct snd_soc_acpi_link_adr *adr_link_next; + struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + struct asoc_sdw_codec_info *codec_info; + int cpu_dai_id[ACP63_SDW_MAX_CPU_DAIS]; + int cpu_dai_num; + unsigned int group_id; + unsigned int sdw_link_id; + int codec_dlc_index = 0; + int codec_num; + int stream; + int i = 0; + int j, k; + int ret; + int cpu_pin_id; + + ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, + &group_id, adr_index); + if (ret) + return ret; + codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; + + sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, + sizeof(*sdw_codec_ch_maps), GFP_KERNEL); + if (!sdw_codec_ch_maps) + return -ENOMEM; + + /* 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; + + /* j reset after loop, adr_index only applies to first link */ + for (k = 0 ; (j < adr_link_next->num_adr) && (k < codec_num) ; j++, k++) { + const struct snd_soc_acpi_endpoint *endpoints; + + endpoints = adr_link_next->adr_d[j].endpoints; + if (group_id && (!endpoints->aggregated || + endpoints->group_id != group_id)) + continue; + + /* sanity check */ + if (*codec_conf >= card->codec_conf + card->num_configs) { + dev_err(dev, "codec_conf array overflowed\n"); + return -EINVAL; + } + + ret = fill_sdw_codec_dlc(dev, adr_link_next, + &codecs[codec_dlc_index], + j, dai_index); + if (ret) + return ret; + (*codec_conf)->dlc = codecs[codec_dlc_index]; + (*codec_conf)->name_prefix = adr_link_next->adr_d[j].name_prefix; + + sdw_codec_ch_maps[codec_dlc_index].cpu = i; + sdw_codec_ch_maps[codec_dlc_index].codec = codec_dlc_index; + + codec_dlc_index++; + (*codec_conf)++; + } + j = 0; + + /* check next link to create codec dai in the processed group */ + i++; + } + + /* find codec info to create BE DAI */ + codec_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[adr_index].adr); + if (!codec_info) + return -EINVAL; + + ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; + + sdw_link_id = (adr_link->adr_d[adr_index].adr) >> 48; + for_each_pcm_streams(stream) { + char *name, *cpu_name; + int playback, capture; + static const char * const sdw_stream_name[] = { + "SDW%d-PIN%d-PLAYBACK", + "SDW%d-PIN%d-CAPTURE", + "SDW%d-PIN%d-PLAYBACK-%s", + "SDW%d-PIN%d-CAPTURE-%s", + }; + + if (!codec_info->dais[dai_index].direction[stream]) + continue; + + *be_id = codec_info->dais[dai_index].dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); + return -EINVAL; + } + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + ret = get_acp63_cpu_pin_id(sdw_link_id, *be_id, &cpu_pin_id, dev); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + /* create stream name according to first link id */ + if (ctx->append_dai_type) { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream + 2], sdw_link_id, cpu_pin_id, + type_strings[codec_info->dais[dai_index].dai_type]); + } else { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream], sdw_link_id, cpu_pin_id); + } + if (!name) + return -ENOMEM; + + cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; + /* + * generate CPU DAI name base on the sdw link ID and + * cpu pin id according to sdw dai driver. + */ + for (k = 0; k < cpu_dai_num; k++) { + cpu_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", sdw_link_id, cpu_pin_id); + if (!cpu_name) + return -ENOMEM; + + cpus[k].dai_name = cpu_name; + } + + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); + capture = (stream == SNDRV_PCM_STREAM_CAPTURE); + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, + playback, capture, + cpus, cpu_dai_num, + platform_component, ARRAY_SIZE(platform_component), + codecs, codec_num, + asoc_sdw_rtd_init, &sdw_ops); + /* + * SoundWire DAILINKs use 'stream' functions and Bank Switch operations + * based on wait_for_completion(), tag them as 'nonatomic'. + */ + (*dai_links)->nonatomic = true; + (*dai_links)->ch_maps = sdw_codec_ch_maps; + + ret = set_codec_init_func(card, adr_link, *dai_links, + playback, group_id, adr_index, dai_index); + if (ret < 0) { + dev_err(dev, "failed to init codec 0x%x\n", codec_info->part_id); + 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 = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec", + 0, 1, // DMIC only supports capture + "acp-sof-dmic", platform_component->name, + ARRAY_SIZE(platform_component), + "dmic-codec", "dmic-hifi", + asoc_sdw_dmic_init, NULL); + if (ret) + return ret; + + (*dai_links)++; + + return 0; +} + +static int sof_card_dai_links_create(struct snd_soc_card *card) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + int sdw_be_num = 0, dmic_num = 0; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; + struct snd_soc_codec_conf *codec_conf; + int codec_conf_num = 0; + bool group_generated[AMD_SDW_MAX_GROUPS] = { }; + struct snd_soc_dai_link *dai_links; + struct asoc_sdw_codec_info *codec_info; + int num_links; + int i, j, be_id = 0; + int ret; + + ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num); + if (ret < 0) { + dev_err(dev, "failed to get sdw link info %d\n", ret); + return ret; + } + + /* enable dmic */ + if (sof_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num) + dmic_num = 1; + + dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); + + /* allocate BE dailinks */ + num_links = sdw_be_num + dmic_num; + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) + return -ENOMEM; + + /* 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; + + card->dai_link = dai_links; + card->num_links = num_links; + card->codec_conf = codec_conf; + card->num_configs = codec_conf_num; + + /* SDW */ + if (!sdw_be_num) + goto DMIC; + + 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_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[i].adr); + if (!codec_info) + return -EINVAL; + if (codec_info->dai_num > 1) { + ctx->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))) { + ctx->append_dai_type = true; + goto out; + } + } + } + } +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_info = asoc_sdw_find_codec_info_part(adr_link->adr_d[i].adr); + if (!codec_info) + return -EINVAL; + + for (j = 0; j < codec_info->dai_num ; j++) { + int current_be_id; + + ret = create_sdw_dailink(card, &dai_links, adr_link, + &codec_conf, ¤t_be_id, + i, j); + if (ret < 0) { + dev_err(dev, + "failed to create dai link %d on 0x%x\n", + j, codec_info->part_id); + 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; + } + + if (endpoint->aggregated) + group_generated[endpoint->group_id] = true; + } + } + +DMIC: + /* dmic */ + if (dmic_num > 0) { + if (ctx->ignore_internal_dmic) { + dev_warn(dev, "Ignoring ACP DMIC\n"); + } else { + be_id = SOC_SDW_DMIC_DAI_ID; + ret = create_dmic_dailinks(card, &dai_links, &be_id); + if (ret) + return ret; + } + } + + WARN_ON(dai_links != card->dai_link + card->num_links); + return 0; +} + +/* SoC card */ +static const char sdw_card_long_name[] = "AMD Soundwire SOF"; + +static int mc_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); + struct snd_soc_card *card; + struct amd_mc_ctx *amd_ctx; + struct asoc_sdw_mc_private *ctx; + int amp_num = 0, i; + int ret; + + amd_ctx = devm_kzalloc(&pdev->dev, sizeof(*amd_ctx), GFP_KERNEL); + if (!amd_ctx) + return -ENOMEM; + + amd_ctx->acp_rev = mach->mach_params.subsystem_rev; + amd_ctx->max_sdw_links = ACP63_SDW_MAX_LINKS; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); + ctx->private = amd_ctx; + card = &ctx->card; + card->dev = &pdev->dev; + card->name = "amd-soundwire", + card->owner = THIS_MODULE, + card->late_probe = asoc_sdw_card_late_probe, + + snd_soc_card_set_drvdata(card, ctx); + + dmi_check_system(sof_sdw_quirk_table); + + if (quirk_override != -1) { + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + sof_sdw_quirk, quirk_override); + sof_sdw_quirk = quirk_override; + } + + log_quirks(card->dev); + + ctx->mc_quirk = sof_sdw_quirk; + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ctx->codec_info_list_count; i++) + codec_info_list[i].amp_num = 0; + + ret = sof_card_dai_links_create(card); + if (ret < 0) + return ret; + + /* + * the default amp_num is zero for each codec and + * amp_num will only be increased for active amp + * codecs on used platform + */ + for (i = 0; i < ctx->codec_info_list_count; i++) + amp_num += codec_info_list[i].amp_num; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + " cfg-amp:%d", amp_num); + if (!card->components) + return -ENOMEM; + + card->long_name = sdw_card_long_name; + + /* Register the card */ + ret = devm_snd_soc_register_card(card->dev, card); + if (ret) { + dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + asoc_sdw_mc_dailink_exit_loop(card); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static void mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + asoc_sdw_mc_dailink_exit_loop(card); +} + +static const struct platform_device_id mc_id_table[] = { + { "amd_sof_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + +static struct platform_driver sof_sdw_driver = { + .driver = { + .name = "amd_sof_sdw", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, + .remove_new = mc_remove, + .id_table = mc_id_table, +}; + +module_platform_driver(sof_sdw_driver); + +MODULE_DESCRIPTION("ASoC AMD SoundWire Generic Machine driver"); +MODULE_AUTHOR("Vijendar Mukunda +#include "../mach-config.h" + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0 +}; + +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1 +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1 +}; + +static const struct snd_soc_acpi_adr_device rt711_rt1316_group_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + }, + { + .adr = 0x000030025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + }, + { + .adr = 0x000032025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + }, +}; + +static const struct snd_soc_acpi_adr_device rt714_adr[] = { + { + .adr = 0x130025d071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + +static const struct snd_soc_acpi_link_adr acp63_4_in_1_sdca[] = { + { .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_rt1316_group_adr), + .adr_d = rt711_rt1316_group_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt714_adr), + .adr_d = rt714_adr, + }, + {} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = { + { + .link_mask = BIT(0) | BIT(1), + .links = acp63_4_in_1_sdca, + .drv_name = "amd_sof_sdw", + .sof_tplg_filename = "sof-acp_6_3-rt711-l0-rt1316-l0-rt714-l1.tplg", + .fw_filename = "sof-acp_6_3.ri", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_sdw_machines); + +MODULE_DESCRIPTION("AMD ACP6.3 tables and support for ACPI enumeration"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h new file mode 100644 index 00000000000000..f1bd5a7afc8eab --- /dev/null +++ b/sound/soc/amd/acp/soc_amd_sdw_common.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved + */ + +/* + * soc_amd_sdw_common.h - prototypes for common helpers + */ + +#ifndef SOC_AMD_SDW_COMMON_H +#define SOC_AMD_SDW_COMMON_H + +#include +#include +#include +#include + +#define ACP63_SDW_MAX_CPU_DAIS 8 +#define ACP63_SDW_MAX_LINKS 2 + +#define AMD_SDW_MAX_GROUPS 9 +#define ACP63_PCI_REV 0x63 +#define SOC_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) +#define ASOC_SDW_FOUR_SPK BIT(4) +#define ASOC_SDW_ACP_DMIC BIT(5) + +#define AMD_SDW0 0 +#define AMD_SDW1 1 +#define ACP63_SW0_AUDIO0_TX 0 +#define ACP63_SW0_AUDIO1_TX 1 +#define ACP63_SW0_AUDIO2_TX 2 + +#define ACP63_SW0_AUDIO0_RX 3 +#define ACP63_SW0_AUDIO1_RX 4 +#define ACP63_SW0_AUDIO2_RX 5 + +#define ACP63_SW1_AUDIO0_TX 0 +#define ACP63_SW1_AUDIO0_RX 1 + +struct amd_mc_ctx { + unsigned int acp_rev; + unsigned int max_sdw_links; +}; + +#endif diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 7af0f9cf392187..32aa8a6931f46c 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -23,6 +23,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f1faa5dd2a4fc9..3d59d6982763eb 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -656,6 +656,7 @@ 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_SDW_UTILS select SND_SOC_MAX98363 select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index dc6fe110f27976..5bd8dc2d166a67 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -35,15 +35,6 @@ 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_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 \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index e5feaef669d145..d258728d64cf51 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "sof_sdw_common.h" #include "../../codecs/rt711.h" @@ -23,24 +22,24 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { - if (SOF_JACK_JDSRC(sof_sdw_quirk)) + if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk)) dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", - SOF_JACK_JDSRC(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_FOUR_SPK) - dev_err(dev, "quirk SOF_SDW_FOUR_SPK enabled but no longer supported\n"); + SOC_SDW_JACK_JDSRC(sof_sdw_quirk)); + if (sof_sdw_quirk & SOC_SDW_FOUR_SPK) + dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n"); if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n"); - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC) - dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n"); + if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) + dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n"); if (SOF_SSP_GET_PORT(sof_sdw_quirk)) dev_dbg(dev, "SSP port %ld\n", SOF_SSP_GET_PORT(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) - dev_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"); + if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION) + dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n"); + if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR) + dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n"); + if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS) + dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n"); } static int sof_sdw_quirk_cb(const struct dmi_system_id *id) @@ -57,7 +56,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)SOC_SDW_PCH_DMIC, }, { .callback = sof_sdw_quirk_cb, @@ -99,7 +98,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)SOC_SDW_PCH_DMIC, }, /* TigerLake devices */ { @@ -111,7 +110,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD1 | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_SSP_PORT(SOF_I2S_SSP2)), }, { @@ -159,7 +158,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -170,7 +169,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), + SOC_SDW_PCH_DMIC), }, { /* @@ -185,7 +184,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -199,7 +198,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "8709"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -210,7 +209,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -221,7 +220,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -232,7 +231,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD2_100K), }, { @@ -243,7 +242,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD2_100K), }, /* TigerLake-SDCA devices */ @@ -293,7 +292,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -501,7 +500,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), }, - .driver_data = (void *)(SOF_SDW_PCH_DMIC | + .driver_data = (void *)(SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(1) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -529,7 +528,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") }, - .driver_data = (void *)(SOF_SIDECAR_AMPS), + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), }, { .callback = sof_sdw_quirk_cb, @@ -537,7 +536,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") }, - .driver_data = (void *)(SOF_SIDECAR_AMPS), + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), }, {} }; @@ -549,900 +548,15 @@ 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"), -}; - -/* these wrappers are only needed to avoid typecast compilation errors */ -int sdw_startup(struct snd_pcm_substream *substream) -{ - return sdw_startup_stream(substream); -} - -int sdw_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - return sdw_prepare_stream(sdw_stream); -} - -int sdw_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - int ret; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - ret = sdw_enable_stream(sdw_stream); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - ret = sdw_disable_stream(sdw_stream); - break; - default: - ret = -EINVAL; - break; - } - - if (ret) - dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); - - return ret; -} - -int sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link_ch_map *ch_maps; - int ch = params_channels(params); - unsigned int ch_mask; - int num_codecs; - int step; - int i; - - if (!rtd->dai_link->ch_maps) - return 0; - - /* Identical data will be sent to all codecs in playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ch_mask = GENMASK(ch - 1, 0); - step = 0; - } else { - num_codecs = rtd->dai_link->num_codecs; - - if (ch < num_codecs || ch % num_codecs != 0) { - dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", - ch, num_codecs); - return -EINVAL; - } - - ch_mask = GENMASK(ch / num_codecs - 1, 0); - step = hweight_long(ch_mask); - - } - - /* - * The captured data will be combined from each cpu DAI if the dai - * link has more than one codec DAIs. Set codec channel mask and - * ASoC will set the corresponding channel numbers for each cpu dai. - */ - for_each_link_ch_maps(rtd->dai_link, i, ch_maps) - ch_maps->ch_mask = ch_mask << (i * step); - - return 0; -} - -int sdw_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - return sdw_deprepare_stream(sdw_stream); -} - -void sdw_shutdown(struct snd_pcm_substream *substream) -{ - sdw_shutdown_stream(substream); -} - static const struct snd_soc_ops sdw_ops = { - .startup = sdw_startup, - .prepare = sdw_prepare, - .trigger = sdw_trigger, - .hw_params = sdw_hw_params, - .hw_free = sdw_hw_free, - .shutdown = sdw_shutdown, -}; - -static struct sof_sdw_codec_info codec_info_list[] = { - { - .part_id = 0x700, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt700-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .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, - }, - { - .part_id = 0x711, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt711-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .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, - }, - { - .part_id = 0x711, - .version_id = 2, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt711-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt711_init, - .exit = sof_sdw_rt711_exit, - .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, - }, - { - .part_id = 0x712, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt712-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .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, - }, - { - .part_id = 0x1712, - .version_id = 3, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt712-sdca-dmic-aif1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x713, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt712-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .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, - }, - { - .part_id = 0x1713, - .version_id = 3, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt712-sdca-dmic-aif1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1308, - .acpi_id = "10EC1308", - .dais = { - { - .direction = {true, false}, - .dai_name = "rt1308-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .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, - .ops = &sof_sdw_rt1308_i2s_ops, - }, - { - .part_id = 0x1316, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt1316-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .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, - }, - { - .part_id = 0x1318, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt1318-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .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, - }, - { - .part_id = 0x714, - .version_id = 3, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x715, - .version_id = 3, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x714, - .version_id = 2, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x715, - .version_id = 2, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x722, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt722-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .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 = "rt722-sdca-aif2", - .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_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}, - .rtd_init = rt_dmic_rtd_init, - }, - }, - .dai_num = 3, - }, - { - .part_id = 0x8373, - .dais = { - { - .direction = {true, true}, - .dai_name = "max98373-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_maxim_init, - .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, - }, - { - .part_id = 0x8363, - .dais = { - { - .direction = {true, false}, - .dai_name = "max98363-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_maxim_init, - .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, - }, - { - .part_id = 0x5682, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt5682-sdw", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .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, - }, - { - .part_id = 0x3556, - .dais = { - { - .direction = {true, true}, - .dai_name = "cs35l56-sdw1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_cs_amp_init, - .rtd_init = cs_spk_rtd_init, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x4242, - .dais = { - { - .direction = {true, true}, - .dai_name = "cs42l42-sdw", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .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, - }, - { - .part_id = 0x4243, - .codec_name = "cs42l43-codec", - .count_sidecar = bridge_cs35l56_count_sidecar, - .add_sidecar = bridge_cs35l56_add_sidecar, - .dais = { - { - .direction = {true, false}, - .dai_name = "cs42l43-dp5", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .rtd_init = cs42l43_hs_rtd_init, - .controls = generic_jack_controls, - .num_controls = ARRAY_SIZE(generic_jack_controls), - .widgets = generic_jack_widgets, - .num_widgets = ARRAY_SIZE(generic_jack_widgets), - }, - { - .direction = {false, true}, - .dai_name = "cs42l43-dp1", - .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}, - .dai_name = "cs42l43-dp2", - .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, - .controls = generic_spk_controls, - .num_controls = ARRAY_SIZE(generic_spk_controls), - .widgets = generic_spk_widgets, - .num_widgets = ARRAY_SIZE(generic_spk_widgets), - .quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS, - }, - }, - .dai_num = 4, - }, - { - .part_id = 0xaaaa, /* generic codec mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0xaa55, /* headset codec mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x55aa, /* amplifier mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x5555, - .version_id = 0, - .dais = { - { - .dai_name = "sdw-mockup-aif1", - .direction = {false, true}, - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - }, - }, - .dai_num = 1, - }, + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, }; -static struct sof_sdw_codec_info *find_codec_info_part(const u64 adr) -{ - unsigned int part_id, sdw_version; - int i; - - part_id = SDW_PART_ID(adr); - sdw_version = SDW_VERSION(adr); - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - /* - * A codec info is for all sdw version with the part id if - * version_id is not specified in the codec info. - */ - if (part_id == codec_info_list[i].part_id && - (!codec_info_list[i].version_id || - sdw_version == codec_info_list[i].version_id)) - return &codec_info_list[i]; - - return NULL; - -} - -static struct sof_sdw_codec_info *find_codec_info_acpi(const u8 *acpi_id) -{ - int i; - - if (!acpi_id[0]) - return NULL; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) - return &codec_info_list[i]; - - return NULL; -} - -static struct sof_sdw_codec_info *find_codec_info_dai(const char *dai_name, - int *dai_index) -{ - int i, j; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - for (j = 0; j < codec_info_list[i].dai_num; j++) { - if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { - *dai_index = j; - return &codec_info_list[i]; - } - } - } - - return NULL; -} - -static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, - int *be_id, char *name, int playback, int capture, - struct snd_soc_dai_link_component *cpus, int cpus_num, - struct snd_soc_dai_link_component *codecs, int codecs_num, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); - dai_links->id = (*be_id)++; - dai_links->name = name; - dai_links->platforms = platform_component; - dai_links->num_platforms = ARRAY_SIZE(platform_component); - dai_links->no_pcm = 1; - dai_links->cpus = cpus; - dai_links->num_cpus = cpus_num; - dai_links->codecs = codecs; - dai_links->num_codecs = codecs_num; - dai_links->dpcm_playback = playback; - dai_links->dpcm_capture = capture; - dai_links->init = init; - dai_links->ops = ops; -} - -static int init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, - int *be_id, char *name, int playback, int capture, - const char *cpu_dai_name, - const char *codec_name, const char *codec_dai_name, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - struct snd_soc_dai_link_component *dlc; - - /* Allocate two DLCs one for the CPU, one for the CODEC */ - dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); - if (!dlc || !name || !cpu_dai_name || !codec_name || !codec_dai_name) - return -ENOMEM; - - dlc[0].dai_name = cpu_dai_name; - - dlc[1].name = codec_name; - dlc[1].dai_name = codec_dai_name; - - init_dai_link(dev, dai_links, be_id, name, playback, capture, - &dlc[0], 1, &dlc[1], 1, init, ops); - - return 0; -} - -static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, - unsigned int sdw_version, - unsigned int mfg_id, - unsigned int part_id, - unsigned int class_id, - int index_in_link) -{ - int i; - - for (i = 0; i < adr_link->num_adr; i++) { - unsigned int sdw1_version, mfg1_id, part1_id, class1_id; - u64 adr; - - /* skip itself */ - if (i == index_in_link) - continue; - - adr = adr_link->adr_d[i].adr; - - sdw1_version = SDW_VERSION(adr); - mfg1_id = SDW_MFG_ID(adr); - part1_id = SDW_PART_ID(adr); - class1_id = SDW_CLASS_ID(adr); - - if (sdw_version == sdw1_version && - mfg_id == mfg1_id && - part_id == part1_id && - class_id == class1_id) - return false; - } - - return true; -} - -static const char *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) -{ - u64 adr = adr_link->adr_d[adr_index].adr; - unsigned int sdw_version = SDW_VERSION(adr); - unsigned int link_id = SDW_DISCO_LINK_ID(adr); - unsigned int unique_id = SDW_UNIQUE_ID(adr); - unsigned int mfg_id = SDW_MFG_ID(adr); - unsigned int part_id = SDW_PART_ID(adr); - unsigned int class_id = SDW_CLASS_ID(adr); - - if (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)) - return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", - link_id, mfg_id, part_id, class_id); - else - return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", - link_id, mfg_id, part_id, class_id, unique_id); - - return NULL; -} - -static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - 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; - - /* - * A codec dai can be connected to different dai links for capture and playback, - * but we only need to call the rtd_init function once. - * The rtd_init for each codec dai is independent. So, the order of rtd_init - * doesn't matter. - */ - if (codec_info->dais[dai_index].rtd_init_done) - continue; - - /* - * Add card controls and dapm widgets for the first codec dai. - * The controls and widgets will be used for all codec dais. - */ - - if (i > 0) - goto skip_add_controls_widgets; - - if (codec_info->dais[dai_index].controls) { - ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, - codec_info->dais[dai_index].num_controls); - if (ret) { - dev_err(card->dev, "%#x controls addition failed: %d\n", - codec_info->part_id, ret); - return ret; - } - } - if (codec_info->dais[dai_index].widgets) { - ret = snd_soc_dapm_new_controls(&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; - } - } - -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; -} - struct sof_sdw_endpoint { struct list_head list; @@ -1451,8 +565,8 @@ struct sof_sdw_endpoint { const char *name_prefix; bool include_sidecar; - struct sof_sdw_codec_info *codec_info; - const struct sof_sdw_dai_info *dai_info; + struct asoc_sdw_codec_info *codec_info; + const struct asoc_sdw_dai_info *dai_info; }; struct sof_sdw_dailink { @@ -1509,7 +623,7 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, int *num_devs) { struct device *dev = card->dev; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link; @@ -1529,7 +643,7 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, 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; + struct asoc_sdw_codec_info *codec_info; const char *codec_name; if (!adr_dev->name_prefix) { @@ -1538,13 +652,13 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, return -EINVAL; } - codec_info = find_codec_info_part(adr_dev->adr); + codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); if (!codec_info) return -EINVAL; - ctx->ignore_pch_dmic |= codec_info->ignore_pch_dmic; + ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; - codec_name = get_codec_name(dev, codec_info, adr_link, i); + codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); if (!codec_name) return -ENOMEM; @@ -1563,7 +677,7 @@ static int parse_sdw_endpoints(struct snd_soc_card *card, 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; + const struct asoc_sdw_dai_info *dai_info; struct sof_sdw_dailink *sof_dai; int stream; @@ -1630,7 +744,8 @@ static int create_sdw_dailink(struct snd_soc_card *card, int *be_id, struct snd_soc_codec_conf **codec_conf) { struct device *dev = card->dev; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct sof_sdw_endpoint *sof_end; int stream; int ret; @@ -1709,7 +824,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, 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]++; + int pin_num = intel_ctx->sdw_pin_index[link_num]++; cur_link = sof_end->link_mask; @@ -1734,9 +849,10 @@ static int create_sdw_dailink(struct snd_soc_card *card, playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - init_dai_link(dev, *dai_links, be_id, name, playback, capture, - cpus, num_cpus, codecs, num_codecs, - sof_sdw_rtd_init, &sdw_ops); + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, platform_component, + ARRAY_SIZE(platform_component), codecs, num_codecs, + asoc_sdw_rtd_init, &sdw_ops); /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations @@ -1763,11 +879,12 @@ static int create_sdw_dailinks(struct snd_soc_card *card, struct sof_sdw_dailink *sof_dais, struct snd_soc_codec_conf **codec_conf) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int ret, i; for (i = 0; i < SDW_MAX_LINKS; i++) - ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; + intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; /* generate DAI links by each sdw link */ while (sof_dais->initialised) { @@ -1790,7 +907,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, 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, + struct asoc_sdw_codec_info *ssp_info, unsigned long ssp_mask) { struct device *dev = card->dev; @@ -1805,10 +922,12 @@ static int create_ssp_dailinks(struct snd_soc_card *card, 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); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + playback, capture, cpu_dai_name, + platform_component->name, + ARRAY_SIZE(platform_component), codec_name, + ssp_info->dais[0].dai_name, NULL, + ssp_info->ops); if (ret) return ret; @@ -1828,20 +947,24 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 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); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", + 0, 1, // DMIC only supports capture + "DMIC01 Pin", platform_component->name, + ARRAY_SIZE(platform_component), + "dmic-codec", "dmic-hifi", + asoc_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); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", + 0, 1, // DMIC only supports capture + "DMIC16k Pin", platform_component->name, + ARRAY_SIZE(platform_component), + "dmic-codec", "dmic-hifi", + /* don't call asoc_sdw_dmic_init() twice */ + NULL, NULL); if (ret) return ret; @@ -1855,7 +978,8 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, int hdmi_num) { struct device *dev = card->dev; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int i, ret; for (i = 0; i < hdmi_num; i++) { @@ -1863,7 +987,7 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, 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) { + if (intel_ctx->hdmi.idisp_codec) { codec_name = "ehdaudio0D2"; codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, "intel-hdmi-hifi%d", i + 1); @@ -1872,10 +996,12 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, 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); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 0, // HDMI only supports playback + cpu_dai_name, platform_component->name, + ARRAY_SIZE(platform_component), + codec_name, codec_dai_name, + i == 0 ? sof_sdw_hdmi_init : NULL, NULL); if (ret) return ret; @@ -1895,9 +1021,11 @@ static int create_bt_dailinks(struct snd_soc_card *card, 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); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 1, cpu_dai_name, platform_component->name, + ARRAY_SIZE(platform_component), + snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, + NULL, NULL); if (ret) return ret; @@ -1911,10 +1039,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct snd_soc_codec_conf *codec_conf; - struct sof_sdw_codec_info *ssp_info; + struct asoc_sdw_codec_info *ssp_info; struct sof_sdw_endpoint *sof_ends; struct sof_sdw_dailink *sof_dais; int num_devs = 0; @@ -1956,14 +1085,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) * system only when I2S mode is supported, not sdw mode. * Here check ACPI ID to confirm I2S is supported. */ - ssp_info = find_codec_info_acpi(mach->id); + ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); if (ssp_info) { ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); ssp_num = hweight_long(ssp_mask); } if (mach_params->codec_mask & IDISP_CODEC_MASK) - ctx->hdmi.idisp_codec = true; + intel_ctx->hdmi.idisp_codec = true; if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) hdmi_num = SOF_TGL_HDMI_COUNT; @@ -1971,7 +1100,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) hdmi_num = SOF_PRE_TGL_HDMI_COUNT; /* enable dmic01 & dmic16k */ - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) + if (sof_sdw_quirk & SOC_SDW_PCH_DMIC || mach_params->dmic_num) dmic_num = 2; if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) @@ -1979,7 +1108,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", sdw_be_num, ssp_num, dmic_num, - ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); + intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) { @@ -2018,7 +1147,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) /* dmic */ if (dmic_num > 0) { - if (ctx->ignore_pch_dmic) { + if (ctx->ignore_internal_dmic) { dev_warn(dev, "Ignoring PCH DMIC\n"); } else { ret = create_dmic_dailinks(card, &dai_links, &be_id); @@ -2052,88 +1181,41 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) static int sof_sdw_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int ret = 0; - int i; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - if (codec_info_list[i].codec_card_late_probe) { - ret = codec_info_list[i].codec_card_late_probe(card); - - if (ret < 0) - return ret; - } - } + ret = asoc_sdw_card_late_probe(card); + if (ret < 0) + return ret; - if (ctx->hdmi.idisp_codec) + if (intel_ctx->hdmi.idisp_codec) ret = sof_sdw_hdmi_card_late_probe(card); return ret; } -/* 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) -{ - struct snd_soc_dai_link *dai_link; - int i; - int j; - - for_each_card_prelinks(card, i, dai_link) { - for (j = 0; j < dai_link->num_codecs; j++) { - /* Check each codec in a link */ - if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) - return dai_link; - } - } - return NULL; -} - -static void mc_dailink_exit_loop(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *dai_link; - int ret; - int i, j; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - for (j = 0; j < codec_info_list[i].dai_num; j++) { - codec_info_list[i].dais[j].rtd_init_done = false; - /* Check each dai in codec_info_lis to see if it is used in the link */ - if (!codec_info_list[i].dais[j].exit) - continue; - /* - * We don't need to call .exit function if there is no matched - * dai link found. - */ - dai_link = mc_find_codec_dai_used(card, - codec_info_list[i].dais[j].dai_name); - if (dai_link) { - /* Do the .exit function if the codec dai is used in the link */ - ret = codec_info_list[i].dais[j].exit(card, dai_link); - if (ret) - dev_warn(card->dev, - "codec exit failed %d\n", - ret); - break; - } - } - } -} - static int mc_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); struct snd_soc_card *card; - struct mc_private *ctx; + struct asoc_sdw_mc_private *ctx; + struct intel_mc_ctx *intel_ctx; int amp_num = 0, i; int ret; dev_dbg(&pdev->dev, "Entry\n"); + intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); + if (!intel_ctx) + return -ENOMEM; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + ctx->private = intel_ctx; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); card = &ctx->card; card->dev = &pdev->dev; card->name = "soundwire"; @@ -2152,8 +1234,9 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); + ctx->mc_quirk = sof_sdw_quirk; /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) codec_info_list[i].amp_num = 0; if (mach->mach_params.subsystem_id_set) { @@ -2171,7 +1254,7 @@ static int mc_probe(struct platform_device *pdev) * amp_num will only be increased for active amp * codecs on used platform */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; card->components = devm_kasprintf(card->dev, GFP_KERNEL, @@ -2192,7 +1275,7 @@ static int mc_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(card->dev, card); if (ret) { dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); - mc_dailink_exit_loop(card); + asoc_sdw_mc_dailink_exit_loop(card); return ret; } @@ -2205,7 +1288,7 @@ static void mc_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - mc_dailink_exit_loop(card); + asoc_sdw_mc_dailink_exit_loop(card); } static const struct platform_device_id mc_id_table[] = { @@ -2232,3 +1315,4 @@ MODULE_AUTHOR("Rander Wang "); MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index 2a3145d1feb61d..02f3eebd019de0 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -12,18 +12,12 @@ #include #include #include +#include #include "sof_hdmi_common.h" -#define MAX_NO_PROPS 2 #define MAX_HDMI_NUM 4 -#define SDW_UNUSED_DAI_ID -1 -#define SDW_JACK_OUT_DAI_ID 0 -#define SDW_JACK_IN_DAI_ID 1 -#define SDW_AMP_OUT_DAI_ID 2 -#define SDW_AMP_IN_DAI_ID 3 -#define SDW_DMIC_DAI_ID 4 -#define SDW_MAX_CPU_DAIS 16 -#define SDW_INTEL_BIDIR_PDI_BASE 2 +#define SOC_SDW_MAX_CPU_DAIS 16 +#define SOC_SDW_INTEL_BIDIR_PDI_BASE 2 #define SDW_MAX_LINKS 4 @@ -44,27 +38,14 @@ enum { SOF_I2S_SSP5 = BIT(5), }; -#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 SOC_SDW_FOUR_SPK BIT(4) #define SOF_SDW_TGL_HDMI BIT(5) -#define SOF_SDW_PCH_DMIC BIT(6) +#define SOC_SDW_PCH_DMIC BIT(6) #define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7) #define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0)) /* 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) +#define SOC_SDW_NO_AGGREGATION BIT(14) /* BT audio offload: reserve 3 bits for future */ #define SOF_BT_OFFLOAD_SSP_SHIFT 15 @@ -73,150 +54,17 @@ enum { (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(18) -#define SOF_SDW_DAI_TYPE_JACK 0 -#define SOF_SDW_DAI_TYPE_AMP 1 -#define SOF_SDW_DAI_TYPE_MIC 2 - -#define SOF_SDW_MAX_DAI_NUM 8 - -struct sof_sdw_codec_info; - -struct sof_sdw_dai_info { - const bool direction[2]; /* playback & capture support */ - const char *dai_name; - const int dai_type; - const int dailink[2]; /* dailink id for each direction */ - 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, - 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, 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 { - const int part_id; - const int version_id; - const char *codec_name; - int amp_num; - const u8 acpi_id[ACPI_ID_LEN]; - const bool ignore_pch_dmic; - const struct snd_soc_ops *ops; - struct sof_sdw_dai_info dais[SOF_SDW_MAX_DAI_NUM]; - const int dai_num; - - int (*codec_card_late_probe)(struct snd_soc_card *card); - - 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 intel_mc_ctx { 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; -int sdw_startup(struct snd_pcm_substream *substream); -int sdw_prepare(struct snd_pcm_substream *substream); -int sdw_trigger(struct snd_pcm_substream *substream, int cmd); -int sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params); -int sdw_hw_free(struct snd_pcm_substream *substream); -void sdw_shutdown(struct snd_pcm_substream *substream); - /* generic HDMI support */ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd); int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card); -/* DMIC support */ -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); - -/* RT711 support */ -int sof_sdw_rt711_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT711-SDCA support */ -int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT1308 I2S support */ -extern const struct snd_soc_ops sof_sdw_rt1308_i2s_ops; - -/* generic amp support */ -int sof_sdw_rt_amp_init(struct snd_soc_card *card, - 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); - -/* MAXIM codec support */ -int sof_sdw_maxim_init(struct snd_soc_card *card, - 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, - 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, 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_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c index f34fabdf9d93b1..4084119a9a5f21 100644 --- a/sound/soc/intel/boards/sof_sdw_hdmi.c +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -17,23 +17,25 @@ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd) { - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - ctx->hdmi.hdmi_comp = dai->component; + intel_ctx->hdmi.hdmi_comp = dai->component; return 0; } int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; - if (!ctx->hdmi.idisp_codec) + if (!intel_ctx->hdmi.idisp_codec) return 0; - if (!ctx->hdmi.hdmi_comp) + if (!intel_ctx->hdmi.hdmi_comp) return -EINVAL; - return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); + return hda_dsp_hdmi_build_controls(card, intel_ctx->hdmi.hdmi_comp); } diff --git a/sound/soc/sdw_utils/Kconfig b/sound/soc/sdw_utils/Kconfig new file mode 100644 index 00000000000000..d915083c388958 --- /dev/null +++ b/sound/soc/sdw_utils/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +config SND_SOC_SDW_UTILS + tristate + help + This option enables to use SoundWire common helper functions and + SoundWire codec helper functions in machine driver. diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile new file mode 100644 index 00000000000000..28229ed96ffb5e --- /dev/null +++ b/sound/soc/sdw_utils/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +snd-soc-sdw-utils-y := soc_sdw_utils.o soc_sdw_dmic.o soc_sdw_rt_dmic.o \ + soc_sdw_rt700.o soc_sdw_rt711.o \ + soc_sdw_rt712_sdca.o soc_sdw_rt722_sdca.o \ + soc_sdw_rt5682.o soc_sdw_rt_sdca_jack_common.o \ + soc_sdw_rt_amp.o \ + soc_sdw_bridge_cs35l56.o \ + soc_sdw_cs42l42.o soc_sdw_cs42l43.o \ + soc_sdw_cs_amp.o \ + soc_sdw_maxim.o +obj-$(CONFIG_SND_SOC_SDW_UTILS) += snd-soc-sdw-utils.o diff --git a/sound/soc/intel/boards/bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c similarity index 63% rename from sound/soc/intel/boards/bridge_cs35l56.c rename to sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c index c3995e724aed98..fcc3ef685af7d3 100644 --- a/sound/soc/intel/boards/bridge_cs35l56.c +++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c @@ -1,6 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only -// -// Intel SOF Machine Driver with Cirrus Logic CS35L56 Smart Amp +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2024 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. + +/* + * soc_sdw_bridge_cs35l56 - codec helper functions for handling CS35L56 Smart AMP + */ #include #include @@ -9,7 +14,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_widget bridge_widgets[] = { SND_SOC_DAPM_SPK("Bridge Speaker", NULL), @@ -25,7 +30,7 @@ static const char * const bridge_cs35l56_name_prefixes[] = { "AMPR", }; -static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) +static int asoc_sdw_bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int i, ret; @@ -73,7 +78,7 @@ static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static const struct snd_soc_pcm_stream bridge_params = { +static const struct snd_soc_pcm_stream asoc_sdw_bridge_params = { .formats = SNDRV_PCM_FMTBIT_S16_LE, .rate_min = 48000, .rate_max = 48000, @@ -81,7 +86,7 @@ static const struct snd_soc_pcm_stream bridge_params = { .channels_max = 2, }; -SND_SOC_DAILINK_DEFS(bridge_dai, +SND_SOC_DAILINK_DEFS(asoc_sdw_bridge_dai, DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")), DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"), COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")), @@ -89,28 +94,33 @@ SND_SOC_DAILINK_DEFS(bridge_dai, static const struct snd_soc_dai_link bridge_dai_template = { .name = "cs42l43-cs35l56", - .init = bridge_cs35l56_asp_init, - .c2c_params = &bridge_params, + .init = asoc_sdw_bridge_cs35l56_asp_init, + .c2c_params = &asoc_sdw_bridge_params, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC, - SND_SOC_DAILINK_REG(bridge_dai), + SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai), }; -int bridge_cs35l56_count_sidecar(struct snd_soc_card *card, - int *num_dais, int *num_devs) +int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, + int *num_dais, int *num_devs) { - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) { (*num_dais)++; (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes); } return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_count_sidecar, SND_SOC_SDW_UTILS); -int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, - struct snd_soc_dai_link **dai_links, - struct snd_soc_codec_conf **codec_conf) +int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, + struct snd_soc_codec_conf **codec_conf) { - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) { + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) { **dai_links = bridge_dai_template; for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) { @@ -124,14 +134,18 @@ int bridge_cs35l56_add_sidecar(struct snd_soc_card *card, return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_add_sidecar, SND_SOC_SDW_UTILS); -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 asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - if (sof_sdw_quirk & SOF_SIDECAR_AMPS) + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes); return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_spk_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/sdw_utils/soc_sdw_cs42l42.c similarity index 82% rename from sound/soc/intel/boards/sof_sdw_cs42l42.c rename to sound/soc/sdw_utils/soc_sdw_cs42l42.c index fc18e4aa3dbe9f..78a6cb059ac06b 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l42.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l42.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation - +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver + * soc_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver */ #include @@ -15,7 +16,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route cs42l42_map[] = { /* HP jack connectors - unknown if we have jack detection */ @@ -36,10 +37,10 @@ static struct snd_soc_jack_pin cs42l42_jack_pins[] = { }, }; -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -87,4 +88,4 @@ int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l42_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c similarity index 73% rename from sound/soc/intel/boards/sof_sdw_cs42l43.c rename to sound/soc/sdw_utils/soc_sdw_cs42l43.c index b7e2750c107459..adb1c008e871d5 100644 --- a/sound/soc/intel/boards/sof_sdw_cs42l43.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only // Based on sof_sdw_rt5682.c +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver + * soc_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver */ #include #include @@ -16,7 +18,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route cs42l43_hs_map[] = { { "Headphone", NULL, "cs42l43 AMP3_OUT" }, @@ -37,7 +39,7 @@ static const struct snd_soc_dapm_route cs42l43_dmic_map[] = { { "cs42l43 PDM2_DIN", NULL, "DMIC" }, }; -static struct snd_soc_jack_pin sof_jack_pins[] = { +static struct snd_soc_jack_pin soc_jack_pins[] = { { .pin = "Headphone", .mask = SND_JACK_HEADPHONE, @@ -48,10 +50,10 @@ static struct snd_soc_jack_pin sof_jack_pins[] = { }, }; -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_jack *jack = &ctx->sdw_headset; struct snd_soc_card *card = rtd->card; int ret; @@ -73,8 +75,8 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack, sof_jack_pins, - ARRAY_SIZE(sof_jack_pins)); + jack, soc_jack_pins, + ARRAY_SIZE(soc_jack_pins)); if (ret) { dev_err(card->dev, "Failed to create jack: %d\n", ret); return ret; @@ -98,13 +100,15 @@ int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, SND_SOC_SDW_UTILS); -int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; - if (!(sof_sdw_quirk & SOF_SIDECAR_AMPS)) { + if (!(ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS)) { /* Will be set by the bridge code in this case */ card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:cs42l43-spk", @@ -120,11 +124,12 @@ int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *da return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_rtd_init, SND_SOC_SDW_UTILS); -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) +int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { /* Do init on playback link only. */ if (!playback) @@ -132,10 +137,11 @@ int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card, info->amp_num++; - return bridge_cs35l56_spk_init(card, dai_links, info, playback); + return asoc_sdw_bridge_cs35l56_spk_init(card, dai_links, info, playback); } +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_init, SND_SOC_SDW_UTILS); -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -152,4 +158,4 @@ int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *d return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_dmic_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c similarity index 66% rename from sound/soc/intel/boards/sof_sdw_cs_amp.c rename to sound/soc/sdw_utils/soc_sdw_cs_amp.c index 10e08207619a9c..58b059b68016b8 100644 --- a/sound/soc/intel/boards/sof_sdw_cs_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver + * soc_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver */ #include @@ -10,11 +12,11 @@ #include #include #include -#include "sof_sdw_common.h" +#include #define CODEC_NAME_SIZE 8 -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_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; @@ -44,11 +46,12 @@ int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_cs_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_cs_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { /* Do init on playback link only. */ if (!playback) @@ -58,3 +61,4 @@ int sof_sdw_cs_amp_init(struct snd_soc_card *card, return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_cs_amp_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/sdw_utils/soc_sdw_dmic.c similarity index 71% rename from sound/soc/intel/boards/sof_sdw_dmic.c rename to sound/soc/sdw_utils/soc_sdw_dmic.c index 19df0f7a1d85af..fc2aae985084b6 100644 --- a/sound/soc/intel/boards/sof_sdw_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_dmic.c @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_dmic - Helpers to handle dmic from generic machine driver + * soc_sdw_dmic - Helpers to handle dmic from generic machine driver */ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_widget dmic_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), @@ -19,7 +21,7 @@ static const struct snd_soc_dapm_route dmic_map[] = { {"DMic", NULL, "SoC DMIC"}, }; -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) +int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; int ret; @@ -40,4 +42,4 @@ int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_dmic_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_maxim.c b/sound/soc/sdw_utils/soc_sdw_maxim.c similarity index 63% rename from sound/soc/intel/boards/sof_sdw_maxim.c rename to sound/soc/sdw_utils/soc_sdw_maxim.c index b7f73177867f46..cdcd8df37e1d3c 100644 --- a/sound/soc/intel/boards/sof_sdw_maxim.c +++ b/sound/soc/sdw_utils/soc_sdw_maxim.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. // -// sof_sdw_maxim - Helpers to handle maxim codecs +// soc_sdw_maxim - Helpers to handle maxim codecs // codec devices from generic machine driver #include @@ -10,18 +12,18 @@ #include #include #include -#include "sof_sdw_common.h" +#include static int maxim_part_id; -#define SOF_SDW_PART_ID_MAX98363 0x8363 -#define SOF_SDW_PART_ID_MAX98373 0x8373 +#define SOC_SDW_PART_ID_MAX98363 0x8363 +#define SOC_SDW_PART_ID_MAX98373 0x8373 static const struct snd_soc_dapm_route max_98373_dapm_routes[] = { { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, }; -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -41,8 +43,9 @@ int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_maxim_spk_rtd_init, SND_SOC_SDW_UTILS); -static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) +static int asoc_sdw_mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -75,40 +78,40 @@ static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enabl return 0; } -static int mx8373_sdw_prepare(struct snd_pcm_substream *substream) +static int asoc_sdw_mx8373_prepare(struct snd_pcm_substream *substream) { int ret; /* according to soc_pcm_prepare dai link prepare is called first */ - ret = sdw_prepare(substream); + ret = asoc_sdw_prepare(substream); if (ret < 0) return ret; - return mx8373_enable_spk_pin(substream, true); + return asoc_sdw_mx8373_enable_spk_pin(substream, true); } -static int mx8373_sdw_hw_free(struct snd_pcm_substream *substream) +static int asoc_sdw_mx8373_hw_free(struct snd_pcm_substream *substream) { int ret; /* according to soc_pcm_hw_free dai link free is called first */ - ret = sdw_hw_free(substream); + ret = asoc_sdw_hw_free(substream); if (ret < 0) return ret; - return mx8373_enable_spk_pin(substream, false); + return asoc_sdw_mx8373_enable_spk_pin(substream, false); } static const struct snd_soc_ops max_98373_sdw_ops = { - .startup = sdw_startup, - .prepare = mx8373_sdw_prepare, - .trigger = sdw_trigger, - .hw_params = sdw_hw_params, - .hw_free = mx8373_sdw_hw_free, - .shutdown = sdw_shutdown, + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_mx8373_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_mx8373_hw_free, + .shutdown = asoc_sdw_shutdown, }; -static int mx8373_sdw_late_probe(struct snd_soc_card *card) +static int asoc_sdw_mx8373_sdw_late_probe(struct snd_soc_card *card) { struct snd_soc_dapm_context *dapm = &card->dapm; @@ -118,22 +121,22 @@ static int mx8373_sdw_late_probe(struct snd_soc_card *card) return snd_soc_dapm_sync(dapm); } -int sof_sdw_maxim_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_maxim_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { info->amp_num++; maxim_part_id = info->part_id; switch (maxim_part_id) { - case SOF_SDW_PART_ID_MAX98363: + case SOC_SDW_PART_ID_MAX98363: /* Default ops are set in function init_dai_link. * called as part of function create_sdw_dailink */ break; - case SOF_SDW_PART_ID_MAX98373: - info->codec_card_late_probe = mx8373_sdw_late_probe; + case SOC_SDW_PART_ID_MAX98373: + info->codec_card_late_probe = asoc_sdw_mx8373_sdw_late_probe; dai_links->ops = &max_98373_sdw_ops; break; default: @@ -142,3 +145,4 @@ int sof_sdw_maxim_init(struct snd_soc_card *card, } return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_maxim_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/sdw_utils/soc_sdw_rt5682.c similarity index 82% rename from sound/soc/intel/boards/sof_sdw_rt5682.c rename to sound/soc/sdw_utils/soc_sdw_rt5682.c index 67737815d016ea..80b4caa926670f 100644 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ b/sound/soc/sdw_utils/soc_sdw_rt5682.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver + * soc_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver */ #include @@ -15,7 +17,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route rt5682_map[] = { /*Headphones*/ @@ -35,10 +37,10 @@ static struct snd_soc_jack_pin rt5682_jack_pins[] = { }, }; -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -86,4 +88,4 @@ int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt5682_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/sdw_utils/soc_sdw_rt700.c similarity index 81% rename from sound/soc/intel/boards/sof_sdw_rt700.c rename to sound/soc/sdw_utils/soc_sdw_rt700.c index 0db730071be236..4dbeeeca343441 100644 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ b/sound/soc/sdw_utils/soc_sdw_rt700.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt700 - Helpers to handle RT700 from generic machine driver + * soc_sdw_rt700 - Helpers to handle RT700 from generic machine driver */ #include @@ -13,7 +15,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route rt700_map[] = { /* Headphones */ @@ -33,10 +35,10 @@ static struct snd_soc_jack_pin rt700_jack_pins[] = { }, }; -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -83,4 +85,4 @@ int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt700_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/sdw_utils/soc_sdw_rt711.c similarity index 70% rename from sound/soc/intel/boards/sof_sdw_rt711.c rename to sound/soc/sdw_utils/soc_sdw_rt711.c index 60ff4d88e2dc78..38b4126dd45f16 100644 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ b/sound/soc/sdw_utils/soc_sdw_rt711.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt711 - Helpers to handle RT711 from generic machine driver + * soc_sdw_rt711 - Helpers to handle RT711 from generic machine driver */ #include @@ -15,21 +17,21 @@ #include #include #include -#include "sof_sdw_common.h" +#include /* * Note this MUST be called before snd_soc_register_card(), so that the props * are in place before the codec component driver's probe function parses them. */ -static int rt711_add_codec_device_props(struct device *sdw_dev) +static int rt711_add_codec_device_props(struct device *sdw_dev, unsigned long quirk) { - struct property_entry props[MAX_NO_PROPS] = {}; + struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {}; struct fwnode_handle *fwnode; int ret; - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) + if (!SOC_SDW_JACK_JDSRC(quirk)) return 0; - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); + props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk)); fwnode = fwnode_create_software_node(props, NULL); if (IS_ERR(fwnode)) @@ -59,10 +61,10 @@ static struct snd_soc_jack_pin rt711_jack_pins[] = { }, }; -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -110,10 +112,11 @@ int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_rt711_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); if (!ctx->headset_codec_dev) return 0; @@ -123,13 +126,14 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt711_exit, SND_SOC_SDW_UTILS); -int sof_sdw_rt711_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_rt711_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *sdw_dev; int ret; @@ -144,7 +148,7 @@ int sof_sdw_rt711_init(struct snd_soc_card *card, if (!sdw_dev) return -EPROBE_DEFER; - ret = rt711_add_codec_device_props(sdw_dev); + ret = rt711_add_codec_device_props(sdw_dev, ctx->mc_quirk); if (ret < 0) { put_device(sdw_dev); return ret; @@ -153,4 +157,4 @@ int sof_sdw_rt711_init(struct snd_soc_card *card, return 0; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt711_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c similarity index 74% rename from sound/soc/intel/boards/sof_sdw_rt712_sdca.c rename to sound/soc/sdw_utils/soc_sdw_rt712_sdca.c index 78879646188585..5127210b9a03c1 100644 --- a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c +++ b/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver + * soc_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver */ #include @@ -13,7 +15,7 @@ #include #include #include -#include "sof_sdw_common.h" +#include /* * dapm routes for rt712 spk will be registered dynamically according @@ -26,7 +28,7 @@ static const struct snd_soc_dapm_route rt712_spk_map[] = { { "Speaker", NULL, "rt712 SPOR" }, }; -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -43,4 +45,4 @@ int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_rt712_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c similarity index 68% rename from sound/soc/intel/boards/sof_sdw_rt722_sdca.c rename to sound/soc/sdw_utils/soc_sdw_rt722_sdca.c index 083d281bd05253..6a402172289fa2 100644 --- a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c +++ b/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver + * soc_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver */ #include @@ -13,13 +15,13 @@ #include #include #include -#include "sof_sdw_common.h" +#include static const struct snd_soc_dapm_route rt722_spk_map[] = { { "Speaker", NULL, "rt722 SPK" }, }; -int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; int ret; @@ -36,4 +38,4 @@ int rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return ret; } - +EXPORT_SYMBOL_NS(asoc_sdw_rt722_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c similarity index 87% rename from sound/soc/intel/boards/sof_sdw_rt_amp.c rename to sound/soc/sdw_utils/soc_sdw_rt_amp.c index d1c0f91ce58979..42be01405ab4e3 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2022 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver + * soc_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver */ #include @@ -14,9 +16,9 @@ #include #include #include -#include "sof_sdw_common.h" -#include "sof_sdw_amp_coeff_tables.h" -#include "../../codecs/rt1308.h" +#include +#include "soc_sdw_rt_amp_coeff_tables.h" +#include "../codecs/rt1308.h" #define CODEC_NAME_SIZE 7 @@ -173,7 +175,7 @@ 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, struct snd_soc_dai *dai) +int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; const struct snd_soc_dapm_route *rt_amp_map; @@ -199,6 +201,7 @@ int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_spk_rtd_init, SND_SOC_SDW_UTILS); static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -233,13 +236,14 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -const struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { +const struct snd_soc_ops soc_sdw_rt1308_i2s_ops = { .hw_params = rt1308_i2s_hw_params, }; +EXPORT_SYMBOL_NS(soc_sdw_rt1308_i2s_ops, SND_SOC_SDW_UTILS); -int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); if (ctx->amp_dev1) { device_remove_software_node(ctx->amp_dev1); @@ -253,13 +257,14 @@ int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_exit, SND_SOC_SDW_UTILS); -int sof_sdw_rt_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_rt_amp_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *sdw_dev1, *sdw_dev2; int ret; @@ -295,3 +300,4 @@ int sof_sdw_rt_amp_init(struct snd_soc_card *card, return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h similarity index 97% rename from sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h rename to sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h index 4a3e6fdbd62379..4803d134d071f6 100644 --- a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp_coeff_tables.h @@ -2,11 +2,11 @@ */ /* - * sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters + * soc_sdw_rt_amp_coeff_tables.h - related coefficients for RTK amplifier parameters */ -#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H -#define SND_SOC_SOF_SDW_AMP_COEFF_H +#ifndef SND_SOC_SDW_RT_SDW_AMP_COEFF_H +#define SND_SOC_SDW_RT_SDW_AMP_COEFF_H #define RT1308_MAX_BQ_REG 480 #define RT1316_MAX_BQ_REG 580 diff --git a/sound/soc/intel/boards/sof_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c similarity index 70% rename from sound/soc/intel/boards/sof_sdw_rt_dmic.c rename to sound/soc/sdw_utils/soc_sdw_rt_dmic.c index ea7c1a4bc5661e..7f24806d809d9d 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c @@ -1,18 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2024 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt_dmic - Helpers to handle Realtek SDW DMIC from generic machine driver + * soc_sdw_rt_dmic - Helpers to handle Realtek SDW DMIC from generic machine driver */ #include #include #include #include -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" +#include -int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; struct snd_soc_component *component; @@ -39,4 +40,4 @@ int rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) return 0; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_dmic_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c similarity index 78% rename from sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c rename to sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c index 4254e30ee4c3dd..3e6211dc1599a8 100644 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: // Copyright (c) 2020 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. /* - * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver + * soc_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver */ #include @@ -15,22 +17,22 @@ #include #include #include -#include "sof_sdw_common.h" +#include /* * Note this MUST be called before snd_soc_register_card(), so that the props * are in place before the codec component driver's probe function parses them. */ -static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev) +static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev, unsigned long quirk) { - struct property_entry props[MAX_NO_PROPS] = {}; + struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {}; struct fwnode_handle *fwnode; int ret; - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) + if (!SOC_SDW_JACK_JDSRC(quirk)) return 0; - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); + props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk)); fwnode = fwnode_create_software_node(props, NULL); if (IS_ERR(fwnode)) @@ -83,10 +85,10 @@ static const char * const need_sdca_suffix[] = { "rt711", "rt713" }; -int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; struct snd_soc_jack *jack; int ret; @@ -160,15 +162,16 @@ int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *d return ret; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init, SND_SOC_SDW_UTILS); -int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); if (!ctx->headset_codec_dev) return 0; - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) + if (!SOC_SDW_JACK_JDSRC(ctx->mc_quirk)) return 0; device_remove_software_node(ctx->headset_codec_dev); @@ -177,13 +180,14 @@ int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link return 0; } +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit, SND_SOC_SDW_UTILS); -int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) +int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_links, + struct asoc_sdw_codec_info *info, + bool playback) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *sdw_dev; int ret; @@ -198,7 +202,7 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, if (!sdw_dev) return -EPROBE_DEFER; - ret = rt_sdca_jack_add_codec_device_props(sdw_dev); + ret = rt_sdca_jack_add_codec_device_props(sdw_dev, ctx->mc_quirk); if (ret < 0) { put_device(sdw_dev); return ret; @@ -207,4 +211,4 @@ int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, return 0; } -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c new file mode 100644 index 00000000000000..6183629d1754ca --- /dev/null +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -0,0 +1,990 @@ +// SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2020 Intel Corporation +// Copyright(c) 2024 Advanced Micro Devices, Inc. +/* + * soc-sdw-utils.c - common SoundWire machine driver helper functions + */ + +#include +#include +#include +#include +#include + +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 asoc_sdw_codec_info codec_info_list[] = { + { + .part_id = 0x700, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt700-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .rtd_init = asoc_sdw_rt700_rtd_init, + .controls = rt700_controls, + .num_controls = ARRAY_SIZE(rt700_controls), + .widgets = rt700_widgets, + .num_widgets = ARRAY_SIZE(rt700_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x711, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt711-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x711, + .version_id = 2, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt711-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt711_init, + .exit = asoc_sdw_rt711_exit, + .rtd_init = asoc_sdw_rt711_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x712, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt712-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {true, false}, + .dai_name = "rt712-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_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, + }, + { + .part_id = 0x1712, + .version_id = 3, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt712-sdca-dmic-aif1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x713, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt712-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1713, + .version_id = 3, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt712-sdca-dmic-aif1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1308, + .acpi_id = "10EC1308", + .dais = { + { + .direction = {true, false}, + .dai_name = "rt1308-aif", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + .ops = &soc_sdw_rt1308_i2s_ops, + }, + { + .part_id = 0x1316, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt1316-aif", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x1318, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt1318-aif", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_amp_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x714, + .version_id = 3, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x715, + .version_id = 3, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x714, + .version_id = 2, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x715, + .version_id = 2, + .ignore_internal_dmic = true, + .dais = { + { + .direction = {false, true}, + .dai_name = "rt715-aif2", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x722, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt722-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {true, false}, + .dai_name = "rt722-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + /* No feedback capability is provided by rt722-sdca codec driver*/ + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_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 = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 3, + }, + { + .part_id = 0x8373, + .dais = { + { + .direction = {true, true}, + .dai_name = "max98373-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_maxim_init, + .rtd_init = asoc_sdw_maxim_spk_rtd_init, + .controls = maxim_controls, + .num_controls = ARRAY_SIZE(maxim_controls), + .widgets = maxim_widgets, + .num_widgets = ARRAY_SIZE(maxim_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x8363, + .dais = { + { + .direction = {true, false}, + .dai_name = "max98363-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_maxim_init, + .rtd_init = asoc_sdw_maxim_spk_rtd_init, + .controls = maxim_controls, + .num_controls = ARRAY_SIZE(maxim_controls), + .widgets = maxim_widgets, + .num_widgets = ARRAY_SIZE(maxim_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x5682, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt5682-sdw", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .rtd_init = asoc_sdw_rt5682_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x3556, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs35l56-sdw1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init = asoc_sdw_cs_amp_init, + .rtd_init = asoc_sdw_cs_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x4242, + .dais = { + { + .direction = {true, true}, + .dai_name = "cs42l42-sdw", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .rtd_init = asoc_sdw_cs42l42_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x4243, + .codec_name = "cs42l43-codec", + .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, + .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, + .dais = { + { + .direction = {true, false}, + .dai_name = "cs42l43-dp5", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .rtd_init = asoc_sdw_cs42l43_hs_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {false, true}, + .dai_name = "cs42l43-dp1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, + .widgets = generic_dmic_widgets, + .num_widgets = ARRAY_SIZE(generic_dmic_widgets), + }, + { + .direction = {false, true}, + .dai_name = "cs42l43-dp2", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + { + .direction = {true, false}, + .dai_name = "cs42l43-dp6", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_cs42l43_spk_init, + .rtd_init = asoc_sdw_cs42l43_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS, + }, + }, + .dai_num = 4, + }, + { + .part_id = 0xaaaa, /* generic codec mockup */ + .version_id = 0, + .dais = { + { + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0xaa55, /* headset codec mockup */ + .version_id = 0, + .dais = { + { + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x55aa, /* amplifier mockup */ + .version_id = 0, + .dais = { + { + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + }, + }, + .dai_num = 1, + }, + { + .part_id = 0x5555, + .version_id = 0, + .dais = { + { + .dai_name = "sdw-mockup-aif1", + .direction = {false, true}, + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + }, + }, + .dai_num = 1, + }, +}; +EXPORT_SYMBOL_NS(codec_info_list, SND_SOC_SDW_UTILS); + +int asoc_sdw_get_codec_info_list_count(void) +{ + return ARRAY_SIZE(codec_info_list); +}; +EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, SND_SOC_SDW_UTILS); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) +{ + unsigned int part_id, sdw_version; + int i; + + part_id = SDW_PART_ID(adr); + sdw_version = SDW_VERSION(adr); + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + /* + * A codec info is for all sdw version with the part id if + * version_id is not specified in the codec info. + */ + if (part_id == codec_info_list[i].part_id && + (!codec_info_list[i].version_id || + sdw_version == codec_info_list[i].version_id)) + return &codec_info_list[i]; + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, SND_SOC_SDW_UTILS); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) +{ + int i; + + if (!acpi_id[0]) + return NULL; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) + return &codec_info_list[i]; + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, SND_SOC_SDW_UTILS); + +struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + for (j = 0; j < codec_info_list[i].dai_num; j++) { + if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { + *dai_index = j; + return &codec_info_list[i]; + } + } + } + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, SND_SOC_SDW_UTILS); + +int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct asoc_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 = asoc_sdw_find_codec_info_dai(dai->name, &dai_index); + if (!codec_info) + return -EINVAL; + + /* + * A codec dai can be connected to different dai links for capture and playback, + * but we only need to call the rtd_init function once. + * The rtd_init for each codec dai is independent. So, the order of rtd_init + * doesn't matter. + */ + if (codec_info->dais[dai_index].rtd_init_done) + continue; + + /* + * Add card controls and dapm widgets for the first codec dai. + * The controls and widgets will be used for all codec dais. + */ + + if (i > 0) + goto skip_add_controls_widgets; + + if (codec_info->dais[dai_index].controls) { + ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls, + codec_info->dais[dai_index].num_controls); + if (ret) { + dev_err(card->dev, "%#x controls addition failed: %d\n", + codec_info->part_id, ret); + return ret; + } + } + if (codec_info->dais[dai_index].widgets) { + ret = snd_soc_dapm_new_controls(&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; + } + } + +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; +} +EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, SND_SOC_SDW_UTILS); + +/* these wrappers are only needed to avoid typecast compilation errors */ +int asoc_sdw_startup(struct snd_pcm_substream *substream) +{ + return sdw_startup_stream(substream); +} +EXPORT_SYMBOL_NS(asoc_sdw_startup, SND_SOC_SDW_UTILS); + +int asoc_sdw_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + + /* Find stream from first CPU DAI */ + dai = snd_soc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); + return PTR_ERR(sdw_stream); + } + + return sdw_prepare_stream(sdw_stream); +} +EXPORT_SYMBOL_NS(asoc_sdw_prepare, SND_SOC_SDW_UTILS); + +int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + int ret; + + /* Find stream from first CPU DAI */ + dai = snd_soc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); + return PTR_ERR(sdw_stream); + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + ret = sdw_enable_stream(sdw_stream); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sdw_disable_stream(sdw_stream); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); + + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_trigger, SND_SOC_SDW_UTILS); + +int asoc_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link_ch_map *ch_maps; + int ch = params_channels(params); + unsigned int ch_mask; + int num_codecs; + int step; + int i; + + if (!rtd->dai_link->ch_maps) + return 0; + + /* Identical data will be sent to all codecs in playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ch_mask = GENMASK(ch - 1, 0); + step = 0; + } else { + num_codecs = rtd->dai_link->num_codecs; + + if (ch < num_codecs || ch % num_codecs != 0) { + dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", + ch, num_codecs); + return -EINVAL; + } + + ch_mask = GENMASK(ch / num_codecs - 1, 0); + step = hweight_long(ch_mask); + } + + /* + * The captured data will be combined from each cpu DAI if the dai + * link has more than one codec DAIs. Set codec channel mask and + * ASoC will set the corresponding channel numbers for each cpu dai. + */ + for_each_link_ch_maps(rtd->dai_link, i, ch_maps) + ch_maps->ch_mask = ch_mask << (i * step); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_hw_params, SND_SOC_SDW_UTILS); + +int asoc_sdw_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sdw_stream_runtime *sdw_stream; + struct snd_soc_dai *dai; + + /* Find stream from first CPU DAI */ + dai = snd_soc_rtd_to_cpu(rtd, 0); + + sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); + if (IS_ERR(sdw_stream)) { + dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); + return PTR_ERR(sdw_stream); + } + + return sdw_deprepare_stream(sdw_stream); +} +EXPORT_SYMBOL_NS(asoc_sdw_hw_free, SND_SOC_SDW_UTILS); + +void asoc_sdw_shutdown(struct snd_pcm_substream *substream) +{ + sdw_shutdown_stream(substream); +} +EXPORT_SYMBOL_NS(asoc_sdw_shutdown, SND_SOC_SDW_UTILS); + +static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, + unsigned int sdw_version, + unsigned int mfg_id, + unsigned int part_id, + unsigned int class_id, + int index_in_link) +{ + int i; + + for (i = 0; i < adr_link->num_adr; i++) { + unsigned int sdw1_version, mfg1_id, part1_id, class1_id; + u64 adr; + + /* skip itself */ + if (i == index_in_link) + continue; + + adr = adr_link->adr_d[i].adr; + + sdw1_version = SDW_VERSION(adr); + mfg1_id = SDW_MFG_ID(adr); + part1_id = SDW_PART_ID(adr); + class1_id = SDW_CLASS_ID(adr); + + if (sdw_version == sdw1_version && + mfg_id == mfg1_id && + part_id == part1_id && + class_id == class1_id) + return false; + } + + return true; +} + +const char *asoc_sdw_get_codec_name(struct device *dev, + const struct asoc_sdw_codec_info *codec_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index) +{ + u64 adr = adr_link->adr_d[adr_index].adr; + unsigned int sdw_version = SDW_VERSION(adr); + unsigned int link_id = SDW_DISCO_LINK_ID(adr); + unsigned int unique_id = SDW_UNIQUE_ID(adr); + unsigned int mfg_id = SDW_MFG_ID(adr); + unsigned int part_id = SDW_PART_ID(adr); + unsigned int class_id = SDW_CLASS_ID(adr); + + if (codec_info->codec_name) + return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); + else if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id, + class_id, adr_index)) + return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x", + link_id, mfg_id, part_id, class_id); + else + return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x", + link_id, mfg_id, part_id, class_id, unique_id); + + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, SND_SOC_SDW_UTILS); + +/* helper to get the link that the codec DAI is used */ +struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, + const char *dai_name) +{ + struct snd_soc_dai_link *dai_link; + int i; + int j; + + for_each_card_prelinks(card, i, dai_link) { + for (j = 0; j < dai_link->num_codecs; j++) { + /* Check each codec in a link */ + if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) + return dai_link; + } + } + return NULL; +} +EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, SND_SOC_SDW_UTILS); + +void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + int ret; + int i, j; + + for (i = 0; i < ctx->codec_info_list_count; i++) { + for (j = 0; j < codec_info_list[i].dai_num; j++) { + codec_info_list[i].dais[j].rtd_init_done = false; + /* Check each dai in codec_info_lis to see if it is used in the link */ + if (!codec_info_list[i].dais[j].exit) + continue; + /* + * We don't need to call .exit function if there is no matched + * dai link found. + */ + dai_link = asoc_sdw_mc_find_codec_dai_used(card, + codec_info_list[i].dais[j].dai_name); + if (dai_link) { + /* Do the .exit function if the codec dai is used in the link */ + ret = codec_info_list[i].dais[j].exit(card, dai_link); + if (ret) + dev_warn(card->dev, + "codec exit failed %d\n", + ret); + break; + } + } + } +} +EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, SND_SOC_SDW_UTILS); + +int asoc_sdw_card_late_probe(struct snd_soc_card *card) +{ + int ret = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { + if (codec_info_list[i].codec_card_late_probe) { + ret = codec_info_list[i].codec_card_late_probe(card); + if (ret < 0) + return ret; + } + } + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, SND_SOC_SDW_UTILS); + +void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + struct snd_soc_dai_link_component *cpus, int cpus_num, + struct snd_soc_dai_link_component *platform_component, + int num_platforms, struct snd_soc_dai_link_component *codecs, + int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops) +{ + dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); + dai_links->id = (*be_id)++; + dai_links->name = name; + dai_links->platforms = platform_component; + dai_links->num_platforms = num_platforms; + dai_links->no_pcm = 1; + dai_links->cpus = cpus; + dai_links->num_cpus = cpus_num; + dai_links->codecs = codecs; + dai_links->num_codecs = codecs_num; + dai_links->dpcm_playback = playback; + dai_links->dpcm_capture = capture; + dai_links->init = init; + dai_links->ops = ops; +} +EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, SND_SOC_SDW_UTILS); + +int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, + int *be_id, char *name, int playback, int capture, + const char *cpu_dai_name, const char *platform_comp_name, + int num_platforms, const char *codec_name, + const char *codec_dai_name, + int (*init)(struct snd_soc_pcm_runtime *rtd), + const struct snd_soc_ops *ops) +{ + struct snd_soc_dai_link_component *dlc; + + /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */ + dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL); + if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name) + return -ENOMEM; + + dlc[0].dai_name = cpu_dai_name; + dlc[1].name = platform_comp_name; + + dlc[2].name = codec_name; + dlc[2].dai_name = codec_dai_name; + + asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture, + &dlc[0], 1, &dlc[1], num_platforms, + &dlc[2], 1, init, ops); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, SND_SOC_SDW_UTILS); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SoundWire ASoC helpers"); diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 2729c6eb3feb6b..848c031ed5fb25 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -23,6 +23,7 @@ config SND_SOC_SOF_AMD_COMMON select SND_AMD_ACP_CONFIG select SND_SOC_SOF_XTENSA select SND_SOC_SOF_ACP_PROBES + select SND_SOC_ACPI_AMD_MATCH select SND_SOC_ACPI if ACPI help This option is not user-selectable but automatically handled by diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index 81bb93e9835864..dbcaac84cb73af 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -153,6 +153,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * break; } if (mach && mach->link_mask) { + mach->mach_params.subsystem_rev = acp_data->pci_rev; mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); @@ -173,6 +174,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; + struct acp_dev_data *acp_data = sdev->pdata->hw_pdata; const struct sof_dev_desc *desc = sof_pdata->desc; struct snd_soc_acpi_mach *mach = NULL; @@ -186,6 +188,7 @@ struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev) } } + mach->mach_params.subsystem_rev = acp_data->pci_rev; sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->fw_filename = mach->fw_filename; diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 74fd5f2b148b85..7b122656efd15c 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -695,6 +695,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) pci_set_master(pci); adata->addr = addr; adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; + adata->pci_rev = pci->revision; mutex_init(&adata->acp_lock); sdev->pdata->hw_pdata = adata; adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 87e79d500865a8..ec9170b3f0680d 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -251,6 +251,7 @@ struct acp_dev_data { bool is_dram_in_use; bool is_sram_in_use; bool sdw_en_stat; + unsigned int pci_rev; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c index fc898444736571..54d42f83ce9e05 100644 --- a/sound/soc/sof/amd/pci-acp63.c +++ b/sound/soc/sof/amd/pci-acp63.c @@ -48,6 +48,7 @@ static const struct sof_amd_acp_desc acp63_chip_info = { static const struct sof_dev_desc acp63_desc = { .machines = snd_soc_acpi_amd_acp63_sof_machines, + .alt_machines = snd_soc_acpi_amd_acp63_sof_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1,