ASoC: SDCA: Add support for -cn- value properties

Many of the DisCo properties that specify Control values have an
additional variant that specifies a separate value for each Control
Number. Add support for these.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20250718135432.1048566-3-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Charles Keepax 2025-07-18 14:54:32 +01:00 committed by Mark Brown
parent 061fade7a6
commit 50a479527e
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
3 changed files with 78 additions and 48 deletions

View file

@ -742,14 +742,14 @@ struct sdca_control_range {
* struct sdca_control - information for one SDCA Control
* @label: Name for the Control, from SDCA Specification v1.0, section 7.1.7.
* @sel: Identifier used for addressing.
* @value: Holds the Control value for constants and defaults.
* @nbits: Number of bits used in the Control.
* @interrupt_position: SCDA interrupt line that will alert to changes on this
* Control.
* @values: Holds the Control value for constants and defaults.
* @cn_list: A bitmask showing the valid Control Numbers within this Control,
* Control Numbers typically represent channels.
* @range: Buffer describing valid range of values for the Control.
* @interrupt_position: SCDA interrupt line that will alert to changes on this
* Control.
* @type: Format of the data in the Control.
* @range: Buffer describing valid range of values for the Control.
* @mode: Access mode of the Control.
* @layers: Bitmask of access layers of the Control.
* @deferrable: Indicates if the access to the Control can be deferred.
@ -760,13 +760,13 @@ struct sdca_control {
const char *label;
int sel;
int value;
int nbits;
int interrupt_position;
int *values;
u64 cn_list;
int interrupt_position;
struct sdca_control_range range;
enum sdca_control_datatype type;
struct sdca_control_range range;
enum sdca_access_mode mode;
u8 layers;

View file

@ -814,6 +814,43 @@ static int find_sdca_control_range(struct device *dev,
return 0;
}
static int find_sdca_control_value(struct device *dev, struct sdca_entity *entity,
struct fwnode_handle *control_node,
struct sdca_control *control,
const char * const label)
{
char property[SDCA_PROPERTY_LENGTH];
bool global = true;
int ret, cn, i;
u32 tmp;
snprintf(property, sizeof(property), "mipi-sdca-control-%s", label);
ret = fwnode_property_read_u32(control_node, property, &tmp);
if (ret == -EINVAL)
global = false;
else if (ret)
return ret;
i = 0;
for_each_set_bit(cn, (unsigned long *)&control->cn_list,
BITS_PER_TYPE(control->cn_list)) {
if (!global) {
snprintf(property, sizeof(property),
"mipi-sdca-control-cn-%d-%s", cn, label);
ret = fwnode_property_read_u32(control_node, property, &tmp);
if (ret)
return ret;
}
control->values[i] = tmp;
i++;
}
return 0;
}
/*
* TODO: Add support for -cn- properties, allowing different channels to have
* different defaults etc.
@ -843,44 +880,44 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->layers = tmp;
ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
&control->cn_list);
if (ret == -EINVAL) {
/* Spec allows not specifying cn-list if only the first number is used */
control->cn_list = 0x1;
} else if (ret || !control->cn_list) {
dev_err(dev, "%s: control %#x: cn list missing: %d\n",
entity->label, control->sel, ret);
return ret;
}
control->values = devm_kzalloc(dev, hweight64(control->cn_list), GFP_KERNEL);
if (!control->values)
return -ENOMEM;
switch (control->mode) {
case SDCA_ACCESS_MODE_DC:
ret = fwnode_property_read_u32(control_node,
"mipi-sdca-control-dc-value",
&tmp);
ret = find_sdca_control_value(dev, entity, control_node, control,
"dc-value");
if (ret) {
dev_err(dev, "%s: control %#x: dc value missing: %d\n",
entity->label, control->sel, ret);
return ret;
}
control->value = tmp;
control->has_fixed = true;
break;
case SDCA_ACCESS_MODE_RW:
case SDCA_ACCESS_MODE_DUAL:
ret = fwnode_property_read_u32(control_node,
"mipi-sdca-control-default-value",
&tmp);
if (!ret) {
control->value = tmp;
ret = find_sdca_control_value(dev, entity, control_node, control,
"default-value");
if (!ret)
control->has_default = true;
}
ret = fwnode_property_read_u32(control_node,
"mipi-sdca-control-fixed-value",
&tmp);
if (!ret) {
if (control->has_default && control->value != tmp) {
dev_err(dev,
"%s: control %#x: default and fixed value don't match\n",
entity->label, control->sel);
return -EINVAL;
}
control->value = tmp;
ret = find_sdca_control_value(dev, entity, control_node, control,
"fixed-value");
if (!ret)
control->has_fixed = true;
}
fallthrough;
case SDCA_ACCESS_MODE_RO:
control->deferrable = fwnode_property_read_bool(control_node,
@ -897,17 +934,6 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
return ret;
}
ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
&control->cn_list);
if (ret == -EINVAL) {
/* Spec allows not specifying cn-list if only the first number is used */
control->cn_list = 0x1;
} else if (ret || !control->cn_list) {
dev_err(dev, "%s: control %#x: cn list missing: %d\n",
entity->label, control->sel, ret);
return ret;
}
ret = fwnode_property_read_u32(control_node,
"mipi-sdca-control-interrupt-position",
&tmp);
@ -923,11 +949,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
control->type = find_sdca_control_datatype(entity, control);
control->nbits = find_sdca_control_bits(entity, control);
dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d value %#x %s\n",
dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n",
entity->label, control->label, control->sel,
control->mode, control->layers, control->cn_list,
control->interrupt_position, control->value,
control->deferrable ? "deferrable" : "");
control->interrupt_position, control->deferrable ? "deferrable" : "");
return 0;
}

View file

@ -253,7 +253,7 @@ int sdca_regmap_populate_constants(struct device *dev,
struct sdca_function_data *function,
struct reg_default *consts)
{
int i, j, k;
int i, j, k, l;
for (i = 0, k = 0; i < function->num_entities; i++) {
struct sdca_entity *entity = &function->entities[i];
@ -265,13 +265,15 @@ int sdca_regmap_populate_constants(struct device *dev,
if (control->mode != SDCA_ACCESS_MODE_DC)
continue;
l = 0;
for_each_set_bit(cn, (unsigned long *)&control->cn_list,
BITS_PER_TYPE(control->cn_list)) {
consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
entity->id,
control->sel, cn);
consts[k].def = control->value;
consts[k].def = control->values[l];
k++;
l++;
}
}
}
@ -295,7 +297,7 @@ EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
struct sdca_function_data *function)
{
int i, j;
int i, j, k;
int ret;
for (i = 0; i < function->num_entities; i++) {
@ -311,6 +313,7 @@ int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
if (!control->has_default && !control->has_fixed)
continue;
k = 0;
for_each_set_bit(cn, (unsigned long *)&control->cn_list,
BITS_PER_TYPE(control->cn_list)) {
unsigned int reg;
@ -318,9 +321,11 @@ int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
control->sel, cn);
ret = regmap_write(regmap, reg, control->value);
ret = regmap_write(regmap, reg, control->values[k]);
if (ret)
return ret;
k++;
}
}
}