diff options
| -rw-r--r-- | include/sound/sdca_function.h | 4 | ||||
| -rw-r--r-- | include/sound/soc_sdw_utils.h | 17 | ||||
| -rw-r--r-- | sound/soc/amd/acp/acp-sdw-legacy-mach.c | 19 | ||||
| -rw-r--r-- | sound/soc/amd/acp/acp-sdw-sof-mach.c | 12 | ||||
| -rw-r--r-- | sound/soc/intel/boards/sof_sdw.c | 21 | ||||
| -rw-r--r-- | sound/soc/sdca/sdca_asoc.c | 51 | ||||
| -rw-r--r-- | sound/soc/sdca/sdca_functions.c | 56 | ||||
| -rw-r--r-- | sound/soc/sdw_utils/Makefile | 1 | ||||
| -rw-r--r-- | sound/soc/sdw_utils/soc_sdw_cs42l45.c | 80 | ||||
| -rw-r--r-- | sound/soc/sdw_utils/soc_sdw_utils.c | 95 |
10 files changed, 275 insertions, 81 deletions
diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index c97861508a15..6e9391b3816c 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -611,7 +611,7 @@ enum sdca_entity0_controls { #define SDCA_CTL_NDAI_PACKETTYPE_NAME "NDAI Packet Type" #define SDCA_CTL_MIXER_NAME "Mixer" #define SDCA_CTL_SELECTOR_NAME "Selector" -#define SDCA_CTL_MUTE_NAME "Mute" +#define SDCA_CTL_MUTE_NAME "Channel" #define SDCA_CTL_CHANNEL_VOLUME_NAME "Channel Volume" #define SDCA_CTL_AGC_NAME "AGC" #define SDCA_CTL_BASS_BOOST_NAME "Bass Boost" @@ -1456,6 +1456,8 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, struct sdca_function_desc *desc, struct sdca_function_data *function); +const char *sdca_find_terminal_name(enum sdca_terminal_type type); + struct sdca_control *sdca_selector_find_control(struct device *dev, struct sdca_entity *entity, const int sel); diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 76c64c5245d4..227347c8f0b3 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -13,6 +13,7 @@ #include <sound/soc-acpi.h> #define SOC_SDW_MAX_DAI_NUM 8 +#define SOC_SDW_MAX_AUX_NUM 2 #define SOC_SDW_MAX_NO_PROPS 2 #define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) @@ -45,6 +46,7 @@ struct asoc_sdw_codec_info; struct asoc_sdw_dai_info { const bool direction[2]; /* playback & capture support */ + const char *codec_name; const char *dai_name; const char *component_name; const int dai_type; @@ -64,10 +66,13 @@ struct asoc_sdw_dai_info { bool quirk_exclude; }; +struct asoc_sdw_aux_info { + const char *codec_name; +}; + struct asoc_sdw_codec_info { const int part_id; const int version_id; - const char *codec_name; const char *name_prefix; int amp_num; const u8 acpi_id[ACPI_ID_LEN]; @@ -75,6 +80,8 @@ struct asoc_sdw_codec_info { const struct snd_soc_ops *ops; struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM]; const int dai_num; + struct asoc_sdw_aux_info auxs[SOC_SDW_MAX_AUX_NUM]; + const int aux_num; int (*codec_card_late_probe)(struct snd_soc_card *card); @@ -131,7 +138,7 @@ 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 asoc_sdw_dai_info *dai_info, const struct snd_soc_acpi_link_adr *adr_link, int adr_index); @@ -165,13 +172,15 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops); -int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends); +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, + int *num_devs, int *num_ends, int *num_aux); struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, const struct snd_soc_acpi_endpoint *new); int asoc_sdw_get_dai_type(u32 type); int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, int *num_devs); @@ -248,6 +257,8 @@ int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da 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_cs42l45_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); +int asoc_sdw_cs42l45_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); /* TI */ diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index 54f823f7cecf..fae94b9edd5a 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -360,20 +360,25 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL; struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL; + struct snd_soc_aux_dev *soc_aux; struct snd_soc_codec_conf *codec_conf; struct snd_soc_dai_link *dai_links; int num_devs = 0; int num_ends = 0; + int num_aux = 0; + int num_confs; int num_links; int be_id = 0; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + num_confs = num_ends; + /* One per DAI link, worst case is a DAI link for every endpoint */ soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL); if (!soc_dais) @@ -384,7 +389,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) if (!soc_ends) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(card, soc_dais, soc_ends, &num_devs); + soc_aux = devm_kcalloc(dev, num_aux, sizeof(*soc_aux), GFP_KERNEL); + if (!soc_aux) + return -ENOMEM; + + ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs); if (ret < 0) return ret; @@ -396,7 +405,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); - codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) return -ENOMEM; @@ -407,9 +416,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) return -ENOMEM; card->codec_conf = codec_conf; - card->num_configs = num_devs; + card->num_configs = num_confs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = soc_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index d055582a3bf1..5677ae63fca9 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -272,15 +272,17 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct asoc_sdw_endpoint *sof_ends __free(kfree) = NULL; struct asoc_sdw_dailink *sof_dais __free(kfree) = NULL; + struct snd_soc_aux_dev *sof_aux; struct snd_soc_codec_conf *codec_conf; struct snd_soc_dai_link *dai_links; int num_devs = 0; int num_ends = 0; + int num_aux = 0; int num_links; int be_id = 0; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; @@ -296,7 +298,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!sof_ends) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL); + if (!sof_aux) + return -ENOMEM; + + ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs); if (ret < 0) return ret; @@ -322,6 +328,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) card->num_configs = num_devs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = sof_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6c86a79e8c24..2c1001148d54 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1189,8 +1189,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct asoc_sdw_codec_info *ssp_info; struct asoc_sdw_endpoint *sof_ends; struct asoc_sdw_dailink *sof_dais; + struct snd_soc_aux_dev *sof_aux; int num_devs = 0; int num_ends = 0; + int num_aux = 0; + int num_confs; struct snd_soc_dai_link *dai_links; int num_links; int be_id = 0; @@ -1198,12 +1201,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) unsigned long ssp_mask; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + num_confs = num_ends; + /* * One per DAI link, worst case is a DAI link for every endpoint, also * add one additional to act as a terminator such that code can iterate @@ -1220,7 +1225,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL); + if (!sof_aux) { + ret = -ENOMEM; + goto err_dai; + } + + ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs); if (ret < 0) goto err_end; @@ -1268,7 +1279,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) sdw_be_num, ssp_num, dmic_num, intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); - codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) { ret = -ENOMEM; goto err_end; @@ -1283,9 +1294,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) } card->codec_conf = codec_conf; - card->num_configs = num_devs; + card->num_configs = num_confs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = sof_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 4e3f193c75ef..2d328bbb95b9 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -115,50 +115,6 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun } EXPORT_SYMBOL_NS(sdca_asoc_count_component, "SND_SOC_SDCA"); -static const char *get_terminal_name(enum sdca_terminal_type type) -{ - switch (type) { - case SDCA_TERM_TYPE_LINEIN_STEREO: - return SDCA_TERM_TYPE_LINEIN_STEREO_NAME; - case SDCA_TERM_TYPE_LINEIN_FRONT_LR: - return SDCA_TERM_TYPE_LINEIN_FRONT_LR_NAME; - case SDCA_TERM_TYPE_LINEIN_CENTER_LFE: - return SDCA_TERM_TYPE_LINEIN_CENTER_LFE_NAME; - case SDCA_TERM_TYPE_LINEIN_SURROUND_LR: - return SDCA_TERM_TYPE_LINEIN_SURROUND_LR_NAME; - case SDCA_TERM_TYPE_LINEIN_REAR_LR: - return SDCA_TERM_TYPE_LINEIN_REAR_LR_NAME; - case SDCA_TERM_TYPE_LINEOUT_STEREO: - return SDCA_TERM_TYPE_LINEOUT_STEREO_NAME; - case SDCA_TERM_TYPE_LINEOUT_FRONT_LR: - return SDCA_TERM_TYPE_LINEOUT_FRONT_LR_NAME; - case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE: - return SDCA_TERM_TYPE_LINEOUT_CENTER_LFE_NAME; - case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR: - return SDCA_TERM_TYPE_LINEOUT_SURROUND_LR_NAME; - case SDCA_TERM_TYPE_LINEOUT_REAR_LR: - return SDCA_TERM_TYPE_LINEOUT_REAR_LR_NAME; - case SDCA_TERM_TYPE_MIC_JACK: - return SDCA_TERM_TYPE_MIC_JACK_NAME; - case SDCA_TERM_TYPE_STEREO_JACK: - return SDCA_TERM_TYPE_STEREO_JACK_NAME; - case SDCA_TERM_TYPE_FRONT_LR_JACK: - return SDCA_TERM_TYPE_FRONT_LR_JACK_NAME; - case SDCA_TERM_TYPE_CENTER_LFE_JACK: - return SDCA_TERM_TYPE_CENTER_LFE_JACK_NAME; - case SDCA_TERM_TYPE_SURROUND_LR_JACK: - return SDCA_TERM_TYPE_SURROUND_LR_JACK_NAME; - case SDCA_TERM_TYPE_REAR_LR_JACK: - return SDCA_TERM_TYPE_REAR_LR_JACK_NAME; - case SDCA_TERM_TYPE_HEADPHONE_JACK: - return SDCA_TERM_TYPE_HEADPHONE_JACK_NAME; - case SDCA_TERM_TYPE_HEADSET_JACK: - return SDCA_TERM_TYPE_HEADSET_JACK_NAME; - default: - return NULL; - } -} - static int entity_early_parse_ge(struct device *dev, struct sdca_function_data *function, struct sdca_entity *entity) @@ -217,7 +173,7 @@ static int entity_early_parse_ge(struct device *dev, type = sdca_range(range, SDCA_SELECTED_MODE_TERM_TYPE, i); values[i + 3] = sdca_range(range, SDCA_SELECTED_MODE_INDEX, i); - texts[i + 3] = get_terminal_name(type); + texts[i + 3] = sdca_find_terminal_name(type); if (!texts[i + 3]) { dev_err(dev, "%s: unrecognised terminal type: %#x\n", entity->label, type); @@ -499,7 +455,7 @@ static int entity_parse_su_device(struct device *dev, return -EINVAL; } - add_route(route, entity->label, get_terminal_name(term), + add_route(route, entity->label, sdca_find_terminal_name(term), entity->sources[affected->val - 1]->label); } } @@ -886,6 +842,9 @@ static int populate_control(struct device *dev, mc->min = 0; mc->max = clamp((0x1ull << control->nbits) - 1, 0, type_max(mc->max)); + if (SDCA_CTL_TYPE(entity->type, control->sel) == SDCA_CTL_TYPE_S(FU, MUTE)) + mc->invert = true; + (*kctl)->name = control_name; (*kctl)->private_value = (unsigned long)mc; (*kctl)->iface = SNDRV_CTL_ELEM_IFACE_MIXER; diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index e4b3efeb30f0..5a1f120487ef 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/property.h> #include <linux/soundwire/sdw.h> +#include <linux/string.h> #include <linux/types.h> #include <sound/sdca.h> #include <sound/sdca_function.h> @@ -1120,6 +1121,14 @@ static int find_sdca_entity_iot(struct device *dev, terminal->type = tmp; terminal->is_dataport = find_sdca_iot_dataport(terminal); + if (!terminal->is_dataport) { + const char *type_name = sdca_find_terminal_name(terminal->type); + + if (type_name) + entity->label = devm_kasprintf(dev, GFP_KERNEL, "%s %s", + entity->label, type_name); + } + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-terminal-reference-number", &tmp); if (!ret) @@ -1565,7 +1574,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data * for (i = 0; i < function->num_entities; i++) { struct sdca_entity *entity = &function->entities[i]; - if (!strcmp(entity->label, entity_label)) + if (!strncmp(entity->label, entity_label, strlen(entity_label))) return entity; } @@ -2156,6 +2165,51 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, } EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); +const char *sdca_find_terminal_name(enum sdca_terminal_type type) +{ + switch (type) { + case SDCA_TERM_TYPE_LINEIN_STEREO: + return SDCA_TERM_TYPE_LINEIN_STEREO_NAME; + case SDCA_TERM_TYPE_LINEIN_FRONT_LR: + return SDCA_TERM_TYPE_LINEIN_FRONT_LR_NAME; + case SDCA_TERM_TYPE_LINEIN_CENTER_LFE: + return SDCA_TERM_TYPE_LINEIN_CENTER_LFE_NAME; + case SDCA_TERM_TYPE_LINEIN_SURROUND_LR: + return SDCA_TERM_TYPE_LINEIN_SURROUND_LR_NAME; + case SDCA_TERM_TYPE_LINEIN_REAR_LR: + return SDCA_TERM_TYPE_LINEIN_REAR_LR_NAME; + case SDCA_TERM_TYPE_LINEOUT_STEREO: + return SDCA_TERM_TYPE_LINEOUT_STEREO_NAME; + case SDCA_TERM_TYPE_LINEOUT_FRONT_LR: + return SDCA_TERM_TYPE_LINEOUT_FRONT_LR_NAME; + case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE: + return SDCA_TERM_TYPE_LINEOUT_CENTER_LFE_NAME; + case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR: + return SDCA_TERM_TYPE_LINEOUT_SURROUND_LR_NAME; + case SDCA_TERM_TYPE_LINEOUT_REAR_LR: + return SDCA_TERM_TYPE_LINEOUT_REAR_LR_NAME; + case SDCA_TERM_TYPE_MIC_JACK: + return SDCA_TERM_TYPE_MIC_JACK_NAME; + case SDCA_TERM_TYPE_STEREO_JACK: + return SDCA_TERM_TYPE_STEREO_JACK_NAME; + case SDCA_TERM_TYPE_FRONT_LR_JACK: + return SDCA_TERM_TYPE_FRONT_LR_JACK_NAME; + case SDCA_TERM_TYPE_CENTER_LFE_JACK: + return SDCA_TERM_TYPE_CENTER_LFE_JACK_NAME; + case SDCA_TERM_TYPE_SURROUND_LR_JACK: + return SDCA_TERM_TYPE_SURROUND_LR_JACK_NAME; + case SDCA_TERM_TYPE_REAR_LR_JACK: + return SDCA_TERM_TYPE_REAR_LR_JACK_NAME; + case SDCA_TERM_TYPE_HEADPHONE_JACK: + return SDCA_TERM_TYPE_HEADPHONE_JACK_NAME; + case SDCA_TERM_TYPE_HEADSET_JACK: + return SDCA_TERM_TYPE_HEADSET_JACK_NAME; + default: + return NULL; + } +} +EXPORT_SYMBOL_NS(sdca_find_terminal_name, "SND_SOC_SDCA"); + struct sdca_control *sdca_selector_find_control(struct device *dev, struct sdca_entity *entity, const int sel) diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile index a87c53e1a2c1..e8bd5ffb1a6a 100644 --- a/sound/soc/sdw_utils/Makefile +++ b/sound/soc/sdw_utils/Makefile @@ -5,6 +5,7 @@ snd-soc-sdw-utils-y := soc_sdw_utils.o soc_sdw_dmic.o soc_sdw_rt_dmic.o \ soc_sdw_rt_amp.o soc_sdw_rt_mf_sdca.o \ soc_sdw_bridge_cs35l56.o \ soc_sdw_cs42l42.o soc_sdw_cs42l43.o \ + soc_sdw_cs42l45.o \ soc_sdw_cs_amp.o \ soc_sdw_maxim.o \ soc_sdw_ti_amp.o diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l45.c b/sound/soc/sdw_utils/soc_sdw_cs42l45.c new file mode 100644 index 000000000000..647923d9669f --- /dev/null +++ b/sound/soc/sdw_utils/soc_sdw_cs42l45.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Based on sof_sdw_rt5682.c +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2023 Intel Corporation +// Copyright (c) 2024 Advanced Micro Devices, Inc. + +/* + * soc_sdw_cs42l45 - Helpers to handle CS42L45 from generic machine driver + */ +#include <linux/device.h> +#include <linux/errno.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-card.h> +#include <sound/soc-component.h> +#include <sound/soc-dai.h> +#include <sound/soc_sdw_utils.h> + +static struct snd_soc_jack_pin soc_jack_pins[] = { + { + .pin = "cs42l45 OT 43 Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "cs42l45 OT 45 Headset", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "cs42l45 IT 31 Microphone", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "cs42l45 IT 33 Headset", + .mask = SND_JACK_MICROPHONE, + }, +}; + +int asoc_sdw_cs42l45_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +{ + struct snd_soc_card *card = rtd->card; + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_jack *jack = &ctx->sdw_headset; + int ret; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs42l45", + card->components); + if (!card->components) + return -ENOMEM; + + ret = snd_soc_card_jack_new_pins(card, "Jack", SND_JACK_MECHANICAL | + SND_JACK_HEADSET | SND_JACK_LINEOUT, jack, + soc_jack_pins, ARRAY_SIZE(soc_jack_pins)); + if (ret) { + dev_err(card->dev, "Failed to create jack: %d\n", ret); + return ret; + } + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(card->dev, "Failed to register jack: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_cs42l45_hs_rtd_init, "SND_SOC_SDW_UTILS"); + +int asoc_sdw_cs42l45_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +{ + struct snd_soc_card *card = rtd->card; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:cs42l45-dmic", + card->components); + if (!card->components) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_cs42l45_dmic_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 824fb613c486..6c656b2f7f3a 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -656,12 +656,12 @@ struct asoc_sdw_codec_info codec_info_list[] = { { .part_id = 0x4243, .name_prefix = "cs42l43", - .codec_name = "cs42l43-codec", .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar, .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar, .dais = { { .direction = {true, false}, + .codec_name = "cs42l43-codec", .dai_name = "cs42l43-dp5", .dai_type = SOC_SDW_DAI_TYPE_JACK, .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, @@ -673,6 +673,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { }, { .direction = {false, true}, + .codec_name = "cs42l43-codec", .dai_name = "cs42l43-dp1", .dai_type = SOC_SDW_DAI_TYPE_MIC, .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, @@ -684,12 +685,14 @@ struct asoc_sdw_codec_info codec_info_list[] = { }, { .direction = {false, true}, + .codec_name = "cs42l43-codec", .dai_name = "cs42l43-dp2", .dai_type = SOC_SDW_DAI_TYPE_JACK, .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, }, { .direction = {true, false}, + .codec_name = "cs42l43-codec", .dai_name = "cs42l43-dp6", .dai_type = SOC_SDW_DAI_TYPE_AMP, .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, @@ -705,6 +708,42 @@ struct asoc_sdw_codec_info codec_info_list[] = { .dai_num = 4, }, { + .part_id = 0x4245, + .name_prefix = "cs42l45", + .dais = { + { + .direction = {true, false}, + .codec_name = "snd_soc_sdca.UAJ.1", + .dai_name = "IT 41", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .rtd_init = asoc_sdw_cs42l45_hs_rtd_init, + }, + { + .direction = {false, true}, + .codec_name = "snd_soc_sdca.SmartMic.0", + .dai_name = "OT 113", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init, + }, + { + .direction = {false, true}, + .codec_name = "snd_soc_sdca.UAJ.1", + .dai_name = "OT 36", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + }, + }, + .dai_num = 3, + .auxs = { + { + .codec_name = "snd_soc_sdca.HID.2", + }, + }, + .aux_num = 1, + }, + { .part_id = 0xaaaa, /* generic codec mockup */ .name_prefix = "sdw_mockup_mmulti-function", .version_id = 0, @@ -1094,7 +1133,6 @@ static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_li } static 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) { @@ -1116,14 +1154,14 @@ static const char *_asoc_sdw_get_codec_name(struct device *dev, } const char *asoc_sdw_get_codec_name(struct device *dev, - const struct asoc_sdw_codec_info *codec_info, + const struct asoc_sdw_dai_info *dai_info, const struct snd_soc_acpi_link_adr *adr_link, int adr_index) { - if (codec_info->codec_name) - return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL); + if (dai_info->codec_name) + return devm_kstrdup(dev, dai_info->codec_name, GFP_KERNEL); - return _asoc_sdw_get_codec_name(dev, codec_info, adr_link, adr_index); + return _asoc_sdw_get_codec_name(dev, adr_link, adr_index); } EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); @@ -1250,7 +1288,8 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d } EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS"); -int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, + int *num_devs, int *num_ends, int *num_aux) { struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); @@ -1261,8 +1300,18 @@ int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int * for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { *num_devs += adr_link->num_adr; - for (i = 0; i < adr_link->num_adr; i++) - *num_ends += adr_link->adr_d[i].num_endpoints; + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; + struct asoc_sdw_codec_info *codec_info; + + *num_ends += adr_dev->num_endpoints; + + codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); + if (!codec_info) + return -EINVAL; + + *num_aux += codec_info->aux_num; + } } dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); @@ -1354,8 +1403,7 @@ static int is_sdca_endpoint_present(struct device *dev, } kfree(dlc); - sdw_codec_name = _asoc_sdw_get_codec_name(dev, codec_info, - adr_link, adr_index); + sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index); if (!sdw_codec_name) return -ENOMEM; @@ -1401,6 +1449,7 @@ put_device: } int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, + struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, int *num_devs) @@ -1440,16 +1489,12 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, if (!codec_info) return -EINVAL; - ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; - - codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); - if (!codec_name) - return -ENOMEM; - - dev_dbg(dev, "Adding prefix %s for %s\n", - adr_dev->name_prefix, codec_name); + for (j = 0; j < codec_info->aux_num; j++) { + soc_aux->dlc.name = codec_info->auxs[j].codec_name; + soc_aux++; + } - soc_end->name_prefix = adr_dev->name_prefix; + ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; if (codec_info->count_sidecar && codec_info->add_sidecar) { ret = codec_info->count_sidecar(card, &num_dais, num_devs); @@ -1538,6 +1583,16 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, num_link_dailinks += !!list_empty(&soc_dai->endpoints); list_add_tail(&soc_end->list, &soc_dai->endpoints); + codec_name = asoc_sdw_get_codec_name(dev, dai_info, + adr_link, i); + if (!codec_name) + return -ENOMEM; + + dev_dbg(dev, "Adding prefix %s for %s\n", + adr_dev->name_prefix, codec_name); + + soc_end->name_prefix = adr_dev->name_prefix; + soc_end->link_mask = adr_link->mask; soc_end->codec_name = codec_name; soc_end->codec_info = codec_info; |
