]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: SDCA: Add support for -cn- value properties
authorCharles Keepax <ckeepax@opensource.cirrus.com>
Fri, 18 Jul 2025 13:54:32 +0000 (14:54 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 24 Jul 2025 12:28:09 +0000 (13:28 +0100)
Many of the DisCo properties that specify Control values have an
additional variant that specifies a separate value for each Control
Number. Add support for these.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20250718135432.1048566-3-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sdca_function.h
sound/soc/sdca/sdca_functions.c
sound/soc/sdca/sdca_regmap.c

index 90d77fc46416b30f7bc0a1bc36884a58e70cd112..06ec126cdcc34abf8ca591c0b8ca2233433137be 100644 (file)
@@ -742,14 +742,14 @@ struct sdca_control_range {
  * struct sdca_control - information for one SDCA Control
  * @label: Name for the Control, from SDCA Specification v1.0, section 7.1.7.
  * @sel: Identifier used for addressing.
- * @value: Holds the Control value for constants and defaults.
  * @nbits: Number of bits used in the Control.
- * @interrupt_position: SCDA interrupt line that will alert to changes on this
- * Control.
+ * @values: Holds the Control value for constants and defaults.
  * @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.
+ * @interrupt_position: SCDA interrupt line that will alert to changes on this
+ * Control.
  * @type: Format of the data in the Control.
+ * @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.
@@ -760,13 +760,13 @@ struct sdca_control {
        const char *label;
        int sel;
 
-       int value;
        int nbits;
-       int interrupt_position;
+       int *values;
        u64 cn_list;
+       int interrupt_position;
 
-       struct sdca_control_range range;
        enum sdca_control_datatype type;
+       struct sdca_control_range range;
        enum sdca_access_mode mode;
        u8 layers;
 
index 4b6da587c4ac3db27d55cf2dae60c981169604d7..0faee522b3af2014e26091117145e27587a99edd 100644 (file)
@@ -814,6 +814,43 @@ static int find_sdca_control_range(struct device *dev,
        return 0;
 }
 
+static int find_sdca_control_value(struct device *dev, struct sdca_entity *entity,
+                                  struct fwnode_handle *control_node,
+                                  struct sdca_control *control,
+                                  const char * const label)
+{
+       char property[SDCA_PROPERTY_LENGTH];
+       bool global = true;
+       int ret, cn, i;
+       u32 tmp;
+
+       snprintf(property, sizeof(property), "mipi-sdca-control-%s", label);
+
+       ret = fwnode_property_read_u32(control_node, property, &tmp);
+       if (ret == -EINVAL)
+               global = false;
+       else if (ret)
+               return ret;
+
+       i = 0;
+       for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+                        BITS_PER_TYPE(control->cn_list)) {
+               if (!global) {
+                       snprintf(property, sizeof(property),
+                                "mipi-sdca-control-cn-%d-%s", cn, label);
+
+                       ret = fwnode_property_read_u32(control_node, property, &tmp);
+                       if (ret)
+                               return ret;
+               }
+
+               control->values[i] = tmp;
+               i++;
+       }
+
+       return 0;
+}
+
 /*
  * TODO: Add support for -cn- properties, allowing different channels to have
  * different defaults etc.
@@ -843,44 +880,44 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
 
        control->layers = tmp;
 
+       ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
+                                      &control->cn_list);
+       if (ret == -EINVAL) {
+               /* Spec allows not specifying cn-list if only the first number is used */
+               control->cn_list = 0x1;
+       } else if (ret || !control->cn_list) {
+               dev_err(dev, "%s: control %#x: cn list missing: %d\n",
+                       entity->label, control->sel, ret);
+               return ret;
+       }
+
+       control->values = devm_kzalloc(dev, hweight64(control->cn_list), GFP_KERNEL);
+       if (!control->values)
+               return -ENOMEM;
+
        switch (control->mode) {
        case SDCA_ACCESS_MODE_DC:
-               ret = fwnode_property_read_u32(control_node,
-                                              "mipi-sdca-control-dc-value",
-                                              &tmp);
+               ret = find_sdca_control_value(dev, entity, control_node, control,
+                                             "dc-value");
                if (ret) {
                        dev_err(dev, "%s: control %#x: dc value missing: %d\n",
                                entity->label, control->sel, ret);
                        return ret;
                }
 
-               control->value = tmp;
                control->has_fixed = true;
                break;
        case SDCA_ACCESS_MODE_RW:
        case SDCA_ACCESS_MODE_DUAL:
-               ret = fwnode_property_read_u32(control_node,
-                                              "mipi-sdca-control-default-value",
-                                              &tmp);
-               if (!ret) {
-                       control->value = tmp;
+               ret = find_sdca_control_value(dev, entity, control_node, control,
+                                             "default-value");
+               if (!ret)
                        control->has_default = true;
-               }
-
-               ret = fwnode_property_read_u32(control_node,
-                                              "mipi-sdca-control-fixed-value",
-                                              &tmp);
-               if (!ret) {
-                       if (control->has_default && control->value != tmp) {
-                               dev_err(dev,
-                                       "%s: control %#x: default and fixed value don't match\n",
-                                       entity->label, control->sel);
-                               return -EINVAL;
-                       }
 
-                       control->value = tmp;
+               ret = find_sdca_control_value(dev, entity, control_node, control,
+                                             "fixed-value");
+               if (!ret)
                        control->has_fixed = true;
-               }
                fallthrough;
        case SDCA_ACCESS_MODE_RO:
                control->deferrable = fwnode_property_read_bool(control_node,
@@ -897,17 +934,6 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
                return ret;
        }
 
-       ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
-                                      &control->cn_list);
-       if (ret == -EINVAL) {
-               /* Spec allows not specifying cn-list if only the first number is used */
-               control->cn_list = 0x1;
-       } else if (ret || !control->cn_list) {
-               dev_err(dev, "%s: control %#x: cn list missing: %d\n",
-                       entity->label, control->sel, ret);
-               return ret;
-       }
-
        ret = fwnode_property_read_u32(control_node,
                                       "mipi-sdca-control-interrupt-position",
                                       &tmp);
@@ -923,11 +949,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
        control->type = find_sdca_control_datatype(entity, control);
        control->nbits = find_sdca_control_bits(entity, control);
 
-       dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d value %#x %s\n",
+       dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n",
                 entity->label, control->label, control->sel,
                 control->mode, control->layers, control->cn_list,
-                control->interrupt_position, control->value,
-                control->deferrable ? "deferrable" : "");
+                control->interrupt_position, control->deferrable ? "deferrable" : "");
 
        return 0;
 }
index c41c67c2204a41966c74687a14c3cb8516a95101..5cb3048ea8cfc3e0b5755df9b1c977bc4d19db77 100644 (file)
@@ -253,7 +253,7 @@ int sdca_regmap_populate_constants(struct device *dev,
                                   struct sdca_function_data *function,
                                   struct reg_default *consts)
 {
-       int i, j, k;
+       int i, j, k, l;
 
        for (i = 0, k = 0; i < function->num_entities; i++) {
                struct sdca_entity *entity = &function->entities[i];
@@ -265,13 +265,15 @@ int sdca_regmap_populate_constants(struct device *dev,
                        if (control->mode != SDCA_ACCESS_MODE_DC)
                                continue;
 
+                       l = 0;
                        for_each_set_bit(cn, (unsigned long *)&control->cn_list,
                                         BITS_PER_TYPE(control->cn_list)) {
                                consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
                                                             entity->id,
                                                             control->sel, cn);
-                               consts[k].def = control->value;
+                               consts[k].def = control->values[l];
                                k++;
+                               l++;
                        }
                }
        }
@@ -295,7 +297,7 @@ EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
 int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
                               struct sdca_function_data *function)
 {
-       int i, j;
+       int i, j, k;
        int ret;
 
        for (i = 0; i < function->num_entities; i++) {
@@ -311,6 +313,7 @@ int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
                        if (!control->has_default && !control->has_fixed)
                                continue;
 
+                       k = 0;
                        for_each_set_bit(cn, (unsigned long *)&control->cn_list,
                                         BITS_PER_TYPE(control->cn_list)) {
                                unsigned int reg;
@@ -318,9 +321,11 @@ int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
                                reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
                                                   control->sel, cn);
 
-                               ret = regmap_write(regmap, reg, control->value);
+                               ret = regmap_write(regmap, reg, control->values[k]);
                                if (ret)
                                        return ret;
+
+                               k++;
                        }
                }
        }