diff mbox series

[2/4] ASoC: SDCA: Add generic regmap SDCA helpers

Message ID 20250217140159.2288784-3-ckeepax@opensource.cirrus.com (mailing list archive)
State New
Headers show
Series Add SDCA register map support | expand

Commit Message

Charles Keepax Feb. 17, 2025, 2:01 p.m. UTC
Add helper functions that SDCA drivers can use to calculate the
properties of SDCA Controls (registers) specified through DisCo.
Most of these are fairly obvious from the SDCA Access Modes.

DisCo Constants, values which are specified in the ACPI rather than on
the device, are handled as unreadable and unwritable registers. The
intention is these will be populated in the register defaults table
allowing drivers to read them normally. This means the drivers can be
agnostic as to which values are DisCo Constants.

Finally, support for SDCA Dual Ranked Controls is currently limited
here, at the moment the current value will be used directly. Writing
the current value directly is valid as per the specification
although the synchronicity of updates across multiple registers is
lost. Support for this will probably need to be added later. But its a
fairly hard problem and doesn't need to be solved immediately.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
---
 include/sound/sdca_regmap.h  |  21 ++++
 sound/soc/sdca/Makefile      |   2 +-
 sound/soc/sdca/sdca_regmap.c | 192 +++++++++++++++++++++++++++++++++++
 3 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100644 include/sound/sdca_regmap.h
 create mode 100644 sound/soc/sdca/sdca_regmap.c
diff mbox series

Patch

diff --git a/include/sound/sdca_regmap.h b/include/sound/sdca_regmap.h
new file mode 100644
index 000000000000..11826f4f0726
--- /dev/null
+++ b/include/sound/sdca_regmap.h
@@ -0,0 +1,21 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ *
+ * Copyright (C) 2025 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __SDCA_REGMAP_H__
+#define __SDCA_REGMAP_H__
+
+struct sdca_function_data;
+
+bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg);
+bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg);
+bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg);
+bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg);
+int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg);
+
+#endif // __SDCA_REGMAP_H__
diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile
index 5d1ddbbfbf62..dddc3e694256 100644
--- a/sound/soc/sdca/Makefile
+++ b/sound/soc/sdca/Makefile
@@ -1,5 +1,5 @@ 
 # SPDX-License-Identifier: GPL-2.0-only
 
-snd-soc-sdca-y	:= sdca_functions.o sdca_device.o
+snd-soc-sdca-y	:= sdca_functions.o sdca_device.o sdca_regmap.o
 
 obj-$(CONFIG_SND_SOC_SDCA)	+= snd-soc-sdca.o
diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c
new file mode 100644
index 000000000000..ae6358f0fc26
--- /dev/null
+++ b/sound/soc/sdca/sdca_regmap.c
@@ -0,0 +1,192 @@ 
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/bitops.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/types.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_regmap.h>
+
+static struct sdca_entity *
+function_find_entity(struct sdca_function_data *function, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < function->num_entities; i++)
+		if (SDW_SDCA_CTL_ENT(reg) == function->entities[i].id)
+			return &function->entities[i];
+
+	return NULL;
+}
+
+static struct sdca_control *
+entity_find_control(struct sdca_entity *entity, unsigned int reg)
+{
+	int i;
+
+	for (i = 0; i < entity->num_controls; i++) {
+		if (SDW_SDCA_CTL_CSEL(reg) == entity->controls[i].sel)
+			return &entity->controls[i];
+	}
+
+	return NULL;
+}
+
+static struct sdca_control *
+function_find_control(struct sdca_function_data *function, unsigned int reg)
+{
+	struct sdca_entity *entity;
+
+	entity = function_find_entity(function, reg);
+	if (!entity)
+		return NULL;
+
+	return entity_find_control(entity, reg);
+}
+
+/**
+ * sdca_regmap_readable - return if a given SDCA Control is readable
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is readable.
+ */
+bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg)
+{
+	struct sdca_control *control;
+
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return false;
+
+	control = function_find_control(function, reg);
+	if (!control)
+		return false;
+
+	switch (control->mode) {
+	case SDCA_ACCESS_MODE_RW:
+	case SDCA_ACCESS_MODE_RO:
+	case SDCA_ACCESS_MODE_DUAL:
+	case SDCA_ACCESS_MODE_RW1S:
+	case SDCA_ACCESS_MODE_RW1C:
+		/* No access to registers marked solely for device use */
+		return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_NS(sdca_regmap_readable, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_writeable - return if a given SDCA Control is writeable
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is writeable.
+ */
+bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg)
+{
+	struct sdca_control *control;
+
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return false;
+
+	control = function_find_control(function, reg);
+	if (!control)
+		return false;
+
+	switch (control->mode) {
+	case SDCA_ACCESS_MODE_RW:
+	case SDCA_ACCESS_MODE_DUAL:
+	case SDCA_ACCESS_MODE_RW1S:
+	case SDCA_ACCESS_MODE_RW1C:
+		/* No access to registers marked solely for device use */
+		return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_NS(sdca_regmap_writeable, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_volatile - return if a given SDCA Control is volatile
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is volatile.
+ */
+bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg)
+{
+	struct sdca_control *control;
+
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return false;
+
+	control = function_find_control(function, reg);
+	if (!control)
+		return false;
+
+	switch (control->mode) {
+	case SDCA_ACCESS_MODE_RO:
+	case SDCA_ACCESS_MODE_RW1S:
+	case SDCA_ACCESS_MODE_RW1C:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_deferrable - return if a given SDCA Control is deferrable
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is deferrable.
+ */
+bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg)
+{
+	struct sdca_control *control;
+
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return false;
+
+	control = function_find_control(function, reg);
+	if (!control)
+		return false;
+
+	return control->deferrable;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_deferrable, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_mbq_size - return size in bytes of a given SDCA Control
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns the size in bytes of the Control.
+ */
+int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg)
+{
+	struct sdca_control *control;
+
+	if (!SDW_SDCA_VALID_CTL(reg))
+		return -EINVAL;
+
+	control = function_find_control(function, reg);
+	if (!control)
+		return false;
+
+	return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32));
+}
+EXPORT_SYMBOL_NS(sdca_regmap_mbq_size, "SND_SOC_SDCA");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SDCA library");