diff --git a/Documentation/devicetree/bindings/sound/adi,adau7002.txt b/Documentation/devicetree/bindings/sound/adi,adau7002.txt deleted file mode 100644 index f144ee1abf8550..00000000000000 --- a/Documentation/devicetree/bindings/sound/adi,adau7002.txt +++ /dev/null @@ -1,19 +0,0 @@ -Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter - -Required properties: - - - compatible: Must be "adi,adau7002" - -Optional properties: - - - IOVDD-supply: Phandle and specifier for the power supply providing the IOVDD - supply as covered in Documentation/devicetree/bindings/regulator/regulator.txt - - If this property is not present it is assumed that the supply pin is - hardwired to always on. - -Example: - adau7002: pdm-to-i2s { - compatible = "adi,adau7002"; - IOVDD-supply = <&supply>; - }; diff --git a/Documentation/devicetree/bindings/sound/adi,adau7002.yaml b/Documentation/devicetree/bindings/sound/adi,adau7002.yaml new file mode 100644 index 00000000000000..fcca0fde7d8663 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau7002.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/adi,adau7002.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter + +maintainers: + - Krzysztof Kozlowski + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: adi,adau7002 + + IOVDD-supply: + description: + IOVDD power supply, if skipped then it is assumed that the supply pin is + hardwired to always on. + + wakeup-delay-ms: + description: + Delay after power up needed for device to settle. + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + audio-codec { + compatible = "adi,adau7002"; + IOVDD-supply = <&pp1800_l15a>; + #sound-dai-cells = <0>; + wakeup-delay-ms = <80>; + }; diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml index 82062d80d700da..18fb471aa891bf 100644 --- a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml @@ -22,6 +22,9 @@ properties: reg: maxItems: 1 + interrupts: + maxItems: 1 + '#sound-dai-cells': description: The first cell indicating the audio interface. @@ -42,7 +45,7 @@ properties: Configures the peak current by monitoring the current through the boost FET. Range starts at 1600 mA and goes to a maximum of 4500 mA with increments of 50 mA. See section 4.3.6 of the datasheet for details. - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 1600 maximum: 4500 default: 4500 @@ -51,7 +54,7 @@ properties: description: Boost inductor value, expressed in nH. Valid values include 1000, 1200, 1500 and 2200. - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 1000 maximum: 2200 @@ -60,7 +63,7 @@ properties: Total equivalent boost capacitance on the VBST and VAMP pins, derated at 11 volts DC. The value must be rounded to the nearest integer and expressed in uF. - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 cirrus,asp-sdout-hiz: description: @@ -70,7 +73,7 @@ properties: 1 = Hi-Z during unused slots but logic 0 while all transmit channels disabled 2 = (Default) Logic 0 during unused slots, but Hi-Z while all transmit channels disabled 3 = Hi-Z during unused slots and while all transmit channels disabled - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 3 default: 2 @@ -84,7 +87,7 @@ properties: enable boost voltage. 0 = Internal Boost 1 = External Boost - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 1 @@ -109,7 +112,7 @@ properties: 1 = GPIO 2 = Sync 3 = MCLK input - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 3 @@ -136,7 +139,7 @@ properties: 3 = MCLK input 4 = Push-pull INTB (active low) 5 = Push-pull INT (active high) - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 5 @@ -176,21 +179,23 @@ unevaluatedProperties: false examples: - | + #include + spi { #address-cells = <1>; #size-cells = <0>; - cs35l41: cs35l41@2 { - #sound-dai-cells = <1>; - compatible = "cirrus,cs35l41"; - reg = <2>; - VA-supply = <&dummy_vreg>; - VP-supply = <&dummy_vreg>; - reset-gpios = <&gpio 110 0>; - - cirrus,boost-type = <0>; - cirrus,boost-peak-milliamp = <4500>; - cirrus,boost-ind-nanohenry = <1000>; - cirrus,boost-cap-microfarad = <15>; + cs35l41: speaker-amp@2 { + #sound-dai-cells = <1>; + compatible = "cirrus,cs35l41"; + reg = <2>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + reset-gpios = <&gpio 110 GPIO_ACTIVE_HIGH>; + + cirrus,boost-type = <0>; + cirrus,boost-peak-milliamp = <4500>; + cirrus,boost-ind-nanohenry = <1000>; + cirrus,boost-cap-microfarad = <15>; }; }; diff --git a/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml b/Documentation/devicetree/bindings/sound/microchip,sama7g5-i2smcc.yaml similarity index 97% rename from Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml rename to Documentation/devicetree/bindings/sound/microchip,sama7g5-i2smcc.yaml index 621022872c8d6e..651f61c7c25a00 100644 --- a/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml +++ b/Documentation/devicetree/bindings/sound/microchip,sama7g5-i2smcc.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/mchp,i2s-mcc.yaml# +$id: http://devicetree.org/schemas/sound/microchip,sama7g5-i2smcc.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip I2S Multi-Channel Controller diff --git a/Documentation/devicetree/bindings/sound/microchip,pdmc.yaml b/Documentation/devicetree/bindings/sound/microchip,sama7g5-pdmc.yaml similarity index 97% rename from Documentation/devicetree/bindings/sound/microchip,pdmc.yaml rename to Documentation/devicetree/bindings/sound/microchip,sama7g5-pdmc.yaml index c37b89d94c1211..c4cf1e5ab84b03 100644 --- a/Documentation/devicetree/bindings/sound/microchip,pdmc.yaml +++ b/Documentation/devicetree/bindings/sound/microchip,sama7g5-pdmc.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/microchip,pdmc.yaml# +$id: http://devicetree.org/schemas/sound/microchip,sama7g5-pdmc.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip Pulse Density Microphone Controller diff --git a/Documentation/devicetree/bindings/sound/mchp,spdifrx.yaml b/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml similarity index 95% rename from Documentation/devicetree/bindings/sound/mchp,spdifrx.yaml rename to Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml index 70a47c6823b1ad..2f43c684ab88d9 100644 --- a/Documentation/devicetree/bindings/sound/mchp,spdifrx.yaml +++ b/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdifrx.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/mchp,spdifrx.yaml# +$id: http://devicetree.org/schemas/sound/microchip,sama7g5-spdifrx.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip S/PDIF Rx Controller diff --git a/Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml b/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdiftx.yaml similarity index 95% rename from Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml rename to Documentation/devicetree/bindings/sound/microchip,sama7g5-spdiftx.yaml index c383162140bba1..4702c528700d4d 100644 --- a/Documentation/devicetree/bindings/sound/mchp,spdiftx.yaml +++ b/Documentation/devicetree/bindings/sound/microchip,sama7g5-spdiftx.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/mchp,spdiftx.yaml# +$id: http://devicetree.org/schemas/sound/microchip,sama7g5-spdiftx.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip S/PDIF Tx Controller diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt index ff1228713f7e52..0c398581d52b0b 100644 --- a/Documentation/devicetree/bindings/sound/rt5640.txt +++ b/Documentation/devicetree/bindings/sound/rt5640.txt @@ -20,6 +20,9 @@ Optional properties: - realtek,in3-differential Boolean. Indicate MIC1/2/3 input are differential, rather than single-ended. +- realtek,lout-differential + Boolean. Indicate LOUT output is differential, rather than stereo. + - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. - realtek,dmic1-data-pin diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320aic3x.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320aic3x.yaml new file mode 100644 index 00000000000000..f0375bbf4c40bc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tlv320aic3x.yaml @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright (C) 2022 Texas Instruments Incorporated +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tlv320aic3x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TLV320AIC3x Codec + +description: | + TLV320AIC3x are a series of low-power stereo audio codecs with stereo + headphone amplifier, as well as multiple inputs and outputs programmable in + single-ended or fully differential configurations. + + The serial control bus supports SPI or I2C protocols, while the serial audio + data bus is programmable for I2S, left/right-justified, DSP, or TDM modes. + + The following pins can be referred in the sound node's audio routing property: + + CODEC output pins: + LLOUT + RLOUT + MONO_LOUT + HPLOUT + HPROUT + HPLCOM + HPRCOM + + CODEC input pins for TLV320AIC3104: + MIC2L + MIC2R + LINE1L + LINE1R + + CODEC input pins for other compatible codecs: + MIC3L + MIC3R + LINE1L + LINE2L + LINE1R + LINE2R + +maintainers: + - Jai Luthra + +properties: + compatible: + enum: + - ti,tlv320aic3x + - ti,tlv320aic33 + - ti,tlv320aic3007 + - ti,tlv320aic3106 + - ti,tlv320aic3104 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + description: + GPIO specification for the active low RESET input. + + gpio-reset: + maxItems: 1 + description: + Deprecated, please use reset-gpios instead. + deprecated: true + + ai3x-gpio-func: + description: AIC3X_GPIO1 & AIC3X_GPIO2 Functionality + $ref: /schemas/types.yaml#/definitions/uint32-array + maxItems: 2 + + ai3x-micbias-vg: + description: MicBias required voltage. If node is omitted then MicBias is powered down. + $ref: /schemas/types.yaml#/definitions/uint32 + oneOf: + - const: 1 + description: MICBIAS output is powered to 2.0V. + - const: 2 + description: MICBIAS output is powered to 2.5V. + - const: 3 + description: MICBIAS output is connected to AVDD. + + ai3x-ocmv: + description: Output Common-Mode Voltage selection. + $ref: /schemas/types.yaml#/definitions/uint32 + oneOf: + - const: 0 + description: 1.35V + - const: 1 + description: 1.5V + - const: 2 + description: 1.65V + - const: 3 + description: 1.8V + + AVDD-supply: + description: Analog DAC voltage. + + IOVDD-supply: + description: I/O voltage. + + DRVDD-supply: + description: ADC analog and output driver voltage. + + DVDD-supply: + description: Digital core voltage. + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tlv320aic3x_i2c: audio-codec@1b { + compatible = "ti,tlv320aic3x"; + reg = <0x1b>; + + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DRVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; + }; + }; + + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + tlv320aic3x_spi: audio-codec@0 { + compatible = "ti,tlv320aic3x"; + reg = <0>; /* CS number */ + #sound-dai-cells = <0>; + + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DRVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; + ai3x-ocmv = <0>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt deleted file mode 100644 index 20931a63fd646b..00000000000000 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ /dev/null @@ -1,97 +0,0 @@ -Texas Instruments - tlv320aic3x Codec module - -The tlv320aic3x serial control bus communicates through both I2C and SPI bus protocols - -Required properties: - -- compatible - "string" - One of: - "ti,tlv320aic3x" - Generic TLV320AIC3x device - "ti,tlv320aic33" - TLV320AIC33 - "ti,tlv320aic3007" - TLV320AIC3007 - "ti,tlv320aic3106" - TLV320AIC3106 - "ti,tlv320aic3104" - TLV320AIC3104 - - -- reg - - I2C slave address - - -Optional properties: - -- reset-gpios - GPIO specification for the active low RESET input. -- ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality - - Not supported on tlv320aic3104 -- ai3x-micbias-vg - MicBias Voltage required. - 1 - MICBIAS output is powered to 2.0V, - 2 - MICBIAS output is powered to 2.5V, - 3 - MICBIAS output is connected to AVDD, - If this node is not mentioned or if the value is incorrect, then MicBias - is powered down. -- ai3x-ocmv - Output Common-Mode Voltage selection: - 0 - 1.35V, - 1 - 1.5V, - 2 - 1.65V, - 3 - 1.8V -- AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the - device as covered in Documentation/devicetree/bindings/regulator/regulator.txt - -Deprecated properties: - -- gpio-reset - gpio pin number used for codec reset - -CODEC output pins: - * LLOUT - * RLOUT - * MONO_LOUT - * HPLOUT - * HPROUT - * HPLCOM - * HPRCOM - -CODEC input pins for TLV320AIC3104: - * MIC2L - * MIC2R - * LINE1L - * LINE1R - -CODEC input pins for other compatible codecs: - * MIC3L - * MIC3R - * LINE1L - * LINE2L - * LINE1R - * LINE2R - -The pins can be used in referring sound node's audio-routing property. - -I2C example: - -#include - -tlv320aic3x: tlv320aic3x@1b { - compatible = "ti,tlv320aic3x"; - reg = <0x1b>; - - reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; - - AVDD-supply = <®ulator>; - IOVDD-supply = <®ulator>; - DRVDD-supply = <®ulator>; - DVDD-supply = <®ulator>; -}; - -SPI example: - -spi0: spi@f0000000 { - tlv320aic3x: codec@0 { - compatible = "ti,tlv320aic3x"; - reg = <0>; /* CS number */ - #sound-dai-cells = <0>; - spi-max-frequency = <1000000>; - - AVDD-supply = <®ulator>; - IOVDD-supply = <®ulator>; - DRVDD-supply = <®ulator>; - DVDD-supply = <®ulator>; - ai3x-ocmv = <0>; - }; -}; diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h index 754f02b2f4440d..4ffe546aa409a1 100644 --- a/include/uapi/sound/intel/avs/tokens.h +++ b/include/uapi/sound/intel/avs/tokens.h @@ -108,6 +108,7 @@ enum avs_tplg_token { AVS_TKN_MOD_CORE_ID_U8 = 1704, AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705, AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706, + AVS_TKN_MOD_KCONTROL_ID_U32 = 1707, /* struct avs_tplg_path_template */ AVS_TKN_PATH_TMPL_ID_U32 = 1801, @@ -121,6 +122,9 @@ enum avs_tplg_token { AVS_TKN_PIN_FMT_INDEX_U32 = 2201, AVS_TKN_PIN_FMT_IOBS_U32 = 2202, AVS_TKN_PIN_FMT_AFMT_ID_U32 = 2203, + + /* struct avs_tplg_kcontrol */ + AVS_TKN_KCONTROL_ID_U32 = 2301, }; #endif diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h index 5e7f9c1c1b0e82..8f024cb309c9f7 100644 --- a/sound/soc/amd/ps/acp63.h +++ b/sound/soc/amd/ps/acp63.h @@ -11,7 +11,6 @@ #define ACP63_REG_START 0x1240000 #define ACP63_REG_END 0x1250200 #define ACP63_DEVS 3 -#define ACP63_PDM_MODE 1 #define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 #define ACP_PGFSM_CNTL_POWER_ON_MASK 1 @@ -54,6 +53,11 @@ /* time in ms for runtime suspend delay */ #define ACP_SUSPEND_DELAY_MS 2000 +#define ACP63_DMIC_ADDR 2 +#define ACP63_PDM_MODE_DEVS 3 +#define ACP63_PDM_DEV_MASK 1 +#define ACP_DMIC_DEV 2 + enum acp_config { ACP_CONFIG_0 = 0, ACP_CONFIG_1, @@ -102,4 +106,7 @@ struct acp63_dev_data { struct resource *res; bool acp63_audio_mode; struct platform_device *pdev[ACP63_DEVS]; + u16 pdev_mask; + u16 pdev_count; + u16 pdm_dev_index; }; diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index 489f01a2069995..401cfd0036bed8 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -116,6 +116,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) struct acp63_dev_data *adata; struct pdm_dev_data *ps_pdm_data; u32 val; + u16 pdev_index; adata = dev_id; if (!adata) @@ -123,7 +124,8 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) val = acp63_readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT); if (val & BIT(PDM_DMA_STAT)) { - ps_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev); + pdev_index = adata->pdm_dev_index; + ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev); acp63_writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); if (ps_pdm_data->capture_stream) snd_pcm_period_elapsed(ps_pdm_data->capture_stream); @@ -132,17 +134,119 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) return IRQ_NONE; } +static void get_acp63_device_config(u32 config, struct pci_dev *pci, + struct acp63_dev_data *acp_data) +{ + struct acpi_device *dmic_dev; + const union acpi_object *obj; + bool is_dmic_dev = false; + + dmic_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0); + if (dmic_dev) { + if (!acpi_dev_get_property(dmic_dev, "acp-audio-device-type", + ACPI_TYPE_INTEGER, &obj) && + obj->integer.value == ACP_DMIC_DEV) + is_dmic_dev = true; + } + + switch (config) { + case ACP_CONFIG_0: + case ACP_CONFIG_1: + case ACP_CONFIG_2: + case ACP_CONFIG_3: + case ACP_CONFIG_9: + case ACP_CONFIG_15: + dev_dbg(&pci->dev, "Audio Mode %d\n", config); + break; + default: + if (is_dmic_dev) { + acp_data->pdev_mask = ACP63_PDM_DEV_MASK; + acp_data->pdev_count = ACP63_PDM_MODE_DEVS; + } + break; + } +} + +void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo, struct device *parent, + struct fwnode_handle *fw_node, char *name, unsigned int id, + const struct resource *res, unsigned int num_res, + const void *data, size_t size_data) +{ + pdevinfo->name = name; + pdevinfo->id = id; + pdevinfo->parent = parent; + pdevinfo->num_res = num_res; + pdevinfo->res = res; + pdevinfo->data = data; + pdevinfo->size_data = size_data; + pdevinfo->fwnode = fw_node; +} + +static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data *adata, u32 addr) +{ + struct platform_device_info pdevinfo[ACP63_DEVS]; + struct device *parent; + int index; + int ret; + + parent = &pci->dev; + dev_dbg(&pci->dev, + "%s pdev_mask:0x%x pdev_count:0x%x\n", __func__, adata->pdev_mask, + adata->pdev_count); + if (adata->pdev_mask) { + adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL); + if (!adata->res) { + ret = -ENOMEM; + goto de_init; + } + adata->res->flags = IORESOURCE_MEM; + adata->res->start = addr; + adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START); + memset(&pdevinfo, 0, sizeof(pdevinfo)); + } + + switch (adata->pdev_mask) { + case ACP63_PDM_DEV_MASK: + adata->pdm_dev_index = 0; + acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma", + 0, adata->res, 1, NULL, 0); + acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "dmic-codec", + 0, NULL, 0, NULL, 0); + acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "acp_ps_mach", + 0, NULL, 0, NULL, 0); + break; + default: + dev_dbg(&pci->dev, "No PDM devices found\n"); + goto de_init; + } + + for (index = 0; index < adata->pdev_count; index++) { + adata->pdev[index] = platform_device_register_full(&pdevinfo[index]); + if (IS_ERR(adata->pdev[index])) { + dev_err(&pci->dev, + "cannot register %s device\n", pdevinfo[index].name); + ret = PTR_ERR(adata->pdev[index]); + goto unregister_devs; + } + } + return 0; +unregister_devs: + for (--index; index >= 0; index--) + platform_device_unregister(adata->pdev[index]); +de_init: + if (acp63_deinit(adata->acp63_base, &pci->dev)) + dev_err(&pci->dev, "ACP de-init failed\n"); + return ret; +} + static int snd_acp63_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct acp63_dev_data *adata; - struct platform_device_info pdevinfo[ACP63_DEVS]; - int index, ret; - int val = 0x00; - struct acpi_device *adev; - const union acpi_object *obj; u32 addr; - unsigned int irqflags; + u32 irqflags; + int val; + int ret; irqflags = IRQF_SHARED; /* Pink Sardine device check */ @@ -182,83 +286,24 @@ static int snd_acp63_probe(struct pci_dev *pci, ret = acp63_init(adata->acp63_base, &pci->dev); if (ret) goto release_regions; + ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler, + irqflags, "ACP_PCI_IRQ", adata); + if (ret) { + dev_err(&pci->dev, "ACP PCI IRQ request failed\n"); + goto de_init; + } val = acp63_readl(adata->acp63_base + ACP_PIN_CONFIG); - switch (val) { - case ACP_CONFIG_0: - case ACP_CONFIG_1: - case ACP_CONFIG_2: - case ACP_CONFIG_3: - case ACP_CONFIG_9: - case ACP_CONFIG_15: - dev_info(&pci->dev, "Audio Mode %d\n", val); - break; - default: - - /* Checking DMIC hardware*/ - adev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), 0x02, 0); - - if (!adev) - break; - - if (!acpi_dev_get_property(adev, "acp-audio-device-type", - ACPI_TYPE_INTEGER, &obj) && - obj->integer.value == 2) { - adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL); - if (!adata->res) { - ret = -ENOMEM; - goto de_init; - } - - adata->res->name = "acp_iomem"; - adata->res->flags = IORESOURCE_MEM; - adata->res->start = addr; - adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START); - adata->acp63_audio_mode = ACP63_PDM_MODE; - - memset(&pdevinfo, 0, sizeof(pdevinfo)); - pdevinfo[0].name = "acp_ps_pdm_dma"; - pdevinfo[0].id = 0; - pdevinfo[0].parent = &pci->dev; - pdevinfo[0].num_res = 1; - pdevinfo[0].res = adata->res; - - pdevinfo[1].name = "dmic-codec"; - pdevinfo[1].id = 0; - pdevinfo[1].parent = &pci->dev; - - pdevinfo[2].name = "acp_ps_mach"; - pdevinfo[2].id = 0; - pdevinfo[2].parent = &pci->dev; - - for (index = 0; index < ACP63_DEVS; index++) { - adata->pdev[index] = - platform_device_register_full(&pdevinfo[index]); - - if (IS_ERR(adata->pdev[index])) { - dev_err(&pci->dev, - "cannot register %s device\n", - pdevinfo[index].name); - ret = PTR_ERR(adata->pdev[index]); - goto unregister_devs; - } - ret = devm_request_irq(&pci->dev, pci->irq, acp63_irq_handler, - irqflags, "ACP_PCI_IRQ", adata); - if (ret) { - dev_err(&pci->dev, "ACP PCI IRQ request failed\n"); - goto unregister_devs; - } - } - } - break; + get_acp63_device_config(val, pci, adata); + ret = create_acp63_platform_devs(pci, adata, addr); + if (ret < 0) { + dev_err(&pci->dev, "ACP platform devices creation failed\n"); + goto de_init; } pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pci->dev); pm_runtime_put_noidle(&pci->dev); pm_runtime_allow(&pci->dev); return 0; -unregister_devs: - for (--index; index >= 0; index--) - platform_device_unregister(adata->pdev[index]); de_init: if (acp63_deinit(adata->acp63_base, &pci->dev)) dev_err(&pci->dev, "ACP de-init failed\n"); @@ -305,10 +350,8 @@ static void snd_acp63_remove(struct pci_dev *pci) int ret, index; adata = pci_get_drvdata(pci); - if (adata->acp63_audio_mode == ACP63_PDM_MODE) { - for (index = 0; index < ACP63_DEVS; index++) - platform_device_unregister(adata->pdev[index]); - } + for (index = 0; index < adata->pdev_count; index++) + platform_device_unregister(adata->pdev[index]); ret = acp63_deinit(adata->acp63_base, &pci->dev); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index aa38cef1776dae..4ba83689482a74 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -315,16 +315,8 @@ static int acp3x_dai_probe(struct platform_device *pdev) return 0; } -static int acp3x_dai_remove(struct platform_device *pdev) -{ - /* As we use devm_ memory alloc there is nothing TBD here */ - - return 0; -} - static struct platform_driver acp3x_dai_driver = { .probe = acp3x_dai_probe, - .remove = acp3x_dai_remove, .driver = { .name = "acp3x_i2s_playcap", }, diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 87d6d6ed026b32..9883e6867fd12f 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -616,11 +616,6 @@ static int atmel_classd_probe(struct platform_device *pdev) return ret; } -static int atmel_classd_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver atmel_classd_driver = { .driver = { .name = "atmel-classd", @@ -628,7 +623,6 @@ static struct platform_driver atmel_classd_driver = { .pm = &snd_soc_pm_ops, }, .probe = atmel_classd_probe, - .remove = atmel_classd_remove, }; module_platform_driver(atmel_classd_driver); diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index 77ff12baead5bc..12cd40b156440b 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -692,11 +692,6 @@ static int atmel_pdmic_probe(struct platform_device *pdev) return ret; } -static int atmel_pdmic_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver atmel_pdmic_driver = { .driver = { .name = "atmel-pdmic", @@ -704,7 +699,6 @@ static struct platform_driver atmel_pdmic_driver = { .pm = &snd_soc_pm_ops, }, .probe = atmel_pdmic_probe, - .remove = atmel_pdmic_remove, }; module_platform_driver(atmel_pdmic_driver); diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index 44aefbd5b62c71..cf4084dcbd5eef 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -112,10 +113,10 @@ struct mchp_pdmc { struct clk *pclk; struct clk *gclk; u32 pdmcen; + u32 suspend_irq; int mic_no; int sinc_order; bool audio_filter_en; - u8 gclk_enabled:1; }; static const char *const mchp_pdmc_sinc_filter_order_text[] = { @@ -454,13 +455,6 @@ static int mchp_pdmc_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai); - int ret; - - ret = clk_prepare_enable(dd->pclk); - if (ret) { - dev_err(dd->dev, "failed to enable the peripheral clock: %d\n", ret); - return ret; - } regmap_write(dd->regmap, MCHP_PDMC_CR, MCHP_PDMC_CR_SWRST); @@ -470,14 +464,6 @@ static int mchp_pdmc_startup(struct snd_pcm_substream *substream, return 0; } -static void mchp_pdmc_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai); - - clk_disable_unprepare(dd->pclk); -} - static int mchp_pdmc_dai_probe(struct snd_soc_dai *dai) { struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai); @@ -594,11 +580,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, cfgr_val |= MCHP_PDMC_CFGR_BSSEL(i); } - if (dd->gclk_enabled) { - clk_disable_unprepare(dd->gclk); - dd->gclk_enabled = 0; - } - for (osr_start = dd->audio_filter_en ? 64 : 8; osr_start <= 256 && best_diff_rate; osr_start *= 2) { long round_rate; @@ -620,8 +601,12 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* CLK is enabled by runtime PM. */ + clk_disable_unprepare(dd->gclk); + /* set the rate */ ret = clk_set_rate(dd->gclk, gclk_rate); + clk_prepare_enable(dd->gclk); if (ret) { dev_err(comp->dev, "unable to set rate %lu to GCLK: %d\n", gclk_rate, ret); @@ -636,9 +621,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, mr_val |= MCHP_PDMC_MR_CHUNK(dd->addr.maxburst); dev_dbg(comp->dev, "maxburst set to %d\n", dd->addr.maxburst); - clk_prepare_enable(dd->gclk); - dd->gclk_enabled = 1; - snd_soc_component_update_bits(comp, MCHP_PDMC_MR, MCHP_PDMC_MR_OSR_MASK | MCHP_PDMC_MR_SINCORDER_MASK | @@ -650,19 +632,6 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream, return 0; } -static int mchp_pdmc_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai); - - if (dd->gclk_enabled) { - clk_disable_unprepare(dd->gclk); - dd->gclk_enabled = 0; - } - - return 0; -} - static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -673,22 +642,27 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, #endif switch (cmd) { - case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_START: /* Enable overrun and underrun error interrupts */ - regmap_write(dd->regmap, MCHP_PDMC_IER, + regmap_write(dd->regmap, MCHP_PDMC_IER, dd->suspend_irq | MCHP_PDMC_IR_RXOVR | MCHP_PDMC_IR_RXUDR); + dd->suspend_irq = 0; + fallthrough; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_soc_component_update_bits(cpu, MCHP_PDMC_MR, MCHP_PDMC_MR_PDMCEN_MASK, dd->pdmcen); break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + regmap_read(dd->regmap, MCHP_PDMC_IMR, &dd->suspend_irq); + fallthrough; + case SNDRV_PCM_TRIGGER_STOP: /* Disable overrun and underrun error interrupts */ - regmap_write(dd->regmap, MCHP_PDMC_IDR, + regmap_write(dd->regmap, MCHP_PDMC_IDR, dd->suspend_irq | MCHP_PDMC_IR_RXOVR | MCHP_PDMC_IR_RXUDR); + fallthrough; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_soc_component_update_bits(cpu, MCHP_PDMC_MR, MCHP_PDMC_MR_PDMCEN_MASK, 0); break; @@ -711,9 +685,7 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { .set_fmt = mchp_pdmc_set_fmt, .startup = mchp_pdmc_startup, - .shutdown = mchp_pdmc_shutdown, .hw_params = mchp_pdmc_hw_params, - .hw_free = mchp_pdmc_hw_free, .trigger = mchp_pdmc_trigger, }; @@ -864,6 +836,7 @@ static const struct regmap_config mchp_pdmc_regmap_config = { .readable_reg = mchp_pdmc_readable_reg, .writeable_reg = mchp_pdmc_writeable_reg, .precious_reg = mchp_pdmc_precious_reg, + .cache_type = REGCACHE_FLAT, }; static int mchp_pdmc_dt_init(struct mchp_pdmc *dd) @@ -970,6 +943,49 @@ static struct snd_dmaengine_pcm_config mchp_pdmc_config = { .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, }; +static int mchp_pdmc_runtime_suspend(struct device *dev) +{ + struct mchp_pdmc *dd = dev_get_drvdata(dev); + + regcache_cache_only(dd->regmap, true); + + clk_disable_unprepare(dd->gclk); + clk_disable_unprepare(dd->pclk); + + return 0; +} + +static int mchp_pdmc_runtime_resume(struct device *dev) +{ + struct mchp_pdmc *dd = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dd->pclk); + if (ret) { + dev_err(dd->dev, + "failed to enable the peripheral clock: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(dd->gclk); + if (ret) { + dev_err(dd->dev, + "failed to enable generic clock: %d\n", ret); + goto disable_pclk; + } + + regcache_cache_only(dd->regmap, false); + regcache_mark_dirty(dd->regmap); + ret = regcache_sync(dd->regmap); + if (ret) { + regcache_cache_only(dd->regmap, true); + clk_disable_unprepare(dd->gclk); +disable_pclk: + clk_disable_unprepare(dd->pclk); + } + + return ret; +} + static int mchp_pdmc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1039,18 +1055,25 @@ static int mchp_pdmc_probe(struct platform_device *pdev) dd->addr.addr = (dma_addr_t)res->start + MCHP_PDMC_RHR; platform_set_drvdata(pdev, dd); + pm_runtime_enable(dd->dev); + if (!pm_runtime_enabled(dd->dev)) { + ret = mchp_pdmc_runtime_resume(dd->dev); + if (ret) + return ret; + } + /* register platform */ ret = devm_snd_dmaengine_pcm_register(dev, &mchp_pdmc_config, 0); if (ret) { dev_err(dev, "could not register platform: %d\n", ret); - return ret; + goto pm_runtime_suspend; } ret = devm_snd_soc_register_component(dev, &mchp_pdmc_dai_component, &mchp_pdmc_dai, 1); if (ret) { dev_err(dev, "could not register CPU DAI: %d\n", ret); - return ret; + goto pm_runtime_suspend; } /* print IP version */ @@ -1059,6 +1082,25 @@ static int mchp_pdmc_probe(struct platform_device *pdev) version & MCHP_PDMC_VER_VERSION); return 0; + +pm_runtime_suspend: + if (!pm_runtime_status_suspended(dd->dev)) + mchp_pdmc_runtime_suspend(dd->dev); + pm_runtime_disable(dd->dev); + + return ret; +} + +static int mchp_pdmc_remove(struct platform_device *pdev) +{ + struct mchp_pdmc *dd = platform_get_drvdata(pdev); + + if (!pm_runtime_status_suspended(dd->dev)) + mchp_pdmc_runtime_suspend(dd->dev); + + pm_runtime_disable(dd->dev); + + return 0; } static const struct of_device_id mchp_pdmc_of_match[] = { @@ -1070,13 +1112,20 @@ static const struct of_device_id mchp_pdmc_of_match[] = { }; MODULE_DEVICE_TABLE(of, mchp_pdmc_of_match); +static const struct dev_pm_ops mchp_pdmc_pm_ops = { + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(mchp_pdmc_runtime_suspend, mchp_pdmc_runtime_resume, + NULL) +}; + static struct platform_driver mchp_pdmc_driver = { .driver = { .name = "mchp-pdmc", .of_match_table = of_match_ptr(mchp_pdmc_of_match), - .pm = &snd_soc_pm_ops, + .pm = pm_ptr(&mchp_pdmc_pm_ops), }, .probe = mchp_pdmc_probe, + .remove = mchp_pdmc_remove, }; module_platform_driver(mchp_pdmc_driver); diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index dc96a6fbf514e1..20d135c718b070 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -6,6 +6,7 @@ // // Author: Codrin Ciubotariu +#include #include #include #include @@ -71,11 +72,11 @@ /* Valid Bits per Sample */ #define SPDIFTX_MR_VBPS_MASK GENMASK(13, 8) -#define SPDIFTX_MR_VBPS(bps) (((bps) << 8) & SPDIFTX_MR_VBPS_MASK) +#define SPDIFTX_MR_VBPS(bps) FIELD_PREP(SPDIFTX_MR_VBPS_MASK, bps) /* Chunk Size */ #define SPDIFTX_MR_CHUNK_MASK GENMASK(19, 16) -#define SPDIFTX_MR_CHUNK(size) (((size) << 16) & SPDIFTX_MR_CHUNK_MASK) +#define SPDIFTX_MR_CHUNK(size) FIELD_PREP(SPDIFTX_MR_CHUNK_MASK, size) /* Validity Bits for Channels 1 and 2 */ #define SPDIFTX_MR_VALID1 BIT(24) @@ -88,8 +89,7 @@ /* Bytes per Sample */ #define SPDIFTX_MR_BPS_MASK GENMASK(29, 28) -#define SPDIFTX_MR_BPS(bytes) \ - ((((bytes) - 1) << 28) & SPDIFTX_MR_BPS_MASK) +#define SPDIFTX_MR_BPS(bytes) FIELD_PREP(SPDIFTX_MR_BPS_MASK, (bytes - 1)) /* * ---- Interrupt Enable/Disable/Mask/Status Register (Write/Read-only) ---- diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index fc65283031cdc2..3574c68e0dda39 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1386,17 +1386,11 @@ static int pm860x_codec_probe(struct platform_device *pdev) return ret; } -static int pm860x_codec_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver pm860x_codec_driver = { .driver = { .name = "88pm860x-codec", }, .probe = pm860x_codec_probe, - .remove = pm860x_codec_remove, }; module_platform_driver(pm860x_codec_driver); diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index cc12052e192046..0e013edfe63d7c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -127,18 +127,12 @@ static int ac97_probe(struct platform_device *pdev) &soc_component_dev_ac97, &ac97_dai, 1); } -static int ac97_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver ac97_codec_driver = { .driver = { .name = "ac97-codec", }, .probe = ac97_probe, - .remove = ac97_remove, }; module_platform_driver(ac97_codec_driver); diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c index 401bafabc8eb4b..c9134e1de0b25b 100644 --- a/sound/soc/codecs/adau7002.c +++ b/sound/soc/codecs/adau7002.c @@ -100,11 +100,6 @@ static int adau7002_probe(struct platform_device *pdev) &adau7002_dai, 1); } -static int adau7002_remove(struct platform_device *pdev) -{ - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id adau7002_dt_ids[] = { { .compatible = "adi,adau7002", }, @@ -128,7 +123,6 @@ static struct platform_driver adau7002_driver = { .acpi_match_table = ACPI_PTR(adau7002_acpi_match), }, .probe = adau7002_probe, - .remove = adau7002_remove, }; module_platform_driver(adau7002_driver); diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index 4086b6a53de8ca..3afcef2dfa3529 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -78,11 +78,6 @@ static int bt_sco_probe(struct platform_device *pdev) bt_sco_dai, ARRAY_SIZE(bt_sco_dai)); } -static int bt_sco_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct platform_device_id bt_sco_driver_ids[] = { { .name = "dfbmcs320", @@ -109,7 +104,6 @@ static struct platform_driver bt_sco_driver = { .of_match_table = of_match_ptr(bt_sco_codec_of_match), }, .probe = bt_sco_probe, - .remove = bt_sco_remove, .id_table = bt_sco_driver_ids, }; diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 14403b76c72434..32b6a417d0e8cd 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -134,18 +134,12 @@ static int cq93vc_platform_probe(struct platform_device *pdev) &soc_component_dev_cq93vc, &cq93vc_dai, 1); } -static int cq93vc_platform_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver cq93vc_codec_driver = { .driver = { .name = "cq93vc-codec", }, .probe = cq93vc_platform_probe, - .remove = cq93vc_platform_remove, }; module_platform_driver(cq93vc_codec_driver); diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 544ccbcfc88442..0068780fe0a745 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1157,13 +1157,31 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); + u8 dai_clk_mode = DA7213_DAI_BCLKS_PER_WCLK_64; u8 dai_ctrl = 0; u8 fs; + /* Set channels */ + switch (params_channels(params)) { + case 1: + if (da7213->fmt != DA7213_DAI_FORMAT_DSP) { + dev_err(component->dev, "Mono supported only in DSP mode\n"); + return -EINVAL; + } + dai_ctrl |= DA7213_DAI_MONO_MODE_EN; + break; + case 2: + dai_ctrl &= ~(DA7213_DAI_MONO_MODE_EN); + break; + default: + return -EINVAL; + } + /* Set DAI format */ switch (params_width(params)) { case 16: dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE; + dai_clk_mode = DA7213_DAI_BCLKS_PER_WCLK_32; /* 32bit for 1ch and 2ch */ break; case 20: dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE; @@ -1224,8 +1242,11 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_WORD_LENGTH_MASK, - dai_ctrl); + snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE, + DA7213_DAI_BCLKS_PER_WCLK_MASK, dai_clk_mode); + + snd_soc_component_update_bits(component, DA7213_DAI_CTRL, + DA7213_DAI_WORD_LENGTH_MASK | DA7213_DAI_MONO_MODE_MASK, dai_ctrl); snd_soc_component_write(component, DA7213_SR, fs); return 0; @@ -1300,19 +1321,24 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: dai_ctrl |= DA7213_DAI_FORMAT_I2S_MODE; + da7213->fmt = DA7213_DAI_FORMAT_I2S_MODE; break; case SND_SOC_DAIFMT_LEFT_J: dai_ctrl |= DA7213_DAI_FORMAT_LEFT_J; + da7213->fmt = DA7213_DAI_FORMAT_LEFT_J; break; case SND_SOC_DAIFMT_RIGHT_J: dai_ctrl |= DA7213_DAI_FORMAT_RIGHT_J; + da7213->fmt = DA7213_DAI_FORMAT_RIGHT_J; break; case SND_SOC_DAI_FORMAT_DSP_A: /* L data MSB after FRM LRC */ dai_ctrl |= DA7213_DAI_FORMAT_DSP; dai_offset = 1; + da7213->fmt = DA7213_DAI_FORMAT_DSP; break; case SND_SOC_DAI_FORMAT_DSP_B: /* L data MSB during FRM LRC */ dai_ctrl |= DA7213_DAI_FORMAT_DSP; + da7213->fmt = DA7213_DAI_FORMAT_DSP; break; default: return -EINVAL; diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 97ccf0ddd2be20..4ca9cfdea06d43 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -195,6 +195,8 @@ #define DA7213_DAI_WORD_LENGTH_S24_LE (0x2 << 2) #define DA7213_DAI_WORD_LENGTH_S32_LE (0x3 << 2) #define DA7213_DAI_WORD_LENGTH_MASK (0x3 << 2) +#define DA7213_DAI_MONO_MODE_EN (0x1 << 4) +#define DA7213_DAI_MONO_MODE_MASK (0x1 << 4) #define DA7213_DAI_EN_SHIFT 7 /* DA7213_DIG_ROUTING_DAI = 0x21 */ @@ -542,6 +544,7 @@ struct da7213_priv { bool alc_en; bool fixed_clk_auto_pll; struct da7213_platform_data *pdata; + int fmt; }; #endif /* _DA7213_H */ diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 71490f11d96ac2..086ac97e83866d 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -776,16 +776,10 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) return ret; } -static int mc13783_codec_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver mc13783_codec_driver = { .driver = { .name = "mc13783-codec", }, - .remove = mc13783_codec_remove, }; module_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe); diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 708e55b7431a75..9e6341a68c6b09 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2717,6 +2717,10 @@ static int rt5640_probe(struct snd_soc_component *component) snd_soc_component_update_bits(component, RT5640_IN1_IN2, RT5640_IN_DF2, RT5640_IN_DF2); + if (device_property_read_bool(component->dev, "realtek,lout-differential")) + snd_soc_component_update_bits(component, RT5640_DUMMY1, + RT5640_EN_LOUT_DF, RT5640_EN_LOUT_DF); + if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin", &val) == 0 && val) { dmic1_data_pin = val - 1; diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index f58b88e3325b5c..9847a1ae01f445 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1978,6 +1978,8 @@ #define RT5640_ZCD_HP_EN (0x1 << 15) /* General Control 1 (0xfa) */ +#define RT5640_EN_LOUT_DF (0x1 << 14) +#define RT5640_EN_LOUT_DF_SFT 14 #define RT5640_M_MONO_ADC_L (0x1 << 13) #define RT5640_M_MONO_ADC_L_SFT 13 #define RT5640_M_MONO_ADC_R (0x1 << 12) diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index b78dd5994edbfd..7cdf184d380b48 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -463,6 +463,21 @@ static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) RT711_HP_JD_FINAL_RESULT_CTL_JD12, RT711_HP_JD_FINAL_RESULT_CTL_JD12); break; + case RT711_JD2_100K: + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL3, 0xa47e); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_JD_CTL1, RT711_JD2_DIGITAL_MODE_SEL, + RT711_JD2_DIGITAL_MODE_SEL); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP | + RT711_JD2_2PORT_100K_DECODE_MASK | RT711_HP_JD_SEL_JD2, + RT711_JD2_2PORT_100K_DECODE_HP | RT711_HP_JD_SEL_JD2); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_CC_DET1, + RT711_HP_JD_FINAL_RESULT_CTL_JD12 | RT711_POW_CC1_AGPI, + RT711_HP_JD_FINAL_RESULT_CTL_JD12 | RT711_POW_CC1_AGPI_OFF); + break; default: dev_warn(rt711->component->dev, "Wrong JD source\n"); break; diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h index 498ca687c47bc3..10e3c801b81330 100644 --- a/sound/soc/codecs/rt711-sdca.h +++ b/sound/soc/codecs/rt711-sdca.h @@ -127,12 +127,17 @@ struct sdw_stream_data { /* jack detect control 2 (0x09)(NID:20h) */ #define RT711_JD2_2PORT_200K_DECODE_HP (0x1 << 13) +#define RT711_JD2_2PORT_100K_DECODE_MASK (0x1 << 12) +#define RT711_JD2_2PORT_100K_DECODE_HP (0x0 << 12) #define RT711_HP_JD_SEL_JD1 (0x0 << 1) #define RT711_HP_JD_SEL_JD2 (0x1 << 1) /* CC DET1 (0x11)(NID:20h) */ #define RT711_HP_JD_FINAL_RESULT_CTL_JD12 (0x1 << 10) #define RT711_HP_JD_FINAL_RESULT_CTL_CCDET (0x0 << 10) +#define RT711_POW_CC1_AGPI (0x1 << 5) +#define RT711_POW_CC1_AGPI_ON (0x1 << 5) +#define RT711_POW_CC1_AGPI_OFF (0x0 << 5) /* Parameter & Verb control (0x1a)(NID:20h) */ #define RT711_HIDDEN_REG_SW_RESET (0x1 << 14) @@ -226,7 +231,8 @@ enum { enum rt711_sdca_jd_src { RT711_JD_NULL, RT711_JD1, - RT711_JD2 + RT711_JD2, + RT711_JD2_100K }; enum rt711_sdca_ver { diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index 626278e4c92380..737ca82cf9764f 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -484,11 +484,6 @@ static int wl1273_platform_probe(struct platform_device *pdev) &wl1273_dai, 1); } -static int wl1273_platform_remove(struct platform_device *pdev) -{ - return 0; -} - MODULE_ALIAS("platform:wl1273-codec"); static struct platform_driver wl1273_platform_driver = { @@ -496,7 +491,6 @@ static struct platform_driver wl1273_platform_driver = { .name = "wl1273-codec", }, .probe = wl1273_platform_probe, - .remove = wl1273_platform_remove, }; module_platform_driver(wl1273_platform_driver); diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 8dac9fd8854705..8eb4782c923207 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -37,7 +37,9 @@ #include "wm8940.h" struct wm8940_priv { - unsigned int sysclk; + unsigned int mclk; + unsigned int fs; + struct regmap *regmap; }; @@ -387,17 +389,24 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +static int wm8940_update_clocks(struct snd_soc_dai *dai); static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct wm8940_priv *priv = snd_soc_component_get_drvdata(component); u16 iface = snd_soc_component_read(component, WM8940_IFACE) & 0xFD9F; u16 addcntrl = snd_soc_component_read(component, WM8940_ADDCNTRL) & 0xFFF1; u16 companding = snd_soc_component_read(component, WM8940_COMPANDINGCTL) & 0xFFDF; int ret; + priv->fs = params_rate(params); + ret = wm8940_update_clocks(dai); + if (ret) + return ret; + /* LoutR control */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && params_channels(params) == 2) @@ -611,24 +620,6 @@ static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, return 0; } -static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_component *component = codec_dai->component; - struct wm8940_priv *wm8940 = snd_soc_component_get_drvdata(component); - - switch (freq) { - case 11289600: - case 12000000: - case 12288000: - case 16934400: - case 18432000: - wm8940->sysclk = freq; - return 0; - } - return -EINVAL; -} - static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { @@ -653,6 +644,78 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, return ret; } +static unsigned int wm8940_get_mclkdiv(unsigned int f_in, unsigned int f_out, + int *mclkdiv) +{ + unsigned int ratio = 2 * f_in / f_out; + + if (ratio <= 2) { + *mclkdiv = WM8940_MCLKDIV_1; + ratio = 2; + } else if (ratio == 3) { + *mclkdiv = WM8940_MCLKDIV_1_5; + } else if (ratio == 4) { + *mclkdiv = WM8940_MCLKDIV_2; + } else if (ratio <= 6) { + *mclkdiv = WM8940_MCLKDIV_3; + ratio = 6; + } else if (ratio <= 8) { + *mclkdiv = WM8940_MCLKDIV_4; + ratio = 8; + } else if (ratio <= 12) { + *mclkdiv = WM8940_MCLKDIV_6; + ratio = 12; + } else if (ratio <= 16) { + *mclkdiv = WM8940_MCLKDIV_8; + ratio = 16; + } else { + *mclkdiv = WM8940_MCLKDIV_12; + ratio = 24; + } + + return f_out * ratio / 2; +} + +static int wm8940_update_clocks(struct snd_soc_dai *dai) +{ + struct snd_soc_component *codec = dai->component; + struct wm8940_priv *priv = snd_soc_component_get_drvdata(codec); + unsigned int fs256; + unsigned int fpll = 0; + unsigned int f; + int mclkdiv; + + if (!priv->mclk || !priv->fs) + return 0; + + fs256 = 256 * priv->fs; + + f = wm8940_get_mclkdiv(priv->mclk, fs256, &mclkdiv); + if (f != priv->mclk) { + /* The PLL performs best around 90MHz */ + fpll = wm8940_get_mclkdiv(22500000, fs256, &mclkdiv); + } + + wm8940_set_dai_pll(dai, 0, 0, priv->mclk, fpll); + wm8940_set_dai_clkdiv(dai, WM8940_MCLKDIV, mclkdiv); + + return 0; +} + +static int wm8940_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *codec = dai->component; + struct wm8940_priv *priv = snd_soc_component_get_drvdata(codec); + + if (dir != SND_SOC_CLOCK_IN) + return -EINVAL; + + priv->mclk = freq; + + return wm8940_update_clocks(dai); +} + #define WM8940_RATES SNDRV_PCM_RATE_8000_48000 #define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ @@ -697,6 +760,17 @@ static int wm8940_probe(struct snd_soc_component *component) int ret; u16 reg; + /* + * Check chip ID for wm8940 - value of 0x00 offset + * SOFTWARE_RESET on write + * CHIP_ID on read + */ + reg = snd_soc_component_read(component, WM8940_SOFTRESET); + if (reg != WM8940_CHIP_ID) { + dev_err(component->dev, "Wrong wm8940 chip ID: 0x%x\n", reg); + return -ENODEV; + } + ret = wm8940_reset(component); if (ret < 0) { dev_err(component->dev, "Failed to issue reset\n"); @@ -709,9 +783,7 @@ static int wm8940_probe(struct snd_soc_component *component) if (ret < 0) return ret; - if (!pdata) - dev_warn(component->dev, "No platform data supplied\n"); - else { + if (pdata) { reg = snd_soc_component_read(component, WM8940_OUTPUTCTL); ret = snd_soc_component_write(component, WM8940_OUTPUTCTL, reg | pdata->vroi); if (ret < 0) diff --git a/sound/soc/codecs/wm8940.h b/sound/soc/codecs/wm8940.h index 0d4f53ada2e622..86bbf902ef5a2b 100644 --- a/sound/soc/codecs/wm8940.h +++ b/sound/soc/codecs/wm8940.h @@ -95,5 +95,8 @@ struct wm8940_setup_data { #define WM8940_OPCLKDIV_3 2 #define WM8940_OPCLKDIV_4 3 +/* Chip ID */ +#define WM8940_CHIP_ID 0x8940 + #endif /* _WM8940_H */ diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index 1c6924a1ebca3a..460ee6599daf03 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \ - topology.o path.o pcm.o board_selection.o + topology.o path.o pcm.o board_selection.o control.o snd-soc-avs-objs += cldma.o snd-soc-avs-objs += skl.o apl.o diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c new file mode 100644 index 00000000000000..a8b14b784f8a51 --- /dev/null +++ b/sound/soc/intel/avs/control.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Amadeusz Slawinski +// Cezary Rojewski +// + +#include +#include "avs.h" +#include "control.h" +#include "messages.h" +#include "path.h" + +static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol) +{ + struct snd_soc_dapm_widget *w; + + w = snd_soc_dapm_kcontrol_widget(kcontrol); + + return to_avs_dev(w->dapm->component->dev); +} + +static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id) +{ + struct avs_path *path; + struct avs_path_pipeline *ppl; + struct avs_path_module *mod; + + list_for_each_entry(path, &adev->path_list, node) + list_for_each_entry(ppl, &path->ppl_list, node) + list_for_each_entry(mod, &ppl->mod_list, node) + if (mod->template->ctl_id && mod->template->ctl_id == id) + return mod; + + return NULL; +} + +int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; + struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); + struct avs_volume_cfg *dspvols = NULL; + struct avs_path_module *active_module; + size_t num_dspvols; + int ret = 0; + + /* prevent access to modules while path is being constructed */ + mutex_lock(&adev->path_mutex); + + active_module = avs_get_kcontrol_module(adev, ctl_data->id); + if (active_module) { + ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id, + active_module->instance_id, &dspvols, + &num_dspvols); + if (!ret) + ucontrol->value.integer.value[0] = dspvols[0].target_volume; + + ret = AVS_IPC_RET(ret); + kfree(dspvols); + } else { + ucontrol->value.integer.value[0] = ctl_data->volume; + } + + mutex_unlock(&adev->path_mutex); + return ret; +} + +int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; + struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); + long *volume = &ctl_data->volume; + struct avs_path_module *active_module; + struct avs_volume_cfg dspvol = {0}; + long ctlvol = ucontrol->value.integer.value[0]; + int ret = 0, changed = 0; + + if (ctlvol < 0 || ctlvol > mc->max) + return -EINVAL; + + /* prevent access to modules while path is being constructed */ + mutex_lock(&adev->path_mutex); + + if (*volume != ctlvol) { + *volume = ctlvol; + changed = 1; + } + + active_module = avs_get_kcontrol_module(adev, ctl_data->id); + if (active_module) { + dspvol.channel_id = AVS_ALL_CHANNELS_MASK; + dspvol.target_volume = *volume; + + ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id, + active_module->instance_id, &dspvol); + ret = AVS_IPC_RET(ret); + } + + mutex_unlock(&adev->path_mutex); + + return ret ? ret : changed; +} diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h new file mode 100644 index 00000000000000..08631bde13c34e --- /dev/null +++ b/sound/soc/intel/avs/control.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * + * Authors: Amadeusz Slawinski + * Cezary Rojewski + */ + +#ifndef __SOUND_SOC_INTEL_AVS_CTRL_H +#define __SOUND_SOC_INTEL_AVS_CTRL_H + +#include + +struct avs_control_data { + u32 id; + + long volume; +}; + +int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + +#endif diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index e11ae4246416cf..f887ab5b0311df 100644 --- a/sound/soc/intel/avs/messages.c +++ b/sound/soc/intel/avs/messages.c @@ -702,6 +702,35 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, (u8 *)&cpr_fmt, sizeof(cpr_fmt)); } +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol) +{ + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol, + sizeof(*vol)); +} + +int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg **vols, size_t *num_vols) +{ + size_t payload_size; + u8 *payload; + int ret; + + ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, NULL, 0, + &payload, &payload_size); + if (ret) + return ret; + + /* Non-zero payload expected for PEAKVOL_VOLUME. */ + if (!payload_size) + return -EREMOTEIO; + + *vols = (struct avs_volume_cfg *)payload; + *num_vols = payload_size / sizeof(**vols); + + return 0; +} + #ifdef CONFIG_DEBUG_FS int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) { diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 9dd835527e02c3..d3b60ae7d7432d 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -561,6 +561,12 @@ int avs_ipc_set_system_time(struct avs_dev *adev); #define AVS_COPIER_MOD_UUID \ GUID_INIT(0x9BA00C83, 0xCA12, 0x4A83, 0x94, 0x3C, 0x1F, 0xA2, 0xE8, 0x2F, 0x9D, 0xDA) +#define AVS_PEAKVOL_MOD_UUID \ + GUID_INIT(0x8A171323, 0x94A3, 0x4E1D, 0xAF, 0xE9, 0xFE, 0x5D, 0xBA, 0xa4, 0xC3, 0x93) + +#define AVS_GAIN_MOD_UUID \ + GUID_INIT(0x61BCA9A8, 0x18D0, 0x4A18, 0x8E, 0x7B, 0x26, 0x39, 0x21, 0x98, 0x04, 0xB7) + #define AVS_KPBUFF_MOD_UUID \ GUID_INIT(0xA8A0CB32, 0x4A77, 0x4DB1, 0x85, 0xC7, 0x53, 0xD7, 0xEE, 0x07, 0xBC, 0xE6) @@ -729,6 +735,19 @@ struct avs_copier_cfg { struct avs_copier_gtw_cfg gtw_cfg; } __packed; +struct avs_volume_cfg { + u32 channel_id; + u32 target_volume; + u32 curve_type; + u32 reserved; /* alignment */ + u64 curve_duration; +} __packed; + +struct avs_peakvol_cfg { + struct avs_modcfg_base base; + struct avs_volume_cfg vols[]; +} __packed; + struct avs_micsel_cfg { struct avs_modcfg_base base; struct avs_audio_format out_fmt; @@ -802,6 +821,20 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, const struct avs_audio_format *src_fmt, const struct avs_audio_format *sink_fmt); +enum avs_peakvol_runtime_param { + AVS_PEAKVOL_VOLUME = 0, +}; + +enum avs_audio_curve_type { + AVS_AUDIO_CURVE_NONE = 0, + AVS_AUDIO_CURVE_WINDOWS_FADE = 1, +}; + +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol); +int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg **vols, size_t *num_vols); + #define AVS_PROBE_INST_ID 0 enum avs_probe_runtime_param { diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index ce157a8d65520a..05302ab705ae02 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -10,6 +10,7 @@ #include #include #include "avs.h" +#include "control.h" #include "path.h" #include "topology.h" @@ -264,6 +265,65 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) return ret; } +static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_tplg_path_template *path_tmpl; + struct snd_soc_dapm_widget *w; + int i; + + path_tmpl = t->owner->owner->owner; + w = path_tmpl->w; + + for (i = 0; i < w->num_kcontrols; i++) { + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + + mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value; + ctl_data = (struct avs_control_data *)mc->dobj.private; + if (ctl_data->id == t->ctl_id) + return ctl_data; + } + + return NULL; +} + +static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_control_data *ctl_data; + struct avs_peakvol_cfg *cfg; + int volume = S32_MAX; + size_t size; + int ret; + + ctl_data = avs_get_module_control(mod); + if (ctl_data) + volume = ctl_data->volume; + + /* As 2+ channels controls are unsupported, have a single block for all channels. */ + size = struct_size(cfg, vols, 1); + cfg = kzalloc(size, GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->base.cpc = t->cfg_base->cpc; + cfg->base.ibs = t->cfg_base->ibs; + cfg->base.obs = t->cfg_base->obs; + cfg->base.is_pages = t->cfg_base->is_pages; + cfg->base.audio_fmt = *t->in_fmt; + cfg->vols[0].target_volume = volume; + cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK; + cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE; + cfg->vols[0].curve_duration = 0; + + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, + t->domain, cfg, size, &mod->instance_id); + + kfree(cfg); + return ret; +} + static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod) { struct avs_tplg_module *t = mod->template; @@ -465,6 +525,8 @@ static struct avs_module_create avs_module_create[] = { { &AVS_MIXOUT_MOD_UUID, avs_modbase_create }, { &AVS_KPBUFF_MOD_UUID, avs_modbase_create }, { &AVS_COPIER_MOD_UUID, avs_copier_create }, + { &AVS_PEAKVOL_MOD_UUID, avs_peakvol_create }, + { &AVS_GAIN_MOD_UUID, avs_peakvol_create }, { &AVS_MICSEL_MOD_UUID, avs_micsel_create }, { &AVS_MUX_MOD_UUID, avs_mux_create }, { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create }, diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index e845eaf0a1e77d..5fee7a8ec06ac1 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -13,6 +13,7 @@ #include #include #include "avs.h" +#include "control.h" #include "topology.h" /* Get pointer to vendor array at the specified offset. */ @@ -1070,6 +1071,12 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, cfg_ext), .parse = avs_parse_modcfg_ext_ptr, }, + { + .token = AVS_TKN_MOD_KCONTROL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, ctl_id), + .parse = avs_parse_byte_token, + }, }; static struct avs_tplg_module * @@ -1435,6 +1442,16 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, return 0; } +static int avs_widget_ready(struct snd_soc_component *comp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *dw) +{ + struct avs_tplg_path_template *template = w->priv; + + template->w = w; + return 0; +} + static int avs_dai_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) @@ -1586,9 +1603,68 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return avs_tplg_parse_bindings(comp, tuples, remaining); } +#define AVS_CONTROL_OPS_VOLUME 257 + +static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = { + { + .id = AVS_CONTROL_OPS_VOLUME, + .get = avs_control_volume_get, + .put = avs_control_volume_put, + }, +}; + +static const struct avs_tplg_token_parser control_parsers[] = { + { + .token = AVS_TKN_KCONTROL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_control_data, id), + .parse = avs_parse_word_token, + }, +}; + +static int +avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_new *ctmpl, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_soc_tplg_vendor_array *tuples; + struct snd_soc_tplg_mixer_control *tmc; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + size_t block_size; + int ret; + + switch (hdr->type) { + case SND_SOC_TPLG_TYPE_MIXER: + tmc = container_of(hdr, typeof(*tmc), hdr); + tuples = tmc->priv.array; + block_size = le32_to_cpu(tmc->priv.size); + break; + default: + return -EINVAL; + } + + ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL); + if (!ctl_data) + return -ENOMEM; + + ret = parse_dictionary_entries(comp, tuples, block_size, ctl_data, 1, sizeof(*ctl_data), + AVS_TKN_KCONTROL_ID_U32, control_parsers, + ARRAY_SIZE(control_parsers)); + if (ret) + return ret; + + mc = (struct soc_mixer_control *)ctmpl->private_value; + mc->dobj.private = ctl_data; + return 0; +} + static struct snd_soc_tplg_ops avs_tplg_ops = { + .io_ops = avs_control_ops, + .io_ops_count = ARRAY_SIZE(avs_control_ops), + .control_load = avs_control_load, .dapm_route_load = avs_route_load, .widget_load = avs_widget_load, + .widget_ready = avs_widget_ready, .dai_load = avs_dai_load, .link_load = avs_link_load, .manifest = avs_manifest, diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 68e5f6312353d2..6e1c8e9b249641 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -138,6 +138,8 @@ struct avs_tplg_path_template_id { struct avs_tplg_path_template { u32 id; + struct snd_soc_dapm_widget *w; + struct list_head path_list; struct avs_tplg *owner; @@ -180,6 +182,7 @@ struct avs_tplg_module { u8 core_id; u8 domain; struct avs_tplg_modcfg_ext *cfg_ext; + u32 ctl_id; struct avs_tplg_pipeline *owner; /* Pipeline modules management. */ diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 94d25aeb6e7cea..f75800d9d6de7f 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -105,7 +105,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) char jack_name[NAME_SIZE]; struct sof_hdmi_pcm *pcm; int err; - int i; if (!(sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT)) return 0; @@ -124,7 +123,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) return hda_dsp_hdmi_build_controls(card, component); } - i = 0; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -139,8 +137,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) &pcm->sof_hdmi); if (err < 0) return err; - - i++; } return hdac_hdmi_jack_port_init(component, &card->dapm); diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 4e0e9b778d4c0a..ec37da331a91bb 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -145,18 +145,12 @@ static int e740_probe(struct platform_device *pdev) return ret; } -static int e740_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver e740_driver = { .driver = { .name = "e740-audio", .pm = &snd_soc_pm_ops, }, .probe = e740_probe, - .remove = e740_remove, }; module_platform_driver(e740_driver); diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index 7a1e0d8bfd1138..60b22d4f92a754 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -124,18 +124,12 @@ static int e750_probe(struct platform_device *pdev) return ret; } -static int e750_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver e750_driver = { .driver = { .name = "e750-audio", .pm = &snd_soc_pm_ops, }, .probe = e750_probe, - .remove = e750_remove, }; module_platform_driver(e750_driver); diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index a39c494127cf74..c7756acd888a8f 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -124,18 +124,12 @@ static int e800_probe(struct platform_device *pdev) return ret; } -static int e800_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver e800_driver = { .driver = { .name = "e800-audio", .pm = &snd_soc_pm_ops, }, .probe = e800_probe, - .remove = e800_remove, }; module_platform_driver(e800_driver); diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 44303b6eb228bf..70442315f5c592 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -306,18 +306,12 @@ static int spitz_probe(struct platform_device *pdev) return ret; } -static int spitz_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver spitz_driver = { .driver = { .name = "spitz-audio", .pm = &snd_soc_pm_ops, }, .probe = spitz_probe, - .remove = spitz_remove, }; module_platform_driver(spitz_driver); diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index de5726251dc610..920155dee819b5 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -85,4 +85,8 @@ #define ACP_SCRATCH_REG_0 0x10000 #define ACP6X_DSP_FUSION_RUNSTALL 0x0644 + +/* Cache window registers */ +#define ACP_DSP0_CACHE_OFFSET0 0x0420 +#define ACP_DSP0_CACHE_SIZE0 0x0424 #endif diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 090c8b18c83c44..a4bce5a3ae482b 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -151,6 +151,7 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); struct acp_dev_data *adata; unsigned int src_addr, size_fw; u32 page_count, dma_size; @@ -183,6 +184,12 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) if (ret < 0) dev_err(sdev->dev, "acp dma transfer status: %d\n", ret); + if (desc->rev > 3) { + /* Cache Window enable */ + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_OFFSET0, desc->sram_pte_offset); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_SIZE0, SRAM1_SIZE | BIT(31)); + } + /* Free memory once DMA is complete */ dma_size = (PAGE_ALIGN(sdev->basefw.fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE; dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 09e16ef8afa050..4314094a97fd77 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -72,6 +72,8 @@ #define EXCEPT_MAX_HDR_SIZE 0x400 #define AMD_STACK_DUMP_SIZE 32 +#define SRAM1_SIZE 0x13A000 + enum clock_source { ACP_CLOCK_96M = 0, ACP_CLOCK_48M, diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index e0e9efd25d34e2..75e13f4fd1eb81 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -22,9 +22,9 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->volume_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_get) return tplg_ops->control->volume_get(scontrol, ucontrol); return 0; @@ -37,9 +37,9 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->volume_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_put) return tplg_ops->control->volume_put(scontrol, ucontrol); return false; @@ -74,9 +74,9 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->switch_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_get) return tplg_ops->control->switch_get(scontrol, ucontrol); return 0; @@ -89,9 +89,9 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->switch_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_put) return tplg_ops->control->switch_put(scontrol, ucontrol); return false; @@ -104,9 +104,9 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->enum_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_get) return tplg_ops->control->enum_get(scontrol, ucontrol); return 0; @@ -119,9 +119,9 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->enum_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_put) return tplg_ops->control->enum_put(scontrol, ucontrol); return false; @@ -134,9 +134,9 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->bytes_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_get) return tplg_ops->control->bytes_get(scontrol, ucontrol); return 0; @@ -149,9 +149,9 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->bytes_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_put) return tplg_ops->control->bytes_put(scontrol, ucontrol); return 0; @@ -165,13 +165,13 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); /* make sure we have at least a header */ if (size < sizeof(struct snd_ctl_tlv)) return -EINVAL; - if (tplg_ops->control->bytes_ext_put) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_put) return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size); return 0; @@ -184,7 +184,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int ret, err; ret = pm_runtime_resume_and_get(scomp->dev); @@ -193,7 +193,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ return ret; } - if (tplg_ops->control->bytes_ext_volatile_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get) ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size); pm_runtime_mark_last_busy(scomp->dev); @@ -212,9 +212,9 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->bytes_ext_get) + if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_get) return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size); return 0; diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 625977a29d8a8c..26a3f7c8c914a3 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,6 +362,9 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->first_boot = true; dev_set_drvdata(dev, sdev); + if (sof_core_debug) + dev_info(dev, "sof_debug value: %#x\n", sof_core_debug); + /* check IPC support */ if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) { dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n", diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index b94cc40485ed6d..989395999d6ec0 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1651,6 +1651,7 @@ static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) { struct sof_ipc_ctrl_data *cdata; + size_t priv_size_check; int ret; if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) { @@ -1694,8 +1695,10 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ goto err; } - if (cdata->data->size + sizeof(struct sof_abi_hdr) != scontrol->priv_size) { - dev_err(sdev->dev, "Conflict in bytes vs. priv size.\n"); + priv_size_check = cdata->data->size + sizeof(struct sof_abi_hdr); + if (priv_size_check != scontrol->priv_size) { + dev_err(sdev->dev, "Conflict in bytes (%zu) vs. priv size (%zu).\n", + priv_size_check, scontrol->priv_size); ret = -EINVAL; goto err; } diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 3c81e84fcecfa2..7c831e18483c6f 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -215,11 +215,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data) adsp->pa_sram = (phys_addr_t)mmio->start; adsp->sramsize = resource_size(mmio); - if (adsp->sramsize < TOTAL_SIZE_SHARED_SRAM_FROM_TAIL) { - dev_err(dev, "adsp SRAM(%#x) is not enough for share\n", - adsp->sramsize); - return -EINVAL; - } dev_dbg(dev, "sram pbase=%pa,%#x\n", &adsp->pa_sram, adsp->sramsize); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.h b/sound/soc/sof/mediatek/mt8195/mt8195.h index 7ffd523f936c82..b4229170049fab 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.h +++ b/sound/soc/sof/mediatek/mt8195/mt8195.h @@ -139,8 +139,6 @@ struct snd_sof_dev; #define DSP_MBOX1_BAR 6 #define DSP_MBOX2_BAR 7 -#define TOTAL_SIZE_SHARED_SRAM_FROM_TAIL 0x0 - #define SIZE_SHARED_DRAM_DL 0x40000 /*Shared buffer for Downlink*/ #define SIZE_SHARED_DRAM_UL 0x40000 /*Shared buffer for Uplink*/ diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 3537805070adad..b13bfdeb2b7062 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -103,14 +103,8 @@ static int sof_nocodec_probe(struct platform_device *pdev) return devm_snd_soc_register_card(&pdev->dev, card); } -static int sof_nocodec_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver sof_nocodec_audio = { .probe = sof_nocodec_probe, - .remove = sof_nocodec_remove, .driver = { .name = "sof-nocodec", .pm = &snd_soc_pm_ops, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 14571b821ecac5..952fc698a58617 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -125,8 +125,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_platform_stream_params platform_params = { 0 }; - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sof_pcm *spcm; int ret; @@ -143,7 +143,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, * Handle repeated calls to hw_params() without free_pcm() in * between. At least ALSA OSS emulation depends on this. */ - if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { ret = pcm_ops->hw_free(component, substream); if (ret < 0) return ret; @@ -177,7 +177,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, return ret; } - if (pcm_ops->hw_params) { + if (pcm_ops && pcm_ops->hw_params) { ret = pcm_ops->hw_params(component, substream, params, &platform_params); if (ret < 0) return ret; @@ -196,7 +196,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; int ret, err = 0; @@ -212,7 +212,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, spcm->pcm.pcm_id, substream->stream); /* free PCM in the DSP */ - if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { ret = pcm_ops->hw_free(component, substream); if (ret < 0) err = ret; @@ -279,7 +279,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); struct snd_sof_pcm *spcm; bool reset_hw_params = false; bool free_widget_list = false; @@ -344,7 +344,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, if (!ipc_first) snd_sof_pcm_platform_trigger(sdev, substream, cmd); - if (pcm_ops->trigger) + if (pcm_ops && pcm_ops->trigger) ret = pcm_ops->trigger(component, substream, cmd); /* need to STOP DMA even if trigger IPC failed */ @@ -569,7 +569,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); /* no topology exists for this BE, try a common configuration */ if (!dai) { @@ -590,7 +590,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa return 0; } - if (pcm_ops->dai_link_fixup) + if (pcm_ops && pcm_ops->dai_link_fixup) return pcm_ops->dai_link_fixup(rtd, params); return 0; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 8722bbd7fd3d78..8d3383085d12c4 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -73,8 +73,8 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev) static int sof_resume(struct device *dev, bool runtime_resume) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); u32 old_state = sdev->dsp_power_state.state; int ret; @@ -155,7 +155,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) } /* restore pipelines */ - if (tplg_ops->set_up_all_pipelines) { + if (tplg_ops && tplg_ops->set_up_all_pipelines) { ret = tplg_ops->set_up_all_pipelines(sdev, false); if (ret < 0) { dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret); @@ -179,8 +179,8 @@ static int sof_resume(struct device *dev, bool runtime_resume) static int sof_suspend(struct device *dev, bool runtime_suspend) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); pm_message_t pm_state; u32 target_state = snd_sof_dsp_power_target(sdev); int ret; @@ -276,7 +276,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev) { - const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; + const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm); /* Notify DSP of upcoming power down */ if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 7306a2649857a7..e1ab8380e7d846 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -16,12 +16,12 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) { - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_route *sroute; list_for_each_entry(sroute, &sdev->route_list, list) if (sroute->src_widget == widget || sroute->sink_widget == widget) { - if (sroute->setup && tplg_ops->route_free) + if (sroute->setup && tplg_ops && tplg_ops->route_free) tplg_ops->route_free(sdev, sroute); sroute->setup = false; @@ -30,7 +30,7 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int err = 0; int ret; @@ -47,7 +47,7 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) sof_reset_route_setup_status(sdev, swidget); /* continue to disable core even if IPC fails */ - if (tplg_ops->widget_free) + if (tplg_ops && tplg_ops->widget_free) err = tplg_ops->widget_free(sdev, swidget); /* @@ -82,7 +82,7 @@ EXPORT_SYMBOL(sof_widget_free); int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); int ret; /* skip if there is no private data */ @@ -124,7 +124,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } /* setup widget in the DSP */ - if (tplg_ops->widget_setup) { + if (tplg_ops && tplg_ops->widget_setup) { ret = tplg_ops->widget_setup(sdev, swidget); if (ret < 0) goto core_put; @@ -134,7 +134,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (WIDGET_IS_DAI(swidget->id)) { unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE; - if (tplg_ops->dai_config) { + if (tplg_ops && tplg_ops->dai_config) { ret = tplg_ops->dai_config(sdev, swidget, flags, NULL); if (ret < 0) goto widget_free; @@ -142,7 +142,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } /* restore kcontrols for widget */ - if (tplg_ops->control->widget_kcontrol_setup) { + if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) { ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget); if (ret < 0) goto widget_free; @@ -169,12 +169,11 @@ EXPORT_SYMBOL(sof_widget_setup); int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *src_widget = wsource->dobj.private; struct snd_sof_widget *sink_widget = wsink->dobj.private; struct snd_sof_route *sroute; bool route_found = false; - int ret; /* ignore routes involving virtual widgets in topology */ switch (src_widget->id) { @@ -212,9 +211,12 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc if (sroute->setup) return 0; - ret = ipc_tplg_ops->route_setup(sdev, sroute); - if (ret < 0) - return ret; + if (tplg_ops && tplg_ops->route_setup) { + int ret = tplg_ops->route_setup(sdev, sroute); + + if (ret < 0) + return ret; + } sroute->setup = true; return 0; @@ -266,16 +268,17 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, static void sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *swidget = widget->dobj.private; + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_dapm_path *p; /* return if the widget is in use or if it is already unprepared */ if (!swidget->prepared || swidget->use_count > 1) return; - if (widget_ops[widget->id].ipc_unprepare) + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (widget_ops && widget_ops[widget->id].ipc_unprepare) /* unprepare the source widget */ widget_ops[widget->id].ipc_unprepare(swidget); @@ -297,12 +300,16 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget struct snd_sof_platform_stream_params *platform_params, struct snd_pcm_hw_params *pipeline_params, int dir) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *swidget = widget->dobj.private; + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_dapm_path *p; int ret; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (!widget_ops) + return 0; + if (!widget_ops[widget->id].ipc_prepare || swidget->prepared) goto sink_prepare; @@ -483,7 +490,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, struct snd_sof_platform_stream_params *platform_params, int dir) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; struct snd_soc_dapm_widget *widget; int i, ret; @@ -537,8 +544,8 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, if (pipe_widget->complete) continue; - if (ipc_tplg_ops->pipeline_complete) { - pipe_widget->complete = ipc_tplg_ops->pipeline_complete(sdev, pipe_widget); + if (tplg_ops && tplg_ops->pipeline_complete) { + pipe_widget->complete = tplg_ops->pipeline_complete(sdev, pipe_widget); if (pipe_widget->complete < 0) { ret = pipe_widget->complete; goto widget_free; @@ -626,11 +633,11 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, int dir, bool free_widget_list) { - const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); int ret; /* Send PCM_FREE IPC to reset pipeline */ - if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { + if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { ret = pcm_ops->hw_free(sdev->component, substream); if (ret < 0) return ret; @@ -760,13 +767,13 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); /* use the tplg configured mclk if existed */ if (!dai) return 0; - if (tplg_ops->dai_get_clk) + if (tplg_ops && tplg_ops->dai_get_clk) return tplg_ops->dai_get_clk(sdev, dai, clk_type); return 0; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 29cf951e3526f9..8e4abb1f5f7331 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -166,7 +166,7 @@ struct sof_ipc_tplg_widget_ops { * initialized to 0. * @control: Pointer to the IPC-specific ops for topology kcontrol IO * @route_setup: Function pointer for setting up pipeline connections - * @route_free: Optional op for freeing pipeline connections. + * @route_free: Function pointer for freeing pipeline connections. * @token_list: List of all tokens supported by the IPC version. The size of the token_list * array should be SOF_TOKEN_COUNT. The unused elements in the array will be * initialized to 0. @@ -179,7 +179,9 @@ struct sof_ipc_tplg_widget_ops { * @dai_get_clk: Function pointer for getting the DAI clock setting * @set_up_all_pipelines: Function pointer for setting up all topology pipelines * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines - * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest + * @parse_manifest: Function pointer for ipc4 specific parsing of topology manifest + * + * Note: function pointers (ops) are optional */ struct sof_ipc_tplg_ops { const struct sof_ipc_tplg_widget_ops *widget; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6760fd89595093..752bf46c7bc968 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -444,7 +444,7 @@ struct sof_ipc_pcm_ops; * @pm: Pointer to PM ops * @pcm: Pointer to PCM ops * @fw_loader: Pointer to Firmware Loader ops - * @fw_tracing: Pointer to Firmware tracing ops + * @fw_tracing: Optional pointer to Firmware tracing ops * * @init: Optional pointer for IPC related initialization * @exit: Optional pointer for IPC related cleanup @@ -502,6 +502,10 @@ struct snd_sof_ipc { const struct sof_ipc_ops *ops; }; +/* Helper to retrieve the IPC ops */ +#define sof_ipc_get_ops(sdev, ops_name) \ + (((sdev)->ipc && (sdev)->ipc->ops) ? (sdev)->ipc->ops->ops_name : NULL) + /* * SOF Device Level. */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c668bd9d21ec9b..560771ba8fb911 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -54,11 +54,16 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so size_t object_size, int token_instance_num) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_token_info *token_list; const struct sof_topology_token *tokens; int i, j; + token_list = tplg_ops ? tplg_ops->token_list : NULL; + /* nothing to do if token_list is NULL */ + if (!token_list) + return 0; + if (token_list[token_id].count < 0) { dev_err(scomp->dev, "Invalid token count for token ID: %d\n", token_id); return -EINVAL; @@ -263,9 +268,9 @@ static int set_up_volume_table(struct snd_sof_control *scontrol, { struct snd_soc_component *scomp = scontrol->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (tplg_ops->control->set_up_volume_table) + if (tplg_ops && tplg_ops->control && tplg_ops->control->set_up_volume_table) return tplg_ops->control->set_up_volume_table(scontrol, tlv, size); dev_err(scomp->dev, "Mandatory op %s not set\n", __func__); @@ -490,13 +495,14 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_ int array_size, u32 token_id, int token_instance_num, struct snd_sof_tuple *tuples, int tuples_size, int *num_copied_tuples) { - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_token_info *token_list; const struct sof_topology_token *tokens; int found = 0; int num_tokens, asize; int i, j; + token_list = tplg_ops ? tplg_ops->token_list : NULL; /* nothing to do if token_list is NULL */ if (!token_list) return 0; @@ -1015,14 +1021,14 @@ static int sof_control_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_control *scontrol = dobj->private; int ret = 0; dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scontrol->name); - if (ipc_tplg_ops->control_free) { - ret = ipc_tplg_ops->control_free(sdev, scontrol); + if (tplg_ops && tplg_ops->control_free) { + ret = tplg_ops->control_free(sdev, scontrol); if (ret < 0) dev_err(scomp->dev, "failed to free control: %s\n", scontrol->name); } @@ -1201,12 +1207,17 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s enum sof_tokens *object_token_list, int count) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &tw->priv; + const struct sof_token_info *token_list; int num_tuples = 0; int ret, i; + token_list = tplg_ops ? tplg_ops->token_list : NULL; + /* nothing to do if token_list is NULL */ + if (!token_list) + return 0; + if (count > 0 && !object_token_list) { dev_err(scomp->dev, "No token list for widget %s\n", swidget->widget->name); return -EINVAL; @@ -1375,13 +1386,13 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_dapm_widget *tw) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_soc_tplg_private *priv = &tw->priv; + enum sof_tokens *token_list = NULL; struct snd_sof_widget *swidget; struct snd_sof_dai *dai; - enum sof_tokens *token_list; - int token_list_size; + int token_list_size = 0; int ret = 0; swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); @@ -1440,8 +1451,11 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, swidget->num_sink_pins, swidget->num_source_pins, strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none"); - token_list = widget_ops[w->id].token_list; - token_list_size = widget_ops[w->id].token_list_size; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (widget_ops) { + token_list = widget_ops[w->id].token_list; + token_list_size = widget_ops[w->id].token_list_size; + } /* handle any special case widgets */ switch (w->id) { @@ -1525,7 +1539,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, /* bind widget to external event */ if (tw->event_type) { - if (widget_ops[w->id].bind_event) { + if (widget_ops && widget_ops[w->id].bind_event) { ret = widget_ops[w->id].bind_event(scomp, swidget, le16_to_cpu(tw->event_type)); if (ret) { @@ -1565,8 +1579,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); + const struct sof_ipc_tplg_widget_ops *widget_ops; const struct snd_kcontrol_new *kc; struct snd_soc_dapm_widget *widget; struct snd_sof_control *scontrol; @@ -1626,7 +1640,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp, out: /* free IPC related data */ - if (widget_ops[swidget->id].ipc_free) + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + if (widget_ops && widget_ops[swidget->id].ipc_free) widget_ops[swidget->id].ipc_free(swidget); ida_destroy(&swidget->src_queue_ida); @@ -1784,9 +1799,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ struct snd_soc_tplg_link_config *cfg) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_token_info *token_list = ipc_tplg_ops->token_list; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_soc_tplg_private *private = &cfg->priv; + const struct sof_token_info *token_list; struct snd_sof_dai_link *slink; u32 token_id = 0; int num_tuples = 0; @@ -1856,6 +1871,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ return ret; } + token_list = tplg_ops ? tplg_ops->token_list : NULL; if (!token_list) goto out; @@ -2100,16 +2116,18 @@ static int sof_set_pipe_widget(struct snd_sof_dev *sdev, struct snd_sof_widget * static int sof_complete(struct snd_soc_component *scomp) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); struct snd_sof_widget *swidget, *comp_swidget; - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; - const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + const struct sof_ipc_tplg_widget_ops *widget_ops; struct snd_sof_control *scontrol; int ret; + widget_ops = tplg_ops ? tplg_ops->widget : NULL; + /* first update all control IPC structures based on the IPC version */ - if (ipc_tplg_ops->control_setup) + if (tplg_ops && tplg_ops->control_setup) list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { - ret = ipc_tplg_ops->control_setup(sdev, scontrol); + ret = tplg_ops->control_setup(sdev, scontrol); if (ret < 0) { dev_err(sdev->dev, "failed updating IPC struct for control %s\n", scontrol->name); @@ -2123,7 +2141,7 @@ static int sof_complete(struct snd_soc_component *scomp) * associated memories. */ list_for_each_entry(swidget, &sdev->widget_list, list) { - if (widget_ops[swidget->id].ipc_setup) { + if (widget_ops && widget_ops[swidget->id].ipc_setup) { ret = widget_ops[swidget->id].ipc_setup(swidget); if (ret < 0) { dev_err(sdev->dev, "failed updating IPC struct for %s\n", @@ -2155,15 +2173,16 @@ static int sof_complete(struct snd_soc_component *scomp) /* verify topology components loading including dynamic pipelines */ if (sof_debug_check_flag(SOF_DBG_VERIFY_TPLG)) { - if (ipc_tplg_ops->set_up_all_pipelines && ipc_tplg_ops->tear_down_all_pipelines) { - ret = ipc_tplg_ops->set_up_all_pipelines(sdev, true); + if (tplg_ops && tplg_ops->set_up_all_pipelines && + tplg_ops->tear_down_all_pipelines) { + ret = tplg_ops->set_up_all_pipelines(sdev, true); if (ret < 0) { dev_err(sdev->dev, "Failed to set up all topology pipelines: %d\n", ret); return ret; } - ret = ipc_tplg_ops->tear_down_all_pipelines(sdev, true); + ret = tplg_ops->tear_down_all_pipelines(sdev, true); if (ret < 0) { dev_err(sdev->dev, "Failed to tear down topology pipelines: %d\n", ret); @@ -2173,8 +2192,8 @@ static int sof_complete(struct snd_soc_component *scomp) } /* set up static pipelines */ - if (ipc_tplg_ops->set_up_all_pipelines) - return ipc_tplg_ops->set_up_all_pipelines(sdev, false); + if (tplg_ops && tplg_ops->set_up_all_pipelines) + return tplg_ops->set_up_all_pipelines(sdev, false); return 0; } @@ -2184,10 +2203,10 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); - if (ipc_tplg_ops->parse_manifest) - return ipc_tplg_ops->parse_manifest(scomp, index, man); + if (tplg_ops && tplg_ops->parse_manifest) + return tplg_ops->parse_manifest(scomp, index, man); return 0; } diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 6f662642d61159..b2ab51e5214a93 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -6,19 +6,21 @@ int sof_fw_trace_init(struct snd_sof_dev *sdev) { - if (!sdev->ipc->ops->fw_tracing) { + const struct sof_ipc_fw_tracing_ops *fw_tracing = sof_ipc_get_ops(sdev, fw_tracing); + + if (!fw_tracing) { dev_info(sdev->dev, "Firmware tracing is not available\n"); sdev->fw_trace_is_supported = false; return 0; } - return sdev->ipc->ops->fw_tracing->init(sdev); + return fw_tracing->init(sdev); } void sof_fw_trace_free(struct snd_sof_dev *sdev) { - if (!sdev->fw_trace_is_supported || !sdev->ipc->ops->fw_tracing) + if (!sdev->fw_trace_is_supported) return; if (sdev->ipc->ops->fw_tracing->free)