]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: SDCA: Add a helper to get the SoundWire port number
authorCharles Keepax <ckeepax@opensource.cirrus.com>
Mon, 7 Jul 2025 12:41:54 +0000 (13:41 +0100)
committerMark Brown <broonie@kernel.org>
Tue, 15 Jul 2025 18:45:50 +0000 (19:45 +0100)
Add a helper function to extract the SoundWire hardware port number
from the SDCA DataPort Selector Control. Typically this would be
called from hw_params() and used to call sdw_stream_add_slave().

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://patch.msgid.link/20250707124155.2596744-7-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sdca_asoc.h
include/sound/sdca_function.h
sound/soc/sdca/sdca_asoc.c

index bbf146e4fcea7c52cf5ac39752be9971dacf1496..800a26adcd8e0c7732c59b80fa20cc1890e0403c 100644 (file)
@@ -48,5 +48,8 @@ int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap,
                              struct snd_soc_dai *dai);
 void sdca_asoc_free_constraints(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai);
+int sdca_asoc_get_port(struct device *dev, struct regmap *regmap,
+                      struct sdca_function_data *function,
+                      struct snd_soc_dai *dai);
 
 #endif // __SDCA_ASOC_H__
index 3bde07409bf36724ac63f2da83c3e702998121a1..90d77fc46416b30f7bc0a1bc36884a58e70cd112 100644 (file)
@@ -185,6 +185,14 @@ enum sdca_usage_range {
        SDCA_USAGE_NCOLS                                = 7,
 };
 
+/**
+ * enum sdca_dataport_selector_range - Column definitions for DataPort_Selector
+ */
+enum sdca_dataport_selector_range {
+       SDCA_DATAPORT_SELECTOR_NCOLS                    = 16,
+       SDCA_DATAPORT_SELECTOR_NROWS                    = 4,
+};
+
 /**
  * enum sdca_mu_controls - SDCA Controls for Mixer Unit
  *
index 1a0149287584117805c669c23fd4c2491aaf6ead..03c663413cc9df9bfd6b5f43b50c43388f2c43a4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/regmap.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/string_helpers.h>
+#include <linux/types.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/sdca.h>
@@ -1368,3 +1369,77 @@ void sdca_asoc_free_constraints(struct snd_pcm_substream *substream,
        kfree(constraint);
 }
 EXPORT_SYMBOL_NS(sdca_asoc_free_constraints, "SND_SOC_SDCA");
+
+/**
+ * sdca_asoc_get_port - return SoundWire port for a DAI
+ * @dev: Pointer to the device, used for error messages.
+ * @regmap: Pointer to the Function register map.
+ * @function: Pointer to the Function information.
+ * @dai: Pointer to the ASoC DAI.
+ *
+ * Typically called from hw_params().
+ *
+ * Return: Returns a positive port number on success, and a negative error
+ * code on failure.
+ */
+int sdca_asoc_get_port(struct device *dev, struct regmap *regmap,
+                      struct sdca_function_data *function,
+                      struct snd_soc_dai *dai)
+{
+       struct sdca_entity *entity = &function->entities[dai->id];
+       struct sdca_control_range *range;
+       unsigned int reg, val;
+       int sel = -EINVAL;
+       int i, ret;
+
+       switch (entity->type) {
+       case SDCA_ENTITY_TYPE_IT:
+               sel = SDCA_CTL_IT_DATAPORT_SELECTOR;
+               break;
+       case SDCA_ENTITY_TYPE_OT:
+               sel = SDCA_CTL_OT_DATAPORT_SELECTOR;
+               break;
+       default:
+               break;
+       }
+
+       if (sel < 0 || !entity->iot.is_dataport) {
+               dev_err(dev, "%s: port number only available for dataports\n",
+                       entity->label);
+               return -EINVAL;
+       }
+
+       range = sdca_selector_find_range(dev, entity, sel, SDCA_DATAPORT_SELECTOR_NCOLS,
+                                        SDCA_DATAPORT_SELECTOR_NROWS);
+       if (!range)
+               return -EINVAL;
+
+       reg = SDW_SDCA_CTL(function->desc->adr, entity->id, sel, 0);
+
+       ret = regmap_read(regmap, reg, &val);
+       if (ret) {
+               dev_err(dev, "%s: failed to read dataport selector: %d\n",
+                       entity->label, ret);
+               return ret;
+       }
+
+       for (i = 0; i < range->rows; i++) {
+               static const u8 port_mask = 0xF;
+
+               sel = sdca_range(range, val & port_mask, i);
+
+               /*
+                * FIXME: Currently only a single dataport is supported, so
+                * return the first one found, technically up to 4 dataports
+                * could be linked, but this is not yet supported.
+                */
+               if (sel != 0xFF)
+                       return sel;
+
+               val >>= hweight8(port_mask);
+       }
+
+       dev_err(dev, "%s: no dataport found\n", entity->label);
+       return -ENODEV;
+}
+EXPORT_SYMBOL_NS(sdca_asoc_get_port, "SND_SOC_SDCA");