Unverified Commit 64fb5af1 authored by Charles Keepax's avatar Charles Keepax Committed by Mark Brown
Browse files

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: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://patch.msgid.link/20250205113801.3699902-7-ckeepax@opensource.cirrus.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 42b144cb
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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;

+45 −0
Original line number Diff line number Diff line
@@ -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) {