Skip to content

Commit 108f878

Browse files
charleskeepaxbroonie
authored andcommitted
ASoC: SDCA: Create DAI drivers from DisCo
Use the previously parsed DisCo information from ACPI to create the DAI drivers required to connect an SDCA Function into an ASoC soundcard. Create DAI driver structures and populate the supported sample rates and sample widths into them based on the Input/Output Terminal and any attach Clock Source entities. More complex relationships with channels etc. will be added later as constraints as part of the DAI startup. Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> Link: https://patch.msgid.link/20250516131011.221310-8-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent c3ca24e commit 108f878

File tree

3 files changed

+256
-6
lines changed

3 files changed

+256
-6
lines changed

include/sound/sdca_asoc.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,29 @@ struct device;
1414
struct sdca_function_data;
1515
struct snd_kcontrol_new;
1616
struct snd_soc_component_driver;
17+
struct snd_soc_dai_driver;
18+
struct snd_soc_dai_ops;
1719
struct snd_soc_dapm_route;
1820
struct snd_soc_dapm_widget;
1921

2022
int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *function,
21-
int *num_widgets, int *num_routes, int *num_controls);
23+
int *num_widgets, int *num_routes, int *num_controls,
24+
int *num_dais);
2225

2326
int sdca_asoc_populate_dapm(struct device *dev, struct sdca_function_data *function,
2427
struct snd_soc_dapm_widget *widgets,
2528
struct snd_soc_dapm_route *routes);
2629
int sdca_asoc_populate_controls(struct device *dev,
2730
struct sdca_function_data *function,
2831
struct snd_kcontrol_new *kctl);
32+
int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *function,
33+
struct snd_soc_dai_driver *dais,
34+
const struct snd_soc_dai_ops *ops);
2935

3036
int sdca_asoc_populate_component(struct device *dev,
3137
struct sdca_function_data *function,
32-
struct snd_soc_component_driver *component_drv);
38+
struct snd_soc_component_driver *component_drv,
39+
struct snd_soc_dai_driver **dai_drv, int *num_dai_drv,
40+
const struct snd_soc_dai_ops *ops);
3341

3442
#endif // __SDCA_ASOC_H__

include/sound/sdca_function.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,20 @@ enum sdca_ot_controls {
168168
SDCA_CTL_OT_NDAI_PACKETTYPE = 0x17,
169169
};
170170

171+
/**
172+
* enum sdca_usage_range - Column definitions for Usage
173+
*/
174+
enum sdca_usage_range {
175+
SDCA_USAGE_NUMBER = 0,
176+
SDCA_USAGE_CBN = 1,
177+
SDCA_USAGE_SAMPLE_RATE = 2,
178+
SDCA_USAGE_SAMPLE_WIDTH = 3,
179+
SDCA_USAGE_FULL_SCALE = 4,
180+
SDCA_USAGE_NOISE_FLOOR = 5,
181+
SDCA_USAGE_TAG = 6,
182+
SDCA_USAGE_NCOLS = 7,
183+
};
184+
171185
/**
172186
* enum sdca_mu_controls - SDCA Controls for Mixer Unit
173187
*
@@ -246,6 +260,15 @@ enum sdca_cs_controls {
246260
SDCA_CTL_CS_SAMPLERATEINDEX = 0x10,
247261
};
248262

263+
/**
264+
* enum sdca_samplerateindex_range - Column definitions for SampleRateIndex
265+
*/
266+
enum sdca_samplerateindex_range {
267+
SDCA_SAMPLERATEINDEX_INDEX = 0,
268+
SDCA_SAMPLERATEINDEX_RATE = 1,
269+
SDCA_SAMPLERATEINDEX_NCOLS = 2,
270+
};
271+
249272
/**
250273
* enum sdca_cx_controls - SDCA Controls for Clock Selector
251274
*

sound/soc/sdca/sdca_asoc.c

Lines changed: 223 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <sound/sdca_function.h>
2323
#include <sound/soc.h>
2424
#include <sound/soc-component.h>
25+
#include <sound/soc-dai.h>
2526
#include <sound/soc-dapm.h>
2627
#include <sound/tlv.h>
2728

@@ -99,6 +100,8 @@ static bool readonly_control(struct sdca_control *control)
99100
* required number of DAPM routes for the Function.
100101
* @num_controls: Output integer pointer, will be filled with the
101102
* required number of ALSA controls for the Function.
103+
* @num_dais: Output integer pointer, will be filled with the
104+
* required number of ASoC DAIs for the Function.
102105
*
103106
* This function counts various things within the SDCA Function such
104107
* that the calling driver can allocate appropriate space before
@@ -107,13 +110,15 @@ static bool readonly_control(struct sdca_control *control)
107110
* Return: Returns zero on success, and a negative error code on failure.
108111
*/
109112
int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *function,
110-
int *num_widgets, int *num_routes, int *num_controls)
113+
int *num_widgets, int *num_routes, int *num_controls,
114+
int *num_dais)
111115
{
112116
int i, j;
113117

114118
*num_widgets = function->num_entities - 1;
115119
*num_routes = 0;
116120
*num_controls = 0;
121+
*num_dais = 0;
117122

118123
for (i = 0; i < function->num_entities - 1; i++) {
119124
struct sdca_entity *entity = &function->entities[i];
@@ -125,6 +130,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun
125130
*num_routes += !!entity->iot.clock;
126131
*num_routes += !!entity->iot.is_dataport;
127132
*num_controls += !entity->iot.is_dataport;
133+
*num_dais += !!entity->iot.is_dataport;
128134
break;
129135
case SDCA_ENTITY_TYPE_PDE:
130136
*num_routes += entity->pde.num_managed;
@@ -1033,6 +1039,205 @@ int sdca_asoc_populate_controls(struct device *dev,
10331039
}
10341040
EXPORT_SYMBOL_NS(sdca_asoc_populate_controls, "SND_SOC_SDCA");
10351041

1042+
static unsigned int rate_find_mask(unsigned int rate)
1043+
{
1044+
switch (rate) {
1045+
case 0:
1046+
return SNDRV_PCM_RATE_8000_768000;
1047+
case 5512:
1048+
return SNDRV_PCM_RATE_5512;
1049+
case 8000:
1050+
return SNDRV_PCM_RATE_8000;
1051+
case 11025:
1052+
return SNDRV_PCM_RATE_11025;
1053+
case 16000:
1054+
return SNDRV_PCM_RATE_16000;
1055+
case 22050:
1056+
return SNDRV_PCM_RATE_22050;
1057+
case 32000:
1058+
return SNDRV_PCM_RATE_32000;
1059+
case 44100:
1060+
return SNDRV_PCM_RATE_44100;
1061+
case 48000:
1062+
return SNDRV_PCM_RATE_48000;
1063+
case 64000:
1064+
return SNDRV_PCM_RATE_64000;
1065+
case 88200:
1066+
return SNDRV_PCM_RATE_88200;
1067+
case 96000:
1068+
return SNDRV_PCM_RATE_96000;
1069+
case 176400:
1070+
return SNDRV_PCM_RATE_176400;
1071+
case 192000:
1072+
return SNDRV_PCM_RATE_192000;
1073+
case 352800:
1074+
return SNDRV_PCM_RATE_352800;
1075+
case 384000:
1076+
return SNDRV_PCM_RATE_384000;
1077+
case 705600:
1078+
return SNDRV_PCM_RATE_705600;
1079+
case 768000:
1080+
return SNDRV_PCM_RATE_768000;
1081+
case 12000:
1082+
return SNDRV_PCM_RATE_12000;
1083+
case 24000:
1084+
return SNDRV_PCM_RATE_24000;
1085+
case 128000:
1086+
return SNDRV_PCM_RATE_128000;
1087+
default:
1088+
return 0;
1089+
}
1090+
}
1091+
1092+
static u64 width_find_mask(unsigned int bits)
1093+
{
1094+
switch (bits) {
1095+
case 0:
1096+
return SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
1097+
SNDRV_PCM_FMTBIT_S20_LE | SNDRV_PCM_FMTBIT_S24_LE |
1098+
SNDRV_PCM_FMTBIT_S32_LE;
1099+
case 8:
1100+
return SNDRV_PCM_FMTBIT_S8;
1101+
case 16:
1102+
return SNDRV_PCM_FMTBIT_S16_LE;
1103+
case 20:
1104+
return SNDRV_PCM_FMTBIT_S20_LE;
1105+
case 24:
1106+
return SNDRV_PCM_FMTBIT_S24_LE;
1107+
case 32:
1108+
return SNDRV_PCM_FMTBIT_S32_LE;
1109+
default:
1110+
return 0;
1111+
}
1112+
}
1113+
1114+
static int populate_rate_format(struct device *dev,
1115+
struct sdca_function_data *function,
1116+
struct sdca_entity *entity,
1117+
struct snd_soc_pcm_stream *stream)
1118+
{
1119+
struct sdca_control_range *range;
1120+
unsigned int sample_rate, sample_width;
1121+
unsigned int clock_rates = 0;
1122+
unsigned int rates = 0;
1123+
u64 formats = 0;
1124+
int sel, i;
1125+
1126+
switch (entity->type) {
1127+
case SDCA_ENTITY_TYPE_IT:
1128+
sel = SDCA_CTL_IT_USAGE;
1129+
break;
1130+
case SDCA_ENTITY_TYPE_OT:
1131+
sel = SDCA_CTL_OT_USAGE;
1132+
break;
1133+
default:
1134+
dev_err(dev, "%s: entity type has no usage control\n",
1135+
entity->label);
1136+
return -EINVAL;
1137+
}
1138+
1139+
if (entity->iot.clock) {
1140+
range = selector_find_range(dev, entity->iot.clock,
1141+
SDCA_CTL_CS_SAMPLERATEINDEX,
1142+
SDCA_SAMPLERATEINDEX_NCOLS, 0);
1143+
if (!range)
1144+
return -EINVAL;
1145+
1146+
for (i = 0; i < range->rows; i++) {
1147+
sample_rate = sdca_range(range, SDCA_SAMPLERATEINDEX_RATE, i);
1148+
clock_rates |= rate_find_mask(sample_rate);
1149+
}
1150+
} else {
1151+
clock_rates = UINT_MAX;
1152+
}
1153+
1154+
range = selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0);
1155+
if (!range)
1156+
return -EINVAL;
1157+
1158+
for (i = 0; i < range->rows; i++) {
1159+
sample_rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i);
1160+
sample_rate = rate_find_mask(sample_rate);
1161+
1162+
if (sample_rate & clock_rates) {
1163+
rates |= sample_rate;
1164+
1165+
sample_width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i);
1166+
formats |= width_find_mask(sample_width);
1167+
}
1168+
}
1169+
1170+
stream->formats = formats;
1171+
stream->rates = rates;
1172+
1173+
return 0;
1174+
}
1175+
1176+
/**
1177+
* sdca_asoc_populate_dais - fill in an array of DAI drivers for a Function
1178+
* @dev: Pointer to the device against which allocations will be done.
1179+
* @function: Pointer to the Function information.
1180+
* @dais: Array of DAI drivers to be populated.
1181+
* @ops: DAI ops to be attached to each of the created DAI drivers.
1182+
*
1183+
* This function populates an array of ASoC DAI drivers from the DisCo
1184+
* information for a particular SDCA Function. Typically,
1185+
* snd_soc_asoc_count_component will be used to allocate an
1186+
* appropriately sized array before calling this function.
1187+
*
1188+
* Return: Returns zero on success, and a negative error code on failure.
1189+
*/
1190+
int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *function,
1191+
struct snd_soc_dai_driver *dais,
1192+
const struct snd_soc_dai_ops *ops)
1193+
{
1194+
int i, j;
1195+
int ret;
1196+
1197+
for (i = 0, j = 0; i < function->num_entities - 1; i++) {
1198+
struct sdca_entity *entity = &function->entities[i];
1199+
struct snd_soc_pcm_stream *stream;
1200+
const char *stream_suffix;
1201+
1202+
switch (entity->type) {
1203+
case SDCA_ENTITY_TYPE_IT:
1204+
stream = &dais[j].playback;
1205+
stream_suffix = "Playback";
1206+
break;
1207+
case SDCA_ENTITY_TYPE_OT:
1208+
stream = &dais[j].capture;
1209+
stream_suffix = "Capture";
1210+
break;
1211+
default:
1212+
continue;
1213+
}
1214+
1215+
/* Can't check earlier as only terminals have an iot member. */
1216+
if (!entity->iot.is_dataport)
1217+
continue;
1218+
1219+
stream->stream_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
1220+
entity->label, stream_suffix);
1221+
if (!stream->stream_name)
1222+
return -ENOMEM;
1223+
/* Channels will be further limited by constraints */
1224+
stream->channels_min = 1;
1225+
stream->channels_max = SDCA_MAX_CHANNEL_COUNT;
1226+
1227+
ret = populate_rate_format(dev, function, entity, stream);
1228+
if (ret)
1229+
return ret;
1230+
1231+
dais[j].id = i;
1232+
dais[j].name = entity->label;
1233+
dais[j].ops = ops;
1234+
j++;
1235+
}
1236+
1237+
return 0;
1238+
}
1239+
EXPORT_SYMBOL_NS(sdca_asoc_populate_dais, "SND_SOC_SDCA");
1240+
10361241
/**
10371242
* sdca_asoc_populate_component - fill in a component driver for a Function
10381243
* @dev: Pointer to the device against which allocations will be done.
@@ -1047,16 +1252,19 @@ EXPORT_SYMBOL_NS(sdca_asoc_populate_controls, "SND_SOC_SDCA");
10471252
*/
10481253
int sdca_asoc_populate_component(struct device *dev,
10491254
struct sdca_function_data *function,
1050-
struct snd_soc_component_driver *component_drv)
1255+
struct snd_soc_component_driver *component_drv,
1256+
struct snd_soc_dai_driver **dai_drv, int *num_dai_drv,
1257+
const struct snd_soc_dai_ops *ops)
10511258
{
10521259
struct snd_soc_dapm_widget *widgets;
10531260
struct snd_soc_dapm_route *routes;
10541261
struct snd_kcontrol_new *controls;
1055-
int num_widgets, num_routes, num_controls;
1262+
struct snd_soc_dai_driver *dais;
1263+
int num_widgets, num_routes, num_controls, num_dais;
10561264
int ret;
10571265

10581266
ret = sdca_asoc_count_component(dev, function, &num_widgets, &num_routes,
1059-
&num_controls);
1267+
&num_controls, &num_dais);
10601268
if (ret)
10611269
return ret;
10621270

@@ -1072,6 +1280,10 @@ int sdca_asoc_populate_component(struct device *dev,
10721280
if (!controls)
10731281
return -ENOMEM;
10741282

1283+
dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL);
1284+
if (!dais)
1285+
return -ENOMEM;
1286+
10751287
ret = sdca_asoc_populate_dapm(dev, function, widgets, routes);
10761288
if (ret)
10771289
return ret;
@@ -1080,13 +1292,20 @@ int sdca_asoc_populate_component(struct device *dev,
10801292
if (ret)
10811293
return ret;
10821294

1295+
ret = sdca_asoc_populate_dais(dev, function, dais, ops);
1296+
if (ret)
1297+
return ret;
1298+
10831299
component_drv->dapm_widgets = widgets;
10841300
component_drv->num_dapm_widgets = num_widgets;
10851301
component_drv->dapm_routes = routes;
10861302
component_drv->num_dapm_routes = num_routes;
10871303
component_drv->controls = controls;
10881304
component_drv->num_controls = num_controls;
10891305

1306+
*dai_drv = dais;
1307+
*num_dai_drv = num_dais;
1308+
10901309
return 0;
10911310
}
10921311
EXPORT_SYMBOL_NS(sdca_asoc_populate_component, "SND_SOC_SDCA");

0 commit comments

Comments
 (0)