Add support for IIO devices in ASoC
Subsystems (5)
v5 cover Add support for IIO devices in ASoC
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/[email protected]/
This v5 series mainly:
- Fixes {min,max}_array macros
Best regards,
Hervé
[1] https://lore.kernel.org/linux-kernel/[email protected]/
[2] https://lore.kernel.org/linux-kernel/[email protected]/
Changes v4 -> v5
- Patches 1, 2, 3, 4, 5, 9, 10, 11, 12, 13
No changes.
- Patch 6
Fix commit log.
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'
- Patch 7
Fix the macros to be able to use them with:
- an array defined as int *buff;
- an array defined as int buff[N];
- Rework the way to "unconstify" the temporary variable to avoid issues due to integer promotion.
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'
- Patch 8
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'
Changes v3 -> v4
- Patches 1, 2
No changes.
- Patches 3, 4, 5
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'.
- 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 <[email protected]>'.
- Patch 9 (patch 8 in v3)
Add 'Suggested-by: Jonathan Cameron <[email protected]>'. Add 'Reviewed-by: Andy Shevchenko <[email protected]>'.
- Patch 10 (patch 9 in v3)
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'.
- Patch 11 (patch 10 in v3)
Fix a typo.
Add 'Suggested-by: Andy Shevchenko <[email protected]>'.
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'.
- 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 <[email protected]>'.
- 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 | 64 ++++ 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, 769 insertions(+), 71 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yaml create mode 100644 sound/soc/codecs/audio-iio-aux.c
Signature · 1 line
2.40.1
PATCH v5 1/13 ASoC: dt-bindings: Add audio-iio-aux
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.
--- .../bindings/sound/audio-iio-aux.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yaml
Documentation/devicetree/bindings/sound/audio-iio-aux.yaml new file +64 -0
@@ -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 <[email protected]> + +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>; + };
Signature · 1 line
2.40.1
Re: [PATCH v5 01/13] ASoC: dt-bindings: Add audio-iio-aux
Quoted 8 lines · On Thu, 15 Jun 2023 17:26:19 +0200 Herve Codina <[email protected]>…
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 <[email protected]>
LGTM
Quoted 75 lines
--- .../bindings/sound/audio-iio-aux.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yamlDocumentation/devicetree/bindings/sound/audio-iio-aux.yaml new file +64
-0@@ -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 <[email protected]> + +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>; + };
Re: [PATCH v5 01/13] ASoC: dt-bindings: Add audio-iio-aux
In reply to Herve CodinaQuoted 4 lines · Herve Codina
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.
Quoted 9 lines
audio-iio-aux allows to consider these Industrial I/O devices as auxliary audio devices.
Signed-off-by Herve Codina <[email protected]>--- .../bindings/sound/audio-iio-aux.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/audio-iio-aux.yaml
PATCH v5 2/13 ASoC: dt-bindings: simple-card: Add additional-devs subnode
In reply to Herve CodinaThe 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.
--- .../bindings/sound/simple-card.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+)
Documentation/devicetree/bindings/sound/simple-card.yaml +53 -0
@@ -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 = <&_in>, <&_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 # --------------------
Signature · 1 line
2.40.1
Re: [PATCH v5 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode
Quoted 9 lines · On Thu, 15 Jun 2023 17:26:20 +0200 Herve Codina <[email protected]>…
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 <[email protected]>
Looks fine to me, but given it's not an area I know that much about (other than the iio consumer bits) take that with a pinch of salt.
Quoted 82 lines
--- .../bindings/sound/simple-card.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+)Documentation/devicetree/bindings/sound/simple-card.yaml +53
-0@@ -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 = <&_in>, <&_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 # --------------------
Rob Herring
maintainerRe: [PATCH v5 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode
In reply to Herve CodinaQuoted 34 lines · Herve Codina
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 <[email protected]>--- .../bindings/sound/simple-card.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+)Documentation/devicetree/bindings/sound/simple-card.yaml +9
-0@@ -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:
Documentation/devicetree/bindings/sound/simple-card.yaml properties: · line 200
Quoted 5 lines
Documentation/devicetree/bindings/sound/simple-card.yaml +2
-0@@ -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"
Why do you need this under the card node? Can't you just use the existing aux-devs?
Quoted 55 lines
Documentation/devicetree/bindings/sound/simple-card.yaml +42
-0simple-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 = <&_in>, <&_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 # --------------------Signature · 1 line
2.40.1
Re: [PATCH v5 02/13] ASoC: dt-bindings: simple-card: Add additional-devs subnode
Hi Rob,
Quoted 35 lines · On Tue, 20 Jun 2023 10:45:21 -0600 Rob Herring <[email protected]> wrote:
Quoted 34 lines · Herve Codina
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 <[email protected]>--- .../bindings/sound/simple-card.yaml | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+)Documentation/devicetree/bindings/sound/simple-card.yaml +9
-0@@ -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:
Quoted 8 lines
Documentation/devicetree/bindings/sound/simple-card.yaml properties: · line 200
Quoted 5 lines
Documentation/devicetree/bindings/sound/simple-card.yaml +2
-0$ref: "#/definitions/mclk-fs" simple-audio-card,aux-devs: $ref: "#/definitions/aux-devs" + simple-audio-card,additional-devs: + $ref: "#/definitions/additional-devs"Why do you need this under the card node? Can't you just use the existing aux-devs?
aux-devs is a phandle array referencing auxiliary devices. I cannot define a node with just aux-devs, just reference.
I need device auxiliary devices that are not defined somewhere else in the DT.
A SPI amplifier is defined as a subnode of a SPI controler. But my IIO/ASoC virtual devices are not defined under some hardware bus. I need to define them here, as a simple-audio-card subnode.
Several subnodes are already defined for a simple-audio-card subnode for other purpose.
Instead of having virtual device nodes directly as chidren mixed with the other purpose nodes of the simple-audio-card, I group them under the additional-devs node in order to ease evolution and maintenance.
Best regards,
Hervé
Quoted 56 lines
Quoted 56 lines
Documentation/devicetree/bindings/sound/simple-card.yaml +42
-0simple-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 = <&_in>, <&_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 # --------------------Signature · 1 line
2.40.1
Signature · 3 lines
Hervé Codina, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
PATCH v5 3/13 iio: inkern: Check error explicitly in iio_channel_read_max()
In reply to Herve CodinaThe 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.
--- drivers/iio/inkern.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/iio/inkern.c +4 -1
@@ -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 ; } }
Signature · 1 line
2.40.1
PATCH v5 4/13 iio: consumer.h: Fix raw values documentation notes
In reply to Herve CodinaThe 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.
--- include/linux/iio/consumer.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
include/linux/iio/consumer.h +15 -10
@@ -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);
Signature · 1 line
2.40.1
PATCH v5 5/13 iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max()
In reply to Herve CodinaThe 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.
--- drivers/iio/inkern.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/iio/inkern.c +2 -5
@@ -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 ;
Signature · 1 line
2.40.1
Re: [PATCH v5 05/13] iio: inkern: Remove the 'unused' variable usage in iio_channel_read_max()
Quoted 8 lines · On Thu, 15 Jun 2023 17:26:23 +0200 Herve Codina <[email protected]>…
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 <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>
A this series has grown more changes in IIO over time.... Hopefully who ever takes it can provide an immutable branch to make it easy to avoid any dependency issues for other work in IIO.
Thanks,
Jonathan
Quoted 33 lines
--- drivers/iio/inkern.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)drivers/iio/inkern.c +2
-5@@ -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 ;
PATCH v5 6/13 iio: inkern: Fix headers inclusion order
In reply to Herve CodinaFix the mutex.h inclusion order as it seems to be the only one misplaces.
--- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/inkern.c +1 -1
@@ -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>
Signature · 1 line
2.40.1
Re: [PATCH v5 06/13] iio: inkern: Fix headers inclusion order
Quoted 6 lines · On Thu, 15 Jun 2023 17:26:24 +0200 Herve Codina <[email protected]>…
Fix the
mutex.hinclusion order as it seems to be the only one misplaces.Signed-off-by Herve Codina <[email protected]>Suggested-by Andy Shevchenko <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>
Quoted 19 lines
--- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/iio/inkern.c +1
-1@@ -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>
PATCH v5 7/13 minmax: Introduce {min,max}_array()
In reply to Herve CodinaIntroduce min_array() (resp max_array()) in order to get the minimal (resp maximum) of values present in an array.
--- include/linux/minmax.h | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)
include/linux/minmax.h +64 -0
@@ -133,6 +133,70 @@*/ #define max_t (type, x, y) __careful_cmp((type)(x), (type)(y), >) +/* +* 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_integer_type_cases (type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +#define __unconst_integer_typeof (x) typeof( \ + _Generic((x), \ + char: (char)0, \ + __unconst_integer_type_cases(char), \ + __unconst_integer_type_cases(short), \ + __unconst_integer_type_cases(int), \ + __unconst_integer_type_cases(long), \ + __unconst_integer_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_integer_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) +/** * clamp_t - return a value clamped to a given range using a given type * @type: the type of variable to use
Signature · 1 line
2.40.1
Re: [PATCH v5 07/13] minmax: Introduce {min,max}_array()
Quoted 3 lines · Herve Codina
Introduce
min_array()(respmax_array()) in order to get the minimal (resp maximum) of values present in an array.
Only in the case if you need to send a new version (otherwise a follow up will be okay)...
...
Quoted 2 lines
+ * The first typeof(&(array)[0]) is needed in order to support arrays of both
+ * 'int *buff' and 'int buf[N]' types.
int buff[N] ?
Quoted 2 lines
+ * The array can be an array of const items.
+ *typeof()keeps the const qualifier. Use__unconst_typeof()in order to
+ _integer
Quoted 1 line
+ * discard the const qualifier for the
__elementvariable.
Signature · 2 lines
With Best Regards, Andy Shevchenko
RE: [PATCH v5 07/13] minmax: Introduce {min,max}_array()
In reply to Herve CodinaFrom: Herve Codina
Quoted 29 lines
Sent: 15 June 2023 16:26
Introduce
min_array()(respmax_array()) in order to get the minimal (resp maximum) of values present in an array.Signed-off-by Herve Codina <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>--- include/linux/minmax.h | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)include/linux/minmax.h +10
-0@@ -133,6 +133,70 @@*/ #define max_t (type, x, y) __careful_cmp((type)(x), (type)(y), >) +/* +* 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_integer_type_cases (type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0
include/linux/minmax.h line 155
Quoted 10 lines
include/linux/minmax.h +10
-0+ +#define __unconst_integer_typeof (x) typeof( \ + _Generic((x), \ + char: (char)0, \ + __unconst_integer_type_cases(char), \ + __unconst_integer_type_cases(short), \ + __unconst_integer_type_cases(int), \ + __unconst_integer_type_cases(long), \ + __unconst_integer_type_cases(long long), \ + default: (x)))
Those are probably more generally useful and belong elsewhere.
include/linux/minmax.h line 165
Quoted 10 lines
include/linux/minmax.h +10
-0+ +/* +* 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< ---
Is that needed in the .h file?
include/linux/minmax.h line 177
Quoted 12 lines
include/linux/minmax.h +12
-0+* +* 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_integer_typeof(__array[0]) __element = __array[--__len]; \
s/__element/__bound/
include/linux/minmax.h line 180
Quoted 3 lines
include/linux/minmax.h +3
-0+while (__len--) \ + __element =op (__element, __array[__len]); \ + __element; })
I'm not all sure that all the shenanigans required to use min() is really needed here.
It would also be generally better to process the array forwards. So something like:
typeof (&array[0]) __ptr = array, __limit = array + len;
typeof (array[0] + 0) __element, __bound = *__ptr++;
while (ptr < __limit) {
__element = *__ptr++;
if (__element > __bound)
__bound = __element;
}
(typeof (array[0]))__bound; })seems fine to me.
The final cast is there to convert 'int' back to un/signed char|short. Not really needed and might generate worse code.
But if you insist on using min/max ignore this bit.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH v5 07/13] minmax: Introduce {min,max}_array()
Hi David, Andy
Quoted 34 lines · On Tue, 20 Jun 2023 11:45:01 +0000 David Laight <[email protected]> wrote:
From: Herve Codina
Quoted 33 lines
Sent: 15 June 2023 16:26
Introduce
min_array()(respmax_array()) in order to get the minimal (resp maximum) of values present in an array.Signed-off-by Herve Codina <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>--- include/linux/minmax.h | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)include/linux/minmax.h +14
-0@@ -133,6 +133,70 @@*/ #define max_t (type, x, y) __careful_cmp((type)(x), (type)(y), >) +/* +* 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_integer_type_cases (type) \ + unsigned type: (unsigned type)0, \ + signed type: (signed type)0 + +#define __unconst_integer_typeof (x) typeof( \ + _Generic((x), \ + char: (char)0, \
Quoted 8 lines
include/linux/minmax.h line 155
Quoted 6 lines
include/linux/minmax.h +6
-0+__unconst_integer_type_cases (char), \ +__unconst_integer_type_cases (short ), \ +__unconst_integer_type_cases (int ), \ +__unconst_integer_type_cases (long ), \ +__unconst_integer_type_cases (long long ), \ + default: (x)))Those are probably more generally useful and belong elsewhere.
Yes but it is only used here.
It can be move somewhere, in a common place, when necessary.
Quoted 46 lines
include/linux/minmax.h line 165
Quoted 11 lines
include/linux/minmax.h +10
-0+ +/* +* 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< --- Is that needed in the .h file?
include/linux/minmax.h line 177
Quoted 12 lines
include/linux/minmax.h +12
-0+* +* 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_integer_typeof(__array[0]) __element = __array[--__len]; \s/__element/__bound/
include/linux/minmax.h line 180
Quoted 3 lines
include/linux/minmax.h +3
-0+while (__len--) \ + __element =op (__element, __array[__len]); \ + __element; })I'm not all sure that all the shenanigans required to use
min()is really needed here.It would also be generally better to process the array forwards. So something like:
typeof (&array[0]) __ptr = array, __limit = array + len; typeof (array[0] + 0) __element, __bound = *__ptr++; while (ptr < __limit) { __element = *__ptr++; if (__element > __bound) __bound = __element; } (typeof (array[0]))__bound; })
Quoted 5 lines
seems fine to me.
The final cast is there to convert 'int' back to un/signed char|short. Not really needed and might generate worse code.But if you insist on using min/max ignore this bit.
I didn't plan to change the {min,max}_array() macros in this series as you suggest.
Maybe min()/max() is too strict but it's a way to be sure about the type used. Also the current version doesn't need any extra cast to get rid of the integer promotion as the integer promotion doesn't occur.
Is it ok for you if we keep as it ?
Thanks for your feedback,
Hervé
Signature · 3 lines
Hervé Codina, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Mark Brown
maintainerRe: [PATCH v5 07/13] minmax: Introduce {min,max}_array()
Quoted 1 line · Herve Codina
Is it ok for you if we keep as it ?
I think any issues here can be addressed incrementally rather than holding up the rest of the series.
Re: [PATCH v5 07/13] minmax: Introduce {min,max}_array()
In reply to Herve CodinaQuoted 5 lines · Herve Codina
Quoted 2 lines · On Tue, 20 Jun 2023 11:45:01 +0000 David Laight <[email protected]> wrote:
From: Herve Codina
Quoted 1 line
Sent: 15 June 2023 16:26
Quoted 8 lines
I didn't plan to change the {min,max}_array() macros in this series as you suggest.
Maybe min()/max() is too strict but it's a way to be sure about the type used. Also the current version doesn't need any extra cast to get rid of the integer promotion as the integer promotion doesn't occur.
Is it ok for you if we keep as it ?
I think the current verison is good enough, and as Mark said we may update incrementally if ever needed.
Signature · 2 lines
With Best Regards, Andy Shevchenko
PATCH v5 8/13 iio: inkern: Use max_array() to get the maximum value from an array
In reply to Herve CodinaUse max_array() to get the maximum value from an array instead of a custom local loop.
--- drivers/iio/inkern.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/iio/inkern.c +2 -5
@@ -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 */
Signature · 1 line
2.40.1
Re: [PATCH v5 08/13] iio: inkern: Use max_array() to get the maximum value from an array
Quoted 5 lines · On Thu, 15 Jun 2023 17:26:26 +0200 Herve Codina <[email protected]>…
Use
max_array()to get the maximum value from an array instead of a custom local loop.Signed-off-by Herve Codina <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>
Quoted 29 lines
--- drivers/iio/inkern.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)drivers/iio/inkern.c +2
-5@@ -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 */
PATCH v5 9/13 iio: inkern: Replace a FIXME comment by a TODO one
In reply to Herve CodinaThis 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.
--- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/inkern.c +1 -1
@@ -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 ;
Signature · 1 line
2.40.1
Re: [PATCH v5 09/13] iio: inkern: Replace a FIXME comment by a TODO one
Quoted 8 lines · On Thu, 15 Jun 2023 17:26:27 +0200 Herve Codina <[email protected]>…
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 <[email protected]>Suggested-by Jonathan Cameron <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>
Quoted 17 lines
--- drivers/iio/inkern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/iio/inkern.c +1
-1@@ -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 ;
PATCH v5 10/13 iio: inkern: Add a helper to query an available minimum raw value
In reply to Herve CodinaA 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().
--- drivers/iio/inkern.c | 63 ++++++++++++++++++++++++++++++++++++ include/linux/iio/consumer.h | 12 +++++++ 2 files changed, 75 insertions(+)
drivers/iio/inkern.c +63 -0
@@ -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);
include/linux/iio/consumer.h +12 -0
@@ -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.
Signature · 1 line
2.40.1
Re: [PATCH v5 10/13] iio: inkern: Add a helper to query an available minimum raw value
Quoted 10 lines · On Thu, 15 Jun 2023 17:26:28 +0200 Herve Codina <[email protected]>…
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 existingiio_read_max_channel_raw().Signed-off-by Herve Codina <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>
LGTM
Quoted 102 lines
--- drivers/iio/inkern.c | 63 ++++++++++++++++++++++++++++++++++++ include/linux/iio/consumer.h | 12 +++++++ 2 files changed, 75 insertions(+)drivers/iio/inkern.c +63
-0@@ -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);include/linux/iio/consumer.h +12
-0@@ -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.
PATCH v5 11/13 ASoC: soc-dapm.h: Convert macros to return a compound literal
In reply to Herve CodinaThe 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);
...}
--- include/sound/soc-dapm.h | 138 ++++++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 46 deletions(-)
include/sound/soc-dapm.h +92 -46
@@ -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, \
Signature · 1 line
2.40.1
PATCH v5 12/13 ASoC: codecs: Add support for the generic IIO auxiliary devices
In reply to Herve CodinaIndustrial 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.
--- 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
sound/soc/codecs/Kconfig +12 -0
@@ -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
sound/soc/codecs/Makefile +2 -0
@@ -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
sound/soc/codecs/audio-iio-aux.c new file +338 -0
338 lines not on this page · raw message
Signature · 1 line
2.40.1
Re: [PATCH v5 12/13] ASoC: codecs: Add support for the generic IIO auxiliary devices
Quoted 9 lines · On Thu, 15 Jun 2023 17:26:30 +0200 Herve Codina <[email protected]>…
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 <[email protected]>
A few trivial things inline.
With those tidied up, (for the IIO bits and general code - but I don't know the snd part well enough to review that).
Quoted 4 lines
index 000000000000..b9d72cbb85f2
sound/soc/codecs/audio-iio-aux.c new file +0
-0@@ -0,0 +1,338 @@
...
sound/soc/codecs/audio-iio-aux.c line 105
Quoted 4 lines
sound/soc/codecs/audio-iio-aux.c new file +4
-0+static int audio_iio_aux_add_controls (struct snd_soc_component *component, +struct audio_iio_aux_chan *chan) +{ +struct snd_kcontrol_new control = {};
Why not:
struct snd_kcontrol_new control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
.name = chan->name;
.info = audio_iio_aux_info_volsw;
.get = audio_iio_aux_get_volsw;
.put = audio_iio_aux_put_volsw;
.private_value = (unsigned long)chan;
};Quoted 32 lines
sound/soc/codecs/audio-iio-aux.c new file +32
-0+ + 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;
sound/soc/codecs/audio-iio-aux.c line 147
Quoted 10 lines
sound/soc/codecs/audio-iio-aux.c new file +10
-0+ + 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; + }
Trivial but a blank line here would be nice.
Quoted 47 lines
sound/soc/codecs/audio-iio-aux.c new file +47
-0+ 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);
sound/soc/codecs/audio-iio-aux.c line 204
Quoted 10 lines
sound/soc/codecs/audio-iio-aux.c new file +10
-0+ + 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);
Why? I'd like a comment here on what circumstances could cause this to happen.
Quoted 26 lines
sound/soc/codecs/audio-iio-aux.c new file +26
-0+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 ; +}
PATCH v5 13/13 ASoC: simple-card: Handle additional devices
In reply to Herve CodinaAn 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.
--- sound/soc/generic/simple-card.c | 46 +++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
sound/soc/generic/simple-card.c +44 -2
@@ -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;
Signature · 1 line
2.40.1