ASoC: SDCA: Add parsing for Control range structures

DisCo/SDCA contains small buffers of data that hold ranges of valid
values for the various SDCA Controls. Add support for parsing these
from ACPI.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://patch.msgid.link/20250205113801.3699902-7-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Charles Keepax
2025-02-05 11:37:57 +00:00
committed by Mark Brown
parent 42b144cb6a
commit 64fb5af1d1
2 changed files with 59 additions and 0 deletions

View File

@@ -612,6 +612,18 @@ enum sdca_access_layer {
SDCA_ACCESS_LAYER_EXTENSION = 1 << 5,
};
/**
* struct sdca_control_range - SDCA Control range table
* @cols: Number of columns in the range table.
* @rows: Number of rows in the range table.
* @data: Array of values contained in the range table.
*/
struct sdca_control_range {
unsigned int cols;
unsigned int rows;
u32 *data;
};
/**
* struct sdca_control - information for one SDCA Control
* @label: Name for the Control, from SDCA Specification v1.0, section 7.1.7.
@@ -622,6 +634,7 @@ enum sdca_access_layer {
* Control.
* @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.
* @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.
@@ -637,6 +650,7 @@ struct sdca_control {
int interrupt_position;
u64 cn_list;
struct sdca_control_range range;
enum sdca_access_mode mode;
u8 layers;

View File

@@ -603,6 +603,44 @@ static unsigned int find_sdca_control_bits(const struct sdca_entity *entity,
}
}
static int find_sdca_control_range(struct device *dev,
struct fwnode_handle *control_node,
struct sdca_control_range *range)
{
u8 *range_list;
int num_range;
u16 *limits;
int i;
num_range = fwnode_property_count_u8(control_node, "mipi-sdca-control-range");
if (!num_range || num_range == -EINVAL)
return 0;
else if (num_range < 0)
return num_range;
range_list = devm_kcalloc(dev, num_range, sizeof(*range_list), GFP_KERNEL);
if (!range_list)
return -ENOMEM;
fwnode_property_read_u8_array(control_node, "mipi-sdca-control-range",
range_list, num_range);
limits = (u16 *)range_list;
range->cols = le16_to_cpu(limits[0]);
range->rows = le16_to_cpu(limits[1]);
range->data = (u32 *)&limits[2];
num_range = (num_range - (2 * sizeof(*limits))) / sizeof(*range->data);
if (num_range != range->cols * range->rows)
return -EINVAL;
for (i = 0; i < num_range; i++)
range->data[i] = le32_to_cpu(range->data[i]);
return 0;
}
/*
* TODO: Add support for -cn- properties, allowing different channels to have
* different defaults etc.
@@ -678,6 +716,13 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
break;
}
ret = find_sdca_control_range(dev, control_node, &control->range);
if (ret) {
dev_err(dev, "%s: control %#x: range missing: %d\n",
entity->label, control->sel, ret);
return ret;
}
ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
&control->cn_list);
if (ret == -EINVAL) {