Skip to content

Commit 4ed357f

Browse files
charleskeepaxbroonie
authored andcommitted
ASoC: SDCA: Add hw_params() helper function
Add a helper function that can be called from hw_params() in the DAI ops to configure the SDCA Cluster, Clock and Usage controls. These setup the channels, sample rate, and bit depths that will be used by the Terminal. 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 264d3d7 commit 4ed357f

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

include/sound/sdca_asoc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct device;
1414
struct regmap;
1515
struct sdca_function_data;
1616
struct snd_kcontrol_new;
17+
struct snd_pcm_hw_params;
1718
struct snd_pcm_substream;
1819
struct snd_soc_component_driver;
1920
struct snd_soc_dai;
@@ -51,5 +52,10 @@ void sdca_asoc_free_constraints(struct snd_pcm_substream *substream,
5152
int sdca_asoc_get_port(struct device *dev, struct regmap *regmap,
5253
struct sdca_function_data *function,
5354
struct snd_soc_dai *dai);
55+
int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap,
56+
struct sdca_function_data *function,
57+
struct snd_pcm_substream *substream,
58+
struct snd_pcm_hw_params *params,
59+
struct snd_soc_dai *dai);
5460

5561
#endif // __SDCA_ASOC_H__

sound/soc/sdca/sdca_asoc.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/types.h>
2323
#include <sound/control.h>
2424
#include <sound/pcm.h>
25+
#include <sound/pcm_params.h>
2526
#include <sound/sdca.h>
2627
#include <sound/sdca_asoc.h>
2728
#include <sound/sdca_function.h>
@@ -1443,3 +1444,182 @@ int sdca_asoc_get_port(struct device *dev, struct regmap *regmap,
14431444
return -ENODEV;
14441445
}
14451446
EXPORT_SYMBOL_NS(sdca_asoc_get_port, "SND_SOC_SDCA");
1447+
1448+
static int set_cluster(struct device *dev, struct regmap *regmap,
1449+
struct sdca_function_data *function,
1450+
struct sdca_entity *entity, unsigned int channels)
1451+
{
1452+
int sel = SDCA_CTL_IT_CLUSTERINDEX;
1453+
struct sdca_control_range *range;
1454+
int i, ret;
1455+
1456+
range = sdca_selector_find_range(dev, entity, sel, SDCA_CLUSTER_NCOLS, 0);
1457+
if (!range)
1458+
return -EINVAL;
1459+
1460+
for (i = 0; i < range->rows; i++) {
1461+
int cluster_id = sdca_range(range, SDCA_CLUSTER_CLUSTERID, i);
1462+
struct sdca_cluster *cluster;
1463+
1464+
cluster = sdca_id_find_cluster(dev, function, cluster_id);
1465+
if (!cluster)
1466+
return -ENODEV;
1467+
1468+
if (cluster->num_channels == channels) {
1469+
int index = sdca_range(range, SDCA_CLUSTER_BYTEINDEX, i);
1470+
unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
1471+
entity->id, sel, 0);
1472+
1473+
ret = regmap_update_bits(regmap, reg, 0xFF, index);
1474+
if (ret) {
1475+
dev_err(dev, "%s: failed to write cluster index: %d\n",
1476+
entity->label, ret);
1477+
return ret;
1478+
}
1479+
1480+
dev_dbg(dev, "%s: set cluster to %d (%d channels)\n",
1481+
entity->label, index, channels);
1482+
1483+
return 0;
1484+
}
1485+
}
1486+
1487+
dev_err(dev, "%s: no cluster for %d channels\n", entity->label, channels);
1488+
return -EINVAL;
1489+
}
1490+
1491+
static int set_clock(struct device *dev, struct regmap *regmap,
1492+
struct sdca_function_data *function,
1493+
struct sdca_entity *entity, int target_rate)
1494+
{
1495+
int sel = SDCA_CTL_CS_SAMPLERATEINDEX;
1496+
struct sdca_control_range *range;
1497+
int i, ret;
1498+
1499+
range = sdca_selector_find_range(dev, entity, sel, SDCA_SAMPLERATEINDEX_NCOLS, 0);
1500+
if (!range)
1501+
return -EINVAL;
1502+
1503+
for (i = 0; i < range->rows; i++) {
1504+
unsigned int rate = sdca_range(range, SDCA_SAMPLERATEINDEX_RATE, i);
1505+
1506+
if (rate == target_rate) {
1507+
unsigned int index = sdca_range(range,
1508+
SDCA_SAMPLERATEINDEX_INDEX,
1509+
i);
1510+
unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
1511+
entity->id, sel, 0);
1512+
1513+
ret = regmap_update_bits(regmap, reg, 0xFF, index);
1514+
if (ret) {
1515+
dev_err(dev, "%s: failed to write clock rate: %d\n",
1516+
entity->label, ret);
1517+
return ret;
1518+
}
1519+
1520+
dev_dbg(dev, "%s: set clock rate to %d (%dHz)\n",
1521+
entity->label, index, rate);
1522+
1523+
return 0;
1524+
}
1525+
}
1526+
1527+
dev_err(dev, "%s: no clock rate for %dHz\n", entity->label, target_rate);
1528+
return -EINVAL;
1529+
}
1530+
1531+
static int set_usage(struct device *dev, struct regmap *regmap,
1532+
struct sdca_function_data *function,
1533+
struct sdca_entity *entity, int sel,
1534+
int target_rate, int target_width)
1535+
{
1536+
struct sdca_control_range *range;
1537+
int i, ret;
1538+
1539+
range = sdca_selector_find_range(dev, entity, sel, SDCA_USAGE_NCOLS, 0);
1540+
if (!range)
1541+
return -EINVAL;
1542+
1543+
for (i = 0; i < range->rows; i++) {
1544+
unsigned int rate = sdca_range(range, SDCA_USAGE_SAMPLE_RATE, i);
1545+
unsigned int width = sdca_range(range, SDCA_USAGE_SAMPLE_WIDTH, i);
1546+
1547+
if ((!rate || rate == target_rate) && width == target_width) {
1548+
unsigned int usage = sdca_range(range, SDCA_USAGE_NUMBER, i);
1549+
unsigned int reg = SDW_SDCA_CTL(function->desc->adr,
1550+
entity->id, sel, 0);
1551+
1552+
ret = regmap_update_bits(regmap, reg, 0xFF, usage);
1553+
if (ret) {
1554+
dev_err(dev, "%s: failed to write usage: %d\n",
1555+
entity->label, ret);
1556+
return ret;
1557+
}
1558+
1559+
dev_dbg(dev, "%s: set usage to %#x (%dHz, %d bits)\n",
1560+
entity->label, usage, target_rate, target_width);
1561+
1562+
return 0;
1563+
}
1564+
}
1565+
1566+
dev_err(dev, "%s: no usage for %dHz, %dbits\n",
1567+
entity->label, target_rate, target_width);
1568+
return -EINVAL;
1569+
}
1570+
1571+
/**
1572+
* sdca_asoc_hw_params - set SDCA channels, sample rate and bit depth
1573+
* @dev: Pointer to the device, used for error messages.
1574+
* @regmap: Pointer to the Function register map.
1575+
* @function: Pointer to the Function information.
1576+
* @substream: Pointer to the PCM substream.
1577+
* @params: Pointer to the hardware parameters.
1578+
* @dai: Pointer to the ASoC DAI.
1579+
*
1580+
* Typically called from hw_params().
1581+
*
1582+
* Return: Returns zero on success, and a negative error code on failure.
1583+
*/
1584+
int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap,
1585+
struct sdca_function_data *function,
1586+
struct snd_pcm_substream *substream,
1587+
struct snd_pcm_hw_params *params,
1588+
struct snd_soc_dai *dai)
1589+
{
1590+
struct sdca_entity *entity = &function->entities[dai->id];
1591+
int channels = params_channels(params);
1592+
int width = params_width(params);
1593+
int rate = params_rate(params);
1594+
int usage_sel;
1595+
int ret;
1596+
1597+
switch (entity->type) {
1598+
case SDCA_ENTITY_TYPE_IT:
1599+
ret = set_cluster(dev, regmap, function, entity, channels);
1600+
if (ret)
1601+
return ret;
1602+
1603+
usage_sel = SDCA_CTL_IT_USAGE;
1604+
break;
1605+
case SDCA_ENTITY_TYPE_OT:
1606+
usage_sel = SDCA_CTL_OT_USAGE;
1607+
break;
1608+
default:
1609+
dev_err(dev, "%s: hw_params on non-terminal entity\n", entity->label);
1610+
return -EINVAL;
1611+
}
1612+
1613+
if (entity->iot.clock) {
1614+
ret = set_clock(dev, regmap, function, entity->iot.clock, rate);
1615+
if (ret)
1616+
return ret;
1617+
}
1618+
1619+
ret = set_usage(dev, regmap, function, entity, usage_sel, rate, width);
1620+
if (ret)
1621+
return ret;
1622+
1623+
return 0;
1624+
}
1625+
EXPORT_SYMBOL_NS(sdca_asoc_hw_params, "SND_SOC_SDCA");

0 commit comments

Comments
 (0)