aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/core-api/kernel-api.rst7
-rw-r--r--Documentation/devicetree/bindings/sound/audio-iio-aux.yaml64
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml7
-rw-r--r--Documentation/devicetree/bindings/sound/nau8821.txt55
-rw-r--r--Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml125
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt101
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml160
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.yaml53
-rw-r--r--Documentation/driver-api/media/dtv-common.rst9
-rw-r--r--drivers/iio/inkern.c86
-rw-r--r--drivers/media/dvb-core/Makefile2
-rw-r--r--drivers/media/dvb-frontends/af9013_priv.h2
-rw-r--r--drivers/media/dvb-frontends/af9033_priv.h2
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_priv.h2
-rw-r--r--drivers/media/dvb-frontends/cxd2841er.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_top.c2
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c2
-rw-r--r--drivers/media/dvb-frontends/dib8000.c2
-rw-r--r--drivers/media/dvb-frontends/dib9000.c2
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c2
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.c2
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.c2
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c2
-rw-r--r--drivers/media/dvb-frontends/m88ds3103_priv.h2
-rw-r--r--drivers/media/dvb-frontends/mn88443x.c2
-rw-r--r--drivers/media/dvb-frontends/mn88472_priv.h2
-rw-r--r--drivers/media/dvb-frontends/mn88473_priv.h2
-rw-r--r--drivers/media/dvb-frontends/or51132.c2
-rw-r--r--drivers/media/dvb-frontends/or51211.c2
-rw-r--r--drivers/media/dvb-frontends/rtl2830_priv.h2
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h2
-rw-r--r--drivers/media/dvb-frontends/si2165.c2
-rw-r--r--drivers/media/dvb-frontends/stv0367.c2
-rw-r--r--drivers/media/dvb-frontends/tc90522.c2
-rw-r--r--drivers/media/dvb-frontends/tda10048.c2
-rw-r--r--include/linux/iio/consumer.h37
-rw-r--r--include/linux/int_log.h (renamed from include/media/dvb_math.h)18
-rw-r--r--include/linux/minmax.h64
-rw-r--r--include/sound/soc-dapm.h138
-rw-r--r--lib/math/Makefile2
-rw-r--r--lib/math/int_log.c (renamed from drivers/media/dvb-core/dvb_math.c)26
-rw-r--r--sound/soc/amd/Kconfig5
-rw-r--r--sound/soc/amd/vangogh/acp5x-mach.c149
-rw-r--r--sound/soc/codecs/Kconfig13
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/audio-iio-aux.c344
-rw-r--r--sound/soc/codecs/es8316.c5
-rw-r--r--sound/soc/codecs/nau8825.c93
-rw-r--r--sound/soc/codecs/rt5645.c50
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c2
-rw-r--r--sound/soc/codecs/rt722-sdca.c3
-rw-r--r--sound/soc/codecs/tas2781-i2c.c1
-rw-r--r--sound/soc/dwc/dwc-i2s.c65
-rw-r--r--sound/soc/dwc/dwc-pcm.c8
-rw-r--r--sound/soc/dwc/local.h24
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c12
-rw-r--r--sound/soc/generic/simple-card.c46
-rw-r--r--sound/soc/intel/avs/board_selection.c16
-rw-r--r--sound/soc/intel/avs/boards/Kconfig20
-rw-r--r--sound/soc/intel/avs/boards/Makefile4
-rw-r--r--sound/soc/intel/avs/boards/es8336.c315
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c254
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c67
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-pcm.c8
-rw-r--r--sound/soc/soc-core.c144
-rw-r--r--sound/soc/sof/amd/acp.c34
-rw-r--r--sound/soc/sof/amd/acp.h4
69 files changed, 2153 insertions, 541 deletions
diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst
index f2bcc5a7ea43..a526fbe06f86 100644
--- a/Documentation/core-api/kernel-api.rst
+++ b/Documentation/core-api/kernel-api.rst
@@ -162,8 +162,11 @@ Base 2 log and power Functions
.. kernel-doc:: include/linux/log2.h
:internal:
-Integer power Functions
------------------------
+Integer log and power Functions
+-------------------------------
+
+.. kernel-doc:: include/linux/int_log.h
+ :export:
.. kernel-doc:: lib/math/int_pow.c
:export:
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 <[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>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml
index e6cb711ece77..0b92c71d8779 100644
--- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml
+++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml
@@ -25,6 +25,12 @@ properties:
reset-names:
const: audiosys
+ memory-region:
+ maxItems: 1
+ description: |
+ Shared memory region for AFE memif. A "shared-dma-pool".
+ See ../reserved-memory/reserved-memory.yaml for details.
+
mediatek,topckgen:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the mediatek topckgen controller
@@ -176,6 +182,7 @@ examples:
interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
resets = <&watchdog 14>;
reset-names = "audiosys";
+ memory-region = <&snd_dma_mem_reserved>;
mediatek,topckgen = <&topckgen>;
mediatek,infracfg = <&infracfg_ao>;
power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
diff --git a/Documentation/devicetree/bindings/sound/nau8821.txt b/Documentation/devicetree/bindings/sound/nau8821.txt
deleted file mode 100644
index 7c84e7c7327a..000000000000
--- a/Documentation/devicetree/bindings/sound/nau8821.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-Nuvoton NAU88L21 audio codec
-
-This device supports I2C only.
-
-Required properties:
- - compatible : Must be "nuvoton,nau8821"
-
- - reg : the I2C address of the device. This is either 0x1B (CSB=0) or 0x54 (CSB=1).
-
-Optional properties:
- - nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
- - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
- otherwise pin in high impedance state.
- - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
- - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
-
- - nuvoton,vref-impedance: VREF Impedance selection
- 0 - Open
- 1 - 25 kOhm
- 2 - 125 kOhm
- 3 - 2.5 kOhm
-
- - nuvoton,micbias-voltage: Micbias voltage level.
- 0 - VDDA
- 1 - VDDA
- 2 - VDDA * 1.1
- 3 - VDDA * 1.2
- 4 - VDDA * 1.3
- 5 - VDDA * 1.4
- 6 - VDDA * 1.53
- 7 - VDDA * 1.53
-
- - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
- - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
-
- - nuvoton,dmic-clk-threshold: the ADC threshold of DMIC clock.
- - nuvoton,key_enable: Headset button detection switch.
-
-Example:
-
- headset: nau8821@1b {
- compatible = "nuvoton,nau8821";
- reg = <0x1b>;
- interrupt-parent = <&gpio>;
- interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
- nuvoton,jkdet-enable;
- nuvoton,jkdet-pull-enable;
- nuvoton,jkdet-pull-up;
- nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
- nuvoton,vref-impedance = <2>;
- nuvoton,micbias-voltage = <6>;
- nuvoton,jack-insert-debounce = <7>;
- nuvoton,jack-eject-debounce = <7>;
- nuvoton,dmic-clk-threshold = 3072000;
- };
diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml
new file mode 100644
index 000000000000..fc2f4ce4db88
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nuvoton,nau8821.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NAU88L21 audio codec
+
+maintainers:
+ - Seven Lee <[email protected]>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: nuvoton,nau8821
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ nuvoton,jkdet-enable:
+ description: Enable jack detection via JKDET pin.
+ type: boolean
+
+ nuvoton,jkdet-pull-enable:
+ description: Enable JKDET pin pull. If set - pin pull enabled,
+ otherwise pin in high impedance state.
+ type: boolean
+
+ nuvoton,jkdet-pull-up:
+ description: Pull-up JKDET pin. If set then JKDET pin is pull up,
+ otherwise pull down.
+ type: boolean
+
+ nuvoton,key-enable:
+ description: handles key press detection.
+ type: boolean
+
+ nuvoton,jkdet-polarity:
+ description: JKDET pin polarity.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum:
+ - 0 # active high
+ - 1 # active low
+ default: 1
+
+ nuvoton,micbias-voltage:
+ description: MICBIAS output level select.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum:
+ - 0 # VDDA
+ - 1 # VDDA * 1
+ - 2 # VDDA * 1.1
+ - 3 # VDDA * 1.2
+ - 4 # VDDA * 1.3
+ - 5 # VDDA * 1.4
+ - 6 # VDDA * 1.53
+ - 7 # VDDA * 1.53
+ default: 6
+
+ nuvoton,vref-impedance:
+ description: VMID Tie-off impedance select.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum:
+ - 0 # open
+ - 1 # 25KOhms
+ - 2 # 125KOhms
+ - 3 # 2.5KOhms
+ default: 2
+
+ nuvoton,jack-insert-debounce:
+ description: number from 0 to 7 that sets debounce time to 2^(n+2)ms.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ maximum: 7
+ default: 7
+
+ nuvoton,jack-eject-debounce:
+ description: number from 0 to 7 that sets debounce time to 2^(n+2)ms.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ maximum: 7
+ default: 0
+
+ nuvoton,dmic-clk-threshold:
+ description: DMIC clock speed expected value. Unit is Hz.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 3072000
+
+ '#sound-dai-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ codec@1b {
+ compatible = "nuvoton,nau8821";
+ reg = <0x1b>;
+ interrupt-parent = <&gpio>;
+ interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+ nuvoton,jkdet-enable;
+ nuvoton,jkdet-pull-enable;
+ nuvoton,jkdet-pull-up;
+ nuvoton,key-enable;
+ nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
+ nuvoton,micbias-voltage = <6>;
+ nuvoton,vref-impedance = <2>;
+ nuvoton,jack-insert-debounce = <7>;
+ nuvoton,jack-eject-debounce = <0>;
+ nuvoton,dmic-clk-threshold = <3072000>;
+ #sound-dai-cells = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
deleted file mode 100644
index e7d17dda55db..000000000000
--- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
+++ /dev/null
@@ -1,101 +0,0 @@
-msm8916 analog audio CODEC
-
-Bindings for codec Analog IP which is integrated in pmic pm8916,
-
-## Bindings for codec core on pmic:
-
-Required properties
- - compatible = "qcom,pm8916-wcd-analog-codec";
- - reg: represents the slave base address provided to the peripheral.
- - interrupts: List of interrupts in given SPMI peripheral.
- - interrupt-names: Names specified to above list of interrupts in same
- order. List of supported interrupt names are:
- "cdc_spk_cnp_int" - Speaker click and pop interrupt.
- "cdc_spk_clip_int" - Speaker clip interrupt.
- "cdc_spk_ocp_int" - Speaker over current protect interrupt.
- "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1.
- "mbhc_but_rel_det" - button release interrupt.
- "mbhc_but_press_det" - button press event
- "mbhc_ins_rem_det" - jack insert removal detect interrupt.
- "mbhc_switch_int" - multi button headset interrupt.
- "cdc_ear_ocp_int" - Earphone over current protect interrupt.
- "cdc_hphr_ocp_int" - Headphone R over current protect interrupt.
- "cdc_hphl_ocp_det" - Headphone L over current protect interrupt.
- "cdc_ear_cnp_int" - earphone cnp interrupt.
- "cdc_hphr_cnp_int" - hphr click and pop interrupt.
- "cdc_hphl_cnp_int" - hphl click and pop interrupt.
-
- - clocks: Handle to mclk.
- - clock-names: should be "mclk"
- - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node.
- - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node.
- - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node.
-
-Optional Properties:
- - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons
- detection on headset when the mbhc is powered up
- by internal current source, this is a low power.
- - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons
- detection on headset when mbhc is powered up
- from micbias.
-- qcom,micbias-lvl: Voltage (mV) for Mic Bias
-- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a
- NO (Normally Open). If not specified, then
- its assumed that hphl pin on jack is NC
- (Normally Closed).
-- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is
- NO (Normally Open). If not specified, then
- its assumed that gnd pin on jack is NC
- (Normally Closed).
-- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor
- connected.
-- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor
- connected.
-
-Example:
-
-spmi_bus {
- ...
- audio-codec@f000{
- compatible = "qcom,pm8916-wcd-analog-codec";
- reg = <0xf000 0x200>;
- reg-names = "pmic-codec-core";
- clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
- clock-names = "mclk";
- qcom,mbhc-vthreshold-low = <75 150 237 450 500>;
- qcom,mbhc-vthreshold-high = <75 150 237 450 500>;
- interrupt-parent = <&spmi_bus>;
- interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
- <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
- <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
- <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
- <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
- <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
- <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
- <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
- interrupt-names = "cdc_spk_cnp_int",
- "cdc_spk_clip_int",
- "cdc_spk_ocp_int",
- "mbhc_ins_rem_det1",
- "mbhc_but_rel_det",
- "mbhc_but_press_det",
- "mbhc_ins_rem_det",
- "mbhc_switch_int",
- "cdc_ear_ocp_int",
- "cdc_hphr_ocp_int",
- "cdc_hphl_ocp_det",
- "cdc_ear_cnp_int",
- "cdc_hphr_cnp_int",
- "cdc_hphl_cnp_int";
- vdd-cdc-io-supply = <&pm8916_l5>;
- vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>;
- vdd-micbias-supply = <&pm8916_l13>;
- #sound-dai-cells = <1>;
- };
-};
diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
new file mode 100644
index 000000000000..c385028c4296
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,pm8916-wcd-analog-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm PM8916 WCD Analog Audio Codec
+
+maintainers:
+ - Konrad Dybcio <[email protected]>
+
+description:
+ The analog WCD audio codec found on Qualcomm PM8916 PMIC.
+
+properties:
+ compatible:
+ const: qcom,pm8916-wcd-analog-codec
+
+ reg:
+ maxItems: 1
+
+ reg-names:
+ items:
+ - const: pmic-codec-core
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: mclk
+
+ interrupts:
+ maxItems: 14
+
+ interrupt-names:
+ items:
+ - const: cdc_spk_cnp_int
+ - const: cdc_spk_clip_int
+ - const: cdc_spk_ocp_int
+ - const: mbhc_ins_rem_det1
+ - const: mbhc_but_rel_det
+ - const: mbhc_but_press_det
+ - const: mbhc_ins_rem_det
+ - const: mbhc_switch_int
+ - const: cdc_ear_ocp_int
+ - const: cdc_hphr_ocp_int
+ - const: cdc_hphl_ocp_det
+ - const: cdc_ear_cnp_int
+ - const: cdc_hphr_cnp_int
+ - const: cdc_hphl_cnp_int
+
+ vdd-cdc-io-supply:
+ description: 1.8V buck supply
+
+ vdd-cdc-tx-rx-cx-supply:
+ description: 1.8V SIDO buck supply
+
+ vdd-micbias-supply:
+ description: micbias supply
+
+ qcom,mbhc-vthreshold-low:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Array of 5 threshold voltages in mV for 5-button detection on
+ headset when MBHC is powered by an internal current source.
+ minItems: 5
+ maxItems: 5
+
+ qcom,mbhc-vthreshold-high:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Array of 5 threshold voltages in mV for 5-button detection on
+ headset when MBHC is powered from micbias.
+ minItems: 5
+ maxItems: 5
+
+ qcom,micbias-lvl:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Voltage (mV) for Mic Bias
+
+ qcom,hphl-jack-type-normally-open:
+ type: boolean
+ description:
+ True if the HPHL pin on the jack is NO (Normally Open), false if it's
+ NC (Normally Closed).
+
+ qcom,gnd-jack-type-normally-open:
+ type: boolean
+ description:
+ True if the GND pin on the jack is NO (Normally Open), false if it's
+ NC (Normally Closed).
+
+ qcom,micbias1-ext-cap:
+ type: boolean
+ description:
+ True if micbias1 has an external capacitor.
+
+ qcom,micbias2-ext-cap:
+ type: boolean
+ description:
+ True if micbias2 has an external capacitor.
+
+ "#sound-dai-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,gcc-msm8916.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ audio-codec@f000{
+ compatible = "qcom,pm8916-wcd-analog-codec";
+ reg = <0xf000 0x200>;
+ reg-names = "pmic-codec-core";
+ clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
+ clock-names = "mclk";
+ qcom,mbhc-vthreshold-low = <75 150 237 450 500>;
+ qcom,mbhc-vthreshold-high = <75 150 237 450 500>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "cdc_spk_cnp_int",
+ "cdc_spk_clip_int",
+ "cdc_spk_ocp_int",
+ "mbhc_ins_rem_det1",
+ "mbhc_but_rel_det",
+ "mbhc_but_press_det",
+ "mbhc_ins_rem_det",
+ "mbhc_switch_int",
+ "cdc_ear_ocp_int",
+ "cdc_hphr_ocp_int",
+ "cdc_hphl_ocp_det",
+ "cdc_ear_cnp_int",
+ "cdc_hphr_cnp_int",
+ "cdc_hphl_cnp_int";
+ vdd-cdc-io-supply = <&pm8916_l5>;
+ vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>;
+ vdd-micbias-supply = <&pm8916_l13>;
+ #sound-dai-cells = <1>;
+ };
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:
@@ -360,6 +371,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
# --------------------
- |
diff --git a/Documentation/driver-api/media/dtv-common.rst b/Documentation/driver-api/media/dtv-common.rst
index f8b2c4dc8170..207a22bcaf4a 100644
--- a/Documentation/driver-api/media/dtv-common.rst
+++ b/Documentation/driver-api/media/dtv-common.rst
@@ -3,15 +3,6 @@
Digital TV Common functions
---------------------------
-Math functions
-~~~~~~~~~~~~~~
-
-Provide some commonly-used math functions, usually required in order to
-estimate signal strength and signal to noise measurements in dB.
-
-.. kernel-doc:: include/media/dvb_math.h
-
-
DVB devices
~~~~~~~~~~~
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 872fd5c24147..7a1f6713318a 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -5,9 +5,10 @@
*/
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/minmax.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>
@@ -849,15 +850,14 @@ 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;
+
switch (ret) {
case IIO_AVAIL_RANGE:
switch (*type) {
@@ -866,7 +866,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;
@@ -875,20 +876,16 @@ 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 */
+ /* TODO: learn about max for other iio values */
return -EINVAL;
}
return 0;
default:
- return ret;
+ return -EINVAL;
}
}
@@ -912,6 +909,69 @@ err_unlock:
}
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/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
index 62b028ded9f7..1cb3ca67bed9 100644
--- a/drivers/media/dvb-core/Makefile
+++ b/drivers/media/dvb-core/Makefile
@@ -8,6 +8,6 @@ dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \
dvb_ca_en50221.o dvb_frontend.o \
- $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o
+ $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y)
obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h
index 3b9b9424fe1a..bba7a9693a23 100644
--- a/drivers/media/dvb-frontends/af9013_priv.h
+++ b/drivers/media/dvb-frontends/af9013_priv.h
@@ -12,7 +12,7 @@
#define AF9013_PRIV_H
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "af9013.h"
#include <linux/firmware.h>
#include <linux/i2c-mux.h>
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index 0e64da0cdeab..7560da75ef00 100644
--- a/drivers/media/dvb-frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -14,7 +14,7 @@
#include <linux/math64.h>
#include <linux/regmap.h>
#include <linux/kernel.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
struct reg_val {
u32 reg;
diff --git a/drivers/media/dvb-frontends/cxd2820r_priv.h b/drivers/media/dvb-frontends/cxd2820r_priv.h
index 9b4d9cf8563d..605320bbc12b 100644
--- a/drivers/media/dvb-frontends/cxd2820r_priv.h
+++ b/drivers/media/dvb-frontends/cxd2820r_priv.h
@@ -11,7 +11,7 @@
#include <linux/dvb/version.h>
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "cxd2820r.h"
#include <linux/gpio/driver.h> /* For gpio_chip */
#include <linux/math64.h>
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c
index 5431f922f55e..ef403a9fb753 100644
--- a/drivers/media/dvb-frontends/cxd2841er.c
+++ b/drivers/media/dvb-frontends/cxd2841er.c
@@ -22,7 +22,7 @@
#include <linux/dynamic_debug.h>
#include <linux/kernel.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <media/dvb_frontend.h>
#include "cxd2841er.h"
#include "cxd2841er_priv.h"
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
index 604580bf7cf7..4e173dd87ecf 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
@@ -11,7 +11,7 @@
#include "cxd2880_tnrdmd_dvbt2.h"
#include "cxd2880_tnrdmd_dvbt2_mon.h"
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
static const int ref_dbm_1000[4][8] = {
{-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
index fedc3b4a2fa0..86d5a1e4022a 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
@@ -11,7 +11,7 @@
#include "cxd2880_tnrdmd_dvbt.h"
#include "cxd2880_tnrdmd_dvbt_mon.h"
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
static const int ref_dbm_1000[3][5] = {
{-93000, -91000, -90000, -89000, -88000},
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
index d5b1b3788e39..f67b6d24b8d4 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
@@ -11,7 +11,7 @@
#include <linux/spi/spi.h>
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "cxd2880.h"
#include "cxd2880_tnrdmd_mon.h"
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index a90d2f51868f..b791e687d2e2 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -13,7 +13,7 @@
#include <linux/mutex.h>
#include <asm/div64.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <media/dvb_frontend.h>
#include "dib7000p.h"
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index fe19d127abb3..2abda7d1cb6e 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -13,7 +13,7 @@
#include <linux/mutex.h>
#include <asm/div64.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <media/dvb_frontend.h>
diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c
index 914ca820c174..1c57587a917a 100644
--- a/drivers/media/dvb-frontends/dib9000.c
+++ b/drivers/media/dvb-frontends/dib9000.c
@@ -11,7 +11,7 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <media/dvb_frontend.h>
#include "dib9000.h"
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 3301ef75d441..6ad4f202f1bf 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -20,7 +20,7 @@
#include <media/dvb_frontend.h>
#include "drxk.h"
#include "drxk_hard.h"
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
static int power_down_dvbt(struct drxk_state *state, bool set_power_mode);
static int power_down_qam(struct drxk_state *state);
diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c
index 62d743988919..c15d3735d34c 100644
--- a/drivers/media/dvb-frontends/lgdt3305.c
+++ b/drivers/media/dvb-frontends/lgdt3305.c
@@ -10,7 +10,7 @@
#include <asm/div64.h>
#include <linux/dvb/frontend.h>
#include <linux/slab.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "lgdt3305.h"
static int debug;
diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
index 70258884126b..3c6650f6e9a3 100644
--- a/drivers/media/dvb-frontends/lgdt3306a.c
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -12,7 +12,7 @@
#include <asm/div64.h>
#include <linux/kernel.h>
#include <linux/dvb/frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "lgdt3306a.h"
#include <linux/i2c-mux.h>
diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
index 83565209c3b1..97a10996c7fa 100644
--- a/drivers/media/dvb-frontends/lgdt330x.c
+++ b/drivers/media/dvb-frontends/lgdt330x.c
@@ -28,7 +28,7 @@
#include <asm/byteorder.h>
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "lgdt330x_priv.h"
#include "lgdt330x.h"
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index aa5306f40201..594ad9cbc2cc 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -10,7 +10,7 @@
#include <media/dvb_frontend.h>
#include "m88ds3103.h"
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <linux/firmware.h>
#include <linux/i2c-mux.h>
#include <linux/regmap.h>
diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c
index 2ce5692bc22c..db2921c736af 100644
--- a/drivers/media/dvb-frontends/mn88443x.c
+++ b/drivers/media/dvb-frontends/mn88443x.c
@@ -10,7 +10,7 @@
#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "mn88443x.h"
diff --git a/drivers/media/dvb-frontends/mn88472_priv.h b/drivers/media/dvb-frontends/mn88472_priv.h
index 337562723f88..41f14bd67bfd 100644
--- a/drivers/media/dvb-frontends/mn88472_priv.h
+++ b/drivers/media/dvb-frontends/mn88472_priv.h
@@ -9,7 +9,7 @@
#define MN88472_PRIV_H
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "mn88472.h"
#include <linux/firmware.h>
#include <linux/regmap.h>
diff --git a/drivers/media/dvb-frontends/mn88473_priv.h b/drivers/media/dvb-frontends/mn88473_priv.h
index eca7f4e2b769..e9daaacfa22f 100644
--- a/drivers/media/dvb-frontends/mn88473_priv.h
+++ b/drivers/media/dvb-frontends/mn88473_priv.h
@@ -9,7 +9,7 @@
#define MN88473_PRIV_H
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "mn88473.h"
#include <linux/math64.h>
#include <linux/firmware.h>
diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c
index 24de1b115158..355f3598627b 100644
--- a/drivers/media/dvb-frontends/or51132.c
+++ b/drivers/media/dvb-frontends/or51132.c
@@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <asm/byteorder.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <media/dvb_frontend.h>
#include "or51132.h"
diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c
index ddcaea5c9941..ae732dc5116e 100644
--- a/drivers/media/dvb-frontends/or51211.c
+++ b/drivers/media/dvb-frontends/or51211.c
@@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <asm/byteorder.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include <media/dvb_frontend.h>
#include "or51211.h"
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
index fae78ed78522..ae1fc24a4d84 100644
--- a/drivers/media/dvb-frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -9,7 +9,7 @@
#define RTL2830_PRIV_H
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "rtl2830.h"
#include <linux/i2c-mux.h>
#include <linux/math64.h>
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 5f79f95b9475..f11ba038d5f0 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -14,7 +14,7 @@
#include <linux/bitops.h>
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "rtl2832.h"
struct rtl2832_dev {
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 72810efd1a96..434d003bf397 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -19,7 +19,7 @@
#include <linux/regmap.h>
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "si2165_priv.h"
#include "si2165.h"
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 95e376f23506..a93f40617469 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -15,7 +15,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "stv0367.h"
#include "stv0367_defs.h"
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index 879f028f9682..1f8cbf45554a 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -21,7 +21,7 @@
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/dvb/frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "tc90522.h"
#define TC90522_I2C_THRU_REG 0xfe
diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c
index 0b3f6999515e..3cb4e5270e4f 100644
--- a/drivers/media/dvb-frontends/tda10048.c
+++ b/drivers/media/dvb-frontends/tda10048.c
@@ -16,7 +16,7 @@
#include <linux/math64.h>
#include <asm/div64.h>
#include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
#include "tda10048.h"
#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 6802596b017c..e9910b41d48e 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,12 +295,25 @@ 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);
/**
+ * 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.
* @vals: Available values read back.
@@ -308,8 +324,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);
diff --git a/include/media/dvb_math.h b/include/linux/int_log.h
index 8690ec42954d..0a6f58c38b61 100644
--- a/include/media/dvb_math.h
+++ b/include/linux/int_log.h
@@ -1,22 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
+ * Provides fixed-point logarithm operations.
*
* Copyright (C) 2006 Christoph Pfister ([email protected])
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
*/
-#ifndef __DVB_MATH_H
-#define __DVB_MATH_H
+#ifndef __LINUX_INT_LOG_H
+#define __LINUX_INT_LOG_H
#include <linux/types.h>
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
index 396df1121bff..798c6963909f 100644
--- a/include/linux/minmax.h
+++ b/include/linux/minmax.h
@@ -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 buff[N]' types.
+ *
+ * The array can be an array of const items.
+ * typeof() keeps the const qualifier. Use __unconst_integer_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
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, \
diff --git a/lib/math/Makefile b/lib/math/Makefile
index bfac26ddfc22..91fcdb0c9efe 100644
--- a/lib/math/Makefile
+++ b/lib/math/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += div64.o gcd.o lcm.o int_pow.o int_sqrt.o reciprocal_div.o
+obj-y += div64.o gcd.o lcm.o int_log.o int_pow.o int_sqrt.o reciprocal_div.o
obj-$(CONFIG_CORDIC) += cordic.o
obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o
diff --git a/drivers/media/dvb-core/dvb_math.c b/lib/math/int_log.c
index dc90564d7f34..8f9da3a2ad39 100644
--- a/drivers/media/dvb-core/dvb_math.c
+++ b/lib/math/int_log.c
@@ -1,25 +1,17 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
+ * Provides fixed-point logarithm operations.
*
* Copyright (C) 2006 Christoph Pfister ([email protected])
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
*/
#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/int_log.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/types.h>
+
#include <asm/bug.h>
-#include <media/dvb_math.h>
static const unsigned short logtable[256] = {
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
@@ -53,7 +45,7 @@ static const unsigned short logtable[256] = {
0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
- 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+ 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47,
};
unsigned int intlog2(u32 value)
@@ -90,7 +82,7 @@ unsigned int intlog2(u32 value)
* so we would use the entry 0x18
*/
significand = value << (31 - msb);
- logentry = (significand >> 23) & 0xff;
+ logentry = (significand >> 23) % ARRAY_SIZE(logtable);
/**
* last step we do is interpolation because of the
@@ -108,7 +100,7 @@ unsigned int intlog2(u32 value)
* logtable_next is 256
*/
interpolation = ((significand & 0x7fffff) *
- ((logtable[(logentry + 1) & 0xff] -
+ ((logtable[(logentry + 1) % ARRAY_SIZE(logtable)] -
logtable[logentry]) & 0xffff)) >> 15;
/* now we return the result */
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 1dd8579e8034..273688c05317 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -79,14 +79,15 @@ config SND_SOC_AMD_ACP5x
ACP DMA driver, CPU DAI driver.
config SND_SOC_AMD_VANGOGH_MACH
- tristate "AMD Vangogh support for NAU8821 CS35L41"
+ tristate "AMD Vangogh support for NAU8821/CS35L41/MAX98388"
select SND_SOC_NAU8821
select SND_SOC_CS35L41_SPI
+ select SND_SOC_MAX98388
select SND_AMD_ACP_CONFIG
depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER
help
This option enables machine driver for Vangogh platform
- using NAU8821 and CS35L41 codecs.
+ using NAU8821 and either CS35L41 or MAX98388 codecs.
Say m if you have such a device.
If unsure select "N".
diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c
index e5bcd1e6eb73..125a8e93478d 100644
--- a/sound/soc/amd/vangogh/acp5x-mach.c
+++ b/sound/soc/amd/vangogh/acp5x-mach.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Machine driver for AMD Vangogh platform using NAU8821 & CS35L41
- * codecs.
+ * Machine driver for AMD Vangogh platform using either
+ * NAU8821 & CS35L41 or NAU8821 & MAX98388 codecs.
*
* Copyright 2021 Advanced Micro Devices, Inc.
*/
@@ -22,7 +22,6 @@
#define DRV_NAME "acp5x_mach"
#define DUAL_CHANNEL 2
-#define VG_JUPITER 1
#define ACP5X_NAU8821_BCLK 3072000
#define ACP5X_NAU8821_FREQ_OUT 12288000
#define ACP5X_NAU8821_COMP_NAME "i2c-NVTN2020:00"
@@ -30,8 +29,10 @@
#define ACP5X_CS35L41_COMP_LNAME "spi-VLV1776:00"
#define ACP5X_CS35L41_COMP_RNAME "spi-VLV1776:01"
#define ACP5X_CS35L41_DAI_NAME "cs35l41-pcm"
+#define ACP5X_MAX98388_COMP_LNAME "i2c-ADS8388:00"
+#define ACP5X_MAX98388_COMP_RNAME "i2c-ADS8388:01"
+#define ACP5X_MAX98388_DAI_NAME "max98388-aif1"
-static unsigned long acp5x_machine_id;
static struct snd_soc_jack vg_headset;
SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0")));
@@ -242,7 +243,6 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
}
return 0;
-
}
static const struct snd_soc_ops acp5x_cs35l41_play_ops = {
@@ -292,8 +292,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = {
},
};
-
-
static const struct snd_soc_dapm_widget acp5x_8821_35l41_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -331,16 +329,110 @@ static struct snd_soc_card acp5x_8821_35l41_card = {
.num_controls = ARRAY_SIZE(acp5x_8821_controls),
};
-static int acp5x_vg_quirk_cb(const struct dmi_system_id *id)
+static int acp5x_max98388_startup(struct snd_pcm_substream *substream)
{
- acp5x_machine_id = VG_JUPITER;
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_pcm_runtime *runtime = substream->runtime;
- return 1;
+ machine->play_i2s_instance = I2S_HS_INSTANCE;
+
+ runtime->hw.channels_max = DUAL_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels);
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+ return 0;
}
+static const struct snd_soc_ops acp5x_max98388_play_ops = {
+ .startup = acp5x_max98388_startup,
+};
+
+static struct snd_soc_codec_conf acp5x_max98388_conf[] = {
+ {
+ .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_LNAME),
+ .name_prefix = "Left",
+ },
+ {
+ .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_RNAME),
+ .name_prefix = "Right",
+ },
+};
+
+SND_SOC_DAILINK_DEF(max98388, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_MAX98388_COMP_LNAME,
+ ACP5X_MAX98388_DAI_NAME),
+ COMP_CODEC(ACP5X_MAX98388_COMP_RNAME,
+ ACP5X_MAX98388_DAI_NAME)));
+
+static struct snd_soc_dai_link acp5x_8821_98388_dai[] = {
+ {
+ .name = "acp5x-8821-play",
+ .stream_name = "Playback/Capture",
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &acp5x_8821_ops,
+ .init = acp5x_8821_init,
+ SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform),
+ },
+ {
+ .name = "acp5x-max98388-play",
+ .stream_name = "MAX98388 Playback",
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBC_CFC,
+ .dpcm_playback = 1,
+ .playback_only = 1,
+ .ops = &acp5x_max98388_play_ops,
+ SND_SOC_DAILINK_REG(acp5x_bt, max98388, platform),
+ },
+};
+
+static const struct snd_soc_dapm_widget acp5x_8821_98388_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SPK("SPK", NULL),
+};
+
+static const struct snd_soc_dapm_route acp5x_8821_98388_route[] = {
+ { "Headphone", NULL, "HPOL" },
+ { "Headphone", NULL, "HPOR" },
+ { "MICL", NULL, "Headset Mic" },
+ { "MICR", NULL, "Headset Mic" },
+ { "DMIC", NULL, "Int Mic" },
+
+ { "Headphone", NULL, "Platform Clock" },
+ { "Headset Mic", NULL, "Platform Clock" },
+ { "Int Mic", NULL, "Platform Clock" },
+
+ { "SPK", NULL, "Left BE_OUT" },
+ { "SPK", NULL, "Right BE_OUT" },
+};
+
+static struct snd_soc_card acp5x_8821_98388_card = {
+ .name = "acp5x-max98388",
+ .owner = THIS_MODULE,
+ .dai_link = acp5x_8821_98388_dai,
+ .num_links = ARRAY_SIZE(acp5x_8821_98388_dai),
+ .dapm_widgets = acp5x_8821_98388_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_98388_widgets),
+ .dapm_routes = acp5x_8821_98388_route,
+ .num_dapm_routes = ARRAY_SIZE(acp5x_8821_98388_route),
+ .codec_conf = acp5x_max98388_conf,
+ .num_configs = ARRAY_SIZE(acp5x_max98388_conf),
+ .controls = acp5x_8821_controls,
+ .num_controls = ARRAY_SIZE(acp5x_8821_controls),
+};
+
static const struct dmi_system_id acp5x_vg_quirk_table[] = {
{
- .callback = acp5x_vg_quirk_cb,
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
@@ -351,23 +443,31 @@ static const struct dmi_system_id acp5x_vg_quirk_table[] = {
static int acp5x_probe(struct platform_device *pdev)
{
+ const struct dmi_system_id *dmi_id;
struct acp5x_platform_info *machine;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int ret;
+ card = (struct snd_soc_card *)device_get_match_data(dev);
+ if (!card) {
+ /*
+ * This is normally the result of directly probing the driver
+ * in pci-acp5x through platform_device_register_full(), which
+ * is necessary for the CS35L41 variant, as it doesn't support
+ * ACPI probing and relies on DMI quirks.
+ */
+ dmi_id = dmi_first_match(acp5x_vg_quirk_table);
+ if (!dmi_id)
+ return -ENODEV;
+
+ card = &acp5x_8821_35l41_card;
+ }
+
machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL);
if (!machine)
return -ENOMEM;
- dmi_check_system(acp5x_vg_quirk_table);
- switch (acp5x_machine_id) {
- case VG_JUPITER:
- card = &acp5x_8821_35l41_card;
- break;
- default:
- return -ENODEV;
- }
card->dev = dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
@@ -379,10 +479,17 @@ static int acp5x_probe(struct platform_device *pdev)
return 0;
}
+static const struct acpi_device_id acp5x_acpi_match[] = {
+ { "AMDI8821", (kernel_ulong_t)&acp5x_8821_98388_card },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, acp5x_acpi_match);
+
static struct platform_driver acp5x_mach_driver = {
.driver = {
- .name = "acp5x_mach",
+ .name = DRV_NAME,
.pm = &snd_soc_pm_ops,
+ .acpi_match_table = acp5x_acpi_match,
},
.probe = acp5x_probe,
};
@@ -390,6 +497,6 @@ static struct platform_driver acp5x_mach_driver = {
module_platform_driver(acp5x_mach_driver);
MODULE_AUTHOR("[email protected]");
-MODULE_DESCRIPTION("NAU8821 & CS35L41 audio support");
+MODULE_DESCRIPTION("NAU8821/CS35L41 & NAU8821/MAX98388 audio support");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c2de4ee72183..88c3dbe47d71 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
@@ -614,6 +615,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
@@ -1708,6 +1720,7 @@ config SND_SOC_STA529
config SND_SOC_STAC9766
tristate
depends on SND_SOC_AC97_BUS
+ select REGMAP_AC97
config SND_SOC_STI_SAS
tristate "codec Audio support for STI SAS codec"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index b48a9a323b84..32dcc6de58bd 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 \
@@ -428,6 +429,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..a8bf14239bd7
--- /dev/null
+++ b/sound/soc/codecs/audio-iio-aux.c
@@ -0,0 +1,344 @@
+// 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 <[email protected]>
+
+#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 = {
+ .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,
+ };
+
+ 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) {
+ /*
+ * This should never happen but to avoid any check
+ * later, just swap values here to ensure that the
+ * minimum value is lower than the maximum value.
+ */
+ 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 <[email protected]>");
+MODULE_DESCRIPTION("IIO ALSA SoC aux driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 34cf60769b62..7e5eb13af428 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -27,9 +27,9 @@
* MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
* Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
*/
-#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
+#define NR_SUPPORTED_MCLK_LRCK_RATIOS ARRAY_SIZE(supported_mclk_lrck_ratios)
static const unsigned int supported_mclk_lrck_ratios[] = {
- 256, 384, 400, 512, 768, 1024
+ 256, 384, 400, 500, 512, 768, 1024
};
struct es8316_priv {
@@ -494,6 +494,7 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
bclk_divider /= 20;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_3LE:
wordlen = ES8316_SERDATA2_LEN_24;
bclk_divider /= 24;
break;
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 9e0e4ddf128e..5cb0de648bd3 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/int_log.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -38,7 +39,6 @@
#define NAU_FVCO_MIN 90000000
/* cross talk suppression detection */
-#define LOG10_MAGIC 646456993
#define GAIN_AUGMENT 22500
#define SIDETONE_BASE 207000
@@ -219,42 +219,6 @@ static const struct reg_sequence nau8825_regmap_patch[] = {
{ NAU8825_REG_MIC_BIAS, 0x0046 },
};
-
-static const unsigned short logtable[256] = {
- 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
- 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
- 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
- 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
- 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
- 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
- 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
- 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
- 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
- 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
- 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
- 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
- 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
- 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
- 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
- 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
- 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
- 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
- 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
- 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
- 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
- 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
- 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
- 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
- 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
- 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
- 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
- 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
- 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
- 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
- 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
- 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
/**
* nau8825_sema_acquire - acquire the semaphore of nau88l25
* @nau8825: component to register the codec private data with
@@ -368,65 +332,14 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
}
/**
- * nau8825_intlog10_dec3 - Computes log10 of a value
- * the result is round off to 3 decimal. This function takes reference to
- * dvb-math. The source code locates as the following.
- * Linux/drivers/media/dvb-core/dvb_math.c
+ * nau8825_intlog10_dec3 - Computes log10 of a value, rounding the result to 3 decimal places.
* @value: input for log10
*
* return log10(value) * 1000
*/
static u32 nau8825_intlog10_dec3(u32 value)
{
- u32 msb, logentry, significand, interpolation, log10val;
- u64 log2val;
-
- /* first detect the msb (count begins at 0) */
- msb = fls(value) - 1;
- /**
- * now we use a logtable after the following method:
- *
- * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
- * where x = msb and therefore 1 <= y < 2
- * first y is determined by shifting the value left
- * so that msb is bit 31
- * 0x00231f56 -> 0x8C7D5800
- * the result is y * 2^31 -> "significand"
- * then the highest 9 bits are used for a table lookup
- * the highest bit is discarded because it's always set
- * the highest nine bits in our example are 100011000
- * so we would use the entry 0x18
- */
- significand = value << (31 - msb);
- logentry = (significand >> 23) & 0xff;
- /**
- * last step we do is interpolation because of the
- * limitations of the log table the error is that part of
- * the significand which isn't used for lookup then we
- * compute the ratio between the error and the next table entry
- * and interpolate it between the log table entry used and the
- * next one the biggest error possible is 0x7fffff
- * (in our example it's 0x7D5800)
- * needed value for next table entry is 0x800000
- * so the interpolation is
- * (error / 0x800000) * (logtable_next - logtable_current)
- * in the implementation the division is moved to the end for
- * better accuracy there is also an overflow correction if
- * logtable_next is 256
- */
- interpolation = ((significand & 0x7fffff) *
- ((logtable[(logentry + 1) & 0xff] -
- logtable[logentry]) & 0xffff)) >> 15;
-
- log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation);
- /**
- * log10(x) = log2(x) * log10(2)
- */
- log10val = (log2val * LOG10_MAGIC) >> 31;
- /**
- * the result is round off to 3 decimal
- */
- return log10val / ((1 << 24) / 1000);
+ return intlog10(value) / ((1 << 24) / 1000);
}
/**
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index a506d940a2ea..5be5ec0260e9 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3258,6 +3258,22 @@ int rt5645_set_jack_detect(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+static int rt5645_component_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct snd_soc_jack *mic_jack = NULL;
+ struct snd_soc_jack *btn_jack = NULL;
+ int *type = (int *)data;
+
+ if (*type & SND_JACK_MICROPHONE)
+ mic_jack = hs_jack;
+ if (*type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3))
+ btn_jack = hs_jack;
+
+ return rt5645_set_jack_detect(component, hs_jack, mic_jack, btn_jack);
+}
+
static void rt5645_jack_detect_work(struct work_struct *work)
{
struct rt5645_priv *rt5645 =
@@ -3532,6 +3548,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = {
.num_dapm_widgets = ARRAY_SIZE(rt5645_dapm_widgets),
.dapm_routes = rt5645_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(rt5645_dapm_routes),
+ .set_jack = rt5645_component_set_jack,
.use_pmdown_time = 1,
.endianness = 1,
};
@@ -4182,11 +4199,44 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
regmap_write(rt5645->regmap, RT5645_RESET, 0);
}
+static int __maybe_unused rt5645_sys_suspend(struct device *dev)
+{
+ struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+
+ del_timer_sync(&rt5645->btn_check_timer);
+ cancel_delayed_work_sync(&rt5645->jack_detect_work);
+ cancel_delayed_work_sync(&rt5645->rcclock_work);
+
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return 0;
+}
+
+static int __maybe_unused rt5645_sys_resume(struct device *dev)
+{
+ struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+
+ regcache_cache_only(rt5645->regmap, false);
+ regcache_sync(rt5645->regmap);
+
+ if (rt5645->hp_jack) {
+ rt5645->jack_type = 0;
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5645->jack_detect_work, msecs_to_jiffies(0));
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops rt5645_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume)
+};
+
static struct i2c_driver rt5645_i2c_driver = {
.driver = {
.name = "rt5645",
.of_match_table = of_match_ptr(rt5645_of_match),
.acpi_match_table = ACPI_PTR(rt5645_acpi_match),
+ .pm = &rt5645_pm,
},
.probe = rt5645_i2c_probe,
.remove = rt5645_i2c_remove,
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index cc57e4e27805..a9416bd163e8 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -175,7 +175,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave,
* This also could sync with the cache value as the rt722_sdca_jack_init set.
*/
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+ SDW_SCP_SDCA_INTMASK_SDCA_6);
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
SDW_SCP_SDCA_INTMASK_SDCA_8);
}
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
index 9c0d34366c9e..0e1c65a20392 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -191,8 +191,7 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work)
return;
/* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
- if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 ||
- rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+ if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6) {
ret = rt722_sdca_headset_detect(rt722);
if (ret < 0)
return;
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 4c59429a42b7..55cd5e3c23a5 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -743,7 +743,6 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
static struct i2c_driver tasdevice_i2c_driver = {
.driver = {
.name = "tas2781-codec",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(tasdevice_of_match),
#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 97d652f0e84d..1f1ee14b04e6 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -183,7 +183,15 @@ static void i2s_start(struct dw_i2s_dev *dev,
{
struct i2s_clk_config_data *config = &dev->config;
- i2s_write_reg(dev->i2s_base, IER, 1);
+ u32 reg = IER_IEN;
+
+ if (dev->tdm_slots) {
+ reg |= (dev->tdm_slots - 1) << IER_TDM_SLOTS_SHIFT;
+ reg |= IER_INTF_TYPE;
+ reg |= dev->frame_offset << IER_FRAME_OFF_SHIFT;
+ }
+
+ i2s_write_reg(dev->i2s_base, IER, reg);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
i2s_write_reg(dev->i2s_base, ITER, 1);
@@ -233,13 +241,15 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
dev->fifo_th - 1);
- i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+ i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
+ dev->tdm_mask << TER_TXSLOT_SHIFT);
} else {
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
dev->xfer_resolution);
i2s_write_reg(dev->i2s_base, RFCR(ch_reg),
dev->fifo_th - 1);
- i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+ i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN |
+ dev->tdm_mask << RER_RXSLOT_SHIFT);
}
}
@@ -276,6 +286,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ if (dev->tdm_slots)
+ config->data_width = 32;
+
config->chan_nr = params_channels(params);
switch (config->chan_nr) {
@@ -384,14 +397,58 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
ret = -EINVAL;
break;
}
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ dev->frame_offset = 1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ dev->frame_offset = 0;
+ break;
+ default:
+ dev_err(dev->dev, "DAI format unsupported");
+ return -EINVAL;
+ }
+
return ret;
}
+static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (slot_width != 32)
+ return -EINVAL;
+
+ if (slots < 0 || slots > 16)
+ return -EINVAL;
+
+ if (rx_mask != tx_mask)
+ return -EINVAL;
+
+ if (!rx_mask)
+ return -EINVAL;
+
+ dev->tdm_slots = slots;
+ dev->tdm_mask = rx_mask;
+
+ dev->l_reg = RSLOT_TSLOT(ffs(rx_mask) - 1);
+ dev->r_reg = RSLOT_TSLOT(fls(rx_mask) - 1);
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
.hw_params = dw_i2s_hw_params,
.prepare = dw_i2s_prepare,
.trigger = dw_i2s_trigger,
.set_fmt = dw_i2s_set_fmt,
+ .set_tdm_slot = dw_i2s_set_tdm_slot,
};
#ifdef CONFIG_PM
@@ -726,6 +783,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
if (irq >= 0) {
ret = dw_pcm_register(pdev);
dev->use_pio = true;
+ dev->l_reg = LRBR_LTHR(0);
+ dev->r_reg = RRBR_RTHR(0);
} else {
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
0);
diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c
index 9f25631d43d3..f99262b89008 100644
--- a/sound/soc/dwc/dwc-pcm.c
+++ b/sound/soc/dwc/dwc-pcm.c
@@ -31,8 +31,8 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \
int i; \
\
for (i = 0; i < dev->fifo_th; i++) { \
- iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \
- iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \
+ iowrite32(p[tx_ptr][0], dev->i2s_base + dev->l_reg); \
+ iowrite32(p[tx_ptr][1], dev->i2s_base + dev->r_reg); \
period_pos++; \
if (++tx_ptr >= runtime->buffer_size) \
tx_ptr = 0; \
@@ -51,8 +51,8 @@ static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \
int i; \
\
for (i = 0; i < dev->fifo_th; i++) { \
- p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \
- p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \
+ p[rx_ptr][0] = ioread32(dev->i2s_base + dev->l_reg); \
+ p[rx_ptr][1] = ioread32(dev->i2s_base + dev->r_reg); \
period_pos++; \
if (++rx_ptr >= runtime->buffer_size) \
rx_ptr = 0; \
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
index ba4e397099be..4ce96bac2f39 100644
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -25,6 +25,13 @@
#define RXFFR 0x014
#define TXFFR 0x018
+/* Enable register fields */
+#define IER_TDM_SLOTS_SHIFT 8
+#define IER_FRAME_OFF_SHIFT 5
+#define IER_FRAME_OFF BIT(5)
+#define IER_INTF_TYPE BIT(1)
+#define IER_IEN BIT(0)
+
/* Interrupt status register fields */
#define ISR_TXFO BIT(5)
#define ISR_TXFE BIT(4)
@@ -46,6 +53,15 @@
#define TFCR(x) (0x40 * x + 0x04C)
#define RFF(x) (0x40 * x + 0x050)
#define TFF(x) (0x40 * x + 0x054)
+#define RSLOT_TSLOT(x) (0x4 * (x) + 0x224)
+
+/* Receive enable register fields */
+#define RER_RXSLOT_SHIFT 8
+#define RER_RXCHEN BIT(0)
+
+/* Transmit enable register fields */
+#define TER_TXSLOT_SHIFT 8
+#define TER_TXCHEN BIT(0)
/* I2SCOMPRegisters */
#define I2S_COMP_PARAM_2 0x01F0
@@ -105,6 +121,8 @@ struct dw_i2s_dev {
u32 ccr;
u32 xfer_resolution;
u32 fifo_th;
+ u32 l_reg;
+ u32 r_reg;
/* data related to DMA transfers b/w i2s and DMAC */
union dw_i2s_snd_dma_data play_dma_data;
@@ -114,6 +132,12 @@ struct dw_i2s_dev {
/* data related to PIO transfers */
bool use_pio;
+
+ /* data related to TDM mode */
+ u32 tdm_slots;
+ u32 tdm_mask;
+ u32 frame_offset;
+
struct snd_pcm_substream __rcu *tx_substream;
struct snd_pcm_substream __rcu *rx_substream;
unsigned int (*tx_fn)(struct dw_i2s_dev *dev,
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 765dad607bf6..d63782b8bdef 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -228,6 +228,10 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct rpmsg_info *info = dev_get_drvdata(component->dev);
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+ struct snd_pcm_hardware pcm_hardware;
struct rpmsg_msg *msg;
int ret = 0;
int cmd;
@@ -255,10 +259,11 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
info->send_message(msg, info);
- imx_rpmsg_pcm_hardware.period_bytes_max =
- imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
+ pcm_hardware = imx_rpmsg_pcm_hardware;
+ pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
+ pcm_hardware.period_bytes_max = pcm_hardware.buffer_bytes_max / 2;
- snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
+ snd_soc_set_runtime_hwparams(substream, &pcm_hardware);
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
@@ -597,7 +602,6 @@ static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
if (ret)
return ret;
- imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
pcm->card->dev, rpmsg->buffer_size);
}
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 0745bf6a09aa..a78babf44f38 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -346,6 +346,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;
@@ -357,6 +358,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;
@@ -365,6 +368,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");
@@ -378,12 +387,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
@@ -426,6 +438,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;
}
@@ -463,6 +476,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);
@@ -492,6 +530,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;
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 60f8fb0bff95..f91ef6c9612f 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -136,6 +136,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
.tplg_filename = "max98927-tplg.bin",
},
{
+ .id = "10EC5663",
+ .drv_name = "avs_rt5663",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(1),
+ },
+ .tplg_filename = "rt5663-tplg.bin",
+ },
+ {
.id = "MX98373",
.drv_name = "avs_max98373",
.mach_params = {
@@ -159,6 +167,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
},
.tplg_filename = "da7219-tplg.bin",
},
+ {
+ .id = "ESSX8336",
+ .drv_name = "avs_es8336",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0),
+ },
+ .tplg_filename = "es8336-tplg.bin",
+ },
{},
};
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index e4c230efe8d7..07353d37ecae 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -22,6 +22,16 @@ config SND_SOC_INTEL_AVS_MACH_DMIC
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+config SND_SOC_INTEL_AVS_MACH_ES8336
+ tristate "es8336 I2S board"
+ depends on X86 && I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_ES8316
+ help
+ This adds support for AVS with ES8336 I2S codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
config SND_SOC_INTEL_AVS_MACH_HDAUDIO
tristate "HD-Audio generic board"
select SND_SOC_HDA
@@ -115,6 +125,16 @@ config SND_SOC_INTEL_AVS_MACH_RT298
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+config SND_SOC_INTEL_AVS_MACH_RT5663
+ tristate "rt5663 in I2S mode"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_RT5663
+ help
+ This adds support for ASoC machine driver with RT5663 I2S audio codec.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
config SND_SOC_INTEL_AVS_MACH_RT5682
tristate "rt5682 in I2S mode"
depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index b81343420370..34347bcd1e7d 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -2,6 +2,7 @@
snd-soc-avs-da7219-objs := da7219.o
snd-soc-avs-dmic-objs := dmic.o
+snd-soc-avs-es8336-objs := es8336.o
snd-soc-avs-hdaudio-objs := hdaudio.o
snd-soc-avs-i2s-test-objs := i2s_test.o
snd-soc-avs-max98927-objs := max98927.o
@@ -12,11 +13,13 @@ snd-soc-avs-probe-objs := probe.o
snd-soc-avs-rt274-objs := rt274.o
snd-soc-avs-rt286-objs := rt286.o
snd-soc-avs-rt298-objs := rt298.o
+snd-soc-avs-rt5663-objs := rt5663.o
snd-soc-avs-rt5682-objs := rt5682.o
snd-soc-avs-ssm4567-objs := ssm4567.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_ES8336) += snd-soc-avs-es8336.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
@@ -27,5 +30,6 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5663) += snd-soc-avs-rt5663.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
new file mode 100644
index 000000000000..0a023f871d93
--- /dev/null
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <[email protected]>
+// Amadeusz Slawinski <[email protected]>
+//
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/processor.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <asm/intel-family.h>
+
+#define ES8336_CODEC_DAI "ES8316 HiFi"
+
+struct avs_card_drvdata {
+ struct snd_soc_jack jack;
+ struct gpio_desc *gpiod;
+};
+
+static const struct acpi_gpio_params enable_gpio = { 0, 0, true };
+
+static const struct acpi_gpio_mapping speaker_gpios[] = {
+ { "speaker-enable-gpios", &enable_gpio, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+ { }
+};
+
+static int avs_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_card *card = w->dapm->card;
+ struct avs_card_drvdata *data;
+ bool speaker_en;
+
+ data = snd_soc_card_get_drvdata(card);
+ /* As enable_gpio has active_low=true, logic is inverted. */
+ speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
+
+ gpiod_set_value_cansleep(data->gpiod, speaker_en);
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Internal Mic", NULL),
+
+ SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
+ avs_es8336_speaker_power_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+
+ /*
+ * There is no separate speaker output instead the speakers are muxed to
+ * the HP outputs. The mux is controlled by the "Speaker Power" widget.
+ */
+ {"Speaker", NULL, "HPOL"},
+ {"Speaker", NULL, "HPOR"},
+ {"Speaker", NULL, "Speaker Power"},
+
+ /* Mic route map */
+ {"MIC1", NULL, "Internal Mic"},
+ {"MIC2", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct snd_soc_card *card = runtime->card;
+ struct snd_soc_jack_pin *pins;
+ struct avs_card_drvdata *data;
+ struct gpio_desc *gpiod;
+ int num_pins, ret;
+
+ data = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &data->jack, pins, num_pins);
+ if (ret)
+ return ret;
+
+ ret = devm_acpi_dev_add_driver_gpios(codec_dai->dev, speaker_gpios);
+ if (ret)
+ dev_warn(codec_dai->dev, "Unable to add GPIO mapping table\n");
+
+ gpiod = gpiod_get_optional(codec_dai->dev, "speaker-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod))
+ return dev_err_probe(codec_dai->dev, PTR_ERR(gpiod), "Get gpiod failed: %ld\n",
+ PTR_ERR(gpiod));
+
+ data->gpiod = gpiod;
+ snd_jack_set_key(data->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_soc_component_set_jack(component, &data->jack, NULL);
+
+ card->dapm.idle_bias_off = true;
+
+ return 0;
+}
+
+static void avs_es8336_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+ struct avs_card_drvdata *data = snd_soc_card_get_drvdata(runtime->card);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+
+ snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+ gpiod_put(data->gpiod);
+}
+
+static int avs_es8336_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+ int clk_freq;
+ int ret;
+
+ switch (boot_cpu_data.x86_model) {
+ case INTEL_FAM6_KABYLAKE_L:
+ case INTEL_FAM6_KABYLAKE:
+ clk_freq = 24000000;
+ break;
+ default:
+ clk_freq = 19200000;
+ break;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1, clk_freq, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_es8336_ops = {
+ .hw_params = avs_es8336_hw_params,
+};
+
+static int avs_es8336_be_fixup(struct snd_soc_pcm_runtime *runtime,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSPN to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_3LE);
+
+ return 0;
+}
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-ESSX8336:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, ES8336_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ dl->init = avs_es8336_codec_init;
+ dl->exit = avs_es8336_codec_exit;
+ dl->be_hw_params_fixup = avs_es8336_be_fixup;
+ dl->ops = &avs_es8336_ops;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI);
+ struct avs_card_drvdata *data = snd_soc_card_get_drvdata(card);
+
+ return snd_soc_component_set_jack(codec_dai->component, &data->jack, NULL);
+}
+
+static int avs_es8336_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct avs_card_drvdata *data;
+ struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!data || !card)
+ return -ENOMEM;
+
+ card->name = "avs_es8336";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_routes);
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, data);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_es8336_driver = {
+ .probe = avs_es8336_probe,
+ .driver = {
+ .name = "avs_es8336",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_es8336_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_es8336");
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
new file mode 100644
index 000000000000..770b36d05bf4
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022-2023 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <[email protected]>
+// Amadeusz Slawinski <[email protected]>
+//
+
+#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt5663.h"
+
+#define RT5663_CODEC_DAI "rt5663-aif"
+
+struct rt5663_private {
+ struct snd_soc_jack jack;
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ /* HP jack connectors */
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* Mic jacks */
+ { "IN1P", NULL, "Headset Mic" },
+ { "IN1N", NULL, "Headset Mic" },
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_card *card = runtime->card;
+ struct rt5663_private *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ int num_pins, ret;
+
+ jack = &priv->jack;
+ num_pins = ARRAY_SIZE(card_headset_pins);
+
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
+ pins, num_pins);
+ if (ret)
+ return ret;
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+
+ return 0;
+}
+
+static void avs_rt5663_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+ snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, NULL, NULL);
+}
+
+static int
+avs_rt5663_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate, *channels;
+ struct snd_mask *fmt;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSPN to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int avs_rt5663_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ int ret;
+
+ /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
+ rt5663_sel_asrc_clk_src(codec_dai->component,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
+
+ return ret;
+}
+
+static const struct snd_soc_ops avs_rt5663_ops = {
+ .hw_params = avs_rt5663_hw_params,
+};
+
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+
+ dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = platform_name;
+
+ dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+ dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+ dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+ if (!dl->name || !dl->cpus || !dl->codecs)
+ return -ENOMEM;
+
+ dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+ dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5663:00");
+ dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5663_CODEC_DAI);
+ if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+ return -ENOMEM;
+
+ dl->num_cpus = 1;
+ dl->num_codecs = 1;
+ dl->platforms = platform;
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ dl->init = avs_rt5663_codec_init;
+ dl->exit = avs_rt5663_codec_exit;
+ dl->be_hw_params_fixup = avs_rt5663_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_capture = 1;
+ dl->dpcm_playback = 1;
+ dl->ops = &avs_rt5663_ops;
+
+ *dai_link = dl;
+
+ return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI);
+
+ return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+ struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI);
+ struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+ return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
+}
+
+static int avs_rt5663_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_link *dai_link;
+ struct snd_soc_acpi_mach *mach;
+ struct snd_soc_card *card;
+ struct rt5663_private *priv;
+ struct device *dev = &pdev->dev;
+ const char *pname;
+ int ssp_port, ret;
+
+ mach = dev_get_platdata(dev);
+ pname = mach->mach_params.platform;
+ ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+ ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+ if (ret) {
+ dev_err(dev, "Failed to create dai link: %d", ret);
+ return ret;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!priv || !card)
+ return -ENOMEM;
+
+ card->name = "avs_rt5663";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->suspend_pre = avs_card_suspend_pre;
+ card->resume_post = avs_card_resume_post;
+ card->dai_link = dai_link;
+ card->num_links = 1;
+ card->controls = card_controls;
+ card->num_controls = ARRAY_SIZE(card_controls);
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_routes);
+ card->fully_routed = true;
+ snd_soc_card_set_drvdata(card, priv);
+
+ ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt5663_driver = {
+ .probe = avs_rt5663_probe,
+ .driver = {
+ .name = "avs_rt5663",
+ .pm = &snd_soc_pm_ops,
+ },
+};
+
+module_platform_driver(avs_rt5663_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt5663");
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 7142a67900bf..b93468ae0977 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -79,14 +79,31 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "IN1P", NULL, "Headset Mic" },
};
+static struct snd_soc_jack_pin card_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
{
struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
- struct snd_soc_jack *jack;
struct snd_soc_card *card = runtime->card;
- int ret;
+ struct snd_soc_jack_pin *pins;
+ struct snd_soc_jack *jack;
+ int num_pins, ret;
jack = snd_soc_card_get_drvdata(card);
+ num_pins = ARRAY_SIZE(card_jack_pins);
+
+ pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
/* Need to enable ASRC function for 24MHz mclk rate */
if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
@@ -95,12 +112,10 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC);
}
- /*
- * Headset buttons map to the google Reference headset.
- * These can be configured by userspace.
- */
- ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack);
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
+ pins, num_pins);
if (ret) {
dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
@@ -130,39 +145,36 @@ avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_para
{
struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
- int clk_id, clk_freq;
- int pll_out, ret;
+ int pll_source, freq_in, freq_out;
+ int ret;
if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
- clk_id = RT5682_PLL1_S_MCLK;
+ pll_source = RT5682_PLL1_S_MCLK;
if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
- clk_freq = 24000000;
+ freq_in = 24000000;
else
- clk_freq = 19200000;
+ freq_in = 19200000;
} else {
- clk_id = RT5682_PLL1_S_BCLK1;
- clk_freq = params_rate(params) * 50;
+ pll_source = RT5682_PLL1_S_BCLK1;
+ freq_in = params_rate(params) * 50;
}
- pll_out = params_rate(params) * 512;
+ freq_out = params_rate(params) * 512;
- ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, pll_source, freq_in, freq_out);
if (ret < 0)
- dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+ dev_err(runtime->dev, "Set PLL failed: %d\n", ret);
- /* Configure sysclk for codec */
- ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN);
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, freq_out, SND_SOC_CLOCK_IN);
if (ret < 0)
- dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+ dev_err(runtime->dev, "Set sysclk failed: %d\n", ret);
- /* slot_width should equal or large than data length, set them be the same */
+ /* slot_width should be equal or larger than data length. */
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params));
- if (ret < 0) {
- dev_err(runtime->dev, "set TDM slot err:%d\n", ret);
- return ret;
- }
+ if (ret < 0)
+ dev_err(runtime->dev, "Set TDM slot failed: %d\n", ret);
- return 0;
+ return ret;
}
static const struct snd_soc_ops avs_rt5682_ops = {
@@ -220,6 +232,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt5682_codec_init;
dl->exit = avs_rt5682_codec_exit;
dl->be_hw_params_fixup = avs_rt5682_be_fixup;
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index 6a24b339444b..5e14655c5617 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/infracfg.h>
#include <linux/reset.h>
@@ -3193,11 +3194,15 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
{
struct mtk_base_afe *afe;
struct mt8188_afe_private *afe_priv;
- struct device *dev;
+ struct device *dev = &pdev->dev;
struct reset_control *rstc;
struct regmap *infra_ao;
int i, irq_id, ret;
+ ret = of_reserved_mem_device_init(dev);
+ if (ret)
+ dev_dbg(dev, "failed to assign memory region: %d\n", ret);
+
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
if (ret)
return ret;
@@ -3213,7 +3218,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
afe_priv = afe->platform_priv;
afe->dev = &pdev->dev;
- dev = afe->dev;
afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(afe->base_addr))
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1a0bde23f5e6..94e856d67a46 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -238,6 +238,21 @@ static inline void snd_soc_debugfs_exit(void) { }
#endif
+static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+ return !(dlc->name || dlc->of_node);
+}
+
+static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc)
+{
+ return (dlc->name && dlc->of_node);
+}
+
+static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+ return !dlc->dai_name;
+}
+
static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_component *component)
{
@@ -829,102 +844,100 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
struct snd_soc_dai_link *link)
{
int i;
- struct snd_soc_dai_link_component *cpu, *codec, *platform;
+ struct snd_soc_dai_link_component *dlc;
- for_each_link_codecs(link, i, codec) {
+ /* Codec check */
+ for_each_link_codecs(link, i, dlc) {
/*
* Codec must be specified by 1 of name or OF node,
* not both or neither.
*/
- if (!!codec->name == !!codec->of_node) {
- dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
+
+ if (snd_soc_dlc_component_is_empty(dlc))
+ goto component_empty;
/* Codec DAI name must be specified */
- if (!codec->dai_name) {
- dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_dai_is_empty(dlc))
+ goto dai_empty;
/*
* Defer card registration if codec component is not added to
* component list.
*/
- if (!soc_find_component(codec)) {
- dev_dbg(card->dev,
- "ASoC: codec component %s not found for link %s\n",
- codec->name, link->name);
- return -EPROBE_DEFER;
- }
+ if (!soc_find_component(dlc))
+ goto component_not_find;
}
- for_each_link_platforms(link, i, platform) {
+ /* Platform check */
+ for_each_link_platforms(link, i, dlc) {
/*
* Platform may be specified by either name or OF node, but it
* can be left unspecified, then no components will be inserted
* in the rtdcom list
*/
- if (!!platform->name == !!platform->of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both platform name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
+
+ if (snd_soc_dlc_component_is_empty(dlc))
+ goto component_empty;
/*
* Defer card registration if platform component is not added to
* component list.
*/
- if (!soc_find_component(platform)) {
- dev_dbg(card->dev,
- "ASoC: platform component %s not found for link %s\n",
- platform->name, link->name);
- return -EPROBE_DEFER;
- }
+ if (!soc_find_component(dlc))
+ goto component_not_find;
}
- for_each_link_cpus(link, i, cpu) {
+ /* CPU check */
+ for_each_link_cpus(link, i, dlc) {
/*
* CPU device may be specified by either name or OF node, but
* can be left unspecified, and will be matched based on DAI
* name alone..
*/
- if (cpu->name && cpu->of_node) {
- dev_err(card->dev,
- "ASoC: Neither/both cpu name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
- }
+ if (snd_soc_dlc_component_is_invalid(dlc))
+ goto component_invalid;
- /*
- * Defer card registration if cpu dai component is not added to
- * component list.
- */
- if ((cpu->of_node || cpu->name) &&
- !soc_find_component(cpu)) {
- dev_dbg(card->dev,
- "ASoC: cpu component %s not found for link %s\n",
- cpu->name, link->name);
- return -EPROBE_DEFER;
- }
- /*
- * At least one of CPU DAI name or CPU device name/node must be
- * specified
- */
- if (!cpu->dai_name &&
- !(cpu->name || cpu->of_node)) {
- dev_err(card->dev,
- "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
- link->name);
- return -EINVAL;
+ if (snd_soc_dlc_component_is_empty(dlc)) {
+ /*
+ * At least one of CPU DAI name or CPU device name/node must be specified
+ */
+ if (snd_soc_dlc_dai_is_empty(dlc))
+ goto component_dai_empty;
+ } else {
+ /*
+ * Defer card registration if Component is not added
+ */
+ if (!soc_find_component(dlc))
+ goto component_not_find;
}
}
return 0;
+
+component_invalid:
+ dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+
+component_empty:
+ dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
+
+component_not_find:
+ dev_err(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
+ return -EPROBE_DEFER;
+
+dai_empty:
+ dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name);
+ return -EINVAL;
+
+component_dai_empty:
+ dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name);
+ return -EINVAL;
}
/**
@@ -3235,11 +3248,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu);
int snd_soc_get_dai_id(struct device_node *ep)
{
struct snd_soc_component *component;
- struct snd_soc_dai_link_component dlc;
+ struct snd_soc_dai_link_component dlc = {
+ .of_node = of_graph_get_port_parent(ep),
+ };
int ret;
- dlc.of_node = of_graph_get_port_parent(ep);
- dlc.name = NULL;
+
/*
* For example HDMI case, HDMI has video/sound port,
* but ALSA SoC needs sound port number only.
@@ -3264,8 +3278,6 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
struct snd_soc_component *pos;
int ret = -EPROBE_DEFER;
- dlc->of_node = args->np;
-
mutex_lock(&client_mutex);
for_each_component(pos) {
struct device_node *component_of_node = soc_component_to_node(pos);
@@ -3319,6 +3331,10 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
break;
}
+
+ if (ret == 0)
+ dlc->of_node = args->np;
+
mutex_unlock(&client_mutex);
return ret;
}
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index afb505461ea1..c450931ae77e 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -28,12 +28,14 @@ static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
return 0;
}
-static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data)
+static int smn_read(struct pci_dev *dev, u32 smn_addr)
{
+ u32 data = 0;
+
pci_write_config_dword(dev, 0x60, smn_addr);
- pci_read_config_dword(dev, 0x64, data);
+ pci_read_config_dword(dev, 0x64, &data);
- return 0;
+ return data;
}
static void init_dma_descriptor(struct acp_dev_data *adata)
@@ -150,15 +152,13 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
{
struct snd_sof_dev *sdev = adata->dev;
- int timeout;
+ int ret;
u32 data;
- for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
- msleep(20);
- smn_read(adata->smn_dev, MP0_C2PMSG_114_REG, &data);
- if (data & MBOX_READY_MASK)
- return 0;
- }
+ ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US,
+ ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG);
+ if (!ret)
+ return 0;
dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK);
@@ -177,23 +177,19 @@ static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
{
struct snd_sof_dev *sdev = adata->dev;
- int ret, timeout;
+ int ret;
u32 data;
if (!cmd)
return -EINVAL;
/* Get a non-zero Doorbell value from PSP */
- for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
- msleep(MBOX_DELAY);
- smn_read(adata->smn_dev, MP0_C2PMSG_73_REG, &data);
- if (data)
- break;
- }
+ ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false,
+ adata->smn_dev, MP0_C2PMSG_73_REG);
- if (!timeout) {
+ if (ret) {
dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG);
- return -EINVAL;
+ return ret;
}
/* Check if PSP is ready for new command */
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index dc624f727aa3..c3659dbc3745 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -61,12 +61,12 @@
#define HOST_BRIDGE_CZN 0x1630
#define HOST_BRIDGE_RMB 0x14B5
#define ACP_SHA_STAT 0x8000
-#define ACP_PSP_TIMEOUT_COUNTER 5
+#define ACP_PSP_TIMEOUT_US 1000000
#define ACP_EXT_INTR_ERROR_STAT 0x20000000
#define MP0_C2PMSG_114_REG 0x3810AC8
#define MP0_C2PMSG_73_REG 0x3810A24
#define MBOX_ACP_SHA_DMA_COMMAND 0x70000
-#define MBOX_DELAY 1000
+#define MBOX_DELAY_US 1000
#define MBOX_READY_MASK 0x80000000
#define MBOX_STATUS_MASK 0xFFFF