diff options
53 files changed, 1653 insertions, 141 deletions
diff --git a/Documentation/devicetree/bindings/sound/ak4375.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml index 587598e122c6..bc07fcba535b 100644 --- a/Documentation/devicetree/bindings/sound/ak4375.yaml +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4375.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/ak4375.yaml# +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4375.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: AK4375 DAC and headphones amplifier diff --git a/Documentation/devicetree/bindings/sound/ak4613.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml index 75e13414d6eb..b49a6cff9f1f 100644 --- a/Documentation/devicetree/bindings/sound/ak4613.yaml +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4613.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/ak4613.yaml# +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4613.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: AK4613 I2C transmitter diff --git a/Documentation/devicetree/bindings/sound/ak4642.yaml b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml index 437fe5d7cae1..fc03f0373a1a 100644 --- a/Documentation/devicetree/bindings/sound/ak4642.yaml +++ b/Documentation/devicetree/bindings/sound/asahi-kasei,ak4642.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/ak4642.yaml# +$id: http://devicetree.org/schemas/sound/asahi-kasei,ak4642.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: AK4642 I2C transmitter diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml new file mode 100644 index 000000000000..9582eb8eb418 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs530x.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs530x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic cs530x family of audio ADCs + +maintainers: + - Paul Handrigan <[email protected]> + +description: + The CS530X devices are a family of high performance audio ADCs. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - cirrus,cs5302 + - cirrus,cs5304 + - cirrus,cs5308 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 1 + + reset-gpios: + maxItems: 1 + + vdd-a-supply: + description: Analog power supply + + vdd-io-supply: + description: Digital IO power supply + + cirrus,in-hiz-pin12: + description: + Sets input channels one and two to high impedance. + type: boolean + + cirrus,in-hiz-pin34: + description: + Sets input channels three and four to high impedance. + type: boolean + + cirrus,in-hiz-pin56: + description: + Sets input channels five and six to high impedance. + type: boolean + + cirrus,in-hiz-pin78: + description: + Sets input channels seven and eight to high impedance. + type: boolean + +required: + - compatible + - reg + - "#sound-dai-cells" + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + cs5304: adc@48 { + compatible = "cirrus,cs5304"; + reg = <0x48>; + #sound-dai-cells = <1>; + reset-gpios = <&gpio 110 GPIO_ACTIVE_LOW>; + vdd-a-supply = <&vreg>; + vdd-io-supply = <&vreg>; + cirrus,in-hiz-pin34; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.yaml b/Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml index 1353c051488f..c6ab1ca16763 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,sgtl5000.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/sgtl5000.yaml# +$id: http://devicetree.org/schemas/sound/fsl,sgtl5000.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Freescale SGTL5000 Stereo Codec diff --git a/Documentation/devicetree/bindings/sound/zl38060.yaml b/Documentation/devicetree/bindings/sound/mscc,zl38060.yaml index 8bd201e573aa..994313fd12b2 100644 --- a/Documentation/devicetree/bindings/sound/zl38060.yaml +++ b/Documentation/devicetree/bindings/sound/mscc,zl38060.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/zl38060.yaml# +$id: http://devicetree.org/schemas/sound/mscc,zl38060.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: ZL38060 Connected Home Audio Processor from Microsemi. diff --git a/Documentation/devicetree/bindings/sound/rt1019.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1019.yaml index 3d5a91a942f4..adf5e38f4dbc 100644 --- a/Documentation/devicetree/bindings/sound/rt1019.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt1019.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/rt1019.yaml# +$id: http://devicetree.org/schemas/sound/realtek,rt1019.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: RT1019 Mono Class-D Audio Amplifier diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/ti,tas2562.yaml index d28c102c0ce7..8bc3b0c7531e 100644 --- a/Documentation/devicetree/bindings/sound/tas2562.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas2562.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2019 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas2562.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas2562.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2562 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas2770.yaml b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml index be2536e8c440..362c2e6154f0 100644 --- a/Documentation/devicetree/bindings/sound/tas2770.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas2770.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2019-20 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas2770.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas2770.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2770 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas27xx.yaml b/Documentation/devicetree/bindings/sound/ti,tas27xx.yaml index f2d878f6f495..530bc3937847 100644 --- a/Documentation/devicetree/bindings/sound/tas27xx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas27xx.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2020-2022 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas27xx.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas27xx.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TAS2764/TAS2780 Smart PA diff --git a/Documentation/devicetree/bindings/sound/tas5805m.yaml b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml index 12c41974274e..c2c2835a9e1d 100644 --- a/Documentation/devicetree/bindings/sound/tas5805m.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas5805m.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tas5805m.yaml# +$id: http://devicetree.org/schemas/sound/ti,tas5805m.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: TAS5805M audio amplifier diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml index 8ac741f4cd56..66b76656229f 100644 --- a/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320adc3xxx.yaml @@ -82,6 +82,26 @@ properties: Note that there is currently no support for reading the GPIO pins as inputs. + ti,micbias1-gpo: + type: boolean + description: | + When set, the MICBIAS1 pin may be controlled via the GPIO framework, + as pin number 3 on the device. + + In this mode, when the pin is activated, it will be set to the voltage + specified by the ti,micbias1-vg property. When deactivated, the pin will + float. + + ti,micbias2-gpo: + type: boolean + description: | + When set, the MICBIAS2 pin may be controlled via the GPIO framework, + as pin number 4 on the device. + + In this mode, when the pin is activated, it will be set to the voltage + specified by the ti,micbias2-vg property. When deactivated, the pin will + float. + ti,micbias1-vg: $ref: /schemas/types.yaml#/definitions/uint32 enum: @@ -104,6 +124,10 @@ properties: description: | Mic bias voltage output on MICBIAS2 pin +dependencies: + ti,micbias1-gpo: ['ti,micbias1-vg'] + ti,micbias2-gpo: ['ti,micbias2-vg'] + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml index f3274bcc4c05..876fa97bfbcd 100644 --- a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml @@ -2,7 +2,7 @@ # Copyright (C) 2019 Texas Instruments Incorporated %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/tlv320adcx140.yaml# +$id: http://devicetree.org/schemas/sound/ti,tlv320adcx140.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments TLV320ADCX140 Quad Channel Analog-to-Digital Converter diff --git a/Documentation/devicetree/bindings/sound/wm8750.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8750.yaml index 24246ac7bbdf..96859e38315b 100644 --- a/Documentation/devicetree/bindings/sound/wm8750.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8750.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2 --- -$id: http://devicetree.org/schemas/sound/wm8750.yaml# +$id: http://devicetree.org/schemas/sound/wlf,wm8750.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: WM8750 and WM8987 audio CODECs diff --git a/MAINTAINERS b/MAINTAINERS index aacccb376c28..c35c03901252 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18210,6 +18210,7 @@ QCOM AUDIO (ASoC) DRIVERS M: Srinivas Kandagatla <[email protected]> M: Banajit Goswami <[email protected]> L: [email protected] (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/soc/qcom/qcom,apr* F: Documentation/devicetree/bindings/sound/qcom,* diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index c11aaf8079fb..f6baa9a01868 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -36,6 +36,7 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, struct dma_chan *chan); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); +int snd_dmaengine_pcm_sync_stop(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 12aa1cef11a1..ed07fa5693d2 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -349,6 +349,16 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); +int snd_dmaengine_pcm_sync_stop(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + dmaengine_synchronize(prtd->dma_chan); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_sync_stop); + /** * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream * @substream: PCM substream diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 0bc8617e922a..97258b4cf89b 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -369,12 +369,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct } writel(period_bytes, adata->acp_base + water_val); writel(buf_size, adata->acp_base + buf_reg); + if (rsrc->soc_mclk) + acp_set_i2s_clk(adata, dai->driver->id); val = readl(adata->acp_base + reg_val); val = val | BIT(0); writel(val, adata->acp_base + reg_val); writel(1, adata->acp_base + ier_val); - if (rsrc->soc_mclk) - acp_set_i2s_clk(adata, dai->driver->id); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -584,29 +584,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } -static int acp_i2s_probe(struct snd_soc_dai *dai) -{ - struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_resource *rsrc = adata->rsrc; - unsigned int val; - - if (!adata->acp_base) { - dev_err(dev, "I2S base is NULL\n"); - return -EINVAL; - } - - val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset); - if (val != rsrc->i2s_mode) { - dev_err(dev, "I2S Mode not supported val %x\n", val); - return -EINVAL; - } - - return 0; -} - const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .probe = acp_i2s_probe, .startup = acp_i2s_startup, .hw_params = acp_i2s_hwparams, .prepare = acp_i2s_prepare, diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index 565623afd42e..b0304b813cad 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -100,6 +100,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id ret = -EINVAL; goto release_regions; } + chip->flag = flag; dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(dmic_dev)) { dev_err(dev, "failed to create DMIC device\n"); @@ -139,7 +140,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id } } - chip->flag = flag; memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.name = chip->name; @@ -199,10 +199,12 @@ static int __maybe_unused snd_acp_resume(struct device *dev) ret = acp_init(chip); if (ret) dev_err(dev, "ACP init failed\n"); - child = chip->chip_pdev->dev; - adata = dev_get_drvdata(&child); - if (adata) - acp_enable_interrupts(adata); + if (chip->chip_pdev) { + child = chip->chip_pdev->dev; + adata = dev_get_drvdata(&child); + if (adata) + acp_enable_interrupts(adata); + } return ret; } diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index aaac8aa744cb..4f409cd09c11 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -197,6 +197,20 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs else runtime->hw = acp_pcm_hardware_capture; + ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, DMA_SIZE); + if (ret) { + dev_err(component->dev, "set hw constraint HW_PARAM_PERIOD_BYTES failed\n"); + kfree(stream); + return ret; + } + + ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, DMA_SIZE); + if (ret) { + dev_err(component->dev, "set hw constraint HW_PARAM_BUFFER_BYTES failed\n"); + kfree(stream); + return ret; + } + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) { dev_err(component->dev, "set integer constraint failed\n"); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 158f819f8da4..e19981c7d65a 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -39,8 +39,6 @@ static struct acp_resource rsrc = { .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, - .i2s_pin_cfg_offset = 0x1440, - .i2s_mode = 0x0a, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, }; @@ -231,12 +229,13 @@ static int rembrandt_audio_probe(struct platform_device *pdev) adata->rsrc = &rsrc; adata->platform = REMBRANDT; adata->flag = chip->flag; + adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_rmb_acp_machines; acp_machine_select(adata); dev_set_drvdata(dev, adata); - if (chip->flag != FLAG_AMD_LEGACY_ONLY_DMIC) { + if (chip->is_i2s_config && rsrc.soc_mclk) { ret = acp6x_master_clock_generate(dev); if (ret) return ret; @@ -269,7 +268,7 @@ static int __maybe_unused rmb_pcm_resume(struct device *dev) snd_pcm_uframes_t buf_in_frames; u64 buf_size; - if (adata->flag != FLAG_AMD_LEGACY_ONLY_DMIC) + if (adata->is_i2s_config && adata->rsrc->soc_mclk) acp6x_master_clock_generate(dev); spin_lock(&adata->acp_lock); diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index b0e181c9a733..db835ed7c208 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -32,8 +32,6 @@ static struct acp_resource rsrc = { .no_of_ctrls = 1, .irqp_used = 0, .irq_reg_offset = 0x1800, - .i2s_pin_cfg_offset = 0x1400, - .i2s_mode = 0x04, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x02052800, }; diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index 4d342441a650..f340920b3289 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -55,8 +55,6 @@ static struct acp_resource rsrc = { .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, - .i2s_pin_cfg_offset = 0x1440, - .i2s_mode = 0x0a, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, }; @@ -241,11 +239,12 @@ static int acp63_audio_probe(struct platform_device *pdev) adata->rsrc = &rsrc; adata->platform = ACP63; adata->flag = chip->flag; + adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_acp63_acp_machines; acp_machine_select(adata); dev_set_drvdata(dev, adata); - if (chip->flag != FLAG_AMD_LEGACY_ONLY_DMIC) { + if (chip->is_i2s_config && rsrc.soc_mclk) { ret = acp63_i2s_master_clock_generate(adata); if (ret) return ret; @@ -278,7 +277,7 @@ static int __maybe_unused acp63_pcm_resume(struct device *dev) snd_pcm_uframes_t buf_in_frames; u64 buf_size; - if (adata->flag != FLAG_AMD_LEGACY_ONLY_DMIC) + if (adata->is_i2s_config && adata->rsrc->soc_mclk) acp63_i2s_master_clock_generate(adata); spin_lock(&adata->acp_lock); diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index 0d7cdd4017e5..a2cbdcca4313 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -31,8 +31,6 @@ static struct acp_resource rsrc = { .irqp_used = 1, .soc_mclk = true, .irq_reg_offset = 0x1a00, - .i2s_pin_cfg_offset = 0x1440, - .i2s_mode = 0x0a, .scratch_reg_offset = 0x12800, .sram_pte_offset = 0x03802800, }; diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index d75b4eb34de8..87a4813783f9 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -162,8 +162,6 @@ struct acp_resource { int irqp_used; bool soc_mclk; u32 irq_reg_offset; - u32 i2s_pin_cfg_offset; - int i2s_mode; u64 scratch_reg_offset; u64 sram_pte_offset; }; @@ -175,6 +173,7 @@ struct acp_dev_data { unsigned int i2s_irq; bool tdm_mode; + bool is_i2s_config; /* SOC specific dais */ struct snd_soc_dai_driver *dai_driver; int num_dai; diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 6aed1ee443b4..ba314b279919 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -473,19 +473,22 @@ static int atmel_classd_asoc_card_init(struct device *dev, if (!dai_link) return -ENOMEM; - comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); + comp = devm_kzalloc(dev, 2 * sizeof(*comp), GFP_KERNEL); if (!comp) return -ENOMEM; - dai_link->cpus = comp; + dai_link->cpus = &comp[0]; dai_link->codecs = &snd_soc_dummy_dlc; + dai_link->platforms = &comp[1]; dai_link->num_cpus = 1; dai_link->num_codecs = 1; + dai_link->num_platforms = 1; dai_link->name = "CLASSD"; dai_link->stream_name = "CLASSD PCM"; dai_link->cpus->dai_name = dev_name(dev); + dai_link->platforms->name = dev_name(dev); card->dai_link = dai_link; card->num_links = 1; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a99cb26eb280..1f539c4b9432 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -99,6 +99,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS47L90 imply SND_SOC_CS47L92 imply SND_SOC_CS53L30 + imply SND_SOC_CS530X_I2C imply SND_SOC_CX20442 imply SND_SOC_CX2072X imply SND_SOC_DA7210 @@ -1000,6 +1001,19 @@ config SND_SOC_CS53L30 tristate "Cirrus Logic CS53L30 CODEC" depends on I2C +config SND_SOC_CS530X + tristate + +config SND_SOC_CS530X_I2C + tristate "Cirrus Logic CS530x ADCs (I2C)" + depends on I2C + select REGMAP + select REGMAP_I2C + select SND_SOC_CS530X + help + Enable support for Cirrus Logic CS530X ADCs + with I2C control. + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index ad0f77224c74..c2c0d02b5484 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -107,6 +107,8 @@ snd-soc-cs47l85-y := cs47l85.o snd-soc-cs47l90-y := cs47l90.o snd-soc-cs47l92-y := cs47l92.o snd-soc-cs53l30-y := cs53l30.o +snd-soc-cs530x-y := cs530x.o +snd-soc-cs530x-i2c-y := cs530x-i2c.o snd-soc-cx20442-y := cx20442.o snd-soc-cx2072x-y := cx2072x.o snd-soc-da7210-y := da7210.o @@ -509,6 +511,8 @@ obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o +obj-$(CONFIG_SND_SOC_CS530X) += snd-soc-cs530x.o +obj-$(CONFIG_SND_SOC_CS530X_I2C) += snd-soc-cs530x-i2c.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 569bab3a2a6e..880228f89baf 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -215,6 +215,10 @@ static const struct reg_sequence cs35l56_asp1_defaults[] = { REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100), REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018), REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018), + REG_SEQ0(CS35L56_ASP1TX1_INPUT, 0x00000000), + REG_SEQ0(CS35L56_ASP1TX2_INPUT, 0x00000000), + REG_SEQ0(CS35L56_ASP1TX3_INPUT, 0x00000000), + REG_SEQ0(CS35L56_ASP1TX4_INPUT, 0x00000000), }; /* diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index 901b9dbcf585..d9ab003e166b 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -121,7 +121,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, priv->buttons[3] = 735; } - ret = cs42l43_find_index(priv, "cirrus,detect-us", 1000, &priv->detect_us, + ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us, cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us)); if (ret < 0) goto error; @@ -433,7 +433,7 @@ irqreturn_t cs42l43_button_press(int irq, void *data) // Wait for 2 full cycles of comb filter to ensure good reading queue_delayed_work(system_wq, &priv->button_press_work, - msecs_to_jiffies(10)); + msecs_to_jiffies(20)); return IRQ_HANDLED; } diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c new file mode 100644 index 000000000000..56659bf735db --- /dev/null +++ b/sound/soc/codecs/cs530x-i2c.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS530x CODEC driver +// +// Copyright (C) 2024 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> + +#include "cs530x.h" + +static const struct of_device_id cs530x_of_match[] = { + { + .compatible = "cirrus,cs5302", + .data = (void *)CS5302, + }, { + .compatible = "cirrus,cs5304", + .data = (void *)CS5304, + }, { + .compatible = "cirrus,cs5308", + .data = (void *)CS5308, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cs530x_of_match); + +static const struct i2c_device_id cs530x_i2c_id[] = { + { "cs5302", CS5302 }, + { "cs5304", CS5304 }, + { "cs5308", CS5308 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs530x_i2c_id); + +static int cs530x_i2c_probe(struct i2c_client *client) +{ + struct cs530x_priv *cs530x; + + cs530x = devm_kzalloc(&client->dev, sizeof(*cs530x), GFP_KERNEL); + if (!cs530x) + return -ENOMEM; + + i2c_set_clientdata(client, cs530x); + + cs530x->regmap = devm_regmap_init_i2c(client, &cs530x_regmap); + if (IS_ERR(cs530x->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(cs530x->regmap), + "Failed to allocate register map\n"); + + cs530x->devtype = (uintptr_t)i2c_get_match_data(client); + cs530x->dev = &client->dev; + + return cs530x_probe(cs530x); +} + +static struct i2c_driver cs530x_i2c_driver = { + .driver = { + .name = "cs530x", + .of_match_table = cs530x_of_match, + }, + .probe = cs530x_i2c_probe, + .id_table = cs530x_i2c_id, +}; +module_i2c_driver(cs530x_i2c_driver); + +MODULE_DESCRIPTION("I2C CS530X driver"); +MODULE_IMPORT_NS(SND_SOC_CS530X); +MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c new file mode 100644 index 000000000000..036d0f45e3ba --- /dev/null +++ b/sound/soc/codecs/cs530x.c @@ -0,0 +1,966 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// CS530x CODEC driver +// +// Copyright (C) 2024 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include <sound/core.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <sound/initval.h> +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/pm.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "cs530x.h" + +#define CS530X_MAX_ADC_CH 8 +#define CS530X_MIN_ADC_CH 2 + +static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = { + "vdd-a", + "vdd-io", +}; + +static const struct reg_default cs530x_reg_defaults[] = { + { CS530X_CLK_CFG_0, 0x30 }, + { CS530X_CLK_CFG_1, 0x0001 }, + { CS530X_CHIP_ENABLE, 0 }, + { CS530X_ASP_CFG, 0 }, + { CS530X_SIGNAL_PATH_CFG, 0 }, + { CS530X_IN_ENABLES, 0 }, + { CS530X_IN_RAMP_SUM, 0x0022 }, + { CS530X_IN_FILTER, 0 }, + { CS530X_IN_HIZ, 0 }, + { CS530X_IN_INV, 0 }, + { CS530X_IN_VOL_CTRL1_0, 0x8000 }, + { CS530X_IN_VOL_CTRL1_1, 0x8000 }, + { CS530X_IN_VOL_CTRL2_0, 0x8000 }, + { CS530X_IN_VOL_CTRL2_1, 0x8000 }, + { CS530X_IN_VOL_CTRL3_0, 0x8000 }, + { CS530X_IN_VOL_CTRL3_1, 0x8000 }, + { CS530X_IN_VOL_CTRL4_0, 0x8000 }, + { CS530X_IN_VOL_CTRL4_1, 0x8000 }, + { CS530X_PAD_FN, 0 }, + { CS530X_PAD_LVL, 0 }, +}; + +static bool cs530x_read_and_write_regs(unsigned int reg) +{ + switch (reg) { + case CS530X_CLK_CFG_0: + case CS530X_CLK_CFG_1: + case CS530X_CHIP_ENABLE: + case CS530X_ASP_CFG: + case CS530X_SIGNAL_PATH_CFG: + case CS530X_IN_ENABLES: + case CS530X_IN_RAMP_SUM: + case CS530X_IN_FILTER: + case CS530X_IN_HIZ: + case CS530X_IN_INV: + case CS530X_IN_VOL_CTRL1_0: + case CS530X_IN_VOL_CTRL1_1: + case CS530X_IN_VOL_CTRL2_0: + case CS530X_IN_VOL_CTRL2_1: + case CS530X_IN_VOL_CTRL3_0: + case CS530X_IN_VOL_CTRL3_1: + case CS530X_IN_VOL_CTRL4_0: + case CS530X_IN_VOL_CTRL4_1: + case CS530X_PAD_FN: + case CS530X_PAD_LVL: + return true; + default: + return false; + } +} + +static bool cs530x_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS530X_DEVID: + case CS530X_REVID: + return true; + default: + return cs530x_read_and_write_regs(reg); + } +} + +static bool cs530x_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS530X_SW_RESET: + case CS530X_IN_VOL_CTRL5: + return true; + default: + return cs530x_read_and_write_regs(reg); + } +} + +static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + int ret; + + snd_soc_dapm_mutex_lock(dapm); + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + if (ret) + goto volsw_err; + + /* Write IN_VU bit for the volume change to take effect */ + regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU); + +volsw_err: + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0); + +static const char * const cs530x_in_hpf_text[] = { + "Min Phase Slow Roll-off", + "Min Phase Fast Roll-off", + "Linear Phase Slow Roll-off", + "Linear Phase Fast Roll-off", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_in_hpf_enum, CS530X_IN_FILTER, + CS530X_IN_FILTER_SHIFT, + cs530x_in_hpf_text); + +static const char * const cs530x_in_4ch_sum_text[] = { + "None", + "Groups of 2", + "Groups of 4", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM, + CS530X_IN_SUM_MODE_SHIFT, + cs530x_in_4ch_sum_text); + +static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = { +SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum), +}; + +static const char * const cs530x_in_8ch_sum_text[] = { + "None", + "Groups of 2", + "Groups of 4", + "Groups of 8", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM, + CS530X_IN_SUM_MODE_SHIFT, + cs530x_in_8ch_sum_text); + +static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = { +SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum), +}; + + +static const char * const cs530x_vol_ramp_text[] = { + "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", + "15ms/6dB", "30ms/6dB", +}; + +static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM, + CS530X_RAMP_RATE_INC_SHIFT, + cs530x_vol_ramp_text); + +static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM, + CS530X_RAMP_RATE_DEC_SHIFT, + cs530x_vol_ramp_text); + +static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = { +SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_ENUM("IN HPF Select", cs530x_in_hpf_enum), +SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum), +SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum), + +SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = { +SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = { +SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), +SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1, + snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv), + +SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0), +SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0), +}; + +static int cs530x_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + cs530x->adc_pairs_count++; + break; + case SND_SOC_DAPM_POST_PMU: + regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + (w->shift * 2), CS530X_IN_MUTE); + regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + ((w->shift+1) * 2), CS530X_IN_MUTE); + + cs530x->adc_pairs_count--; + if (!cs530x->adc_pairs_count) { + usleep_range(1000, 1100); + return regmap_write(regmap, CS530X_IN_VOL_CTRL5, + CS530X_IN_VU); + } + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + (w->shift * 2), CS530X_IN_MUTE); + regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 + + ((w->shift+1) * 2), CS530X_IN_MUTE); + return regmap_write(regmap, CS530X_IN_VOL_CTRL5, + CS530X_IN_VU); + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_kcontrol_new adc12_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new adc34_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new adc56_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new adc78_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const struct snd_kcontrol_new in_hpf_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +/* General DAPM widgets for all devices */ +static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0), +}; + +/* ADC's Channels 1 and 2 plus generic ADC DAPM events */ +static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN1"), +SND_SOC_DAPM_INPUT("IN2"), +SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0), +SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl), +SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT, + 0, &in_hpf_ctrl), +}; + +/* ADC's Channels 3 and 4 */ +static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN3"), +SND_SOC_DAPM_INPUT("IN4"), +SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0), +SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl), +}; + +/* ADC's Channels 5 to 8 */ +static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("IN5"), +SND_SOC_DAPM_INPUT("IN6"), +SND_SOC_DAPM_INPUT("IN7"), +SND_SOC_DAPM_INPUT("IN8"), +SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0), +SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl), +SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0, + cs530x_adc_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0), +SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl), +}; + +static const struct snd_soc_dapm_route adc_ch1_2_routes[] = { + { "ADC1", NULL, "Global Enable" }, + { "ADC2", NULL, "Global Enable" }, + + { "ADC12 Enable", "Switch", "IN1" }, + { "ADC12 Enable", "Switch", "IN2" }, + { "ADC1", NULL, "ADC12 Enable" }, + { "ADC2", NULL, "ADC12 Enable" }, + { "IN HPF", "Switch", "ADC1" }, + { "IN HPF", "Switch", "ADC2" }, + + { "AIF Capture", NULL, "IN HPF" }, + { "AIF Capture", NULL, "ADC1" }, + { "AIF Capture", NULL, "ADC2" }, +}; + +static const struct snd_soc_dapm_route adc_ch3_4_routes[] = { + { "ADC3", NULL, "Global Enable" }, + { "ADC4", NULL, "Global Enable" }, + + { "ADC34 Enable", "Switch", "IN3" }, + { "ADC34 Enable", "Switch", "IN4" }, + { "ADC3", NULL, "ADC34 Enable" }, + { "ADC4", NULL, "ADC34 Enable" }, + { "IN HPF", "Switch", "ADC3" }, + { "IN HPF", "Switch", "ADC4" }, + + { "AIF Capture", NULL, "ADC3" }, + { "AIF Capture", NULL, "ADC4" }, +}; + +static const struct snd_soc_dapm_route adc_ch5_8_routes[] = { + { "ADC5", NULL, "Global Enable" }, + { "ADC6", NULL, "Global Enable" }, + { "ADC7", NULL, "Global Enable" }, + { "ADC8", NULL, "Global Enable" }, + + { "ADC56 Enable", "Switch", "IN5" }, + { "ADC56 Enable", "Switch", "IN6" }, + { "ADC5", NULL, "ADC56 Enable" }, + { "ADC6", NULL, "ADC56 Enable" }, + { "IN HPF", "Switch", "ADC5" }, + { "IN HPF", "Switch", "ADC6" }, + + { "AIF Capture", NULL, "ADC5" }, + { "AIF Capture", NULL, "ADC6" }, + + { "ADC78 Enable", "Switch", "IN7" }, + { "ADC78 Enable", "Switch", "IN8" }, + { "ADC7", NULL, "ADC78 Enable" }, + { "ADC8", NULL, "ADC78 Enable" }, + { "IN HPF", "Switch", "ADC7" }, + { "IN HPF", "Switch", "ADC8" }, + + { "AIF Capture", NULL, "ADC7" }, + { "AIF Capture", NULL, "ADC8" }, +}; + +static void cs530x_add_12_adc_widgets(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_add_component_controls(component, + cs530x_in_1_to_2_controls, + ARRAY_SIZE(cs530x_in_1_to_2_controls)); + + snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets, + ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes, + ARRAY_SIZE(adc_ch1_2_routes)); +} + +static void cs530x_add_34_adc_widgets(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_add_component_controls(component, + cs530x_in_3_to_4_controls, + ARRAY_SIZE(cs530x_in_3_to_4_controls)); + + snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets, + ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes, + ARRAY_SIZE(adc_ch3_4_routes)); +} + +static int cs530x_set_bclk(struct snd_soc_component *component) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + unsigned int bclk_val; + + switch (cs530x->bclk) { + case 2822400: + case 3072000: + bclk_val = CS530X_BCLK_2P822_3P072; + break; + case 5644800: + case 6144000: + bclk_val = CS530X_BCLK_5P6448_6P144; + break; + case 11289600: + case 12288000: + bclk_val = CS530X_BCLK_11P2896_12P288; + break; + case 22579200: + case 24576000: + bclk_val = CS530X_BCLK_24P5792_24P576; + break; + default: + dev_err(component->dev, "Invalid BCLK %d\n", cs530x->bclk); + return -EINVAL; + } + + dev_dbg(component->dev, "BCLK is %d\n", cs530x->bclk); + + return regmap_update_bits(regmap, CS530X_ASP_CFG, + CS530X_ASP_BCLK_FREQ_MASK, bclk_val); +} + +static int cs530x_set_pll_refclk(struct snd_soc_component *component, + const unsigned int freq) +{ + struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); + struct regmap *regmap = priv->regmap; + unsigned int refclk; + + switch (freq) { + case 2822400: + case 3072000: + refclk = CS530X_REFCLK_2P822_3P072; + break; + case 5644800: + case 6144000: + refclk = CS530X_REFCLK_5P6448_6P144; + break; + case 11289600: + case 12288000: + refclk = CS530X_REFCLK_11P2896_12P288; + break; + case 22579200: + case 24576000: + refclk = CS530X_REFCLK_24P5792_24P576; + break; + default: + dev_err(component->dev, "Invalid PLL refclk %d\n", freq); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_CLK_CFG_0, + CS530X_PLL_REFCLK_FREQ_MASK, refclk); +} + +static int cs530x_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 cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + int ret = 0, fs = params_rate(params); + unsigned int fs_val; + + + switch (fs) { + case 32000: + fs_val = CS530X_FS_32K; + break; + case 44100: + case 48000: + fs_val = CS530X_FS_48K_44P1K; + break; + case 88200: + case 96000: + fs_val = CS530X_FS_96K_88P2K; + break; + case 176400: + case 192000: + fs_val = CS530X_FS_192K_176P4K; + break; + case 356800: + case 384000: + fs_val = CS530X_FS_384K_356P8K; + break; + case 705600: + case 768000: + fs_val = CS530X_FS_768K_705P6K; + break; + default: + dev_err(component->dev, "Invalid sample rate %d\n", fs); + return -EINVAL; + } + + cs530x->fs = fs; + regmap_update_bits(regmap, CS530X_CLK_CFG_1, + CS530X_SAMPLE_RATE_MASK, fs_val); + + if (cs530x->tdm_slots) { + dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n", + cs530x->tdm_slots, cs530x->tdm_width); + cs530x->bclk = snd_soc_calc_bclk(cs530x->fs, + cs530x->tdm_width, + params_channels(params), + cs530x->tdm_slots); + } else { + cs530x->bclk = snd_soc_params_to_bclk(params); + } + + if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0, + CS530X_PLL_REFCLK_SRC_MASK)) { + ret = cs530x_set_pll_refclk(component, cs530x->bclk); + if (ret) + return ret; + } + + return cs530x_set_bclk(component); +} + +static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct cs530x_priv *priv = snd_soc_component_get_drvdata(component); + struct regmap *regmap = priv->regmap; + unsigned int asp_fmt, asp_cfg = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + case SND_SOC_DAIFMT_CBM_CFM: + asp_cfg = CS530X_ASP_PRIMARY; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + asp_fmt = CS530X_ASP_FMT_DSP_A; + break; + case SND_SOC_DAIFMT_I2S: + asp_fmt = CS530X_ASP_FMT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + asp_fmt = CS530X_ASP_FMT_LJ; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + asp_cfg |= CS530X_ASP_BCLK_INV; + break; + default: + return -EINVAL; + } + + regmap_update_bits(regmap, CS530X_ASP_CFG, + CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV, + asp_cfg); + + return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, + CS530X_ASP_FMT_MASK, asp_fmt); +} + +static bool cs530x_check_mclk_freq(struct snd_soc_component *component, + const unsigned int freq) +{ + switch (freq) { + case 24576000: + case 22579200: + case 12288000: + case 11289600: + return true; + default: + dev_err(component->dev, "Invalid MCLK %d\n", freq); + return false; + } +} + +static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + unsigned int val; + + switch (tx_mask) { + case CS530X_0_1_TDM_SLOT_MASK: + case CS530X_0_3_TDM_SLOT_MASK: + case CS530X_0_7_TDM_SLOT_MASK: + val = CS530X_0_7_TDM_SLOT_VAL; + break; + case CS530X_2_3_TDM_SLOT_MASK: + val = CS530X_2_3_TDM_SLOT_VAL; + break; + case CS530X_4_5_TDM_SLOT_MASK: + case CS530X_4_7_TDM_SLOT_MASK: + val = CS530X_4_7_TDM_SLOT_VAL; + break; + case CS530X_6_7_TDM_SLOT_MASK: + val = CS530X_6_7_TDM_SLOT_VAL; + break; + case CS530X_8_9_TDM_SLOT_MASK: + case CS530X_8_11_TDM_SLOT_MASK: + case CS530X_8_15_TDM_SLOT_MASK: + val = CS530X_8_15_TDM_SLOT_VAL; + break; + case CS530X_10_11_TDM_SLOT_MASK: + val = CS530X_10_11_TDM_SLOT_VAL; + break; + case CS530X_12_13_TDM_SLOT_MASK: + case CS530X_12_15_TDM_SLOT_MASK: + val = CS530X_12_15_TDM_SLOT_VAL; + break; + case CS530X_14_15_TDM_SLOT_MASK: + val = CS530X_14_15_TDM_SLOT_VAL; + break; + default: + dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG, + CS530X_ASP_TDM_SLOT_MASK, + val << CS530X_ASP_TDM_SLOT_SHIFT); +} + +static const struct snd_soc_dai_ops cs530x_dai_ops = { + .set_fmt = cs530x_set_fmt, + .hw_params = cs530x_hw_params, + .set_tdm_slot = cs530x_set_tdm_slot, +}; + +static const struct snd_soc_dai_driver cs530x_dai = { + .name = "cs530x-dai", + .capture = { + .stream_name = "AIF Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &cs530x_dai_ops, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, +}; + +static int cs530x_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + unsigned int sysclk_src; + int ret; + + regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src); + + /* Check if the source is the PLL */ + if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0) + return 0; + + switch (source) { + case CS530X_PLL_SRC_MCLK: + if (!cs530x_check_mclk_freq(component, freq_in)) + return -EINVAL; + + ret = cs530x_set_pll_refclk(component, freq_in); + if (ret) + return ret; + + break; + case CS530X_PLL_SRC_BCLK: + break; + default: + dev_err(component->dev, "Invalid PLL source %d\n", source); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_CLK_CFG_0, + CS530X_PLL_REFCLK_SRC_MASK, source); +} + +static int cs530x_component_probe(struct snd_soc_component *component) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + int num_widgets; + + snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets, + ARRAY_SIZE(cs530x_gen_dapm_widgets)); + + switch (cs530x->devtype) { + case CS5302: + cs530x_add_12_adc_widgets(component); + break; + case CS5304: + cs530x_add_12_adc_widgets(component); + cs530x_add_34_adc_widgets(component); + + num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls); + snd_soc_add_component_controls(component, + cs530x_in_sum_4ch_controls, + num_widgets); + break; + + case CS5308: + cs530x_add_12_adc_widgets(component); + cs530x_add_34_adc_widgets(component); + + num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls); + snd_soc_add_component_controls(component, + cs530x_in_5_to_8_controls, + num_widgets); + + num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls); + snd_soc_add_component_controls(component, + cs530x_in_sum_8ch_controls, + num_widgets); + + num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets); + snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets, + num_widgets); + + snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes, + ARRAY_SIZE(adc_ch5_8_routes)); + break; + default: + dev_err(component->dev, "Invalid device type %d\n", + cs530x->devtype); + return -EINVAL; + } + + return 0; +} + +static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id, + int source, unsigned int freq, int dir) +{ + struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cs530x->regmap; + + switch (source) { + case CS530X_SYSCLK_SRC_MCLK: + if (freq != 24560000 && freq != 22572000) { + dev_err(component->dev, "Invalid MCLK source rate %d\n", + freq); + return -EINVAL; + } + + cs530x->mclk_rate = freq; + break; + case CS530X_SYSCLK_SRC_PLL: + break; + default: + dev_err(component->dev, "Invalid clock id %d\n", clk_id); + return -EINVAL; + } + + return regmap_update_bits(regmap, CS530X_CLK_CFG_0, + CS530X_SYSCLK_SRC_MASK, + source << CS530X_SYSCLK_SRC_SHIFT); +} + +static const struct snd_soc_component_driver soc_component_dev_cs530x = { + .probe = cs530x_component_probe, + .set_sysclk = cs530x_set_sysclk, + .set_pll = cs530x_set_pll, + .endianness = 1, +}; + +const struct regmap_config cs530x_regmap = { + .reg_bits = 16, + .val_bits = 16, + + .max_register = CS530X_MAX_REGISTER, + .readable_reg = cs530x_readable_register, + .writeable_reg = cs530x_writeable_register, + + .cache_type = REGCACHE_MAPLE, + .reg_defaults = cs530x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), +}; +EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X); + +static int cs530x_check_device_id(struct cs530x_priv *cs530x) +{ + struct device *dev = cs530x->dev; + unsigned int dev_id, rev; + int ret; + + ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id); + if (ret) + return dev_err_probe(dev, ret, "Can't read device ID\n"); + + ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev); + if (ret) + return dev_err_probe(dev, ret, "Can't read REV ID\n"); + + dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev); + + switch (dev_id) { + case CS530X_2CH_ADC_DEV_ID: + cs530x->num_adcs = 2; + break; + case CS530X_4CH_ADC_DEV_ID: + cs530x->num_adcs = 4; + break; + case CS530X_8CH_ADC_DEV_ID: + cs530x->num_adcs = 8; + break; + default: + return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n", + dev_id); + } + + return 0; +} + +static int cs530x_parse_device_properties(struct cs530x_priv *cs530x) +{ + struct regmap *regmap = cs530x->regmap; + struct device *dev = cs530x->dev; + unsigned int val = 0; + + switch (cs530x->num_adcs) { + case 8: + if (device_property_read_bool(dev, "cirrus,in-hiz-pin78")) + val = CS530X_IN78_HIZ; + + if (device_property_read_bool(dev, "cirrus,in-hiz-pin56")) + val |= CS530X_IN56_HIZ; + + fallthrough; + case 4: + if (device_property_read_bool(dev, "cirrus,in-hiz-pin34")) + val |= CS530X_IN34_HIZ; + + fallthrough; + case 2: + if (device_property_read_bool(dev, "cirrus,in-hiz-pin12")) + val |= CS530X_IN12_HIZ; + + return regmap_set_bits(regmap, CS530X_IN_HIZ, val); + default: + return dev_err_probe(dev, -EINVAL, + "Invalid number of adcs %d\n", + cs530x->num_adcs); + } +} + +int cs530x_probe(struct cs530x_priv *cs530x) +{ + struct device *dev = cs530x->dev; + int ret, i; + + cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai, + sizeof(*(cs530x->dev_dai)), + GFP_KERNEL); + if (!cs530x->dev_dai) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++) + cs530x->supplies[i].supply = cs530x_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies), + cs530x->supplies); + if (ret != 0) + return dev_err_probe(dev, ret, "Failed to request supplies"); + + ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies), + cs530x->supplies); + if (ret != 0) + return dev_err_probe(dev, ret, "Failed to enable supplies"); + + cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(cs530x->reset_gpio)) { + ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio), + "Reset gpio not available\n"); + goto err_regulator; + } + + if (cs530x->reset_gpio) { + usleep_range(2000, 2100); + gpiod_set_value_cansleep(cs530x->reset_gpio, 0); + } + + usleep_range(5000, 5100); + ret = cs530x_check_device_id(cs530x); + if (ret) + goto err_reset; + + if (!cs530x->reset_gpio) { + ret = regmap_write(cs530x->regmap, CS530X_SW_RESET, + CS530X_SW_RST_VAL); + if (ret) { + dev_err_probe(dev, ret, "Soft Reset Failed\n"); + goto err_reset; + } + } + + ret = cs530x_parse_device_properties(cs530x); + if (ret) + goto err_reset; + + cs530x->dev_dai->capture.channels_max = cs530x->num_adcs; + + ret = devm_snd_soc_register_component(dev, + &soc_component_dev_cs530x, cs530x->dev_dai, 1); + if (ret) { + dev_err_probe(dev, ret, "Can't register cs530x component\n"); + goto err_reset; + } + + return 0; + +err_reset: + gpiod_set_value_cansleep(cs530x->reset_gpio, 1); + +err_regulator: + regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies), + cs530x->supplies); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X); + +MODULE_DESCRIPTION("CS530X CODEC Driver"); +MODULE_AUTHOR("Paul Handrigan <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h new file mode 100644 index 000000000000..1c85310a5d03 --- /dev/null +++ b/sound/soc/codecs/cs530x.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CS530x CODEC driver internal data + * + * Copyright (C) 2023-2024 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#ifndef _CS530X_H +#define _CS530X_H + +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +/* Devices */ +#define CS530X_2CH_ADC_DEV_ID 0x5302 +#define CS530X_4CH_ADC_DEV_ID 0x5304 +#define CS530X_8CH_ADC_DEV_ID 0x5308 + +/* Registers */ + +#define CS530X_DEVID 0x0000000 +#define CS530X_REVID 0x0000004 +#define CS530X_SW_RESET 0x0000022 + +#define CS530X_CLK_CFG_0 0x0000040 +#define CS530X_CLK_CFG_1 0x0000042 +#define CS530X_CHIP_ENABLE 0x0000044 +#define CS530X_ASP_CFG 0x0000048 +#define CS530X_SIGNAL_PATH_CFG 0x0000050 +#define CS530X_IN_ENABLES 0x0000080 +#define CS530X_IN_RAMP_SUM 0x0000082 +#define CS530X_IN_FILTER 0x0000086 +#define CS530X_IN_HIZ 0x0000088 +#define CS530X_IN_INV 0x000008A +#define CS530X_IN_VOL_CTRL1_0 0x0000090 +#define CS530X_IN_VOL_CTRL1_1 0x0000092 +#define CS530X_IN_VOL_CTRL2_0 0x0000094 +#define CS530X_IN_VOL_CTRL2_1 0x0000096 +#define CS530X_IN_VOL_CTRL3_0 0x0000098 +#define CS530X_IN_VOL_CTRL3_1 0x000009A +#define CS530X_IN_VOL_CTRL4_0 0x000009C +#define CS530X_IN_VOL_CTRL4_1 0x000009E +#define CS530X_IN_VOL_CTRL5 0x00000A0 + +#define CS530X_PAD_FN 0x0003D24 +#define CS530X_PAD_LVL 0x0003D28 + +#define CS530X_MAX_REGISTER CS530X_PAD_LVL + +/* Register Fields */ + +/* REVID */ +#define CS530X_MTLREVID GENMASK(3, 0) +#define CS530X_AREVID GENMASK(7, 4) + +/* SW_RESET */ +#define CS530X_SW_RST_SHIFT 8 +#define CS530X_SW_RST_VAL (0x5A << CS530X_SW_RST_SHIFT) + +/* CLK_CFG_0 */ +#define CS530X_PLL_REFCLK_SRC_MASK BIT(0) +#define CS530X_PLL_REFCLK_FREQ_MASK GENMASK(5, 4) +#define CS530X_SYSCLK_SRC_MASK BIT(12) +#define CS530X_SYSCLK_SRC_SHIFT 12 +#define CS530X_REFCLK_2P822_3P072 0 +#define CS530X_REFCLK_5P6448_6P144 0x10 +#define CS530X_REFCLK_11P2896_12P288 0x20 +#define CS530X_REFCLK_24P5792_24P576 0x30 + +/* CLK_CFG_1 */ +#define CS530X_SAMPLE_RATE_MASK GENMASK(2, 0) +#define CS530X_FS_32K 0 +#define CS530X_FS_48K_44P1K 1 +#define CS530X_FS_96K_88P2K 2 +#define CS530X_FS_192K_176P4K 3 +#define CS530X_FS_384K_356P8K 4 +#define CS530X_FS_768K_705P6K 5 + +/* CHIP_ENABLE */ +#define CS530X_GLOBAL_EN BIT(0) + +/* ASP_CFG */ +#define CS530X_ASP_BCLK_FREQ_MASK GENMASK(1, 0) +#define CS530X_ASP_PRIMARY BIT(5) +#define CS530X_ASP_BCLK_INV BIT(6) +#define CS530X_BCLK_2P822_3P072 0 +#define CS530X_BCLK_5P6448_6P144 1 +#define CS530X_BCLK_11P2896_12P288 2 +#define CS530X_BCLK_24P5792_24P576 3 + +/* SIGNAL_PATH_CFG */ +#define CS530X_ASP_FMT_MASK GENMASK(2, 0) +#define CS530X_ASP_TDM_SLOT_MASK GENMASK(5, 3) +#define CS530X_ASP_TDM_SLOT_SHIFT 3 +#define CS530X_ASP_CH_REVERSE BIT(9) +#define CS530X_ASP_FMT_I2S 0 +#define CS530X_ASP_FMT_LJ 1 +#define CS530X_ASP_FMT_DSP_A 0x6 + +/* TDM Slots */ +#define CS530X_0_1_TDM_SLOT_MASK GENMASK(1, 0) +#define CS530X_0_3_TDM_SLOT_MASK GENMASK(3, 0) +#define CS530X_0_7_TDM_SLOT_MASK GENMASK(7, 0) +#define CS530X_0_7_TDM_SLOT_VAL 0 + +#define CS530X_2_3_TDM_SLOT_MASK GENMASK(3, 2) +#define CS530X_2_3_TDM_SLOT_VAL 1 + +#define CS530X_4_5_TDM_SLOT_MASK GENMASK(5, 4) +#define CS530X_4_7_TDM_SLOT_MASK GENMASK(7, 4) +#define CS530X_4_7_TDM_SLOT_VAL 2 + +#define CS530X_6_7_TDM_SLOT_MASK GENMASK(7, 6) +#define CS530X_6_7_TDM_SLOT_VAL 3 + +#define CS530X_8_9_TDM_SLOT_MASK GENMASK(9, 8) +#define CS530X_8_11_TDM_SLOT_MASK GENMASK(11, 8) +#define CS530X_8_15_TDM_SLOT_MASK GENMASK(15, 8) +#define CS530X_8_15_TDM_SLOT_VAL 4 + +#define CS530X_10_11_TDM_SLOT_MASK GENMASK(11, 10) +#define CS530X_10_11_TDM_SLOT_VAL 5 + +#define CS530X_12_13_TDM_SLOT_MASK GENMASK(13, 12) +#define CS530X_12_15_TDM_SLOT_MASK GENMASK(15, 12) +#define CS530X_12_15_TDM_SLOT_VAL 6 + +#define CS530X_14_15_TDM_SLOT_MASK GENMASK(15, 14) +#define CS530X_14_15_TDM_SLOT_VAL 7 + +/* IN_RAMP_SUM */ +#define CS530X_RAMP_RATE_INC_SHIFT 0 +#define CS530X_RAMP_RATE_DEC_SHIFT 4 +#define CS530X_IN_SUM_MODE_SHIFT 13 + +/* IN_FILTER */ +#define CS530X_IN_FILTER_SHIFT 8 +#define CS530X_IN_HPF_EN_SHIFT 12 + +/* IN_HIZ */ +#define CS530X_IN12_HIZ BIT(0) +#define CS530X_IN34_HIZ BIT(1) +#define CS530X_IN56_HIZ BIT(2) +#define CS530X_IN78_HIZ BIT(3) + +/* IN_INV */ +#define CS530X_IN1_INV_SHIFT 0 +#define CS530X_IN2_INV_SHIFT 1 +#define CS530X_IN3_INV_SHIFT 2 +#define CS530X_IN4_INV_SHIFT 3 +#define CS530X_IN5_INV_SHIFT 4 +#define CS530X_IN6_INV_SHIFT 5 +#define CS530X_IN7_INV_SHIFT 6 +#define CS530X_IN8_INV_SHIFT 7 + +/* IN_VOL_CTLy_z */ +#define CS530X_IN_MUTE BIT(15) + +/* IN_VOL_CTL5 */ +#define CS530X_IN_VU BIT(0) + +/* PAD_FN */ +#define CS530X_DOUT2_FN BIT(0) +#define CS530X_DOUT3_FN BIT(1) +#define CS530X_DOUT4_FN BIT(2) +#define CS530X_SPI_CS_FN BIT(3) +#define CS530X_CONFIG2_FN BIT(6) +#define CS530X_CONFIG3_FN BIT(7) +#define CS530X_CONFIG4_FN BIT(8) +#define CS530X_CONFIG5_FN BIT(9) + +/* PAD_LVL */ +#define CS530X_CONFIG2_LVL BIT(6) +#define CS530X_CONFIG3_LVL BIT(7) +#define CS530X_CONFIG4_LVL BIT(8) +#define CS530X_CONFIG5_LVL BIT(9) + +/* System Clock Source */ +#define CS530X_SYSCLK_SRC_MCLK 0 +#define CS530X_SYSCLK_SRC_PLL 1 + +/* PLL Reference Clock Source */ +#define CS530X_PLL_SRC_BCLK 0 +#define CS530X_PLL_SRC_MCLK 1 + +#define CS530X_NUM_SUPPLIES 2 + +enum cs530x_type { + CS5302, + CS5304, + CS5308, +}; + +/* codec private data */ +struct cs530x_priv { + struct regmap *regmap; + struct device *dev; + struct snd_soc_dai_driver *dev_dai; + + enum cs530x_type devtype; + int num_adcs; + int num_dacs; + + struct regulator_bulk_data supplies[CS530X_NUM_SUPPLIES]; + + unsigned int mclk_rate; + + int tdm_width; + int tdm_slots; + int bclk; + int fs; + int adc_pairs_count; + + struct gpio_desc *reset_gpio; +}; + +extern const struct regmap_config cs530x_regmap; +int cs530x_probe(struct cs530x_priv *cs530x); + +#endif diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index 03b539ba540f..6a4e42e5e35b 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -857,12 +857,16 @@ static void es8326_jack_detect_handler(struct work_struct *work) * set auto-check mode, then restart jack_detect_work after 400ms. * Don't report jack status. */ - regmap_write(es8326->regmap, ES8326_INT_SOURCE, - (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x00); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x00); es8326_enable_micbias(es8326->component); usleep_range(50000, 70000); regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00); + regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x10, 0x10); + usleep_range(50000, 70000); + regmap_write(es8326->regmap, ES8326_INT_SOURCE, + (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x1f); regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x0f, 0x08); queue_delayed_work(system_wq, &es8326->jack_detect_work, diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 86e126783a1d..8f7057e689fb 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -2087,10 +2087,8 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) #endif pcm_dev = devm_kzalloc(&i2c->dev, sizeof(*pcm_dev), GFP_KERNEL); - if (!pcm_dev) { - ret = -ENOMEM; - goto out; - } + if (!pcm_dev) + return -ENOMEM; pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0; diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index b33da2215ade..87354bb1564e 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -68,6 +68,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x200007f: case 0x2000082 ... 0x200008e: case 0x2000090 ... 0x2000094: + case 0x3110000: case 0x5300000 ... 0x5300002: case 0x5400002: case 0x5600000 ... 0x5600007: @@ -125,6 +126,7 @@ static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int re case 0x2000067: case 0x2000084: case 0x2000086: + case 0x3110000: return true; default: return false; @@ -350,7 +352,7 @@ static int rt722_sdca_interrupt_callback(struct sdw_slave *slave, if (status->sdca_cascade && !rt722->disable_irq) mod_delayed_work(system_power_efficient_wq, - &rt722->jack_detect_work, msecs_to_jiffies(30)); + &rt722->jack_detect_work, msecs_to_jiffies(280)); mutex_unlock(&rt722->disable_irq_lock); diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index eb180df9a72a..7073b9d1cda8 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -39,9 +39,10 @@ */ #define ADC3XXX_MICBIAS_PINS 2 +#define ADC3XXX_GPIO_PINS 2 /* Number of GPIO pins exposed via the gpiolib interface */ -#define ADC3XXX_GPIOS_MAX 2 +#define ADC3XXX_GPIOS_MAX (ADC3XXX_MICBIAS_PINS + ADC3XXX_GPIO_PINS) #define ADC3XXX_RATES SNDRV_PCM_RATE_8000_96000 #define ADC3XXX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -320,7 +321,8 @@ struct adc3xxx { struct gpio_desc *rst_pin; unsigned int pll_mode; unsigned int sysclk; - unsigned int gpio_cfg[ADC3XXX_GPIOS_MAX]; /* value+1 (0 => not set) */ + unsigned int gpio_cfg[ADC3XXX_GPIO_PINS]; /* value+1 (0 => not set) */ + unsigned int micbias_gpo[ADC3XXX_MICBIAS_PINS]; /* 1 => pin is GPO */ unsigned int micbias_vg[ADC3XXX_MICBIAS_PINS]; int master; u8 page_no; @@ -328,7 +330,7 @@ struct adc3xxx { struct gpio_chip gpio_chip; }; -static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIOS_MAX] = { +static const unsigned int adc3xxx_gpio_ctrl_reg[ADC3XXX_GPIO_PINS] = { ADC3XXX_GPIO1_CTRL, ADC3XXX_GPIO2_CTRL }; @@ -959,14 +961,23 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset) if (offset >= ADC3XXX_GPIOS_MAX) return -EINVAL; - /* GPIO1 is offset 0, GPIO2 is offset 1 */ - /* We check here that the GPIO pins are either not configured in the - * DT, or that they purposely are set as outputs. - * (Input mode not yet implemented). - */ - if (adc3xxx->gpio_cfg[offset] != 0 && - adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1) - return -EINVAL; + if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) { + /* GPIO1 is offset 0, GPIO2 is offset 1 */ + /* We check here that the GPIO pins are either not configured + * in the DT, or that they purposely are set as outputs. + * (Input mode not yet implemented). + */ + if (adc3xxx->gpio_cfg[offset] != 0 && + adc3xxx->gpio_cfg[offset] != ADC3XXX_GPIO_GPO + 1) + return -EINVAL; + } else if (offset >= ADC3XXX_GPIO_PINS && offset < ADC3XXX_GPIOS_MAX) { + /* MICBIAS1 is offset 2, MICBIAS2 is offset 3 */ + /* We check here if the MICBIAS pins are in fact configured + * as GPOs. + */ + if (!adc3xxx->micbias_gpo[offset - ADC3XXX_GPIO_PINS]) + return -EINVAL; + } return 0; } @@ -976,6 +987,21 @@ static int adc3xxx_gpio_direction_out(struct gpio_chip *chip, { struct adc3xxx *adc3xxx = gpiochip_get_data(chip); + /* For the MICBIAS pins, they are by definition outputs. */ + if (offset >= ADC3XXX_GPIO_PINS) { + unsigned int vg; + unsigned int micbias = offset - ADC3XXX_GPIO_PINS; + + if (value) + vg = adc3xxx->micbias_vg[micbias]; + else + vg = ADC3XXX_MICBIAS_OFF; + return regmap_update_bits(adc3xxx->regmap, + ADC3XXX_MICBIAS_CTRL, + ADC3XXX_MICBIAS_MASK << adc3xxx_micbias_shift[micbias], + vg << adc3xxx_micbias_shift[micbias]); + } + /* Set GPIO output function. */ return regmap_update_bits(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], @@ -1004,9 +1030,17 @@ static int adc3xxx_gpio_get(struct gpio_chip *chip, unsigned int offset) unsigned int regval; int ret; - /* We only allow output pins, so just read the value set in the output - * pin register field. - */ + /* We only allow output pins, so just read the value prevously set. */ + if (offset >= ADC3XXX_GPIO_PINS) { + /* MICBIAS pins */ + unsigned int micbias = offset - ADC3XXX_GPIO_PINS; + + ret = regmap_read(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, ®val); + if (ret) + return ret; + return ((regval >> adc3xxx_micbias_shift[micbias]) & ADC3XXX_MICBIAS_MASK) != + ADC3XXX_MICBIAS_OFF; + } ret = regmap_read(adc3xxx->regmap, adc3xxx_gpio_ctrl_reg[offset], ®val); if (ret) return ret; @@ -1048,7 +1082,7 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx) * This allows us to set up things which are not software * controllable GPIOs, such as PDM microphone I/O, */ - for (gpio = 0; gpio < ADC3XXX_GPIOS_MAX; gpio++) { + for (gpio = 0; gpio < ADC3XXX_GPIO_PINS; gpio++) { unsigned int cfg = adc3xxx->gpio_cfg[gpio]; if (cfg) { @@ -1060,9 +1094,15 @@ static void adc3xxx_init_gpio(struct adc3xxx *adc3xxx) } } - /* Set up micbias voltage */ + /* Set up micbias voltage. */ + /* If pin is configured as GPO, set off initially. */ for (micbias = 0; micbias < ADC3XXX_MICBIAS_PINS; micbias++) { - unsigned int vg = adc3xxx->micbias_vg[micbias]; + unsigned int vg; + + if (adc3xxx->micbias_gpo[micbias]) + vg = ADC3XXX_MICBIAS_OFF; + else + vg = adc3xxx->micbias_vg[micbias]; regmap_update_bits(adc3xxx->regmap, ADC3XXX_MICBIAS_CTRL, @@ -1090,8 +1130,19 @@ static int adc3xxx_parse_dt_gpio(struct adc3xxx *adc3xxx, return 0; } -static int adc3xxx_parse_dt_micbias(struct adc3xxx *adc3xxx, - const char *propname, unsigned int *vg) +static int adc3xxx_parse_dt_micbias_gpo(struct adc3xxx *adc3xxx, + const char *propname, + unsigned int *cfg) +{ + struct device *dev = adc3xxx->dev; + struct device_node *np = dev->of_node; + + *cfg = of_property_read_bool(np, propname); + return 0; +} + +static int adc3xxx_parse_dt_micbias_vg(struct adc3xxx *adc3xxx, + const char *propname, unsigned int *vg) { struct device *dev = adc3xxx->dev; struct device_node *np = dev->of_node; @@ -1382,16 +1433,28 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c) dev_dbg(dev, "Enabled MCLK, freq %lu Hz\n", clk_get_rate(adc3xxx->mclk)); } + /* Configure mode for DMDIN/GPIO1 pin */ ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmdin-gpio1", &adc3xxx->gpio_cfg[0]); if (ret < 0) goto err_unprepare_mclk; + /* Configure mode for DMCLK/GPIO2 pin */ ret = adc3xxx_parse_dt_gpio(adc3xxx, "ti,dmclk-gpio2", &adc3xxx->gpio_cfg[1]); if (ret < 0) goto err_unprepare_mclk; - ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); + /* Configure mode for MICBIAS1: as Mic Bias output or GPO */ + ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias1-gpo", &adc3xxx->micbias_gpo[0]); + if (ret < 0) + goto err_unprepare_mclk; + /* Configure mode for MICBIAS2: as Mic Bias output or GPO */ + ret = adc3xxx_parse_dt_micbias_gpo(adc3xxx, "ti,micbias2-gpo", &adc3xxx->micbias_gpo[1]); + if (ret < 0) + goto err_unprepare_mclk; + /* Configure voltage for MICBIAS1 pin (ON voltage when used as GPO) */ + ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias1-vg", &adc3xxx->micbias_vg[0]); if (ret < 0) goto err_unprepare_mclk; - ret = adc3xxx_parse_dt_micbias(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); + /* Configure voltage for MICBIAS2 pin (ON voltage when used as GPO) */ + ret = adc3xxx_parse_dt_micbias_vg(adc3xxx, "ti,micbias2-vg", &adc3xxx->micbias_vg[1]); if (ret < 0) goto err_unprepare_mclk; diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 5ddc0c2fe53f..eb67689dcd6e 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -559,6 +559,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->pdev = pdev; + cpu_np = of_parse_phandle(np, "audio-cpu", 0); /* Give a chance to old DT binding */ if (!cpu_np) @@ -787,7 +789,6 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } /* Initialize sound card */ - priv->pdev = pdev; priv->card.dev = &pdev->dev; priv->card.owner = THIS_MODULE; ret = snd_soc_of_parse_card_name(&priv->card, "model"); diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 14e94270911c..4fa208d6a032 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -50,4 +50,5 @@ int imx_pcm_dma_init(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(imx_pcm_dma_init); +MODULE_DESCRIPTION("Freescale i.MX PCM DMA interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 35381a835c93..5cda527020c7 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1545,8 +1545,8 @@ static int avs_route_load(struct snd_soc_component *comp, int index, { struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev); size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN; - char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ssp_port, tdm_slot; + char *buf; /* See parse_link_formatted_string() for dynamic naming when(s). */ if (!avs_mach_singular_ssp(mach)) @@ -1557,13 +1557,24 @@ static int avs_route_load(struct snd_soc_component *comp, int index, return 0; tdm_slot = avs_mach_ssp_tdm(mach, ssp_port); + buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot); - strscpy((char *)route->source, buf, len); + route->source = buf; + + buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; avs_ssp_sprint(buf, len, route->sink, ssp_port, tdm_slot); - strscpy((char *)route->sink, buf, len); + route->sink = buf; + if (route->control) { + buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; avs_ssp_sprint(buf, len, route->control, ssp_port, tdm_slot); - strscpy((char *)route->control, buf, len); + route->control = buf; } return 0; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index b41a1147f1c3..a64d1989e28a 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -613,6 +613,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 101 CESIUM"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index 48252fa9e39e..8e0ae3635a35 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -293,7 +293,7 @@ static const struct snd_soc_acpi_adr_device rt1318_1_single_adr[] = { .adr = 0x000130025D131801, .num_endpoints = 1, .endpoints = &single_endpoint, - .name_prefix = "rt1318" + .name_prefix = "rt1318-1" } }; diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index acaf81fd6c9b..f848e14b091a 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -31,7 +31,7 @@ struct mt8183_da7219_max98357_priv { static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = { { - .pin = "Headphone", + .pin = "Headphones", .mask = SND_JACK_HEADPHONE, }, { @@ -626,7 +626,7 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Speakers"), SOC_DAPM_PIN_SWITCH("Line Out"), @@ -634,7 +634,7 @@ static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = { static const struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_SPK("Line Out", NULL), @@ -680,7 +680,7 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = { }; static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Right Spk"), @@ -689,7 +689,7 @@ static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = { static const struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index df2e4be992d2..9bb08cadeb18 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -43,4 +43,5 @@ int mxs_pcm_platform_register(struct device *dev) } EXPORT_SYMBOL_GPL(mxs_pcm_platform_register); +MODULE_DESCRIPTION("MXS ASoC PCM driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index ba28ec9dff86..9c98a35ad099 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -146,14 +146,17 @@ static void q6apm_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); int rc; - if (!dai_data->is_port_started[dai->id]) - return; - rc = q6apm_graph_stop(dai_data->graph[dai->id]); - if (rc < 0) - dev_err(dai->dev, "fail to close APM port (%d)\n", rc); + if (dai_data->is_port_started[dai->id]) { + rc = q6apm_graph_stop(dai_data->graph[dai->id]); + dai_data->is_port_started[dai->id] = false; + if (rc < 0) + dev_err(dai->dev, "fail to close APM port (%d)\n", rc); + } - q6apm_graph_close(dai_data->graph[dai->id]); - dai_data->is_port_started[dai->id] = false; + if (dai_data->graph[dai->id]) { + q6apm_graph_close(dai_data->graph[dai->id]); + dai_data->graph[dai->id] = NULL; + } } static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -168,8 +171,10 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s q6apm_graph_stop(dai_data->graph[dai->id]); dai_data->is_port_started[dai->id] = false; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { q6apm_graph_close(dai_data->graph[dai->id]); + dai_data->graph[dai->id] = NULL; + } } /** @@ -188,26 +193,29 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s cfg->direction = substream->stream; rc = q6apm_graph_media_format_pcm(dai_data->graph[dai->id], cfg); - if (rc) { dev_err(dai->dev, "Failed to set media format %d\n", rc); - return rc; + goto err; } rc = q6apm_graph_prepare(dai_data->graph[dai->id]); if (rc) { dev_err(dai->dev, "Failed to prepare Graph %d\n", rc); - return rc; + goto err; } rc = q6apm_graph_start(dai_data->graph[dai->id]); if (rc < 0) { dev_err(dai->dev, "fail to start APM port %x\n", dai->id); - return rc; + goto err; } dai_data->is_port_started[dai->id] = true; return 0; +err: + q6apm_graph_close(dai_data->graph[dai->id]); + dai_data->graph[dai->id] = NULL; + return rc; } static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index eaa8bb016e50..f2eda2ff46c0 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -160,4 +160,5 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, return 0; } EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free); +MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 9fa020ef7eab..ee517d7b5b7b 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -655,8 +655,17 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream, int err; if (i2s_tdm->is_master_mode) { - struct clk *mclk = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - i2s_tdm->mclk_tx : i2s_tdm->mclk_rx; + struct clk *mclk; + + if (i2s_tdm->clk_trcm == TRCM_TX) { + mclk = i2s_tdm->mclk_tx; + } else if (i2s_tdm->clk_trcm == TRCM_RX) { + mclk = i2s_tdm->mclk_rx; + } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mclk = i2s_tdm->mclk_tx; + } else { + mclk = i2s_tdm->mclk_rx; + } err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params)); if (err) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index ea3bc9318412..a63e942fdc0b 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -318,6 +318,12 @@ static int dmaengine_copy(struct snd_soc_component *component, return 0; } +static int dmaengine_pcm_sync_stop(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return snd_dmaengine_pcm_sync_stop(substream); +} + static const struct snd_soc_component_driver dmaengine_pcm_component = { .name = SND_DMAENGINE_PCM_DRV_NAME, .probe_order = SND_SOC_COMP_ORDER_LATE, @@ -327,6 +333,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component = { .trigger = dmaengine_pcm_trigger, .pointer = dmaengine_pcm_pointer, .pcm_construct = dmaengine_pcm_new, + .sync_stop = dmaengine_pcm_sync_stop, }; static const struct snd_soc_component_driver dmaengine_pcm_component_process = { @@ -339,6 +346,7 @@ static const struct snd_soc_component_driver dmaengine_pcm_component_process = { .pointer = dmaengine_pcm_pointer, .copy = dmaengine_copy, .pcm_construct = dmaengine_pcm_new, + .sync_stop = dmaengine_pcm_sync_stop, }; static const char * const dmaengine_pcm_dma_channel_names[] = { diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b00ec01361c2..4b166294602f 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1021,6 +1021,7 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; + const size_t maxlen = SNDRV_CTL_ELEM_ID_NAME_MAXLEN; struct snd_soc_tplg_dapm_graph_elem *elem; struct snd_soc_dapm_route *route; int count, i; @@ -1044,31 +1045,27 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); /* validate routes */ - if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + if ((strnlen(elem->source, maxlen) == maxlen) || + (strnlen(elem->sink, maxlen) == maxlen) || + (strnlen(elem->control, maxlen) == maxlen)) { ret = -EINVAL; break; } - if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { - ret = -EINVAL; - break; - } - if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { - ret = -EINVAL; + + route->source = devm_kstrdup(tplg->dev, elem->source, GFP_KERNEL); + route->sink = devm_kstrdup(tplg->dev, elem->sink, GFP_KERNEL); + if (!route->source || !route->sink) { + ret = -ENOMEM; break; } - route->source = elem->source; - route->sink = elem->sink; - - /* set to NULL atm for tplg users */ - route->connected = NULL; - if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) - route->control = NULL; - else - route->control = elem->control; + if (strnlen(elem->control, maxlen) != 0) { + route->control = devm_kstrdup(tplg->dev, elem->control, GFP_KERNEL); + if (!route->control) { + ret = -ENOMEM; + break; + } + } /* add route dobj to dobj_list */ route->dobj.type = SND_SOC_DOBJ_GRAPH; diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index ce675c22a5ab..c61d298ea6b3 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -379,7 +379,7 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream, sdev = widget_to_sdev(w); if (sdev->dspless_mode_selected) - goto skip_tlv; + return 0; /* get stream_id */ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); @@ -423,7 +423,6 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream, dma_config->dma_stream_channel_map.device_count = 1; dma_config->dma_priv_config_size = 0; -skip_tlv: return 0; } @@ -525,6 +524,9 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, return ret; } + if (sdev->dspless_mode_selected) + return 0; + ipc4_copier = widget_to_copier(w); dma_config_tlv = &ipc4_copier->dma_config_tlv[cpu_dai_id]; dma_config = &dma_config_tlv->dma_config; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 881eec38c2e2..9a52781bf8d8 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -485,7 +485,7 @@ sink_prepare: if (ret < 0) { /* unprepare the source widget */ if (widget_ops[widget->id].ipc_unprepare && - swidget && swidget->prepared) { + swidget && swidget->prepared && swidget->use_count == 0) { widget_ops[widget->id].ipc_unprepare(swidget); swidget->prepared = false; } diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index 1e760c315521..2b1ed91a736c 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -1472,10 +1472,11 @@ static int davinci_mcasp_hw_rule_min_periodsize( { struct snd_interval *period_size = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + u8 numevt = *((u8 *)rule->private); struct snd_interval frames; snd_interval_any(&frames); - frames.min = 64; + frames.min = numevt; frames.integer = 1; return snd_interval_refine(period_size, &frames); @@ -1490,6 +1491,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, u32 max_channels = 0; int i, dir, ret; int tdm_slots = mcasp->tdm_slots; + u8 *numevt; /* Do not allow more then one stream per direction */ if (mcasp->substreams[substream->stream]) @@ -1589,9 +1591,12 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, return ret; } + numevt = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + &mcasp->txnumevt : + &mcasp->rxnumevt; snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - davinci_mcasp_hw_rule_min_periodsize, NULL, + davinci_mcasp_hw_rule_min_periodsize, numevt, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); return 0; diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index 639bc83f4263..cf43ac19c4a6 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -354,11 +354,7 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = devm_kasprintf(dev, GFP_KERNEL, - "HDMI %s", dev_name(ad->dssdev)); - if (!card->name) - return -ENOMEM; - + card->name = "HDMI"; card->owner = THIS_MODULE; card->dai_link = devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL); |