Skip to content

Commit 7b0d60d

Browse files
charleskeepaxbroonie
authored andcommitted
ASoC: SDCA: Add helper to add DAI constraints
Currently the core SDCA code simply creates a place holder available channels from 1 to SDCA_MAX_CHANNEL_COUNT. Add a helper function that will constrain the number of channels based on the actual available SDCA Clusters in DisCo. Currently this code only handles Input Terminal Entities as they directly specify the Cluster. More work will be required later for Output Terminals which inherit their Cluster. Typically this new helper would be called from the DAIs startup callback. Signed-off-by: Charles Keepax <[email protected]> Reviewed-by: Pierre-Louis Bossart <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 5f86d41 commit 7b0d60d

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

include/sound/sdca_asoc.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
#define __SDCA_ASOC_H__
1212

1313
struct device;
14+
struct regmap;
1415
struct sdca_function_data;
1516
struct snd_kcontrol_new;
17+
struct snd_pcm_substream;
1618
struct snd_soc_component_driver;
19+
struct snd_soc_dai;
1720
struct snd_soc_dai_driver;
1821
struct snd_soc_dai_ops;
1922
struct snd_soc_dapm_route;
@@ -39,4 +42,11 @@ int sdca_asoc_populate_component(struct device *dev,
3942
struct snd_soc_dai_driver **dai_drv, int *num_dai_drv,
4043
const struct snd_soc_dai_ops *ops);
4144

45+
int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap,
46+
struct sdca_function_data *function,
47+
struct snd_pcm_substream *substream,
48+
struct snd_soc_dai *dai);
49+
void sdca_asoc_free_constraints(struct snd_pcm_substream *substream,
50+
struct snd_soc_dai *dai);
51+
4252
#endif // __SDCA_ASOC_H__

include/sound/sdca_function.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,6 +1268,15 @@ struct sdca_cluster {
12681268
struct sdca_channel *channels;
12691269
};
12701270

1271+
/**
1272+
* enum sdca_cluster_range - SDCA Range column definitions for ClusterIndex
1273+
*/
1274+
enum sdca_cluster_range {
1275+
SDCA_CLUSTER_BYTEINDEX = 0,
1276+
SDCA_CLUSTER_CLUSTERID = 1,
1277+
SDCA_CLUSTER_NCOLS = 2,
1278+
};
1279+
12711280
/**
12721281
* struct sdca_function_data - top-level information for one SDCA function
12731282
* @desc: Pointer to short descriptor from initial parsing.
@@ -1326,5 +1335,8 @@ struct sdca_control_range *sdca_control_find_range(struct device *dev,
13261335
struct sdca_control_range *sdca_selector_find_range(struct device *dev,
13271336
struct sdca_entity *entity,
13281337
int sel, int cols, int rows);
1338+
struct sdca_cluster *sdca_id_find_cluster(struct device *dev,
1339+
struct sdca_function_data *function,
1340+
const int id);
13291341

13301342
#endif

sound/soc/sdca/sdca_asoc.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
* https://www.mipi.org/mipi-sdca-v1-0-download
88
*/
99

10+
#include <linux/bits.h>
1011
#include <linux/bitmap.h>
12+
#include <linux/build_bug.h>
1113
#include <linux/delay.h>
1214
#include <linux/dev_printk.h>
1315
#include <linux/device.h>
1416
#include <linux/minmax.h>
1517
#include <linux/module.h>
1618
#include <linux/overflow.h>
19+
#include <linux/regmap.h>
1720
#include <linux/soundwire/sdw_registers.h>
1821
#include <linux/string_helpers.h>
1922
#include <sound/control.h>
23+
#include <sound/pcm.h>
2024
#include <sound/sdca.h>
2125
#include <sound/sdca_asoc.h>
2226
#include <sound/sdca_function.h>
@@ -1269,3 +1273,98 @@ int sdca_asoc_populate_component(struct device *dev,
12691273
return 0;
12701274
}
12711275
EXPORT_SYMBOL_NS(sdca_asoc_populate_component, "SND_SOC_SDCA");
1276+
1277+
/**
1278+
* sdca_asoc_set_constraints - constrain channels available on a DAI
1279+
* @dev: Pointer to the device, used for error messages.
1280+
* @regmap: Pointer to the Function register map.
1281+
* @function: Pointer to the Function information.
1282+
* @substream: Pointer to the PCM substream.
1283+
* @dai: Pointer to the ASoC DAI.
1284+
*
1285+
* Typically called from startup().
1286+
*
1287+
* Return: Returns zero on success, and a negative error code on failure.
1288+
*/
1289+
int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap,
1290+
struct sdca_function_data *function,
1291+
struct snd_pcm_substream *substream,
1292+
struct snd_soc_dai *dai)
1293+
{
1294+
static const unsigned int channel_list[] = {
1295+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
1296+
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
1297+
};
1298+
struct sdca_entity *entity = &function->entities[dai->id];
1299+
struct snd_pcm_hw_constraint_list *constraint;
1300+
struct sdca_control_range *range;
1301+
struct sdca_control *control;
1302+
unsigned int channel_mask = 0;
1303+
int i, ret;
1304+
1305+
static_assert(ARRAY_SIZE(channel_list) == SDCA_MAX_CHANNEL_COUNT);
1306+
static_assert(sizeof(channel_mask) * BITS_PER_BYTE >= SDCA_MAX_CHANNEL_COUNT);
1307+
1308+
if (entity->type != SDCA_ENTITY_TYPE_IT)
1309+
return 0;
1310+
1311+
control = sdca_selector_find_control(dev, entity, SDCA_CTL_IT_CLUSTERINDEX);
1312+
if (!control)
1313+
return -EINVAL;
1314+
1315+
range = sdca_control_find_range(dev, entity, control, SDCA_CLUSTER_NCOLS, 0);
1316+
if (!range)
1317+
return -EINVAL;
1318+
1319+
for (i = 0; i < range->rows; i++) {
1320+
int clusterid = sdca_range(range, SDCA_CLUSTER_CLUSTERID, i);
1321+
struct sdca_cluster *cluster;
1322+
1323+
cluster = sdca_id_find_cluster(dev, function, clusterid);
1324+
if (!cluster)
1325+
return -ENODEV;
1326+
1327+
channel_mask |= (1 << (cluster->num_channels - 1));
1328+
}
1329+
1330+
dev_dbg(dev, "%s: set channel constraint mask: %#x\n",
1331+
entity->label, channel_mask);
1332+
1333+
constraint = kzalloc(sizeof(*constraint), GFP_KERNEL);
1334+
if (!constraint)
1335+
return -ENOMEM;
1336+
1337+
constraint->count = ARRAY_SIZE(channel_list);
1338+
constraint->list = channel_list;
1339+
constraint->mask = channel_mask;
1340+
1341+
ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
1342+
SNDRV_PCM_HW_PARAM_CHANNELS,
1343+
constraint);
1344+
if (ret) {
1345+
dev_err(dev, "%s: failed to add constraint: %d\n", entity->label, ret);
1346+
kfree(constraint);
1347+
return ret;
1348+
}
1349+
1350+
dai->priv = constraint;
1351+
1352+
return 0;
1353+
}
1354+
EXPORT_SYMBOL_NS(sdca_asoc_set_constraints, "SND_SOC_SDCA");
1355+
1356+
/**
1357+
* sdca_asoc_free_constraints - free constraint allocations
1358+
* @substream: Pointer to the PCM substream.
1359+
* @dai: Pointer to the ASoC DAI.
1360+
*
1361+
* Typically called from shutdown().
1362+
*/
1363+
void sdca_asoc_free_constraints(struct snd_pcm_substream *substream,
1364+
struct snd_soc_dai *dai)
1365+
{
1366+
struct snd_pcm_hw_constraint_list *constraint = dai->priv;
1367+
1368+
kfree(constraint);
1369+
}
1370+
EXPORT_SYMBOL_NS(sdca_asoc_free_constraints, "SND_SOC_SDCA");

sound/soc/sdca/sdca_functions.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,5 +1991,23 @@ struct sdca_control_range *sdca_selector_find_range(struct device *dev,
19911991
}
19921992
EXPORT_SYMBOL_NS(sdca_selector_find_range, "SND_SOC_SDCA");
19931993

1994+
struct sdca_cluster *sdca_id_find_cluster(struct device *dev,
1995+
struct sdca_function_data *function,
1996+
const int id)
1997+
{
1998+
int i;
1999+
2000+
for (i = 0; i < function->num_clusters; i++) {
2001+
struct sdca_cluster *cluster = &function->clusters[i];
2002+
2003+
if (cluster->id == id)
2004+
return cluster;
2005+
}
2006+
2007+
dev_err(dev, "%s: cluster %#x: missing\n", function->desc->name, id);
2008+
return NULL;
2009+
}
2010+
EXPORT_SYMBOL_NS(sdca_id_find_cluster, "SND_SOC_SDCA");
2011+
19942012
MODULE_LICENSE("Dual BSD/GPL");
19952013
MODULE_DESCRIPTION("SDCA library");

0 commit comments

Comments
 (0)