linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/13] Add support for IIO devices in ASoC
@ 2023-06-14  7:48 Herve Codina
  2023-06-14  7:48 ` [PATCH v4 01/13] ASoC: dt-bindings: Add audio-iio-aux Herve Codina
                   ` (12 more replies)
  0 siblings, 13 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

Several weeks ago, I sent a series [1] for adding a potentiometer as an
auxiliary device in ASoC. The feedback was that the potentiometer should
be directly handled in IIO (as other potentiometers) and something more
generic should be present in ASoC in order to have a binding to import
some IIO devices into sound cards.

The series related to the IIO potentiometer device is already applied.

This series introduces audio-iio-aux. Its goal is to offer the binding
between IIO and ASoC.
It exposes attached IIO devices as ASoC auxiliary devices and allows to
control them through mixer controls.

On my system, the IIO device is a potentiometer and it is present in an
amplifier design present in the audio path.

Compare to the previous iteration
  https://lore.kernel.org/linux-kernel/20230612122926.107333-1-herve.codina@bootlin.com/
This v4 series mainly:
 - Fixes headers inclusion
 - Removes unneeded variable initialization
 - Adds a missing error check
 - Fixes typos

Best regards,
Hervé

[1] https://lore.kernel.org/linux-kernel/20230203111422.142479-1-herve.codina@bootlin.com/
[2] https://lore.kernel.org/linux-kernel/20230421085245.302169-1-herve.codina@bootlin.com/

Changes v3 -> v4
  - Patches 1, 2
    No changes.

  - Patches 3, 4, 5
    Add 'Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>'.

  - Patch 6 (new in v4)
    Fix headers inclusion order.

  - Patch 7 (patch 6 in v3)
    Add a comment related to __must_be_array()
    Use __array[0] of *__array

  - Patch 8 (patch 7 in v3)
    Fix minmax.h inclusion order.
    Add 'Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>'.

  - Patch 9 (patch 8 in v3)
    Add 'Suggested-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>'.
    Add 'Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>'.

  - Patch 10 (patch 9 in v3)
    Add 'Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>'.

  - Patch 11 (patch 10 in v3)
    Fix a typo.
    Add	'Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com>'.
    Add	'Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>'.

  - Patch 12 (patch 11 in v3)
    Fix typos in the commit log.
    Fix headers inclusion order.
    Removed unneeded variable initialization.
    Replace {0} by {}.
    Use struct device *dev in probe().
    Check an error on the snd-control-invert-range property read.

  - Patch 13 (patch12 in v3)
    No changes.

Changes v2 -> v3
  - Patches 1, 2
    No changes.

  - Patch 3, 4
    Add 'Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>'.

  - Patch 5 (new in v3)
    Removed the 'unused' variable and check the null pointer when used.

  - Patch 6 (new in v3)
    Introduce {min,max}_array().

  - Patch 7 (new in v3)
    Use max_array() in iio_channel_read_max().

  - Patch 8 (new in v3)
    Replace a FIXME comment by a TODO one.

  - Patch 9 (patch 5 in v2)
    Removed the 'unused' variable and check the null pointer when used.
    Use min_array().
    Remplace a FIXME comment by a TODO one.

  - Patch 10 (patch 6 in v2)
    Convert existing macros to return a compound litteral instead of
    adding a new helper.

  - Patch 11 (patch 7 in v2)
    Remove the file name from the C file header.
    Use directly converted DAPM macros.
    Replace <linux/module.h> by <linux/mod_devicetable.h>.
    Add <linux/platform_device.h>.
    Be sure that min <= max. Swap values if it is not the case.
    Move the bool structure member after the int ones.
    Remove unneeded assignements.
    Use dev_err_probe() when relevant.
    Use str_on_off().
    Use static_assert() instead of BUILD_BUG_ON().
    Remove unneeded comma and blank line.
    Use device_property_*() instead of the OF API.

  - patch 8 available in v2 removed as already applied

  - Patch 12 (patch 9 in v2)
    Use devm_add_action_or_reset().
    Call simple_populate_aux() from simple_parse_of().

Changes v1 -> v2
  - Patch 1
    Rename simple-iio-aux to audio-iio-aux
    Rename invert to snd-control-invert-range
    Remove the /schemas/iio/iio-consumer.yaml reference
    Remove the unneeded '|' after description

  - Patch 2 (new in v2)
    Introduce the simple-audio-card additional-devs subnode

  - Patch 3 (new in v2)
    Check err before switch() in iio_channel_read_max()

  - Patch 4 (new in v2)
    Fix raw reads and raw writes documentation

  - Patch 5 (patch 2 in v1)
    Check err before switch() in iio_channel_read_min()
    Fix documentation

  - Patch 6 (path 3 in v1)
    No changes

  - Patch 7 (patch 4 in v1)
    Rename simple-iio-aux to audio-iio-aux
    Rename invert to snd-control-invert-range
    Remove the mask usage from audio_iio_aux_{get,put}_volsw helpers
    Use directly PTR_ERR() in dev_err_probe() parameter
    Remove the '!!' construction
    Remove of_match_ptr()

  - Patch 8 (new in v2)
    Add a missing of_node_put() in the simple-card driver

  - Patch 9 (new in v2)
    Handle additional-devs in the simple-card driver

Herve Codina (13):
  ASoC: dt-bindings: Add audio-iio-aux
  ASoC: dt-bindings: simple-card: Add additional-devs subnode
  iio: inkern: Check error explicitly in iio_channel_read_max()
  iio: consumer.h: Fix raw values documentation notes
  iio: inkern: Remove the 'unused' variable usage in
    iio_channel_read_max()
  iio: inkern: Fix headers inclusion order
  minmax: Introduce {min,max}_array()
  iio: inkern: Use max_array() to get the maximum value from an array
  iio: inkern: Replace a FIXME comment by a TODO one
  iio: inkern: Add a helper to query an available minimum raw value
  ASoC: soc-dapm.h: Convert macros to return a compound literal
  ASoC: codecs: Add support for the generic IIO auxiliary devices
  ASoC: simple-card: Handle additional devices

 .../bindings/sound/audio-iio-aux.yaml         |  64 ++++
 .../bindings/sound/simple-card.yaml           |  53 +++
 drivers/iio/inkern.c                          |  86 ++++-
 include/linux/iio/consumer.h                  |  37 +-
 include/linux/minmax.h                        |  36 ++
 include/sound/soc-dapm.h                      | 138 ++++---
 sound/soc/codecs/Kconfig                      |  12 +
 sound/soc/codecs/Makefile                     |   2 +
 sound/soc/codecs/audio-iio-aux.c              | 338 ++++++++++++++++++
 sound/soc/generic/simple-card.c               |  46 ++-
 10 files changed, 741 insertions(+), 71 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yaml
 create mode 100644 sound/soc/codecs/audio-iio-aux.c

-- 
2.40.1


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v4 01/13] ASoC: dt-bindings: Add audio-iio-aux
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  7:48 ` [PATCH v4 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode Herve Codina
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

Industrial I/O devices can be present in the audio path.
These devices needs to be viewed as audio components in order to be
fully integrated in the audio path.

audio-iio-aux allows to consider these Industrial I/O devices as
auxliary audio devices.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/sound/audio-iio-aux.yaml         | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yaml

diff --git a/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml
new file mode 100644
index 000000000000..d3cc1ea4a175
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/audio-iio-aux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio IIO auxiliary
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description:
+  Auxiliary device based on Industrial I/O device channels
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: audio-iio-aux
+
+  io-channels:
+    description:
+      Industrial I/O device channels used
+
+  io-channel-names:
+    description:
+      Industrial I/O channel names related to io-channels.
+      These names are used to provides sound controls, widgets and routes names.
+
+  snd-control-invert-range:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      A list of 0/1 flags defining whether or not the related channel is
+      inverted
+    items:
+      enum: [0, 1]
+      default: 0
+      description: |
+        Invert the sound control value compared to the IIO channel raw value.
+          - 1: The related sound control value is inverted meaning that the
+               minimum sound control value correspond to the maximum IIO channel
+               raw value and the maximum sound control value correspond to the
+               minimum IIO channel raw value.
+          - 0: The related sound control value is not inverted meaning that the
+               minimum (resp maximum) sound control value correspond to the
+               minimum (resp maximum) IIO channel raw value.
+
+required:
+  - compatible
+  - io-channels
+  - io-channel-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    iio-aux {
+        compatible = "audio-iio-aux";
+        io-channels = <&iio 0>, <&iio 1>, <&iio 2>, <&iio 3>;
+        io-channel-names = "CH0", "CH1", "CH2", "CH3";
+        /* Invert CH1 and CH2 */
+        snd-control-invert-range = <0 1 1 0>;
+    };
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
  2023-06-14  7:48 ` [PATCH v4 01/13] ASoC: dt-bindings: Add audio-iio-aux Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  7:48 ` [PATCH v4 03/13] iio: inkern: Check error explicitly in iio_channel_read_max() Herve Codina
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

The additional-devs subnode allows to declared some virtual devices
as sound card children.
These virtual devices can then be used by the sound card and so be
present in the audio path.

The first virtual device supported is the audio IIO auxiliary device
in order to support an IIO device as an audio auxiliary device.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/sound/simple-card.yaml           | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml
index b05e05c81cc4..59ac2d1d1ccf 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.yaml
+++ b/Documentation/devicetree/bindings/sound/simple-card.yaml
@@ -148,6 +148,15 @@ definitions:
     required:
       - sound-dai
 
+  additional-devs:
+    type: object
+    description:
+      Additional devices used by the simple audio card.
+    patternProperties:
+      '^iio-aux(-.+)?$':
+        type: object
+        $ref: audio-iio-aux.yaml#
+
 properties:
   compatible:
     contains:
@@ -187,6 +196,8 @@ properties:
     $ref: "#/definitions/mclk-fs"
   simple-audio-card,aux-devs:
     $ref: "#/definitions/aux-devs"
+  simple-audio-card,additional-devs:
+    $ref: "#/definitions/additional-devs"
   simple-audio-card,convert-rate:
     $ref: "#/definitions/convert-rate"
   simple-audio-card,convert-channels:
@@ -359,6 +370,48 @@ examples:
         };
     };
 
+# --------------------
+# route audio to/from a codec through an amplifier
+# designed with a potentiometer driven by IIO:
+# --------------------
+  - |
+    sound {
+        compatible = "simple-audio-card";
+
+        simple-audio-card,aux-devs = <&amp_in>, <&amp_out>;
+        simple-audio-card,routing =
+            "CODEC LEFTIN", "AMP_IN LEFT OUT",
+            "CODEC RIGHTIN", "AMP_IN RIGHT OUT",
+            "AMP_OUT LEFT IN", "CODEC LEFTOUT",
+            "AMP_OUT RIGHT IN", "CODEC RIGHTOUT";
+
+        simple-audio-card,additional-devs {
+            amp_out: iio-aux-out {
+                compatible = "audio-iio-aux";
+                io-channels = <&pot_out 0>, <&pot_out 1>;
+                io-channel-names = "LEFT", "RIGHT";
+                snd-control-invert-range = <1 1>;
+                sound-name-prefix = "AMP_OUT";
+            };
+
+            amp_in: iio_aux-in {
+                compatible = "audio-iio-aux";
+                io-channels = <&pot_in 0>, <&pot_in 1>;
+                io-channel-names = "LEFT", "RIGHT";
+                sound-name-prefix = "AMP_IN";
+            };
+        };
+
+        simple-audio-card,cpu {
+            sound-dai = <&cpu>;
+        };
+
+        simple-audio-card,codec {
+            sound-dai = <&codec>;
+            clocks = <&clocks>;
+        };
+    };
+
 # --------------------
 # Sampling Rate Conversion
 # --------------------
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 03/13] iio: inkern: Check error explicitly in iio_channel_read_max()
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
  2023-06-14  7:48 ` [PATCH v4 01/13] ASoC: dt-bindings: Add audio-iio-aux Herve Codina
  2023-06-14  7:48 ` [PATCH v4 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  7:48 ` [PATCH v4 04/13] iio: consumer.h: Fix raw values documentation notes Herve Codina
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni, Jonathan Cameron

The current implementation returns the error code as part of the
default switch case.
This can lead to returning an incorrect positive value in case of
iio_avail_type enum entries evolution.

In order to avoid this case, be more strict in error checking.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/iio/inkern.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 872fd5c24147..f738db9a0c04 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -858,6 +858,9 @@ static int iio_channel_read_max(struct iio_channel *chan,
 		val2 = &unused;
 
 	ret = iio_channel_read_avail(chan, &vals, type, &length, info);
+	if (ret < 0)
+		return ret;
+
 	switch (ret) {
 	case IIO_AVAIL_RANGE:
 		switch (*type) {
@@ -888,7 +891,7 @@ static int iio_channel_read_max(struct iio_channel *chan,
 		return 0;
 
 	default:
-		return ret;
+		return -EINVAL;
 	}
 }
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 04/13] iio: consumer.h: Fix raw values documentation notes
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (2 preceding siblings ...)
  2023-06-14  7:48 ` [PATCH v4 03/13] iio: inkern: Check error explicitly in iio_channel_read_max() Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  7:48 ` [PATCH v4 05/13] iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max() Herve Codina
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni, Jonathan Cameron

The raw values notes mention 'ADC counts' and are not fully accurate.

Reword the notes in order to remove the 'ADC counts' and describe the
conversion needed between a raw value and a value in the standard units.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 include/linux/iio/consumer.h | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 6802596b017c..f536820b9cf2 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -201,8 +201,9 @@ struct iio_dev
  * @chan:		The channel being queried.
  * @val:		Value read back.
  *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units required.
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  */
 int iio_read_channel_raw(struct iio_channel *chan,
 			 int *val);
@@ -212,8 +213,9 @@ int iio_read_channel_raw(struct iio_channel *chan,
  * @chan:		The channel being queried.
  * @val:		Value read back.
  *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units required.
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  *
  * In opposit to the normal iio_read_channel_raw this function
  * returns the average of multiple reads.
@@ -281,8 +283,9 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val,
  * @chan:		The channel being queried.
  * @val:		Value being written.
  *
- * Note raw writes to iio channels are in dac counts and hence
- * scale will need to be applied if standard units required.
+ * Note that for raw writes to iio channels, if the value provided is
+ * in standard units, the affect of the scale and offset must be removed
+ * as (value / scale) - offset.
  */
 int iio_write_channel_raw(struct iio_channel *chan, int val);
 
@@ -292,8 +295,9 @@ int iio_write_channel_raw(struct iio_channel *chan, int val);
  * @chan:		The channel being queried.
  * @val:		Value read back.
  *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units are required.
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  */
 int iio_read_max_channel_raw(struct iio_channel *chan, int *val);
 
@@ -308,8 +312,9 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val);
  * For ranges, three vals are always returned; min, step and max.
  * For lists, all the possible values are enumerated.
  *
- * Note raw available values from iio channels are in adc counts and
- * hence scale will need to be applied if standard units are required.
+ * Note, if standard units are required, raw available values from iio
+ * channels need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  */
 int iio_read_avail_channel_raw(struct iio_channel *chan,
 			       const int **vals, int *length);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 05/13] iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max()
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (3 preceding siblings ...)
  2023-06-14  7:48 ` [PATCH v4 04/13] iio: consumer.h: Fix raw values documentation notes Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  7:48 ` [PATCH v4 06/13] iio: inkern: Fix headers inclusion order Herve Codina
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

The code uses a local variable to initialize a null pointer in order to
avoid accessing this null pointer later on.

Simply removed the 'unused' variable and check for the null pointer just
before accessing it.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/iio/inkern.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index f738db9a0c04..ce537b4ca6ca 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -849,14 +849,10 @@ static int iio_channel_read_max(struct iio_channel *chan,
 				int *val, int *val2, int *type,
 				enum iio_chan_info_enum info)
 {
-	int unused;
 	const int *vals;
 	int length;
 	int ret;
 
-	if (!val2)
-		val2 = &unused;
-
 	ret = iio_channel_read_avail(chan, &vals, type, &length, info);
 	if (ret < 0)
 		return ret;
@@ -869,7 +865,8 @@ static int iio_channel_read_max(struct iio_channel *chan,
 			break;
 		default:
 			*val = vals[4];
-			*val2 = vals[5];
+			if (val2)
+				*val2 = vals[5];
 		}
 		return 0;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 06/13] iio: inkern: Fix headers inclusion order
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (4 preceding siblings ...)
  2023-06-14  7:48 ` [PATCH v4 05/13] iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max() Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  8:58   ` Andy Shevchenko
  2023-06-14  7:48 ` [PATCH v4 07/13] minmax: Introduce {min,max}_array() Herve Codina
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

Sort headers inclusion in alphabetic order.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/iio/inkern.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index ce537b4ca6ca..71d0424383b6 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -5,9 +5,9 @@
  */
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/slab.h>
-#include <linux/mutex.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/iio-opaque.h>
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (5 preceding siblings ...)
  2023-06-14  7:48 ` [PATCH v4 06/13] iio: inkern: Fix headers inclusion order Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  9:02   ` Andy Shevchenko
  2023-06-14  7:48 ` [PATCH v4 08/13] iio: inkern: Use max_array() to get the maximum value from an array Herve Codina
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

Introduce min_array() (resp max_array()) in order to get the
minimal (resp maximum) of values present in an array.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 include/linux/minmax.h | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 396df1121bff..2cd0d34ce921 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -133,6 +133,42 @@
  */
 #define max_t(type, x, y)	__careful_cmp((type)(x), (type)(y), >)
 
+/*
+ * Do not check the array parameter using __must_be_array().
+ * In the following legit use-case where the "array" passed is a simple pointer,
+ * __must_be_array() will return a failure.
+ * --- 8< ---
+ * int *buff
+ * ...
+ * min = min_array(buff, nb_items);
+ * --- 8< ---
+ */
+#define __minmax_array(op, array, len) ({			\
+	typeof(array) __array = (array);			\
+	typeof(len) __len = (len);				\
+	typeof(__array[0] + 0) __element = __array[--__len];	\
+	while (__len--)						\
+		__element = op(__element, __array[__len]);	\
+	__element; })
+
+/**
+ * min_array - return minimum of values present in an array
+ * @array: array
+ * @len: array length
+ *
+ * Note that @len must not be zero (empty array).
+ */
+#define min_array(array, len) __minmax_array(min, array, len)
+
+/**
+ * max_array - return maximum of values present in an array
+ * @array: array
+ * @len: array length
+ *
+ * Note that @len must not be zero (empty array).
+ */
+#define max_array(array, len) __minmax_array(max, array, len)
+
 /**
  * clamp_t - return a value clamped to a given range using a given type
  * @type: the type of variable to use
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 08/13] iio: inkern: Use max_array() to get the maximum value from an array
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (6 preceding siblings ...)
  2023-06-14  7:48 ` [PATCH v4 07/13] minmax: Introduce {min,max}_array() Herve Codina
@ 2023-06-14  7:48 ` Herve Codina
  2023-06-14  9:03   ` Andy Shevchenko
  2023-06-14  7:49 ` [PATCH v4 09/13] iio: inkern: Replace a FIXME comment by a TODO one Herve Codina
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:48 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

Use max_array() to get the maximum value from an array instead of a
custom local loop.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/iio/inkern.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 71d0424383b6..8bfd91f74101 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -5,6 +5,7 @@
  */
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/minmax.h>
 #include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/slab.h>
@@ -875,11 +876,7 @@ static int iio_channel_read_max(struct iio_channel *chan,
 			return -EINVAL;
 		switch (*type) {
 		case IIO_VAL_INT:
-			*val = vals[--length];
-			while (length) {
-				if (vals[--length] > *val)
-					*val = vals[length];
-			}
+			*val = max_array(vals, length);
 			break;
 		default:
 			/* FIXME: learn about max for other iio values */
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 09/13] iio: inkern: Replace a FIXME comment by a TODO one
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (7 preceding siblings ...)
  2023-06-14  7:48 ` [PATCH v4 08/13] iio: inkern: Use max_array() to get the maximum value from an array Herve Codina
@ 2023-06-14  7:49 ` Herve Codina
  2023-06-14  7:49 ` [PATCH v4 10/13] iio: inkern: Add a helper to query an available minimum raw value Herve Codina
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:49 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni, Jonathan Cameron

This FIXME comment is more a TODO one.
It is a note when someone will need for this currently unsupported case.

Change from FIXME to TODO.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Suggested-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/iio/inkern.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 8bfd91f74101..19ddd77adb11 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -879,7 +879,7 @@ static int iio_channel_read_max(struct iio_channel *chan,
 			*val = max_array(vals, length);
 			break;
 		default:
-			/* FIXME: learn about max for other iio values */
+			/* TODO: learn about max for other iio values */
 			return -EINVAL;
 		}
 		return 0;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 10/13] iio: inkern: Add a helper to query an available minimum raw value
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (8 preceding siblings ...)
  2023-06-14  7:49 ` [PATCH v4 09/13] iio: inkern: Replace a FIXME comment by a TODO one Herve Codina
@ 2023-06-14  7:49 ` Herve Codina
  2023-06-14  7:49 ` [PATCH v4 11/13] ASoC: soc-dapm.h: Convert macros to return a compound literal Herve Codina
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:49 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

A helper, iio_read_max_channel_raw() exists to read the available
maximum raw value of a channel but nothing similar exists to read the
available minimum raw value.

This new helper, iio_read_min_channel_raw(), fills the hole and can be
used for reading the available minimum raw value of a channel.
It is fully based on the existing iio_read_max_channel_raw().

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/iio/inkern.c         | 63 ++++++++++++++++++++++++++++++++++++
 include/linux/iio/consumer.h | 12 +++++++
 2 files changed, 75 insertions(+)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 19ddd77adb11..7a1f6713318a 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -909,6 +909,69 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
 }
 EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
 
+static int iio_channel_read_min(struct iio_channel *chan,
+				int *val, int *val2, int *type,
+				enum iio_chan_info_enum info)
+{
+	const int *vals;
+	int length;
+	int ret;
+
+	ret = iio_channel_read_avail(chan, &vals, type, &length, info);
+	if (ret < 0)
+		return ret;
+
+	switch (ret) {
+	case IIO_AVAIL_RANGE:
+		switch (*type) {
+		case IIO_VAL_INT:
+			*val = vals[0];
+			break;
+		default:
+			*val = vals[0];
+			if (val2)
+				*val2 = vals[1];
+		}
+		return 0;
+
+	case IIO_AVAIL_LIST:
+		if (length <= 0)
+			return -EINVAL;
+		switch (*type) {
+		case IIO_VAL_INT:
+			*val = min_array(vals, length);
+			break;
+		default:
+			/* TODO: learn about min for other iio values */
+			return -EINVAL;
+		}
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int iio_read_min_channel_raw(struct iio_channel *chan, int *val)
+{
+	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
+	int ret;
+	int type;
+
+	mutex_lock(&iio_dev_opaque->info_exist_lock);
+	if (!chan->indio_dev->info) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
+err_unlock:
+	mutex_unlock(&iio_dev_opaque->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_read_min_channel_raw);
+
 int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
 {
 	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index f536820b9cf2..e9910b41d48e 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -301,6 +301,18 @@ int iio_write_channel_raw(struct iio_channel *chan, int val);
  */
 int iio_read_max_channel_raw(struct iio_channel *chan, int *val);
 
+/**
+ * iio_read_min_channel_raw() - read minimum available raw value from a given
+ *				channel, i.e. the minimum possible value.
+ * @chan:		The channel being queried.
+ * @val:		Value read back.
+ *
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
+ */
+int iio_read_min_channel_raw(struct iio_channel *chan, int *val);
+
 /**
  * iio_read_avail_channel_raw() - read available raw values from a given channel
  * @chan:		The channel being queried.
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 11/13] ASoC: soc-dapm.h: Convert macros to return a compound literal
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (9 preceding siblings ...)
  2023-06-14  7:49 ` [PATCH v4 10/13] iio: inkern: Add a helper to query an available minimum raw value Herve Codina
@ 2023-06-14  7:49 ` Herve Codina
  2023-06-14  7:49 ` [PATCH v4 12/13] ASoC: codecs: Add support for the generic IIO auxiliary devices Herve Codina
  2023-06-14  7:49 ` [PATCH v4 13/13] ASoC: simple-card: Handle additional devices Herve Codina
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:49 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

The SND_SOC_DAPM_* helpers family are used to build widgets array in a
static way.

Convert them to return a compound literal in order to use them in both
static and dynamic way.
With this conversion, the different SND_SOC_DAPM_* parameters can be
computed by the code and the widget can be built based on this parameter
computation.
  static int create_widget(char *input_name)
  {
          struct snd_soc_dapm_widget widget;
          char name*;
          ...
          name = input_name;
          if (!name)
                  name = "default";

          widget = SND_SOC_DAPM_INPUT(name);
          ...
  }

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 include/sound/soc-dapm.h | 138 ++++++++++++++++++++++++++-------------
 1 file changed, 92 insertions(+), 46 deletions(-)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 87f8e1793af1..2e38dff16779 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -42,36 +42,45 @@ struct soc_enum;
 
 /* codec domain */
 #define SND_SOC_DAPM_VMID(wname) \
-{	.id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0}
 
 /* platform domain */
 #define SND_SOC_DAPM_SIGGEN(wname) \
-{	.id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_SINK(wname) \
-{	.id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_INPUT(wname) \
-{	.id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_OUTPUT(wname) \
-{	.id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_MIC(wname, wevent) \
-{	.id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_HP(wname, wevent) \
-{	.id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_SPK(wname, wevent) \
-{	.id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_LINE(wname, wevent) \
-{	.id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
@@ -82,93 +91,110 @@ struct soc_enum;
 /* path domain */
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
-{	.id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pga, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
-{	.id = snd_soc_dapm_out_drv, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_out_drv, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
-{	.id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 /* DEPRECATED: use SND_SOC_DAPM_SUPPLY */
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_micbias, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_micbias, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_switch, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_switch, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_mux, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mux, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_demux, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_demux, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 	 wcontrols) \
-{	.id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pga, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
-{	.id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
-{	.id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pga, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
-{	.id = snd_soc_dapm_out_drv, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_out_drv, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
-{	.id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
 	wcontrols, wncontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_switch, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_switch, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_mux, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mux, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
@@ -176,101 +202,121 @@ struct soc_enum;
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pga, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags, \
 	.subseq = wsubseq}
 #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
 	wflags)	\
-{	.id = snd_soc_dapm_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_supply, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags, .subseq = wsubseq}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pga, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
 	wcontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_mixer, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
-{	.id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_POST(wname, wevent) \
-{	.id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 
 /* stream domain */
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
 	.channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \
 			      wevent, wflags)				\
-{	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
 	.channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
 	.channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \
 			     wevent, wflags)				\
-{	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
 	.channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
 #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
 			   wevent, wflags)				\
-{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags}
 
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
 			   wevent, wflags)				\
-{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
-{	.id = snd_soc_dapm_clock_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_clock_supply, .name = wname, \
 	.reg = SND_SOC_NOPM, .event = dapm_clock_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
-{	.id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
+(struct snd_soc_dapm_widget) { \
+	.id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
 	.reg = wreg, .shift = wshift, .mask = wmask, \
 	.on_val = won_val, .off_val = woff_val, }
 #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
-{	.id = snd_soc_dapm_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_supply, .name = wname, \
 	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)	    \
-{	.id = snd_soc_dapm_regulator_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_regulator_supply, .name = wname, \
 	.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
 	.on_val = wflags}
 #define SND_SOC_DAPM_PINCTRL(wname, active, sleep) \
-{	.id = snd_soc_dapm_pinctrl, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+	.id = snd_soc_dapm_pinctrl, .name = wname, \
 	.priv = (&(struct snd_soc_dapm_pinctrl_priv) \
 		{ .active_state = active, .sleep_state = sleep,}), \
 	.reg = SND_SOC_NOPM, .event = dapm_pinctrl_event, \
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 12/13] ASoC: codecs: Add support for the generic IIO auxiliary devices
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (10 preceding siblings ...)
  2023-06-14  7:49 ` [PATCH v4 11/13] ASoC: soc-dapm.h: Convert macros to return a compound literal Herve Codina
@ 2023-06-14  7:49 ` Herve Codina
  2023-06-14  7:49 ` [PATCH v4 13/13] ASoC: simple-card: Handle additional devices Herve Codina
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:49 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

Industrial I/O devices can be present in the audio path.
These devices needs to be used as audio components in order to be
fully integrated in the audio path.

This support allows to consider these Industrial I/O devices as
auxiliary audio devices and allows one to control them using mixer
controls.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 sound/soc/codecs/Kconfig         |  12 ++
 sound/soc/codecs/Makefile        |   2 +
 sound/soc/codecs/audio-iio-aux.c | 338 +++++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)
 create mode 100644 sound/soc/codecs/audio-iio-aux.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 44806bfe8ee5..92b7c417f1b2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -53,6 +53,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_AK5558
 	imply SND_SOC_ALC5623
 	imply SND_SOC_ALC5632
+	imply SND_SOC_AUDIO_IIO_AUX
 	imply SND_SOC_AW8738
 	imply SND_SOC_AW88395
 	imply SND_SOC_BT_SCO
@@ -608,6 +609,17 @@ config SND_SOC_ALC5632
 	tristate
 	depends on I2C
 
+config SND_SOC_AUDIO_IIO_AUX
+	tristate "Audio IIO Auxiliary device"
+	depends on IIO
+	help
+	  Enable support for Industrial I/O devices as audio auxiliary devices.
+	  This allows to have an IIO device present in the audio path and
+	  controlled using mixer controls.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-soc-audio-iio-aux.
+
 config SND_SOC_AW8738
 	tristate "Awinic AW8738 Audio Amplifier"
 	select GPIOLIB
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 2c45c2f97e4e..f2828d3616c5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -45,6 +45,7 @@ snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-ak5558-objs := ak5558.o
 snd-soc-arizona-objs := arizona.o arizona-jack.o
+snd-soc-audio-iio-aux-objs := audio-iio-aux.o
 snd-soc-aw8738-objs := aw8738.o
 snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o
 snd-soc-aw88395-objs := aw88395/aw88395.o \
@@ -421,6 +422,7 @@ obj-$(CONFIG_SND_SOC_AK5558)	+= snd-soc-ak5558.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
+obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX)	+= snd-soc-audio-iio-aux.o
 obj-$(CONFIG_SND_SOC_AW8738)	+= snd-soc-aw8738.o
 obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o
 obj-$(CONFIG_SND_SOC_AW88395)	+=snd-soc-aw88395.o
diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c
new file mode 100644
index 000000000000..b9d72cbb85f2
--- /dev/null
+++ b/sound/soc/codecs/audio-iio-aux.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// ALSA SoC glue to use IIO devices as audio components
+//
+// Copyright 2023 CS GROUP France
+//
+// Author: Herve Codina <herve.codina@bootlin.com>
+
+#include <linux/iio/consumer.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+struct audio_iio_aux_chan {
+	struct iio_channel *iio_chan;
+	const char *name;
+	int max;
+	int min;
+	bool is_invert_range;
+};
+
+struct audio_iio_aux {
+	struct device *dev;
+	struct audio_iio_aux_chan *chans;
+	unsigned int num_chans;
+};
+
+static int audio_iio_aux_info_volsw(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = chan->max - chan->min;
+	uinfo->type = (uinfo->value.integer.max == 1) ?
+			SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	return 0;
+}
+
+static int audio_iio_aux_get_volsw(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+	int max = chan->max;
+	int min = chan->min;
+	bool invert_range = chan->is_invert_range;
+	int ret;
+	int val;
+
+	ret = iio_read_channel_raw(chan->iio_chan, &val);
+	if (ret < 0)
+		return ret;
+
+	ucontrol->value.integer.value[0] = val - min;
+	if (invert_range)
+		ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0];
+
+	return 0;
+}
+
+static int audio_iio_aux_put_volsw(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+	int max = chan->max;
+	int min = chan->min;
+	bool invert_range = chan->is_invert_range;
+	int val;
+	int ret;
+	int tmp;
+
+	val = ucontrol->value.integer.value[0];
+	if (val < 0)
+		return -EINVAL;
+	if (val > max - min)
+		return -EINVAL;
+
+	val = val + min;
+	if (invert_range)
+		val = max - val;
+
+	ret = iio_read_channel_raw(chan->iio_chan, &tmp);
+	if (ret < 0)
+		return ret;
+
+	if (tmp == val)
+		return 0;
+
+	ret = iio_write_channel_raw(chan->iio_chan, val);
+	if (ret)
+		return ret;
+
+	return 1; /* The value changed */
+}
+
+static int audio_iio_aux_add_controls(struct snd_soc_component *component,
+				      struct audio_iio_aux_chan *chan)
+{
+	struct snd_kcontrol_new control = {};
+
+	control.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	control.name = chan->name;
+	control.info = audio_iio_aux_info_volsw;
+	control.get = audio_iio_aux_get_volsw;
+	control.put = audio_iio_aux_put_volsw;
+	control.private_value = (unsigned long)chan;
+
+	return snd_soc_add_component_controls(component, &control, 1);
+}
+
+/*
+ * These data could be on stack but they are pretty big.
+ * As ASoC internally copy them and protect them against concurrent accesses
+ * (snd_soc_bind_card() protects using client_mutex), keep them in the global
+ * data area.
+ */
+static struct snd_soc_dapm_widget widgets[3];
+static struct snd_soc_dapm_route routes[2];
+
+/* Be sure sizes are correct (need 3 widgets and 2 routes) */
+static_assert(ARRAY_SIZE(widgets) >= 3, "3 widgets are needed");
+static_assert(ARRAY_SIZE(routes) >= 2, "2 routes are needed");
+
+static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
+				   struct audio_iio_aux_chan *chan)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+	char *output_name;
+	char *input_name;
+	char *pga_name;
+	int ret;
+
+	input_name = kasprintf(GFP_KERNEL, "%s IN", chan->name);
+	if (!input_name)
+		return -ENOMEM;
+
+	output_name = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
+	if (!output_name) {
+		ret = -ENOMEM;
+		goto out_free_input_name;
+	}
+	pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
+	if (!pga_name) {
+		ret = -ENOMEM;
+		goto out_free_output_name;
+	}
+
+	widgets[0] = SND_SOC_DAPM_INPUT(input_name);
+	widgets[1] = SND_SOC_DAPM_OUTPUT(output_name);
+	widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0);
+	ret = snd_soc_dapm_new_controls(dapm, widgets, 3);
+	if (ret)
+		goto out_free_pga_name;
+
+	routes[0].sink = pga_name;
+	routes[0].control = NULL;
+	routes[0].source = input_name;
+	routes[1].sink = output_name;
+	routes[1].control = NULL;
+	routes[1].source = pga_name;
+	ret = snd_soc_dapm_add_routes(dapm, routes, 2);
+
+	/* Allocated names are no more needed (duplicated in ASoC internals) */
+
+out_free_pga_name:
+	kfree(pga_name);
+out_free_output_name:
+	kfree(output_name);
+out_free_input_name:
+	kfree(input_name);
+	return ret;
+}
+
+static int audio_iio_aux_component_probe(struct snd_soc_component *component)
+{
+	struct audio_iio_aux *iio_aux = snd_soc_component_get_drvdata(component);
+	struct audio_iio_aux_chan *chan;
+	int ret;
+	int i;
+
+	for (i = 0; i < iio_aux->num_chans; i++) {
+		chan = iio_aux->chans + i;
+
+		ret = iio_read_max_channel_raw(chan->iio_chan, &chan->max);
+		if (ret)
+			return dev_err_probe(component->dev, ret,
+					     "chan[%d] %s: Cannot get max raw value\n",
+					     i, chan->name);
+
+		ret = iio_read_min_channel_raw(chan->iio_chan, &chan->min);
+		if (ret)
+			return dev_err_probe(component->dev, ret,
+					     "chan[%d] %s: Cannot get min raw value\n",
+					     i, chan->name);
+
+		if (chan->min > chan->max) {
+			dev_dbg(component->dev, "chan[%d] %s: Swap min and max\n",
+				i, chan->name);
+			swap(chan->min, chan->max);
+		}
+
+		/* Set initial value */
+		ret = iio_write_channel_raw(chan->iio_chan,
+					    chan->is_invert_range ? chan->max : chan->min);
+		if (ret)
+			return dev_err_probe(component->dev, ret,
+					     "chan[%d] %s: Cannot set initial value\n",
+					     i, chan->name);
+
+		ret = audio_iio_aux_add_controls(component, chan);
+		if (ret)
+			return ret;
+
+		ret = audio_iio_aux_add_dapms(component, chan);
+		if (ret)
+			return ret;
+
+		dev_dbg(component->dev, "chan[%d]: Added %s (min=%d, max=%d, invert=%s)\n",
+			i, chan->name, chan->min, chan->max,
+			str_on_off(chan->is_invert_range));
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver audio_iio_aux_component_driver = {
+	.probe = audio_iio_aux_component_probe,
+};
+
+static int audio_iio_aux_probe(struct platform_device *pdev)
+{
+	struct audio_iio_aux_chan *iio_aux_chan;
+	struct device *dev = &pdev->dev;
+	struct audio_iio_aux *iio_aux;
+	const char **names;
+	u32 *invert_ranges;
+	int count;
+	int ret;
+	int i;
+
+	iio_aux = devm_kzalloc(dev, sizeof(*iio_aux), GFP_KERNEL);
+	if (!iio_aux)
+		return -ENOMEM;
+
+	iio_aux->dev = dev;
+
+	count = device_property_string_array_count(dev, "io-channel-names");
+	if (count < 0)
+		return dev_err_probe(dev, count, "failed to count io-channel-names\n");
+
+	iio_aux->num_chans = count;
+
+	iio_aux->chans = devm_kmalloc_array(dev, iio_aux->num_chans,
+					    sizeof(*iio_aux->chans), GFP_KERNEL);
+	if (!iio_aux->chans)
+		return -ENOMEM;
+
+	names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL);
+	if (!names)
+		return -ENOMEM;
+
+	invert_ranges = kcalloc(iio_aux->num_chans, sizeof(*invert_ranges), GFP_KERNEL);
+	if (!invert_ranges) {
+		ret = -ENOMEM;
+		goto out_free_names;
+	}
+
+	ret = device_property_read_string_array(dev, "io-channel-names",
+						names, iio_aux->num_chans);
+	if (ret < 0) {
+		dev_err_probe(dev, ret, "failed to read io-channel-names\n");
+		goto out_free_invert_ranges;
+	}
+
+	/*
+	 * snd-control-invert-range is optional and can contain fewer items
+	 * than the number of channels. Unset values default to 0.
+	 */
+	count = device_property_count_u32(dev, "snd-control-invert-range");
+	if (count > 0) {
+		count = min_t(unsigned int, count, iio_aux->num_chans);
+		ret = device_property_read_u32_array(dev, "snd-control-invert-range",
+						     invert_ranges, count);
+		if (ret < 0) {
+			dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
+			goto out_free_invert_ranges;
+		}
+	}
+
+	for (i = 0; i < iio_aux->num_chans; i++) {
+		iio_aux_chan = iio_aux->chans + i;
+		iio_aux_chan->name = names[i];
+		iio_aux_chan->is_invert_range = invert_ranges[i];
+
+		iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name);
+		if (IS_ERR(iio_aux_chan->iio_chan)) {
+			ret = PTR_ERR(iio_aux_chan->iio_chan);
+			dev_err_probe(dev, ret, "get IIO channel '%s' failed\n",
+				      iio_aux_chan->name);
+			goto out_free_invert_ranges;
+		}
+	}
+
+	platform_set_drvdata(pdev, iio_aux);
+
+	ret = devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
+					      NULL, 0);
+out_free_invert_ranges:
+	kfree(invert_ranges);
+out_free_names:
+	kfree(names);
+	return ret;
+}
+
+static const struct of_device_id audio_iio_aux_ids[] = {
+	{ .compatible = "audio-iio-aux" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, audio_iio_aux_ids);
+
+static struct platform_driver audio_iio_aux_driver = {
+	.driver = {
+		.name = "audio-iio-aux",
+		.of_match_table = audio_iio_aux_ids,
+	},
+	.probe = audio_iio_aux_probe,
+};
+module_platform_driver(audio_iio_aux_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("IIO ALSA SoC aux driver");
+MODULE_LICENSE("GPL");
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v4 13/13] ASoC: simple-card: Handle additional devices
  2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
                   ` (11 preceding siblings ...)
  2023-06-14  7:49 ` [PATCH v4 12/13] ASoC: codecs: Add support for the generic IIO auxiliary devices Herve Codina
@ 2023-06-14  7:49 ` Herve Codina
  12 siblings, 0 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-14  7:49 UTC (permalink / raw)
  To: Herve Codina, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, Andy Shevchenko
  Cc: alsa-devel, devicetree, linux-kernel, linux-iio,
	Christophe Leroy, Thomas Petazzoni

An additional-devs subnode can be present in the simple-card top node.
This subnode is used to declared some "virtual" additional devices.

Create related devices from this subnode and avoid this subnode presence
to interfere with the already supported subnodes analysis.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 sound/soc/generic/simple-card.c | 46 +++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 6f044cc8357e..ae4a47018278 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -348,6 +348,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 	struct device *dev = simple_priv_to_dev(priv);
 	struct device_node *top = dev->of_node;
 	struct device_node *node;
+	struct device_node *add_devs;
 	uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
 	bool is_top = 0;
 	int ret = 0;
@@ -359,6 +360,8 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 		is_top = 1;
 	}
 
+	add_devs = of_get_child_by_name(top, PREFIX "additional-devs");
+
 	/* loop for all dai-link */
 	do {
 		struct asoc_simple_data adata;
@@ -367,6 +370,12 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 		struct device_node *np;
 		int num = of_get_child_count(node);
 
+		/* Skip additional-devs node */
+		if (node == add_devs) {
+			node = of_get_next_child(top, node);
+			continue;
+		}
+
 		/* get codec */
 		codec = of_get_child_by_name(node, is_top ?
 					     PREFIX "codec" : "codec");
@@ -380,12 +389,15 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 
 		/* get convert-xxx property */
 		memset(&adata, 0, sizeof(adata));
-		for_each_child_of_node(node, np)
+		for_each_child_of_node(node, np) {
+			if (np == add_devs)
+				continue;
 			simple_parse_convert(dev, np, &adata);
+		}
 
 		/* loop for all CPU/Codec node */
 		for_each_child_of_node(node, np) {
-			if (plat == np)
+			if (plat == np || add_devs == np)
 				continue;
 			/*
 			 * It is DPCM
@@ -427,6 +439,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 	} while (!is_top && node);
 
  error:
+	of_node_put(add_devs);
 	of_node_put(node);
 	return ret;
 }
@@ -464,6 +477,31 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
 	return ret;
 }
 
+static void simple_depopulate_aux(void *data)
+{
+	struct asoc_simple_priv *priv = data;
+
+	of_platform_depopulate(simple_priv_to_dev(priv));
+}
+
+static int simple_populate_aux(struct asoc_simple_priv *priv)
+{
+	struct device *dev = simple_priv_to_dev(priv);
+	struct device_node *node;
+	int ret;
+
+	node = of_get_child_by_name(dev->of_node, PREFIX "additional-devs");
+	if (!node)
+		return 0;
+
+	ret = of_platform_populate(node, NULL, NULL, dev);
+	of_node_put(node);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(dev, simple_depopulate_aux, priv);
+}
+
 static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
 {
 	struct snd_soc_card *card = simple_priv_to_card(priv);
@@ -493,6 +531,10 @@ static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
 	if (ret < 0)
 		return ret;
 
+	ret = simple_populate_aux(priv);
+	if (ret < 0)
+		return ret;
+
 	ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
 
 	return ret;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 06/13] iio: inkern: Fix headers inclusion order
  2023-06-14  7:48 ` [PATCH v4 06/13] iio: inkern: Fix headers inclusion order Herve Codina
@ 2023-06-14  8:58   ` Andy Shevchenko
  0 siblings, 0 replies; 26+ messages in thread
From: Andy Shevchenko @ 2023-06-14  8:58 UTC (permalink / raw)
  To: Herve Codina
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:
>
> Sort headers inclusion in alphabetic order.

More precisely fix mutex.h inclusion order as it seems to be the only
one misplaced.
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> ---
>  drivers/iio/inkern.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index ce537b4ca6ca..71d0424383b6 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -5,9 +5,9 @@
>   */
>  #include <linux/err.h>
>  #include <linux/export.h>
> +#include <linux/mutex.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
> -#include <linux/mutex.h>
>
>  #include <linux/iio/iio.h>
>  #include <linux/iio/iio-opaque.h>
> --
> 2.40.1
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14  7:48 ` [PATCH v4 07/13] minmax: Introduce {min,max}_array() Herve Codina
@ 2023-06-14  9:02   ` Andy Shevchenko
  2023-06-14  9:42     ` Herve Codina
  0 siblings, 1 reply; 26+ messages in thread
From: Andy Shevchenko @ 2023-06-14  9:02 UTC (permalink / raw)
  To: Herve Codina
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:
>
> Introduce min_array() (resp max_array()) in order to get the
> minimal (resp maximum) of values present in an array.

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
See a remark below.

> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  include/linux/minmax.h | 36 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 36 insertions(+)
>
> diff --git a/include/linux/minmax.h b/include/linux/minmax.h
> index 396df1121bff..2cd0d34ce921 100644
> --- a/include/linux/minmax.h
> +++ b/include/linux/minmax.h
> @@ -133,6 +133,42 @@
>   */
>  #define max_t(type, x, y)      __careful_cmp((type)(x), (type)(y), >)
>
> +/*
> + * Do not check the array parameter using __must_be_array().
> + * In the following legit use-case where the "array" passed is a simple pointer,
> + * __must_be_array() will return a failure.
> + * --- 8< ---
> + * int *buff
> + * ...
> + * min = min_array(buff, nb_items);
> + * --- 8< ---
> + */
> +#define __minmax_array(op, array, len) ({                      \
> +       typeof(array) __array = (array);                        \
> +       typeof(len) __len = (len);                              \
> +       typeof(__array[0] + 0) __element = __array[--__len];    \

Do we need the ' + 0' part?

> +       while (__len--)                                         \
> +               __element = op(__element, __array[__len]);      \
> +       __element; })
> +
> +/**
> + * min_array - return minimum of values present in an array
> + * @array: array
> + * @len: array length
> + *
> + * Note that @len must not be zero (empty array).
> + */
> +#define min_array(array, len) __minmax_array(min, array, len)
> +
> +/**
> + * max_array - return maximum of values present in an array
> + * @array: array
> + * @len: array length
> + *
> + * Note that @len must not be zero (empty array).
> + */
> +#define max_array(array, len) __minmax_array(max, array, len)
> +
>  /**
>   * clamp_t - return a value clamped to a given range using a given type
>   * @type: the type of variable to use
> --
> 2.40.1
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 08/13] iio: inkern: Use max_array() to get the maximum value from an array
  2023-06-14  7:48 ` [PATCH v4 08/13] iio: inkern: Use max_array() to get the maximum value from an array Herve Codina
@ 2023-06-14  9:03   ` Andy Shevchenko
  0 siblings, 0 replies; 26+ messages in thread
From: Andy Shevchenko @ 2023-06-14  9:03 UTC (permalink / raw)
  To: Herve Codina
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:
>
> Use max_array() to get the maximum value from an array instead of a
> custom local loop.

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  drivers/iio/inkern.c | 7 ++-----
>  1 file changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index 71d0424383b6..8bfd91f74101 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -5,6 +5,7 @@
>   */
>  #include <linux/err.h>
>  #include <linux/export.h>
> +#include <linux/minmax.h>
>  #include <linux/mutex.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
> @@ -875,11 +876,7 @@ static int iio_channel_read_max(struct iio_channel *chan,
>                         return -EINVAL;
>                 switch (*type) {
>                 case IIO_VAL_INT:
> -                       *val = vals[--length];
> -                       while (length) {
> -                               if (vals[--length] > *val)
> -                                       *val = vals[length];
> -                       }
> +                       *val = max_array(vals, length);
>                         break;
>                 default:
>                         /* FIXME: learn about max for other iio values */
> --
> 2.40.1
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14  9:02   ` Andy Shevchenko
@ 2023-06-14  9:42     ` Herve Codina
  2023-06-14 11:51       ` Andy Shevchenko
  0 siblings, 1 reply; 26+ messages in thread
From: Herve Codina @ 2023-06-14  9:42 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

Hi Andy,

On Wed, 14 Jun 2023 12:02:57 +0300
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:
> >
> > Introduce min_array() (resp max_array()) in order to get the
> > minimal (resp maximum) of values present in an array.  
> 
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> See a remark below.
> 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  include/linux/minmax.h | 36 ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 36 insertions(+)
> >
> > diff --git a/include/linux/minmax.h b/include/linux/minmax.h
> > index 396df1121bff..2cd0d34ce921 100644
> > --- a/include/linux/minmax.h
> > +++ b/include/linux/minmax.h
> > @@ -133,6 +133,42 @@
> >   */
> >  #define max_t(type, x, y)      __careful_cmp((type)(x), (type)(y), >)
> >
> > +/*
> > + * Do not check the array parameter using __must_be_array().
> > + * In the following legit use-case where the "array" passed is a simple pointer,
> > + * __must_be_array() will return a failure.
> > + * --- 8< ---
> > + * int *buff
> > + * ...
> > + * min = min_array(buff, nb_items);
> > + * --- 8< ---
> > + */
> > +#define __minmax_array(op, array, len) ({                      \
> > +       typeof(array) __array = (array);                        \
> > +       typeof(len) __len = (len);                              \
> > +       typeof(__array[0] + 0) __element = __array[--__len];    \  
> 
> Do we need the ' + 0' part?

Yes.

__array can be an array of const items and it is legitimate to get the
minimum value from const items.

typeof(__array[0]) keeps the const qualifier but we need to assign __element
in the loop.
One way to drop the const qualifier is to get the type from a rvalue computed
from __array[0]. This rvalue has to have the exact same type with only the const
dropped.
'__array[0] + 0' was a perfect canditate.

Regards,
Hervé

> 
> > +       while (__len--)                                         \
> > +               __element = op(__element, __array[__len]);      \
> > +       __element; })
> > +
> > +/**
> > + * min_array - return minimum of values present in an array
> > + * @array: array
> > + * @len: array length
> > + *
> > + * Note that @len must not be zero (empty array).
> > + */
> > +#define min_array(array, len) __minmax_array(min, array, len)
> > +
> > +/**
> > + * max_array - return maximum of values present in an array
> > + * @array: array
> > + * @len: array length
> > + *
> > + * Note that @len must not be zero (empty array).
> > + */
> > +#define max_array(array, len) __minmax_array(max, array, len)
> > +
> >  /**
> >   * clamp_t - return a value clamped to a given range using a given type
> >   * @type: the type of variable to use
> > --
> > 2.40.1
> >  
> 
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14  9:42     ` Herve Codina
@ 2023-06-14 11:51       ` Andy Shevchenko
  2023-06-14 20:34         ` Herve Codina
  0 siblings, 1 reply; 26+ messages in thread
From: Andy Shevchenko @ 2023-06-14 11:51 UTC (permalink / raw)
  To: Herve Codina
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

On Wed, Jun 14, 2023 at 12:42 PM Herve Codina <herve.codina@bootlin.com> wrote:
> On Wed, 14 Jun 2023 12:02:57 +0300
> Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> > On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:

...

> > > +       typeof(__array[0] + 0) __element = __array[--__len];    \
> >
> > Do we need the ' + 0' part?
>
> Yes.
>
> __array can be an array of const items and it is legitimate to get the
> minimum value from const items.
>
> typeof(__array[0]) keeps the const qualifier but we need to assign __element
> in the loop.
> One way to drop the const qualifier is to get the type from a rvalue computed
> from __array[0]. This rvalue has to have the exact same type with only the const
> dropped.
> '__array[0] + 0' was a perfect canditate.

Seems like this also deserves a comment. But if the series is accepted
as is, it may be done as a follow up.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14 11:51       ` Andy Shevchenko
@ 2023-06-14 20:34         ` Herve Codina
  2023-06-14 22:05           ` Andy Shevchenko
  0 siblings, 1 reply; 26+ messages in thread
From: Herve Codina @ 2023-06-14 20:34 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

Hi Andy,

On Wed, 14 Jun 2023 14:51:43 +0300
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Wed, Jun 14, 2023 at 12:42 PM Herve Codina <herve.codina@bootlin.com> wrote:
> > On Wed, 14 Jun 2023 12:02:57 +0300
> > Andy Shevchenko <andy.shevchenko@gmail.com> wrote:  
> > > On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:  
> 
> ...
> 
> > > > +       typeof(__array[0] + 0) __element = __array[--__len];    \  
> > >
> > > Do we need the ' + 0' part?  
> >
> > Yes.
> >
> > __array can be an array of const items and it is legitimate to get the
> > minimum value from const items.
> >
> > typeof(__array[0]) keeps the const qualifier but we need to assign __element
> > in the loop.
> > One way to drop the const qualifier is to get the type from a rvalue computed
> > from __array[0]. This rvalue has to have the exact same type with only the const
> > dropped.
> > '__array[0] + 0' was a perfect canditate.  
> 
> Seems like this also deserves a comment. But if the series is accepted
> as is, it may be done as a follow up.
> 

Finally not so simple ...
I did some deeper tests and the macros need to be fixed.

I hope this one (with comments added) is correct:
--- 8 ---
/*
 * Do not check the array parameter using __must_be_array().
 * In the following legit use-case where the "array" passed is a simple pointer,
 * __must_be_array() will return a failure.
 * --- 8< ---
 * int *buff
 * ...
 * min = min_array(buff, nb_items);
 * --- 8< ---
 *
 * The first typeof(&(array)[0]) is needed in order to support arrays of both
 * 'int *buff' and 'int buf[N]' types.
 *
 * typeof(__array[0] + 0) used for __element is needed as the array can be an
 * array of const items.
 * In order to discard the const qualifier use an arithmetic operation (rvalue).
 * This arithmetic operation discard the const but also can lead to an integer
 * promotion. For instance, a const s8 __array[0] lead to an int __element due
 * to the promotion.
 * In this case, simple min() or max() operation fails (type mismatch).
 * Use min_t() or max_t() (op_t parameter) enforcing the type in order to avoid
 * the min() or max() failure.
 */
#define __minmax_array(op_t, array, len) ({			\
	typeof(&(array)[0]) __array = (array);			\
	typeof(len) __len = (len);				\
	typeof(__array[0] + 0) __element = __array[--__len];	\
	while (__len--)						\
		__element = op_t(typeof(__array[0]), __element, __array[__len]); \
	__element; })

/**
 * min_array - return minimum of values present in an array
 * @array: array
 * @len: array length
 *
 * Note that @len must not be zero (empty array).
 */
#define min_array(array, len) __minmax_array(min_t, array, len)

/**
 * max_array - return maximum of values present in an array
 * @array: array
 * @len: array length
 *
 * Note that @len must not be zero (empty array).
 */
#define max_array(array, len) __minmax_array(max_t, array, len)

--- 8< ---

Tested ok from user-space on my x86_64 using the following types for *buff
and buff[N]:
- signed/unsigned char
- signed/unsigned short
- signed/unsigned int
- signed/unsigned long
- signed/unsigned long long
- float, double, long double (even if not used in the kernel)

Can you give me your feedback on this last version ?

If you are ok, it will be present in the next iteration of the series.
Otherwise, as a last ressort, I will drop the {min,max}_array() and switch
back to the specific min/max computation in IIO inkern.c

Sorry for this back and forth and this last minute detected bug.

Best regards,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14 20:34         ` Herve Codina
@ 2023-06-14 22:05           ` Andy Shevchenko
  2023-06-15  9:35             ` Herve Codina
  0 siblings, 1 reply; 26+ messages in thread
From: Andy Shevchenko @ 2023-06-14 22:05 UTC (permalink / raw)
  To: Herve Codina
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

On Wed, Jun 14, 2023 at 11:34 PM Herve Codina <herve.codina@bootlin.com> wrote:
> On Wed, 14 Jun 2023 14:51:43 +0300
> Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> > On Wed, Jun 14, 2023 at 12:42 PM Herve Codina <herve.codina@bootlin.com> wrote:
> > > On Wed, 14 Jun 2023 12:02:57 +0300
> > > Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> > > > On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:

...

> > > > > +       typeof(__array[0] + 0) __element = __array[--__len];    \
> > > >
> > > > Do we need the ' + 0' part?
> > >
> > > Yes.
> > >
> > > __array can be an array of const items and it is legitimate to get the
> > > minimum value from const items.
> > >
> > > typeof(__array[0]) keeps the const qualifier but we need to assign __element
> > > in the loop.
> > > One way to drop the const qualifier is to get the type from a rvalue computed
> > > from __array[0]. This rvalue has to have the exact same type with only the const
> > > dropped.
> > > '__array[0] + 0' was a perfect canditate.
> >
> > Seems like this also deserves a comment. But if the series is accepted
> > as is, it may be done as a follow up.
> >
>
> Finally not so simple ...
> I did some deeper tests and the macros need to be fixed.
>
> I hope this one (with comments added) is correct:
> --- 8 ---
> /*
>  * Do not check the array parameter using __must_be_array().
>  * In the following legit use-case where the "array" passed is a simple pointer,
>  * __must_be_array() will return a failure.
>  * --- 8< ---
>  * int *buff
>  * ...
>  * min = min_array(buff, nb_items);
>  * --- 8< ---
>  *
>  * The first typeof(&(array)[0]) is needed in order to support arrays of both
>  * 'int *buff' and 'int buf[N]' types.
>  *
>  * typeof(__array[0] + 0) used for __element is needed as the array can be an
>  * array of const items.
>  * In order to discard the const qualifier use an arithmetic operation (rvalue).


>  * This arithmetic operation discard the const but also can lead to an integer

discards

>  * promotion. For instance, a const s8 __array[0] lead to an int __element due

leads

>  * to the promotion.
>  * In this case, simple min() or max() operation fails (type mismatch).
>  * Use min_t() or max_t() (op_t parameter) enforcing the type in order to avoid
>  * the min() or max() failure.

This part perhaps can be avoided. See below.

>  */
> #define __minmax_array(op_t, array, len) ({                     \
>         typeof(&(array)[0]) __array = (array);                  \
>         typeof(len) __len = (len);                              \
>         typeof(__array[0] + 0) __element = __array[--__len];    \
>         while (__len--)                                         \
>                 __element = op_t(typeof(__array[0]), __element, __array[__len]); \

But can't we instead have typeof(+(array[0])) in the definition of __element?
There are also other possible solutions: a) _Generic() with listed
const types to move them to non-const, and b) __auto_type (which is
supported by GCC 4.9 and clang, but not in the C11 standard).

>         __element; })

...

> Can you give me your feedback on this last version ?

Sure!

> If you are ok, it will be present in the next iteration of the series.
> Otherwise, as a last ressort, I will drop the {min,max}_array() and switch
> back to the specific min/max computation in IIO inkern.c
>
> Sorry for this back and forth and this last minute detected bug.

It's good that we have some tests (perhaps you can add something to
unit test these)? Perhaps move your code to lib/test_minmax.c as KUnit
module?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-14 22:05           ` Andy Shevchenko
@ 2023-06-15  9:35             ` Herve Codina
  2023-06-15 13:51               ` Andy Shevchenko
  2023-06-16  9:08               ` David Laight
  0 siblings, 2 replies; 26+ messages in thread
From: Herve Codina @ 2023-06-15  9:35 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

Hi Andy,
On Thu, 15 Jun 2023 01:05:40 +0300
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Wed, Jun 14, 2023 at 11:34 PM Herve Codina <herve.codina@bootlin.com> wrote:
> > On Wed, 14 Jun 2023 14:51:43 +0300
> > Andy Shevchenko <andy.shevchenko@gmail.com> wrote:  
> > > On Wed, Jun 14, 2023 at 12:42 PM Herve Codina <herve.codina@bootlin.com> wrote:  
> > > > On Wed, 14 Jun 2023 12:02:57 +0300
> > > > Andy Shevchenko <andy.shevchenko@gmail.com> wrote:  
> > > > > On Wed, Jun 14, 2023 at 10:49 AM Herve Codina <herve.codina@bootlin.com> wrote:  
> 
> ...
> 
> > > > > > +       typeof(__array[0] + 0) __element = __array[--__len];    \  
> > > > >
> > > > > Do we need the ' + 0' part?  
> > > >
> > > > Yes.
> > > >
> > > > __array can be an array of const items and it is legitimate to get the
> > > > minimum value from const items.
> > > >
> > > > typeof(__array[0]) keeps the const qualifier but we need to assign __element
> > > > in the loop.
> > > > One way to drop the const qualifier is to get the type from a rvalue computed
> > > > from __array[0]. This rvalue has to have the exact same type with only the const
> > > > dropped.
> > > > '__array[0] + 0' was a perfect canditate.  
> > >
> > > Seems like this also deserves a comment. But if the series is accepted
> > > as is, it may be done as a follow up.
> > >  
> >
> > Finally not so simple ...
> > I did some deeper tests and the macros need to be fixed.
> >
> > I hope this one (with comments added) is correct:
> > --- 8 ---
> > /*
> >  * Do not check the array parameter using __must_be_array().
> >  * In the following legit use-case where the "array" passed is a simple pointer,
> >  * __must_be_array() will return a failure.
> >  * --- 8< ---
> >  * int *buff
> >  * ...
> >  * min = min_array(buff, nb_items);
> >  * --- 8< ---
> >  *
> >  * The first typeof(&(array)[0]) is needed in order to support arrays of both
> >  * 'int *buff' and 'int buf[N]' types.
> >  *
> >  * typeof(__array[0] + 0) used for __element is needed as the array can be an
> >  * array of const items.
> >  * In order to discard the const qualifier use an arithmetic operation (rvalue).  
> 
> 
> >  * This arithmetic operation discard the const but also can lead to an integer  
> 
> discards
> 
> >  * promotion. For instance, a const s8 __array[0] lead to an int __element due  
> 
> leads
> 
> >  * to the promotion.
> >  * In this case, simple min() or max() operation fails (type mismatch).
> >  * Use min_t() or max_t() (op_t parameter) enforcing the type in order to avoid
> >  * the min() or max() failure.  
> 
> This part perhaps can be avoided. See below.
> 
> >  */
> > #define __minmax_array(op_t, array, len) ({                     \
> >         typeof(&(array)[0]) __array = (array);                  \
> >         typeof(len) __len = (len);                              \
> >         typeof(__array[0] + 0) __element = __array[--__len];    \
> >         while (__len--)                                         \
> >                 __element = op_t(typeof(__array[0]), __element, __array[__len]); \  
> 
> But can't we instead have typeof(+(array[0])) in the definition of __element?
> There are also other possible solutions: a) _Generic() with listed
> const types to move them to non-const, and b) __auto_type (which is
> supported by GCC 4.9 and clang, but not in the C11 standard).

typeof(+(array[0])) keeps the promotion.

__auto_type works with my gcc-12 but not with a gcc-5.5. Depending on the
compiler version, it discards or keeps the const qualifier. For this reason
I would prefer to not use it.

Did the job using _Generic().

This lead to:
--- 8< ---
/*
 * Remove a const qualifier
 * _Generic(foo, type-name: association, ..., default: association) performs a
 * comparison against the foo type (not the qualified type).
 * Do not use the const keyword in the type-name as it will not match the
 * unqualified type of foo.
 */
#define __unconst_type_cases(type)		\
	unsigned type:  (unsigned type)0,	\
	signed type:    (signed type)0


#define __unconst_typeof(x) typeof(			\
	_Generic((x),					\
		char: (char)0,				\
		__unconst_type_cases(char),		\
		__unconst_type_cases(short),		\
		__unconst_type_cases(int),		\
		__unconst_type_cases(long),		\
		__unconst_type_cases(long long),	\
		default: (x)))

/*
 * Do not check the array parameter using __must_be_array().
 * In the following legit use-case where the "array" passed is a simple pointer,
 * __must_be_array() will return a failure.
 * --- 8< ---
 * int *buff
 * ...
 * min = min_array(buff, nb_items);
 * --- 8< ---
 *
 * The first typeof(&(array)[0]) is needed in order to support arrays of both
 * 'int *buff' and 'int buf[N]' types.
 *
 * The array can be an array of const items.
 * typeof() keeps the const qualifier. Use __unconst_typeof() in order to
 * discard the const qualifier for the __element variable.
 */
#define __minmax_array(op, array, len) ({				\
	typeof(&(array)[0]) __array = (array);				\
	typeof(len) __len = (len);					\
	__unconst_typeof(__array[0]) __element = __array[--__len];	\
	while (__len--)							\
		__element = op(__element, __array[__len]);		\
	__element; })

/**
 * min_array - return minimum of values present in an array
 * @array: array
 * @len: array length
 *
 * Note that @len must not be zero (empty array).
 */
#define min_array(array, len) __minmax_array(min, array, len)

/**
 * max_array - return maximum of values present in an array
 * @array: array
 * @len: array length
 *
 * Note that @len must not be zero (empty array).
 */
#define max_array(array, len) __minmax_array(max, array, len)
--- 8< ---

Do you think it looks good ?

For, the KUnit tests, I agree, it would be nice to have something.
I need some more substantial work to implement and run the test in KUnit
and the first task will be learning the KUnit test system. 
I will do that but out of this series.

Thanks for your feedback and pointers,
Hervé

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-15  9:35             ` Herve Codina
@ 2023-06-15 13:51               ` Andy Shevchenko
  2023-06-16  9:08               ` David Laight
  1 sibling, 0 replies; 26+ messages in thread
From: Andy Shevchenko @ 2023-06-15 13:51 UTC (permalink / raw)
  To: Herve Codina
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

On Thu, Jun 15, 2023 at 12:35 PM Herve Codina <herve.codina@bootlin.com> wrote:
> On Thu, 15 Jun 2023 01:05:40 +0300
> Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

...

> Did the job using _Generic().

Cool! Keep my tag for that version and thank you for pursuing the
implementation that works for everybody.

> This lead to:
> --- 8< ---
> /*
>  * Remove a const qualifier

...from integer types

>  * _Generic(foo, type-name: association, ..., default: association) performs a
>  * comparison against the foo type (not the qualified type).
>  * Do not use the const keyword in the type-name as it will not match the
>  * unqualified type of foo.
>  */
> #define __unconst_type_cases(type)              \

__unconst_integer_type_cases() ?

>         unsigned type:  (unsigned type)0,       \
>         signed type:    (signed type)0
>
>

Single blank line is enough.

> #define __unconst_typeof(x) typeof(                     \

__unconst_integer_typeof() ?

>         _Generic((x),                                   \
>                 char: (char)0,                          \
>                 __unconst_type_cases(char),             \
>                 __unconst_type_cases(short),            \
>                 __unconst_type_cases(int),              \
>                 __unconst_type_cases(long),             \
>                 __unconst_type_cases(long long),        \
>                 default: (x)))
>
> /*
>  * Do not check the array parameter using __must_be_array().
>  * In the following legit use-case where the "array" passed is a simple pointer,
>  * __must_be_array() will return a failure.
>  * --- 8< ---
>  * int *buff
>  * ...
>  * min = min_array(buff, nb_items);
>  * --- 8< ---
>  *
>  * The first typeof(&(array)[0]) is needed in order to support arrays of both
>  * 'int *buff' and 'int buf[N]' types.
>  *
>  * The array can be an array of const items.
>  * typeof() keeps the const qualifier. Use __unconst_typeof() in order to
>  * discard the const qualifier for the __element variable.
>  */
> #define __minmax_array(op, array, len) ({                               \
>         typeof(&(array)[0]) __array = (array);                          \
>         typeof(len) __len = (len);                                      \
>         __unconst_typeof(__array[0]) __element = __array[--__len];      \
>         while (__len--)                                                 \
>                 __element = op(__element, __array[__len]);              \
>         __element; })
>
> /**
>  * min_array - return minimum of values present in an array
>  * @array: array
>  * @len: array length
>  *
>  * Note that @len must not be zero (empty array).
>  */
> #define min_array(array, len) __minmax_array(min, array, len)
>
> /**
>  * max_array - return maximum of values present in an array
>  * @array: array
>  * @len: array length
>  *
>  * Note that @len must not be zero (empty array).
>  */
> #define max_array(array, len) __minmax_array(max, array, len)
> --- 8< ---
>
> Do you think it looks good ?

Yes!

> For, the KUnit tests, I agree, it would be nice to have something.
> I need some more substantial work to implement and run the test in KUnit
> and the first task will be learning the KUnit test system.
> I will do that but out of this series.

Thank you, it's fine with me.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-15  9:35             ` Herve Codina
  2023-06-15 13:51               ` Andy Shevchenko
@ 2023-06-16  9:08               ` David Laight
  2023-06-16 11:48                 ` Herve Codina
  1 sibling, 1 reply; 26+ messages in thread
From: David Laight @ 2023-06-16  9:08 UTC (permalink / raw)
  To: 'Herve Codina', Andy Shevchenko
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jonathan Cameron, Lars-Peter Clausen,
	Jaroslav Kysela, Takashi Iwai, Kuninori Morimoto, alsa-devel,
	devicetree, linux-kernel, linux-iio, Christophe Leroy,
	Thomas Petazzoni

From: Herve Codina
> Sent: 15 June 2023 10:35
> > ...
> >
> > > > > > > +       typeof(__array[0] + 0) __element = __array[--__len];    \
> > > > > >
> > > > > > Do we need the ' + 0' part?
> > > > >
> > > > > Yes.
> > > > >
> > > > > __array can be an array of const items and it is legitimate to get the
> > > > > minimum value from const items.
> > > > >
> > > > > typeof(__array[0]) keeps the const qualifier but we need to assign __element
> > > > > in the loop.
> > > > > One way to drop the const qualifier is to get the type from a rvalue computed
> > > > > from __array[0]. This rvalue has to have the exact same type with only the const
> > > > > dropped.
> > > > > '__array[0] + 0' was a perfect canditate.
> > > >
> > > > Seems like this also deserves a comment. But if the series is accepted
> > > > as is, it may be done as a follow up.
> > > >
> > >
> > > Finally not so simple ...
> > > I did some deeper tests and the macros need to be fixed.
> > >
> > > I hope this one (with comments added) is correct:
> > > --- 8 ---
> > > /*
> > >  * Do not check the array parameter using __must_be_array().
> > >  * In the following legit use-case where the "array" passed is a simple pointer,
> > >  * __must_be_array() will return a failure.
> > >  * --- 8< ---
> > >  * int *buff
> > >  * ...
> > >  * min = min_array(buff, nb_items);
> > >  * --- 8< ---
> > >  *
> > >  * The first typeof(&(array)[0]) is needed in order to support arrays of both
> > >  * 'int *buff' and 'int buf[N]' types.
> > >  *
> > >  * typeof(__array[0] + 0) used for __element is needed as the array can be an
> > >  * array of const items.
> > >  * In order to discard the const qualifier use an arithmetic operation (rvalue).
> >
> >
> > >  * This arithmetic operation discard the const but also can lead to an integer
> >
> > discards
> >
> > >  * promotion. For instance, a const s8 __array[0] lead to an int __element due
> >
> > leads
> >
> > >  * to the promotion.
> > >  * In this case, simple min() or max() operation fails (type mismatch).
> > >  * Use min_t() or max_t() (op_t parameter) enforcing the type in order to avoid
> > >  * the min() or max() failure.
> >
> > This part perhaps can be avoided. See below.
> >
> > >  */
> > > #define __minmax_array(op_t, array, len) ({                     \
> > >         typeof(&(array)[0]) __array = (array);                  \
> > >         typeof(len) __len = (len);                              \
> > >         typeof(__array[0] + 0) __element = __array[--__len];    \
> > >         while (__len--)                                         \
> > >                 __element = op_t(typeof(__array[0]), __element, __array[__len]); \
> >
> > But can't we instead have typeof(+(array[0])) in the definition of __element?
> > There are also other possible solutions: a) _Generic() with listed
> > const types to move them to non-const, and b) __auto_type (which is
> > supported by GCC 4.9 and clang, but not in the C11 standard).
> 
> typeof(+(array[0])) keeps the promotion.
> 
> __auto_type works with my gcc-12 but not with a gcc-5.5. Depending on the
> compiler version, it discards or keeps the const qualifier. For this reason
> I would prefer to not use it.

Just define two variables typeof(__array[0] + 0) one for an element
and one for the limit.
The just test (eg):
	if (limit > item) limit = item;
finally cast the limit back to the original type.
The promotions of char/short to signed int won't matter.
There is no need for all the type-checking in min/max.

Indeed, if min_t(type, a, b) is in anyway sane it should
expand to:
	type _a = a, _b = b;
	_a < _b ? _a : _b
without any of the checks that min() does.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-16  9:08               ` David Laight
@ 2023-06-16 11:48                 ` Herve Codina
  2023-06-16 12:42                   ` David Laight
  0 siblings, 1 reply; 26+ messages in thread
From: Herve Codina @ 2023-06-16 11:48 UTC (permalink / raw)
  To: David Laight
  Cc: Andy Shevchenko, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, alsa-devel, devicetree, linux-kernel,
	linux-iio, Christophe Leroy, Thomas Petazzoni

Hi David,

On Fri, 16 Jun 2023 09:08:22 +0000
David Laight <David.Laight@ACULAB.COM> wrote:

...

> 
> Just define two variables typeof(__array[0] + 0) one for an element
> and one for the limit.
> The just test (eg):
> 	if (limit > item) limit = item;
> finally cast the limit back to the original type.
> The promotions of char/short to signed int won't matter.
> There is no need for all the type-checking in min/max.
> 
> Indeed, if min_t(type, a, b) is in anyway sane it should
> expand to:
> 	type _a = a, _b = b;
> 	_a < _b ? _a : _b
> without any of the checks that min() does.

I finally move to use _Generic() in order to "unconstify" and avoid the
integer promotion. With this done, no extra cast is needed and min()/max()
are usable.

The patch is available in the v5 series.
  https://lore.kernel.org/linux-kernel/20230615152631.224529-8-herve.codina@bootlin.com/

Do you think the code present in the v5 series should be changed ?
If so, can you give me your feedback on the v5 series ?

Thanks for your review,
Hervé

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v4 07/13] minmax: Introduce {min,max}_array()
  2023-06-16 11:48                 ` Herve Codina
@ 2023-06-16 12:42                   ` David Laight
  0 siblings, 0 replies; 26+ messages in thread
From: David Laight @ 2023-06-16 12:42 UTC (permalink / raw)
  To: 'Herve Codina'
  Cc: Andy Shevchenko, Liam Girdwood, Mark Brown, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jonathan Cameron,
	Lars-Peter Clausen, Jaroslav Kysela, Takashi Iwai,
	Kuninori Morimoto, alsa-devel, devicetree, linux-kernel,
	linux-iio, Christophe Leroy, Thomas Petazzoni

From: Herve Codina <herve.codina@bootlin.com>
> Sent: 16 June 2023 12:49
> 
> Hi David,
> 
> On Fri, 16 Jun 2023 09:08:22 +0000
> David Laight <David.Laight@ACULAB.COM> wrote:
> 
> ...
> 
> >
> > Just define two variables typeof(__array[0] + 0) one for an element
> > and one for the limit.
> > The just test (eg):
> > 	if (limit > item) limit = item;
> > finally cast the limit back to the original type.
> > The promotions of char/short to signed int won't matter.
> > There is no need for all the type-checking in min/max.
> >
> > Indeed, if min_t(type, a, b) is in anyway sane it should
> > expand to:
> > 	type _a = a, _b = b;
> > 	_a < _b ? _a : _b
> > without any of the checks that min() does.
> 
> I finally move to use _Generic() in order to "unconstify" and avoid the
> integer promotion. With this done, no extra cast is needed and min()/max()
> are usable.
> 
> The patch is available in the v5 series.
>   https://lore.kernel.org/linux-kernel/20230615152631.224529-8-herve.codina@bootlin.com/
> 
> Do you think the code present in the v5 series should be changed ?
> If so, can you give me your feedback on the v5 series ?

It seems horribly over-complicated just to get around the perverse
over-strong type checking that min/max do just to avoid sign
extension issues.

Maybe I ought to try getting a patch accepted that just checks
  is_signed_type(typeof(x)) == is_signed_type(typeof(y))
instead of
  typeof(x) == typeof(y)
Then worry about the valid signed v unsigned cases.

Indeed, since the array index can be assumed not to have side
effects you could use __cmp(x, y, op) directly.

No one has pointed out that __element should be __bound.

	David

	

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2023-06-16 12:42 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-14  7:48 [PATCH v4 00/13] Add support for IIO devices in ASoC Herve Codina
2023-06-14  7:48 ` [PATCH v4 01/13] ASoC: dt-bindings: Add audio-iio-aux Herve Codina
2023-06-14  7:48 ` [PATCH v4 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode Herve Codina
2023-06-14  7:48 ` [PATCH v4 03/13] iio: inkern: Check error explicitly in iio_channel_read_max() Herve Codina
2023-06-14  7:48 ` [PATCH v4 04/13] iio: consumer.h: Fix raw values documentation notes Herve Codina
2023-06-14  7:48 ` [PATCH v4 05/13] iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max() Herve Codina
2023-06-14  7:48 ` [PATCH v4 06/13] iio: inkern: Fix headers inclusion order Herve Codina
2023-06-14  8:58   ` Andy Shevchenko
2023-06-14  7:48 ` [PATCH v4 07/13] minmax: Introduce {min,max}_array() Herve Codina
2023-06-14  9:02   ` Andy Shevchenko
2023-06-14  9:42     ` Herve Codina
2023-06-14 11:51       ` Andy Shevchenko
2023-06-14 20:34         ` Herve Codina
2023-06-14 22:05           ` Andy Shevchenko
2023-06-15  9:35             ` Herve Codina
2023-06-15 13:51               ` Andy Shevchenko
2023-06-16  9:08               ` David Laight
2023-06-16 11:48                 ` Herve Codina
2023-06-16 12:42                   ` David Laight
2023-06-14  7:48 ` [PATCH v4 08/13] iio: inkern: Use max_array() to get the maximum value from an array Herve Codina
2023-06-14  9:03   ` Andy Shevchenko
2023-06-14  7:49 ` [PATCH v4 09/13] iio: inkern: Replace a FIXME comment by a TODO one Herve Codina
2023-06-14  7:49 ` [PATCH v4 10/13] iio: inkern: Add a helper to query an available minimum raw value Herve Codina
2023-06-14  7:49 ` [PATCH v4 11/13] ASoC: soc-dapm.h: Convert macros to return a compound literal Herve Codina
2023-06-14  7:49 ` [PATCH v4 12/13] ASoC: codecs: Add support for the generic IIO auxiliary devices Herve Codina
2023-06-14  7:49 ` [PATCH v4 13/13] ASoC: simple-card: Handle additional devices Herve Codina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).