public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Charles Keepax <ckeepax@opensource.cirrus.com>
To: <broonie@kernel.org>
Cc: <lgirdwood@gmail.com>, <peter.ujfalusi@linux.intel.com>,
	<yung-chuan.liao@linux.intel.com>,
	<pierre-louis.bossart@linux.dev>, <linux-kernel@vger.kernel.org>,
	<linux-sound@vger.kernel.org>
Subject: [PATCH 2/4] ASoC: SDCA: Add generic regmap SDCA helpers
Date: Mon, 17 Feb 2025 14:01:57 +0000	[thread overview]
Message-ID: <20250217140159.2288784-3-ckeepax@opensource.cirrus.com> (raw)
In-Reply-To: <20250217140159.2288784-1-ckeepax@opensource.cirrus.com>

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 --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");
-- 
2.39.5


  parent reply	other threads:[~2025-02-17 14:02 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-17 14:01 [PATCH 0/4] Add SDCA register map support Charles Keepax
2025-02-17 14:01 ` [PATCH 1/4] regcache: Add support for sorting defaults arrays Charles Keepax
2025-02-17 14:01 ` Charles Keepax [this message]
2025-02-17 14:01 ` [PATCH 3/4] ASoC: SDCA: Add regmap helpers for parsing for DisCo Constant values Charles Keepax
2025-02-17 14:01 ` [PATCH 4/4] ASoC: SDCA: Add helper to write out defaults and fixed values Charles Keepax
2025-02-20 13:01 ` [PATCH 0/4] Add SDCA register map support Pierre-Louis Bossart
2025-02-21  9:46   ` Charles Keepax
2025-02-27 17:27 ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250217140159.2288784-3-ckeepax@opensource.cirrus.com \
    --to=ckeepax@opensource.cirrus.com \
    --cc=broonie@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=peter.ujfalusi@linux.intel.com \
    --cc=pierre-louis.bossart@linux.dev \
    --cc=yung-chuan.liao@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox