Add support for cs42l45 into the Intel machine driver

Merge series from Charles Keepax <ckeepax@opensource.cirrus.com>:

Now that the full class driver is in place we can add support to the
Intel machine driver for Cirrus's new SDCA audio CODEC the cs42l45. This
makes some minor tweaks to the machine driver itself to support SDCA
devices, and then adds the necessary tables etc. to define the device.

Note, this series shouldn't have any dependencies on the other series of
improvements to the class driver that is already on the list. So either
can be merged first.
pull/1354/merge
Mark Brown 2025-11-27 21:50:42 +00:00
commit f2b4592300
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
10 changed files with 275 additions and 81 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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");

View File

@ -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},
@ -704,6 +707,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",
@ -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,17 +1489,13 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
if (!codec_info)
return -EINVAL;
for (j = 0; j < codec_info->aux_num; j++) {
soc_aux->dlc.name = codec_info->auxs[j].codec_name;
soc_aux++;
}
ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
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);
soc_end->name_prefix = adr_dev->name_prefix;
if (codec_info->count_sidecar && codec_info->add_sidecar) {
ret = codec_info->count_sidecar(card, &num_dais, num_devs);
if (ret)
@ -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;