From 11e828cd6b0f283ebe9dc6b4cffd38e3321e7725 Mon Sep 17 00:00:00 2001 From: Mert Seftali Date: Sun, 14 Jun 2026 14:40:19 +0200 Subject: [PATCH 001/438] ASoC: SOF: ipc4-topology: Return error for invalid number of formats When the number of input or output formats is zero, sof_ipc4_widget_setup_comp_src() and sof_ipc4_widget_setup_comp_asrc() print an error and jump to the cleanup label. At that point 'ret' is still 0, because the earlier sof_ipc4_get_audio_fmt() call succeeded, so the function returns success and the caller never finds out that the widget setup actually failed. Set ret to -EINVAL before the goto so the error gets reported. Fixes: 21a5adffad46 ("ASoC: SOF: ipc4-topology: Validate the number of in/out formats for src/asrc") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202606111431.Uky3T0tF-lkp@intel.com/ Signed-off-by: Mert Seftali Link: https://patch.msgid.link/20260614124019.19259-1-mertsftl@gmail.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 95ad5266b0c6..8ac7dde32f77 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1127,6 +1127,7 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) "Invalid number of formats: input: %d, output: %d\n", src->available_fmt.num_input_formats, src->available_fmt.num_output_formats); + ret = -EINVAL; goto err; } @@ -1179,6 +1180,7 @@ static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget) "Invalid number of formats: input: %d, output: %d\n", asrc->available_fmt.num_input_formats, asrc->available_fmt.num_output_formats); + ret = -EINVAL; goto err; } From 6ed013a581d00f84bbd0c3c60f7a108bef93fc4e Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 12 Jun 2026 09:01:12 +0700 Subject: [PATCH 002/438] ASoC: meson: Use dev_err_probe() for device reset failures device_reset() may return -EPROBE_DEFER. Switch to dev_err_probe() so probe failures are reported consistently and deferred probing is handled properly. This matches the existing pattern used in aiu_probe(). No functional change intended. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260612020113.9557-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/meson/g12a-toacodec.c | 2 +- sound/soc/meson/g12a-tohdmitx.c | 2 +- sound/soc/meson/t9015.c | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c index a95375b53f0a..21941ee552c5 100644 --- a/sound/soc/meson/g12a-toacodec.c +++ b/sound/soc/meson/g12a-toacodec.c @@ -312,7 +312,7 @@ static int g12a_toacodec_probe(struct platform_device *pdev) ret = device_reset(dev); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to reset device\n"); regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index d541ca4acfaf..967109ca2b57 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -251,7 +251,7 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev) ret = device_reset(dev); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to reset device\n"); regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index da1a93946d67..f0b55aee5241 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -265,10 +265,8 @@ static int t9015_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n"); ret = device_reset(dev); - if (ret) { - dev_err(dev, "reset failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to reset device\n"); regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { From ce3733792d38ade8df8ce288a96ff0c6ad858bf3 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Mon, 15 Jun 2026 14:44:56 +0800 Subject: [PATCH 003/438] ASoC: sma1303: remove fault-check sysfs group on remove sma1303_i2c_probe() creates a sysfs group that exposes the fault-check controls. The check_fault_status store callback can queue check_fault_work. sma1303_i2c_remove() only cancels the delayed work. It does not remove the sysfs group, so the controls can remain published after remove while their callbacks still use the driver data and can queue the work again. Remove the sysfs group before cancelling the delayed work. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260615064456.28615-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/sma1303.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c index c7aaf98ef71e..38677badfc18 100644 --- a/sound/soc/codecs/sma1303.c +++ b/sound/soc/codecs/sma1303.c @@ -1778,6 +1778,8 @@ static void sma1303_i2c_remove(struct i2c_client *client) struct sma1303_priv *sma1303 = (struct sma1303_priv *) i2c_get_clientdata(client); + if (sma1303->attr_grp) + sysfs_remove_group(sma1303->kobj, sma1303->attr_grp); cancel_delayed_work_sync(&sma1303->check_fault_work); } From ae375f8d063d71e598c0d7e14fc056154c84d7a7 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Mon, 15 Jun 2026 14:45:48 +0800 Subject: [PATCH 004/438] ASoC: tlv320aic26: remove keyclick sysfs file aic26_probe() creates the keyclick sysfs file on the component device. The file callback uses the ASoC component pointer stored in the driver private data. There is no matching remove callback, so the sysfs file can remain after the component is removed while its backing component state is gone. Add a component remove callback that removes the keyclick file. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260615064549.34110-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic26.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index e5dfb3d752a3..84e954311c1b 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -320,8 +320,14 @@ static int aic26_probe(struct snd_soc_component *component) return 0; } +static void aic26_remove(struct snd_soc_component *component) +{ + device_remove_file(component->dev, &dev_attr_keyclick); +} + static const struct snd_soc_component_driver aic26_soc_component_dev = { .probe = aic26_probe, + .remove = aic26_remove, .controls = aic26_snd_controls, .num_controls = ARRAY_SIZE(aic26_snd_controls), .dapm_widgets = tlv320aic26_dapm_widgets, From e9f08e779976bbfef7d168c70350083878db7e2e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 15 Jun 2026 21:44:39 +0800 Subject: [PATCH 005/438] ASoC: SOF: add Intel UAOL sof_ipc_dai_type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The type will be used for Intel USB Audio Offload Link (UAOL) DAI. Signed-off-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Péter Ujfalusi Link: https://patch.msgid.link/20260615134439.1044872-1-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 36809f712723..0b6a6ba6489a 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -90,6 +90,7 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */ SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */ SOF_DAI_AMD_SDW, /**< AMD ACP SDW */ + SOF_DAI_INTEL_UAOL, /**< Intel UAOL */ }; /* general purpose DAI configuration */ From 012dfa0c45ecaadd48549938a9f35d1a329a2c5d Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Mon, 15 Jun 2026 20:57:50 +0200 Subject: [PATCH 006/438] ASoC: dt-bindings: mtk-btcvsd-snd: Convert to DT Schema Convert the mtk-btcvsd-snd.txt DT binding to DT Schema format. Signed-off-by: Luca Leonardo Scorcia Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260615185810.11804-1-l.scorcia@gmail.com Signed-off-by: Mark Brown --- .../sound/mediatek,mtk-btcvsd-snd.yaml | 59 +++++++++++++++++++ .../bindings/sound/mtk-btcvsd-snd.txt | 24 -------- 2 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml delete mode 100644 Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt diff --git a/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml new file mode 100644 index 000000000000..1b7451655476 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mtk-btcvsd-snd.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek ALSA BT SCO CVSD/MSBC + +maintainers: + - Luca Leonardo Scorcia + +properties: + compatible: + const: mediatek,mtk-btcvsd-snd + + reg: + items: + - description: PKV region + - description: SRAM_BANK2 region + + interrupts: + items: + - description: BT-SCO interrupt + + mediatek,infracfg: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle of the infracfg controller + + mediatek,offset: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Array of register offsets and masks + items: + - description: infra_misc_offset + - description: infra_conn_bt_cvsd_mask + - description: cvsd_mcu_read_offset + - description: cvsd_mcu_write_offset + - description: cvsd_packet_indicator_offset + +required: + - compatible + - reg + - interrupts + - mediatek,infracfg + - mediatek,offset + +additionalProperties: false + +examples: + - | + #include + + mtk-btcvsd-snd@18000000 { + compatible = "mediatek,mtk-btcvsd-snd"; + reg = <0x18000000 0x1000>, + <0x18080000 0x8000>; + interrupts = ; + mediatek,infracfg = <&infrasys>; + mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>; + }; diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt deleted file mode 100644 index 679e44839b48..000000000000 --- a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt +++ /dev/null @@ -1,24 +0,0 @@ -Mediatek ALSA BT SCO CVSD/MSBC Driver - -Required properties: -- compatible = "mediatek,mtk-btcvsd-snd"; -- reg: register location and size of PKV and SRAM_BANK2 -- interrupts: should contain BTSCO interrupt -- mediatek,infracfg: the phandles of INFRASYS -- mediatek,offset: Array contains of register offset and mask - infra_misc_offset, - infra_conn_bt_cvsd_mask, - cvsd_mcu_read_offset, - cvsd_mcu_write_offset, - cvsd_packet_indicator_offset - -Example: - - mtk-btcvsd-snd@18000000 { - compatible = "mediatek,mtk-btcvsd-snd"; - reg=<0 0x18000000 0 0x1000>, - <0 0x18080000 0 0x8000>; - interrupts = ; - mediatek,infracfg = <&infrasys>; - mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>; - }; From a33e6fa400d174e7970d4efc30dd2e10911281ab Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 17 Jun 2026 09:33:45 +0200 Subject: [PATCH 007/438] ASoC: SOF: topology: Use more common error handling code in sof_link_load() Use an additional label so that a bit of exception handling can be better reused at the end of this function implementation. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Link: https://patch.msgid.link/40b93192-68d2-4de1-845b-9c9ba994a75b@web.de Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 42a2d90bb705..f709935593ef 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1943,8 +1943,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ private->array, le32_to_cpu(private->size)); if (ret < 0) { dev_err(scomp->dev, "Failed tp parse common DAI link tokens\n"); - kfree(slink); - return ret; + goto free_slink; } token_list = tplg_ops ? tplg_ops->token_list : NULL; @@ -2013,8 +2012,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ /* allocate memory for tuples array */ slink->tuples = kzalloc_objs(*slink->tuples, num_tuples); if (!slink->tuples) { - kfree(slink); - return -ENOMEM; + ret = -ENOMEM; + goto free_slink; } if (token_list[SOF_DAI_LINK_TOKENS].tokens) { @@ -2070,6 +2069,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ err: kfree(slink->tuples); +free_slink: kfree(slink); return ret; From 612ccf42acd14bb2685fa60c3495ca13e63e8989 Mon Sep 17 00:00:00 2001 From: Runyu Xiao Date: Fri, 19 Jun 2026 20:23:25 +0800 Subject: [PATCH 008/438] ASoC: rt700-sdw: always drain jack work on remove rt700_sdw_remove() drains jack_detect_work and jack_btn_check_work only when rt700->hw_init is true. That state bit is cleared by rt700_update_status() when the SoundWire slave becomes UNATTACHED, but a jack work item can already have been queued by rt700_interrupt_callback() or rt700_jack_init() while the device was initialized. Do not use hw_init as the remove-time guard for draining these work objects. The delayed works are initialized during rt700_init(), so remove can cancel them unconditionally and pair the object lifetime with the codec-private data lifetime instead of a mutable hardware state bit. This issue was found by our static analysis tool and then confirmed by manual review of the SoundWire status, interrupt and remove paths. The remove path should drain work based on whether the work object exists, not on a runtime hardware state bit that can change after the work was queued. A QEMU PoC queued jack_detect_work, simulated SDW_SLAVE_UNATTACHED, and then entered remove. DEBUG_OBJECTS reported an active timer/work object associated with the rt700 jack work path after remove skipped the cancel. This is sent as an RFC because the practical trigger depends on SoundWire core remove ordering after an UNATTACHED status update. If remove cannot run after hw_init has been cleared while jack work is still pending, this is a defensive lifecycle cleanup rather than a reachable race on current systems. Fixes: 737ee8bdf682 ("ASoC: rt700-sdw: use cancel_work_sync() in .remove as well as .suspend") Signed-off-by: Runyu Xiao Link: https://patch.msgid.link/20260619122325.2504287-1-runyu.xiao@seu.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt700-sdw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 6bc636c86f42..83f7d52cb598 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -459,10 +459,8 @@ static void rt700_sdw_remove(struct sdw_slave *slave) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); - if (rt700->hw_init) { - cancel_delayed_work_sync(&rt700->jack_detect_work); - cancel_delayed_work_sync(&rt700->jack_btn_check_work); - } + cancel_delayed_work_sync(&rt700->jack_detect_work); + cancel_delayed_work_sync(&rt700->jack_btn_check_work); pm_runtime_disable(&slave->dev); } From 3a89ddcf0c3d9a068631e8c24d5c9e81d1e6512a Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Mon, 22 Jun 2026 17:48:22 +0800 Subject: [PATCH 009/438] ASoC: fsl: mpc5200-i2s: Free DMA resources on probe failure mpc5200_audio_dma_create() creates the DMA resources before registering the component. If snd_soc_register_component() fails, the function returns directly and leaves the DMA resources allocated. Call mpc5200_audio_dma_destroy() before returning from this error path. Fixes: f515b67381de ("ASoC: fsl: mpc5200 combine psc_dma platform data") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20260622094822.926166-1-haoxiang_li2024@163.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_i2s.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9ad44eeed6ad..7831136f4f12 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -170,6 +170,7 @@ static int psc_i2s_of_probe(struct platform_device *op) psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); if (rc != 0) { pr_err("Failed to register DAI\n"); + mpc5200_audio_dma_destroy(op); return rc; } From 016f29997ebd29d6ab59c8162ce0e7f73bd1e517 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Mon, 22 Jun 2026 17:16:20 +0800 Subject: [PATCH 010/438] AsoC: intel: sst: fix PCI device reference leak on probe failure intel_sst_probe() takes a reference to the PCI device with pci_dev_get(). If sst_platform_get_resources() fails afterwards, the probe error path cleans up the driver context but does not drop the PCI device reference. Add a pci_dev_put() error path for failures after pci_dev_get(). Fixes: f533a035e4da ("ASoC: Intel: mrfld - create separate module for pci part") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20260622091620.897478-1-haoxiang_li2024@163.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index 22ae2d22f121..44bb11c69490 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -130,13 +130,15 @@ static int intel_sst_probe(struct pci_dev *pci, sst_drv_ctx->pci = pci_dev_get(pci); ret = sst_platform_get_resources(sst_drv_ctx); if (ret < 0) - goto do_free_drv_ctx; + goto do_put_pci; pci_set_drvdata(pci, sst_drv_ctx); sst_configure_runtime_pm(sst_drv_ctx); return ret; +do_put_pci: + pci_dev_put(sst_drv_ctx->pci); do_free_drv_ctx: sst_context_cleanup(sst_drv_ctx); dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret); From 6ad4892c4f5cb437a928a02f5b7d37d496aa9268 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Mon, 22 Jun 2026 22:56:45 +0800 Subject: [PATCH 011/438] ASoC: hdac_hda: Fix hlink refcount leak on component registration failure hdac_hda_dev_probe() gets the HDA link with snd_hdac_ext_bus_link_get() before registering the ASoC component. If component registration fails, the function returns without dropping the link reference. Always call snd_hdac_ext_bus_link_put() after the registration attempt so the reference taken during probe is balanced on both success and failure. Fixes: 6bae5ea94989 ("ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20260622145645.1184986-1-haoxiang_li2024@163.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 680e341aa7f1..1ab5f8a26e03 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -642,10 +642,8 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) &hdac_hda_codec, hdac_hda_dais, ARRAY_SIZE(hdac_hda_dais)); - if (ret < 0) { + if (ret < 0) dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret); - return ret; - } snd_hdac_ext_bus_link_put(hdev->bus, hlink); From 2e5bf7f48bf170f8e615cea408289440c3328926 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jun 2026 01:07:54 +0000 Subject: [PATCH 012/438] ASoC: codecs: max98090: add missing describe "data" for max98090_set_jack() "data" is missing. Add it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87zf0ids7p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index da416329b038..bccce322ccc3 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2341,6 +2341,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data) * * @component: MAX98090 component * @jack: jack to report detection events on + * @data: can be used if codec driver need extra data for configuring jack * * Enable microphone detection via IRQ on the MAX98090. If GPIOs are * being used to bring out signals to the processor then only platform From 785903b7770f19ea05b8a76081dff691c56fa771 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Mon, 22 Jun 2026 23:11:27 +0800 Subject: [PATCH 013/438] ASoC: hdac_hdmi: Fix resource cleanup on probe failure hdac_hdmi_dev_probe() gets the HDA link before allocating and initializing the HDMI codec private data. Several later error paths return directly without dropping the link reference, leaving the hlink refcount unbalanced. Release the link reference on probe failures. Also turn display power off if the failure happens after it has been enabled. This issue was dicussed in: https://lore.kernel.org/all/s5h1s0esk8o.wl-tiwai@suse.de/ I think the paths fixed here are probe failure paths: the device has not been fully initialized or bound, and runtime PM suspend cannot be relied on to balance the reference taken during probe. Signed-off-by: Haoxiang Li Link: https://patch.msgid.link/20260622151127.1198196-1-haoxiang_li2024@163.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3220f9226e0b..38073a70fa61 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1866,8 +1866,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) snd_hdac_ext_bus_link_get(hdev->bus, hlink); hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL); - if (hdmi_priv == NULL) + if (hdmi_priv == NULL) { + snd_hdac_ext_bus_link_put(hdev->bus, hlink); return -ENOMEM; + } snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap); hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; @@ -1876,8 +1878,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; hdmi_priv->hdev = hdev; - if (!hdac_id) + if (!hdac_id) { + snd_hdac_ext_bus_link_put(hdev->bus, hlink); return -ENODEV; + } if (hdac_id->driver_data) hdmi_priv->drv_data = @@ -1902,6 +1906,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) if (ret < 0) { dev_err(&hdev->dev, "Failed in parse and map nid with err: %d\n", ret); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + snd_hdac_display_power(hdev->bus, hdev->addr, false); return ret; } snd_hdac_refresh_widgets(hdev); From 3359ba93d01a23b2e4249e9e44ccfe48eb9c5d71 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 18 Jun 2026 10:38:18 +0800 Subject: [PATCH 014/438] ASoC: fsl_audmix: rework runtime PM handling in probe After pm_runtime_enable() the AUDMIX block is powered off and stays suspended until the first runtime resume. Register writes issued between probe() and the first resume (e.g. from DAPM or ALSA control paths) target unpowered hardware and cause a system hang. Fix this by calling pm_runtime_resume_and_get() immediately after pm_runtime_enable() to power the hardware up and enable its clocks. Release the reference afterwards with pm_runtime_put() to allow the runtime PM framework to suspend the device and switch the regmap to cache-only mode when idle. When CONFIG_PM is disabled or runtime PM is not enabled, pm_runtime_* calls are stubs that do not power up the hardware. Handle this case explicitly by calling fsl_audmix_runtime_resume() directly so the hardware is always initialised and its clocks are enabled, ensuring register accesses succeed regardless of PM configuration. Fixes: be1df61cf06ef ("ASoC: fsl: Add Audio Mixer CPU DAI driver") Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20260618023818.31618-1-shengjiu.wang@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index f819f33ec46b..2885cc10b02d 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -457,6 +457,9 @@ static const struct of_device_id fsl_audmix_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_audmix_ids); +static int fsl_audmix_runtime_resume(struct device *dev); +static int fsl_audmix_runtime_suspend(struct device *dev); + static int fsl_audmix_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -488,13 +491,25 @@ static int fsl_audmix_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); platform_set_drvdata(pdev, priv); pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = fsl_audmix_runtime_resume(dev); + if (ret) + goto err_disable_pm; + } + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto err_pm_get_sync; + + /* To enable regmap cache only when runtime PM enabled */ + pm_runtime_put(dev); ret = devm_snd_soc_register_component(dev, &fsl_audmix_component, fsl_audmix_dai, ARRAY_SIZE(fsl_audmix_dai)); if (ret) { dev_err(dev, "failed to register ASoC DAI\n"); - goto err_disable_pm; + goto err_pm_get_sync; } /* @@ -506,12 +521,15 @@ static int fsl_audmix_probe(struct platform_device *pdev) if (IS_ERR(priv->pdev)) { ret = PTR_ERR(priv->pdev); dev_err(dev, "failed to register platform: %d\n", ret); - goto err_disable_pm; + goto err_pm_get_sync; } } return 0; +err_pm_get_sync: + if (!pm_runtime_status_suspended(dev)) + fsl_audmix_runtime_suspend(dev); err_disable_pm: pm_runtime_disable(dev); return ret; @@ -522,6 +540,8 @@ static void fsl_audmix_remove(struct platform_device *pdev) struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_audmix_runtime_suspend(&pdev->dev); if (priv->pdev) platform_device_unregister(priv->pdev); From d7e261b7ad1bc96a2ee249c6694691244c099acf Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:14 +0700 Subject: [PATCH 015/438] ASoC: fsl_asrc: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260615093824.115751-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 5fda9b647c70..0b28bcfa47fe 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -222,10 +222,9 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) enum asrc_pair_index index = ASRC_INVALID_PAIR; struct fsl_asrc *asrc = pair->asrc; struct device *dev = &asrc->pdev->dev; - unsigned long lock_flags; int i, ret = 0; - spin_lock_irqsave(&asrc->lock, lock_flags); + guard(spinlock_irqsave)(&asrc->lock); for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { if (asrc->pair[i] != NULL) @@ -250,8 +249,6 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) pair->index = index; } - spin_unlock_irqrestore(&asrc->lock, lock_flags); - return ret; } @@ -265,19 +262,16 @@ static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) { struct fsl_asrc *asrc = pair->asrc; enum asrc_pair_index index = pair->index; - unsigned long lock_flags; /* Make sure the pair is disabled */ regmap_update_bits(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEi_MASK(index), 0); - spin_lock_irqsave(&asrc->lock, lock_flags); + guard(spinlock_irqsave)(&asrc->lock); asrc->channel_avail += pair->channels; asrc->pair[index] = NULL; pair->error = 0; - - spin_unlock_irqrestore(&asrc->lock, lock_flags); } /** From 58712476dee21cc3d3cb3b0b85a8ca3a86d480fe Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:15 +0700 Subject: [PATCH 016/438] ASoC: fsl_audmix: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index f819f33ec46b..a27370862ee8 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -286,7 +286,6 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai); - unsigned long lock_flags; /* Capture stream shall not be handled */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -296,16 +295,14 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - spin_lock_irqsave(&priv->lock, lock_flags); - priv->tdms |= BIT(dai->driver->id); - spin_unlock_irqrestore(&priv->lock, lock_flags); + scoped_guard(spinlock_irqsave, &priv->lock) + priv->tdms |= BIT(dai->driver->id); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irqsave(&priv->lock, lock_flags); - priv->tdms &= ~BIT(dai->driver->id); - spin_unlock_irqrestore(&priv->lock, lock_flags); + scoped_guard(spinlock_irqsave, &priv->lock) + priv->tdms &= ~BIT(dai->driver->id); break; default: return -EINVAL; From 48d84310be60578d4413139661b433b1d33aca1d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:16 +0700 Subject: [PATCH 017/438] ASoC: fsl_easrc: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 114a6c0b6b73..edfd943197a0 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1025,7 +1025,6 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id) struct fsl_easrc_ctx_priv *ctx_priv; struct fsl_asrc_pair *ctx; struct device *dev; - unsigned long lock_flags; int ret; if (!easrc) @@ -1053,9 +1052,8 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id) if (ret) return ret; - spin_lock_irqsave(&easrc->lock, lock_flags); - ret = fsl_easrc_config_slot(easrc, ctx->index); - spin_unlock_irqrestore(&easrc->lock, lock_flags); + scoped_guard(spinlock_irqsave, &easrc->lock) + ret = fsl_easrc_config_slot(easrc, ctx->index); if (ret) return ret; @@ -1301,13 +1299,12 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) enum asrc_pair_index index = ASRC_INVALID_PAIR; struct fsl_asrc *easrc = ctx->asrc; struct device *dev; - unsigned long lock_flags; int ret = 0; int i; dev = &easrc->pdev->dev; - spin_lock_irqsave(&easrc->lock, lock_flags); + guard(spinlock_irqsave)(&easrc->lock); for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) { if (easrc->pair[i]) @@ -1331,8 +1328,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) easrc->channel_avail -= channels; } - spin_unlock_irqrestore(&easrc->lock, lock_flags); - return ret; } @@ -1343,7 +1338,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) */ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx) { - unsigned long lock_flags; struct fsl_asrc *easrc; if (!ctx) @@ -1351,14 +1345,12 @@ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx) easrc = ctx->asrc; - spin_lock_irqsave(&easrc->lock, lock_flags); + guard(spinlock_irqsave)(&easrc->lock); fsl_easrc_release_slot(easrc, ctx->index); easrc->channel_avail += ctx->channels; easrc->pair[ctx->index] = NULL; - - spin_unlock_irqrestore(&easrc->lock, lock_flags); } /* @@ -2292,15 +2284,13 @@ static int fsl_easrc_runtime_suspend(struct device *dev) { struct fsl_asrc *easrc = dev_get_drvdata(dev); struct fsl_easrc_priv *easrc_priv = easrc->private; - unsigned long lock_flags; regcache_cache_only(easrc->regmap, true); clk_disable_unprepare(easrc->mem_clk); - spin_lock_irqsave(&easrc->lock, lock_flags); - easrc_priv->firmware_loaded = 0; - spin_unlock_irqrestore(&easrc->lock, lock_flags); + scoped_guard(spinlock_irqsave, &easrc->lock) + easrc_priv->firmware_loaded = 0; return 0; } @@ -2311,7 +2301,6 @@ static int fsl_easrc_runtime_resume(struct device *dev) struct fsl_easrc_priv *easrc_priv = easrc->private; struct fsl_easrc_ctx_priv *ctx_priv; struct fsl_asrc_pair *ctx; - unsigned long lock_flags; int ret; int i; @@ -2323,13 +2312,11 @@ static int fsl_easrc_runtime_resume(struct device *dev) regcache_mark_dirty(easrc->regmap); regcache_sync(easrc->regmap); - spin_lock_irqsave(&easrc->lock, lock_flags); - if (easrc_priv->firmware_loaded) { - spin_unlock_irqrestore(&easrc->lock, lock_flags); - goto skip_load; + scoped_guard(spinlock_irqsave, &easrc->lock) { + if (easrc_priv->firmware_loaded) + return 0; + easrc_priv->firmware_loaded = 1; } - easrc_priv->firmware_loaded = 1; - spin_unlock_irqrestore(&easrc->lock, lock_flags); ret = fsl_easrc_get_firmware(easrc); if (ret) { @@ -2377,9 +2364,6 @@ static int fsl_easrc_runtime_resume(struct device *dev) goto disable_mem_clk; } -skip_load: - return 0; - disable_mem_clk: clk_disable_unprepare(easrc->mem_clk); return ret; From cb87bdabd341e399a6fb18e5d9a7c0c669191719 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:17 +0700 Subject: [PATCH 018/438] ASoC: fsl_esai: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index cde0b0c6c1ef..4a530a6c33f0 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -709,10 +709,9 @@ static void fsl_esai_hw_reset(struct work_struct *work) { struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work); bool tx = true, rx = false, enabled[2]; - unsigned long lock_flags; u32 tfcr, rfcr; - spin_lock_irqsave(&esai_priv->lock, lock_flags); + guard(spinlock_irqsave)(&esai_priv->lock); /* Save the registers */ regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr); regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr); @@ -750,8 +749,6 @@ static void fsl_esai_hw_reset(struct work_struct *work) fsl_esai_trigger_start(esai_priv, tx); if (enabled[rx]) fsl_esai_trigger_start(esai_priv, rx); - - spin_unlock_irqrestore(&esai_priv->lock, lock_flags); } static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, @@ -759,7 +756,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - unsigned long lock_flags; esai_priv->channels[tx] = substream->runtime->channels; @@ -767,16 +763,14 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - spin_lock_irqsave(&esai_priv->lock, lock_flags); - fsl_esai_trigger_start(esai_priv, tx); - spin_unlock_irqrestore(&esai_priv->lock, lock_flags); + scoped_guard(spinlock_irqsave, &esai_priv->lock) + fsl_esai_trigger_start(esai_priv, tx); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irqsave(&esai_priv->lock, lock_flags); - fsl_esai_trigger_stop(esai_priv, tx); - spin_unlock_irqrestore(&esai_priv->lock, lock_flags); + scoped_guard(spinlock_irqsave, &esai_priv->lock) + fsl_esai_trigger_stop(esai_priv, tx); break; default: return -EINVAL; From a1b865cff274b8dc35f520f63ca4ef711b442869 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:18 +0700 Subject: [PATCH 019/438] ASoC: fsl_spdif: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 1b9be85b34c2..ad1206ed9882 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -853,17 +853,15 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; - unsigned long flags; int ret = -EAGAIN; - spin_lock_irqsave(&ctrl->ctl_lock, flags); + guard(spinlock_irqsave)(&ctrl->ctl_lock); if (ctrl->ready_buf) { int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; memcpy(&ucontrol->value.iec958.subcode[0], &ctrl->subcode[idx], SPDIF_UBITS_SIZE); ret = 0; } - spin_unlock_irqrestore(&ctrl->ctl_lock, flags); return ret; } @@ -885,17 +883,15 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; - unsigned long flags; int ret = -EAGAIN; - spin_lock_irqsave(&ctrl->ctl_lock, flags); + guard(spinlock_irqsave)(&ctrl->ctl_lock); if (ctrl->ready_buf) { int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; memcpy(&ucontrol->value.bytes.data[0], &ctrl->qsub[idx], SPDIF_QSUB_SIZE); ret = 0; } - spin_unlock_irqrestore(&ctrl->ctl_lock, flags); return ret; } From 4d748e7082ec11764863bd184f6d58cd43584f54 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:19 +0700 Subject: [PATCH 020/438] ASoC: fsl_ssi: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-7-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index b2e1da1781ae..dc022976c982 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1218,13 +1218,13 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, if (reg > 0x7f) return; - mutex_lock(&fsl_ac97_data->ac97_reg_lock); + guard(mutex)(&fsl_ac97_data->ac97_reg_lock); ret = clk_prepare_enable(fsl_ac97_data->clk); if (ret) { pr_err("ac97 write clk_prepare_enable failed: %d\n", ret); - goto ret_unlock; + return; } lreg = reg << 12; @@ -1238,9 +1238,6 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, udelay(100); clk_disable_unprepare(fsl_ac97_data->clk); - -ret_unlock: - mutex_unlock(&fsl_ac97_data->ac97_reg_lock); } static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, @@ -1252,12 +1249,12 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, unsigned int lreg; int ret; - mutex_lock(&fsl_ac97_data->ac97_reg_lock); + guard(mutex)(&fsl_ac97_data->ac97_reg_lock); ret = clk_prepare_enable(fsl_ac97_data->clk); if (ret) { pr_err("ac97 read clk_prepare_enable failed: %d\n", ret); - goto ret_unlock; + return val; } lreg = (reg & 0x7f) << 12; @@ -1272,8 +1269,6 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, clk_disable_unprepare(fsl_ac97_data->clk); -ret_unlock: - mutex_unlock(&fsl_ac97_data->ac97_reg_lock); return val; } From 94b0cb1dd6d9633d17bcd3242597b0c70e5118a8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:20 +0700 Subject: [PATCH 021/438] ASoC: fsl_xcvr: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-8-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 6677d3bf36ec..41d100500534 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -797,10 +797,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - unsigned long lock_flags; int ret = 0; - spin_lock_irqsave(&xcvr->lock, lock_flags); + guard(spinlock_irqsave)(&xcvr->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -812,7 +811,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); - goto release_lock; + return ret; } if (tx) { @@ -824,7 +823,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) { dev_err(dai->dev, "err updating isr %d\n", ret); - goto release_lock; + return ret; } fallthrough; case FSL_XCVR_MODE_SPDIF: @@ -833,7 +832,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); - goto release_lock; + return ret; } break; } @@ -844,14 +843,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); if (ret < 0) { dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); - goto release_lock; + return ret; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); if (ret < 0) { dev_err(dai->dev, "Error while setting IER0: %d\n", ret); - goto release_lock; + return ret; } /* clear DPATH RESET */ @@ -860,7 +859,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); - goto release_lock; + return ret; } break; @@ -873,14 +872,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); - goto release_lock; + return ret; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); - goto release_lock; + return ret; } if (tx) { @@ -891,7 +890,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); - goto release_lock; + return ret; } if (xcvr->soc_data->spdif_only) break; @@ -905,7 +904,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, if (ret < 0) { dev_err(dai->dev, "Err updating ISR %d\n", ret); - goto release_lock; + return ret; } break; } @@ -916,8 +915,6 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, break; } -release_lock: - spin_unlock_irqrestore(&xcvr->lock, lock_flags); return ret; } @@ -1448,11 +1445,10 @@ static void reset_rx_work(struct work_struct *work) { struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst); struct device *dev = &xcvr->pdev->dev; - unsigned long lock_flags; u32 ext_ctrl; dev_dbg(dev, "reset rx path\n"); - spin_lock_irqsave(&xcvr->lock, lock_flags); + guard(spinlock_irqsave)(&xcvr->lock); regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl); if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) { @@ -1469,7 +1465,6 @@ static void reset_rx_work(struct work_struct *work) FSL_XCVR_EXT_CTRL_RX_DPTH_RESET, 0); } - spin_unlock_irqrestore(&xcvr->lock, lock_flags); } static irqreturn_t irq0_isr(int irq, void *devid) From 929d412fdb0d9cb0bd7bae1b1b64cfaf3cc24524 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:21 +0700 Subject: [PATCH 022/438] ASoC: imx-audio-rpmsg: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-9-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-audio-rpmsg.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index 38aafb8954c7..b55dfbdb4502 100644 --- a/sound/soc/fsl/imx-audio-rpmsg.c +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -22,7 +22,6 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len, struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data; struct rpmsg_info *info; struct rpmsg_msg *msg; - unsigned long flags; if (!rpmsg->rpmsg_pdev) return 0; @@ -37,21 +36,21 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len, /* TYPE C is notification from M core */ switch (r_msg->header.cmd) { case TX_PERIOD_DONE: - spin_lock_irqsave(&info->lock[TX], flags); - msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; - msg->r_msg.param.buffer_tail = - r_msg->param.buffer_tail; - msg->r_msg.param.buffer_tail %= info->num_period[TX]; - spin_unlock_irqrestore(&info->lock[TX], flags); + scoped_guard(spinlock_irqsave, &info->lock[TX]) { + msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->r_msg.param.buffer_tail = + r_msg->param.buffer_tail; + msg->r_msg.param.buffer_tail %= info->num_period[TX]; + } info->callback[TX](info->callback_param[TX]); break; case RX_PERIOD_DONE: - spin_lock_irqsave(&info->lock[RX], flags); - msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; - msg->r_msg.param.buffer_tail = - r_msg->param.buffer_tail; - msg->r_msg.param.buffer_tail %= info->num_period[1]; - spin_unlock_irqrestore(&info->lock[RX], flags); + scoped_guard(spinlock_irqsave, &info->lock[RX]) { + msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->r_msg.param.buffer_tail = + r_msg->param.buffer_tail; + msg->r_msg.param.buffer_tail %= info->num_period[1]; + } info->callback[RX](info->callback_param[RX]); break; default: From 11ce4dd4e7bef521e82694a895dbd926b25084da Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:22 +0700 Subject: [PATCH 023/438] ASoC: fsl_rpmsg: Use guard() for mutex & spin locks Clean up the code using guard() for mutex & spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-10-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-rpmsg.c | 69 +++++++++++++++-------------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 2a4813c6cda9..ee741f3d79bd 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -39,10 +39,9 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, struct rpmsg_device *rpdev = info->rpdev; int ret = 0; - mutex_lock(&info->msg_lock); + guard(mutex)(&info->msg_lock); if (!rpdev) { dev_err(info->dev, "rpmsg channel not ready\n"); - mutex_unlock(&info->msg_lock); return -EINVAL; } @@ -55,15 +54,12 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, sizeof(struct rpmsg_s_msg)); if (ret) { dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret); - mutex_unlock(&info->msg_lock); return ret; } /* No receive msg for TYPE_C command */ - if (msg->s_msg.header.type == MSG_TYPE_C) { - mutex_unlock(&info->msg_lock); + if (msg->s_msg.header.type == MSG_TYPE_C) return 0; - } /* wait response from rpmsg */ ret = wait_for_completion_timeout(&info->cmd_complete, @@ -71,7 +67,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, if (!ret) { dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n", msg->s_msg.header.cmd); - mutex_unlock(&info->msg_lock); return -ETIMEDOUT; } @@ -100,8 +95,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd, info->r_msg.param.resp); - mutex_unlock(&info->msg_lock); - return 0; } @@ -109,14 +102,13 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream, struct rpmsg_msg *msg, struct rpmsg_info *info) { - unsigned long flags; int ret = 0; /* * Queue the work to workqueue. * If the queue is full, drop the message. */ - spin_lock_irqsave(&info->wq_lock, flags); + guard(spinlock_irqsave)(&info->wq_lock); if (info->work_write_index != info->work_read_index) { int index = info->work_write_index; @@ -130,7 +122,6 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream, info->msg_drop_count[substream->stream]++; ret = -EPIPE; } - spin_unlock_irqrestore(&info->wq_lock, flags); return ret; } @@ -523,7 +514,6 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component, snd_pcm_sframes_t avail; struct timer_list *timer; struct rpmsg_msg *msg; - unsigned long flags; int buffer_tail = 0; int written_num; @@ -553,11 +543,11 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component, msg->s_msg.param.buffer_tail = buffer_tail; /* The notification message is updated to latest */ - spin_lock_irqsave(&info->lock[substream->stream], flags); - memcpy(&info->notify[substream->stream], msg, - sizeof(struct rpmsg_s_msg)); - info->notify_updated[substream->stream] = true; - spin_unlock_irqrestore(&info->lock[substream->stream], flags); + scoped_guard(spinlock_irqsave, &info->lock[substream->stream]) { + memcpy(&info->notify[substream->stream], msg, + sizeof(struct rpmsg_s_msg)); + info->notify_updated[substream->stream] = true; + } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) avail = snd_pcm_playback_hw_avail(runtime); @@ -641,7 +631,7 @@ static void imx_rpmsg_pcm_work(struct work_struct *work) bool is_notification = false; struct rpmsg_info *info; struct rpmsg_msg msg; - unsigned long flags; + bool updated; work_of_rpmsg = container_of(work, struct work_of_rpmsg, work); info = work_of_rpmsg->info; @@ -652,25 +642,26 @@ static void imx_rpmsg_pcm_work(struct work_struct *work) * enough data in M core side, need to let M core know * data is updated immediately. */ - spin_lock_irqsave(&info->lock[TX], flags); - if (info->notify_updated[TX]) { - memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg)); - info->notify_updated[TX] = false; - spin_unlock_irqrestore(&info->lock[TX], flags); - info->send_message(&msg, info); - } else { - spin_unlock_irqrestore(&info->lock[TX], flags); + scoped_guard(spinlock_irqsave, &info->lock[TX]) { + updated = info->notify_updated[TX]; + if (updated) { + memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg)); + info->notify_updated[TX] = false; + } } + if (updated) + info->send_message(&msg, info); - spin_lock_irqsave(&info->lock[RX], flags); - if (info->notify_updated[RX]) { - memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg)); - info->notify_updated[RX] = false; - spin_unlock_irqrestore(&info->lock[RX], flags); - info->send_message(&msg, info); - } else { - spin_unlock_irqrestore(&info->lock[RX], flags); + scoped_guard(spinlock_irqsave, &info->lock[RX]) { + updated = info->notify_updated[RX]; + if (updated) { + memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg)); + info->notify_updated[RX] = false; + } } + if (updated) + info->send_message(&msg, info); + /* Skip the notification message for it has been processed above */ if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C && @@ -682,10 +673,10 @@ static void imx_rpmsg_pcm_work(struct work_struct *work) info->send_message(&work_of_rpmsg->msg, info); /* update read index */ - spin_lock_irqsave(&info->wq_lock, flags); - info->work_read_index++; - info->work_read_index %= WORK_MAX_NUM; - spin_unlock_irqrestore(&info->wq_lock, flags); + scoped_guard(spinlock_irqsave, &info->wq_lock) { + info->work_read_index++; + info->work_read_index %= WORK_MAX_NUM; + } } static int imx_rpmsg_pcm_probe(struct platform_device *pdev) From caed9fb2e428e0866c500b8dddabf4993a3aaa30 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:23 +0700 Subject: [PATCH 024/438] ASoC: fsl: mpc5200_dma: Use guard() for spin locks Clean up the code using guard() for spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-11-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 56 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 56e2cf2f727b..bfedb2dea0b3 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -77,18 +77,20 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) { struct psc_dma_stream *s = _psc_dma_stream; - spin_lock(&s->psc_dma->lock); - /* For each finished period, dequeue the completed period buffer - * and enqueue a new one in it's place. */ - while (bcom_buffer_done(s->bcom_task)) { - bcom_retrieve_buffer(s->bcom_task, NULL, NULL); + scoped_guard(spinlock, &s->psc_dma->lock) { + /* + * For each finished period, dequeue the completed period buffer + * and enqueue a new one in its place + */ + while (bcom_buffer_done(s->bcom_task)) { + bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - s->period_current = (s->period_current+1) % s->runtime->periods; - s->period_count++; + s->period_current = (s->period_current+1) % s->runtime->periods; + s->period_count++; - psc_dma_bcom_enqueue_next_buffer(s); + psc_dma_bcom_enqueue_next_buffer(s); + } } - spin_unlock(&s->psc_dma->lock); /* If the stream is active, then also inform the PCM middle layer * of the period finished event. */ @@ -116,7 +118,6 @@ static int psc_dma_trigger(struct snd_soc_component *component, struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; u16 imr; - unsigned long flags; int i; switch (cmd) { @@ -135,19 +136,18 @@ static int psc_dma_trigger(struct snd_soc_component *component, /* Fill up the bestcomm bd queue and enable DMA. * This will begin filling the PSC's fifo. */ - spin_lock_irqsave(&psc_dma->lock, flags); + scoped_guard(spinlock_irqsave, &psc_dma->lock) { + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + bcom_gen_bd_rx_reset(s->bcom_task); + else + bcom_gen_bd_tx_reset(s->bcom_task); - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - bcom_gen_bd_rx_reset(s->bcom_task); - else - bcom_gen_bd_tx_reset(s->bcom_task); + for (i = 0; i < runtime->periods; i++) + if (!bcom_queue_full(s->bcom_task)) + psc_dma_bcom_enqueue_next_buffer(s); - for (i = 0; i < runtime->periods; i++) - if (!bcom_queue_full(s->bcom_task)) - psc_dma_bcom_enqueue_next_buffer(s); - - bcom_enable(s->bcom_task); - spin_unlock_irqrestore(&psc_dma->lock, flags); + bcom_enable(s->bcom_task); + } out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); @@ -158,13 +158,13 @@ static int psc_dma_trigger(struct snd_soc_component *component, substream->pstr->stream, s->period_count); s->active = 0; - spin_lock_irqsave(&psc_dma->lock, flags); - bcom_disable(s->bcom_task); - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - bcom_gen_bd_rx_reset(s->bcom_task); - else - bcom_gen_bd_tx_reset(s->bcom_task); - spin_unlock_irqrestore(&psc_dma->lock, flags); + scoped_guard(spinlock_irqsave, &psc_dma->lock) { + bcom_disable(s->bcom_task); + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + bcom_gen_bd_rx_reset(s->bcom_task); + else + bcom_gen_bd_tx_reset(s->bcom_task); + } break; From 8a2d7e46317a85327f8a7ea7d33139394b2b9662 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 15 Jun 2026 16:38:24 +0700 Subject: [PATCH 025/438] ASoC: fsl: mpc5200_psc_ac97: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Frank Li Link: https://patch.msgid.link/20260615093824.115751-12-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_psc_ac97.c | 34 +++++++++++--------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 8554fb690772..d4d9f5b6bc07 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -31,14 +31,13 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg) int status; unsigned int val; - mutex_lock(&psc_dma->mutex); + guard(mutex)(&psc_dma->mutex); /* Wait for command send status zero = ready */ status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & MPC52xx_PSC_SR_CMDSEND), 100, 0); if (status == 0) { pr_err("timeout on ac97 bus (rdy)\n"); - mutex_unlock(&psc_dma->mutex); return -ENODEV; } @@ -54,19 +53,16 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg) if (status == 0) { pr_err("timeout on ac97 read (val) %x\n", in_be16(&psc_dma->psc_regs->sr_csr.status)); - mutex_unlock(&psc_dma->mutex); return -ENODEV; } /* Get the data */ val = in_be32(&psc_dma->psc_regs->ac97_data); if (((val >> 24) & 0x7f) != reg) { pr_err("reg echo error on ac97 read\n"); - mutex_unlock(&psc_dma->mutex); return -ENODEV; } val = (val >> 8) & 0xffff; - mutex_unlock(&psc_dma->mutex); return (unsigned short) val; } @@ -75,52 +71,46 @@ static void psc_ac97_write(struct snd_ac97 *ac97, { int status; - mutex_lock(&psc_dma->mutex); + guard(mutex)(&psc_dma->mutex); /* Wait for command status zero = ready */ status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & MPC52xx_PSC_SR_CMDSEND), 100, 0); if (status == 0) { pr_err("timeout on ac97 bus (write)\n"); - goto out; + return; } /* Write data */ out_be32(&psc_dma->psc_regs->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8)); - - out: - mutex_unlock(&psc_dma->mutex); } static void psc_ac97_warm_reset(struct snd_ac97 *ac97) { struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - mutex_lock(&psc_dma->mutex); + guard(mutex)(&psc_dma->mutex); out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); udelay(3); out_be32(®s->sicr, psc_dma->sicr); - - mutex_unlock(&psc_dma->mutex); } static void psc_ac97_cold_reset(struct snd_ac97 *ac97) { struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - mutex_lock(&psc_dma->mutex); - dev_dbg(psc_dma->dev, "cold reset\n"); + scoped_guard(mutex, &psc_dma->mutex) { + dev_dbg(psc_dma->dev, "cold reset\n"); - mpc5200_psc_ac97_gpio_reset(psc_dma->id); + mpc5200_psc_ac97_gpio_reset(psc_dma->id); - /* Notify the PSC that a reset has occurred */ - out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB); + /* Notify the PSC that a reset has occurred */ + out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB); - /* Re-enable RX and TX */ - out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); - - mutex_unlock(&psc_dma->mutex); + /* Re-enable RX and TX */ + out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + } usleep_range(1000, 2000); psc_ac97_warm_reset(ac97); From f16513ffa944347fe2680a236810fa2d236bb1cc Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 26 Jun 2026 15:29:00 +0700 Subject: [PATCH 026/438] ASoC: Intel: avs: Use guard() for locking Clean up the code using guard() for spin & mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260626082904.32344-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/apl.c | 8 +++---- sound/soc/intel/avs/control.c | 7 ++---- sound/soc/intel/avs/core.c | 4 ++-- sound/soc/intel/avs/debug.h | 10 +++----- sound/soc/intel/avs/ipc.c | 11 ++++----- sound/soc/intel/avs/path.c | 30 +++++++---------------- sound/soc/intel/avs/utils.c | 45 +++++++++++++---------------------- 7 files changed, 39 insertions(+), 76 deletions(-) diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index b922eeaba843..cf600e1c986e 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski // +#include #include #include #include @@ -190,7 +191,7 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev) { struct avs_path *path; - spin_lock(&adev->path_list_lock); + guard(spinlock)(&adev->path_list_lock); /* Any gateway without buffer allocated in LP area disqualifies D0IX. */ list_for_each_entry(path, &adev->path_list, node) { struct avs_path_pipeline *ppl; @@ -210,14 +211,11 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev) if (cfg->copier.dma_type == INVALID_OBJECT_ID) continue; - if (!mod->gtw_attrs.lp_buffer_alloc) { - spin_unlock(&adev->path_list_lock); + if (!mod->gtw_attrs.lp_buffer_alloc) return false; - } } } } - spin_unlock(&adev->path_list_lock); return true; } diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c index a8f05de338e0..370069247a7d 100644 --- a/sound/soc/intel/avs/control.c +++ b/sound/soc/intel/avs/control.c @@ -27,7 +27,7 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i struct avs_path_pipeline *ppl; struct avs_path_module *mod; - spin_lock(&adev->path_list_lock); + guard(spinlock)(&adev->path_list_lock); 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) { @@ -35,14 +35,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) || guid_equal(type, &AVS_GAIN_MOD_UUID)) && - mod->template->ctl_id == id) { - spin_unlock(&adev->path_list_lock); + mod->template->ctl_id == id) return mod; - } } } } - spin_unlock(&adev->path_list_lock); return NULL; } diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 1a53856c2ffb..2afe59646896 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -14,6 +14,7 @@ // foundation of this driver // +#include #include #include #include @@ -273,7 +274,7 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus) if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream)) ret = IRQ_HANDLED; - spin_lock_irq(&bus->reg_lock); + guard(spinlock_irq)(&bus->reg_lock); /* Clear RIRB interrupt. */ status = snd_hdac_chip_readb(bus, RIRBSTS); if (status & RIRB_INT_MASK) { @@ -283,7 +284,6 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus) ret = IRQ_HANDLED; } - spin_unlock_irq(&bus->reg_lock); return ret; } diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h index 94fe8729a5c1..c47fc4e8b02b 100644 --- a/sound/soc/intel/avs/debug.h +++ b/sound/soc/intel/avs/debug.h @@ -9,6 +9,7 @@ #ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H #define __SOUND_SOC_INTEL_AVS_DEBUG_H +#include #include "messages.h" #include "registers.h" @@ -26,14 +27,9 @@ struct avs_dev; static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) { - unsigned long flags; - int ret; + guard(spinlock_irqsave)(&adev->trace_lock); - spin_lock_irqsave(&adev->trace_lock, flags); - ret = avs_dsp_op(adev, log_buffer_status, msg); - spin_unlock_irqrestore(&adev->trace_lock, flags); - - return ret; + return avs_dsp_op(adev, log_buffer_status, msg); } struct avs_apl_log_buffer_layout { diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index c0feb9edd7f6..e99cb703eb7e 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski // +#include #include #include #include @@ -397,7 +398,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request if (!ipc->ready) return -EPERM; - mutex_lock(&ipc->msg_mutex); + guard(mutex)(&ipc->msg_mutex); spin_lock(&ipc->rx_lock); avs_ipc_msg_init(ipc, reply); @@ -412,7 +413,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request /* Same treatment as on exception, just stack_dump=0. */ avs_dsp_exception_caught(adev, &msg); } - goto exit; + return ret; } ret = ipc->rx.rsp.status; @@ -436,8 +437,6 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request memcpy(reply->data, ipc->rx.data, reply->size); } -exit: - mutex_unlock(&ipc->msg_mutex); return ret; } @@ -501,7 +500,7 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req struct avs_ipc *ipc = adev->ipc; int ret; - mutex_lock(&ipc->msg_mutex); + guard(mutex)(&ipc->msg_mutex); spin_lock(&ipc->rx_lock); avs_ipc_msg_init(ipc, NULL); @@ -522,8 +521,6 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n", name, request->glb.primary, request->glb.ext.val, ret); - mutex_unlock(&ipc->msg_mutex); - return ret; } diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index 2291f9728a54..213d6ecdd7cc 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski // +#include #include #include #include @@ -69,16 +70,13 @@ avs_path_find_path(struct avs_dev *adev, const char *name, u32 template_id) if (!template) return NULL; - spin_lock(&adev->path_list_lock); + guard(spinlock)(&adev->path_list_lock); /* Only one variant of given path template may be instantiated at a time. */ list_for_each_entry(path, &adev->path_list, node) { - if (path->template->owner == template) { - spin_unlock(&adev->path_list_lock); + if (path->template->owner == template) return path; - } } - spin_unlock(&adev->path_list_lock); return NULL; } @@ -1305,7 +1303,7 @@ void avs_path_free(struct avs_path *path) struct avs_path *cpath, *csave; struct avs_dev *adev = path->owner; - mutex_lock(&adev->path_mutex); + guard(mutex)(&adev->path_mutex); /* Free all condpaths this path spawned. */ list_for_each_entry_safe(cpath, csave, &path->source_list, source_node) @@ -1314,8 +1312,6 @@ void avs_path_free(struct avs_path *path) avs_condpath_free(path->owner, cpath); avs_path_free_unlocked(path); - - mutex_unlock(&adev->path_mutex); } struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, @@ -1334,13 +1330,13 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, } /* Serialize path and its components creation. */ - mutex_lock(&adev->path_mutex); + guard(mutex)(&adev->path_mutex); /* Satisfy needs of avs_path_find_tplg(). */ - mutex_lock(&adev->comp_list_mutex); + guard(mutex)(&adev->comp_list_mutex); path = avs_path_create_unlocked(adev, dma_id, variant); if (IS_ERR(path)) - goto exit; + return path; ret = avs_condpaths_walk_all(adev, path); if (ret) { @@ -1348,10 +1344,6 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, path = ERR_PTR(ret); } -exit: - mutex_unlock(&adev->comp_list_mutex); - mutex_unlock(&adev->path_mutex); - return path; } @@ -1496,15 +1488,13 @@ static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path) { struct avs_path *cpath; - mutex_lock(&adev->path_mutex); + guard(mutex)(&adev->path_mutex); /* If either source or sink stops, so do the attached conditional paths. */ list_for_each_entry(cpath, &path->source_list, source_node) avs_condpath_pause(adev, cpath); list_for_each_entry(cpath, &path->sink_list, sink_node) avs_condpath_pause(adev, cpath); - - mutex_unlock(&adev->path_mutex); } int avs_path_pause(struct avs_path *path) @@ -1560,7 +1550,7 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t { struct avs_path *cpath; - mutex_lock(&adev->path_mutex); + guard(mutex)(&adev->path_mutex); /* Run conditional paths only if source and sink are both running. */ list_for_each_entry(cpath, &path->source_list, source_node) @@ -1572,8 +1562,6 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t if (cpath->source->state == AVS_PPL_STATE_RUNNING && cpath->sink->state == AVS_PPL_STATE_RUNNING) avs_condpath_run(adev, cpath, trigger); - - mutex_unlock(&adev->path_mutex); } int avs_path_run(struct avs_path *path, int trigger) diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c index ee36725ac731..ea14ec173855 100644 --- a/sound/soc/intel/avs/utils.c +++ b/sound/soc/intel/avs/utils.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski // +#include #include #include #include @@ -48,13 +49,12 @@ int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_mo { int idx; - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); idx = avs_module_entry_index(adev, uuid); if (idx >= 0) memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry)); - mutex_unlock(&adev->modres_mutex); return (idx < 0) ? idx : 0; } @@ -62,13 +62,12 @@ int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_modu { int idx; - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); idx = avs_module_id_entry_index(adev, module_id); if (idx >= 0) memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry)); - mutex_unlock(&adev->modres_mutex); return (idx < 0) ? idx : 0; } @@ -86,13 +85,12 @@ bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id) bool ret = false; int idx; - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); idx = avs_module_id_entry_index(adev, module_id); if (idx >= 0) ret = ida_is_empty(adev->mod_idas[idx]); - mutex_unlock(&adev->modres_mutex); return ret; } @@ -163,68 +161,57 @@ int avs_module_info_init(struct avs_dev *adev, bool purge) if (ret) return AVS_IPC_RET(ret); - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); ret = avs_module_ida_alloc(adev, info, purge); if (ret < 0) { dev_err(adev->dev, "initialize module idas failed: %d\n", ret); - goto exit; + return ret; } /* Refresh current information with newly received table. */ kfree(adev->mods_info); adev->mods_info = info; -exit: - mutex_unlock(&adev->modres_mutex); return ret; } void avs_module_info_free(struct avs_dev *adev) { - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); avs_module_ida_destroy(adev); kfree(adev->mods_info); adev->mods_info = NULL; - - mutex_unlock(&adev->modres_mutex); } int avs_module_id_alloc(struct avs_dev *adev, u16 module_id) { - int ret, idx, max_id; + int idx, max_id; - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); idx = avs_module_id_entry_index(adev, module_id); if (idx == -ENOENT) { dev_err(adev->dev, "invalid module id: %d", module_id); - ret = -EINVAL; - goto exit; + return -EINVAL; } max_id = adev->mods_info->entries[idx].instance_max_count - 1; - ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL); -exit: - mutex_unlock(&adev->modres_mutex); - return ret; + + return ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL); } void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id) { int idx; - mutex_lock(&adev->modres_mutex); + guard(mutex)(&adev->modres_mutex); idx = avs_module_id_entry_index(adev, module_id); - if (idx == -ENOENT) { + if (idx == -ENOENT) dev_err(adev->dev, "invalid module id: %d", module_id); - goto exit; - } - - ida_free(adev->mod_idas[idx], instance_id); -exit: - mutex_unlock(&adev->modres_mutex); + else + ida_free(adev->mod_idas[idx], instance_id); } /* From 6aaac9f6baa55cbc4c5cd6071dba11928dc15302 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 26 Jun 2026 15:29:01 +0700 Subject: [PATCH 027/438] ASoC: Intel: avs: Use scoped_guard() for scoped locking Clean up the code using scoped_guard() for mutex & spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260626082904.32344-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/avs/debugfs.c | 19 +++++++------- sound/soc/intel/avs/ipc.c | 48 +++++++++++++++++------------------ sound/soc/intel/avs/loader.c | 15 ++++++----- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index 701c247227bf..9ab503da3b75 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski // +#include #include #include #include @@ -251,24 +252,22 @@ static int strace_release(struct inode *inode, struct file *file) union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS); struct avs_dev *adev = file->private_data; unsigned long resource_mask; - unsigned long flags, i; + unsigned long i; u32 num_cores; resource_mask = adev->logged_resources; num_cores = adev->hw_cfg.dsp_cores; - spin_lock_irqsave(&adev->trace_lock, flags); + scoped_guard(spinlock_irqsave, &adev->trace_lock) { + /* Gather any remaining logs. */ + for_each_set_bit(i, &resource_mask, num_cores) { + msg.log.core = i; + avs_dsp_op(adev, log_buffer_status, &msg); + } - /* Gather any remaining logs. */ - for_each_set_bit(i, &resource_mask, num_cores) { - msg.log.core = i; - avs_dsp_op(adev, log_buffer_status, &msg); + kfifo_free(&adev->trace_fifo); } - kfifo_free(&adev->trace_fifo); - - spin_unlock_irqrestore(&adev->trace_lock, flags); - module_put(adev->dev->driver->owner); return 0; } diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index e99cb703eb7e..71e7997e52c2 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -100,39 +100,39 @@ static void avs_dsp_recovery(struct avs_dev *adev) unsigned int core_mask; int ret; - mutex_lock(&adev->comp_list_mutex); - /* disconnect all running streams */ - list_for_each_entry(acomp, &adev->comp_list, node) { - struct snd_soc_pcm_runtime *rtd; - struct snd_soc_card *card; + scoped_guard(mutex, &adev->comp_list_mutex) { + /* disconnect all running streams */ + list_for_each_entry(acomp, &adev->comp_list, node) { + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_card *card; - card = acomp->base.card; - if (!card) - continue; - - for_each_card_rtds(card, rtd) { - struct snd_pcm *pcm; - int dir; - - pcm = rtd->pcm; - if (!pcm || rtd->dai_link->no_pcm) + card = acomp->base.card; + if (!card) continue; - for_each_pcm_streams(dir) { - struct snd_pcm_substream *substream; + for_each_card_rtds(card, rtd) { + struct snd_pcm *pcm; + int dir; - substream = pcm->streams[dir].substream; - if (!substream || !substream->runtime) + pcm = rtd->pcm; + if (!pcm || rtd->dai_link->no_pcm) continue; - /* No need for _irq() as we are in nonatomic context. */ - snd_pcm_stream_lock(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); - snd_pcm_stream_unlock(substream); + for_each_pcm_streams(dir) { + struct snd_pcm_substream *substream; + + substream = pcm->streams[dir].substream; + if (!substream || !substream->runtime) + continue; + + /* No need for _irq() as we are in nonatomic context. */ + snd_pcm_stream_lock(substream); + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + snd_pcm_stream_unlock(substream); + } } } } - mutex_unlock(&adev->comp_list_mutex); /* forcibly shutdown all cores */ core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0); diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 353e343b1d28..bebdc79ec88e 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski // +#include #include #include #include @@ -630,15 +631,15 @@ static int avs_load_firmware(struct avs_dev *adev, bool purge) if (ret) goto reenable_gating; - mutex_lock(&adev->comp_list_mutex); - list_for_each_entry(acomp, &adev->comp_list, node) { - struct avs_tplg *tplg = acomp->tplg; + scoped_guard(mutex, &adev->comp_list_mutex) { + list_for_each_entry(acomp, &adev->comp_list, node) { + struct avs_tplg *tplg = acomp->tplg; - ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); - if (ret < 0) - break; + ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); + if (ret < 0) + break; + } } - mutex_unlock(&adev->comp_list_mutex); reenable_gating: avs_hda_l1sen_enable(adev, true); From 4889a8a73f65b8e4feb49ea434b8a41806513574 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 26 Jun 2026 15:29:02 +0700 Subject: [PATCH 028/438] ASoC: intel: atom: Use __free(kfree) for stream pointer Declare 'stream' with __free(kfree) so it is automatically freed when leaving scope. This allows direct returns from error paths and removes the explicit kfree(stream) call. Set 'stream' to NULL after ownership has been transferred to runtime->private_data to prevent it from being freed on the success path. This cleanup is a preparation step for upcoming locking changes. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260626082904.32344-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index f074af2499c8..67506a718158 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -11,6 +11,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -304,7 +305,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, { int ret_val = 0; struct snd_pcm_runtime *runtime = substream->runtime; - struct sst_runtime_stream *stream; + struct sst_runtime_stream *stream __free(kfree) = NULL; stream = kzalloc_obj(*stream); if (!stream) @@ -330,7 +331,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, ret_val = power_up_sst(stream); if (ret_val < 0) - goto out_power_up; + return ret_val; /* * Make sure the period to be multiple of 1ms to align the @@ -347,12 +348,19 @@ static int sst_media_open(struct snd_pcm_substream *substream, snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); - return snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); + ret_val = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + if (ret_val < 0) + return ret_val; + + stream = NULL; + + return ret_val; + out_ops: mutex_unlock(&sst_lock); -out_power_up: - kfree(stream); + return ret_val; } From 71c0f725d35de81b06076a4d1448ea4733993a4b Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 26 Jun 2026 15:29:03 +0700 Subject: [PATCH 029/438] ASoC: Intel: atom: Use guard() for locking Clean up the code using guard() for spin & mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260626082904.32344-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 29 ++++++-------------- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 25 ++++++----------- sound/soc/intel/atom/sst/sst_ipc.c | 5 ++-- sound/soc/intel/atom/sst/sst_pvt.c | 9 +++--- 4 files changed, 23 insertions(+), 45 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 3629ceaaac17..701369349fb6 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -14,6 +14,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -73,14 +74,10 @@ static int sst_fill_and_send_cmd(struct sst_data *drv, u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, void *cmd_data, u16 len) { - int ret; + guard(mutex)(&drv->lock); - mutex_lock(&drv->lock); - ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, - task_id, pipe_id, cmd_data, len); - mutex_unlock(&drv->lock); - - return ret; + return sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, + task_id, pipe_id, cmd_data, len); } /* @@ -167,7 +164,7 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol, unsigned int val, mux; u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map; - mutex_lock(&drv->lock); + guard(mutex)(&drv->lock); val = 1 << ctl_no; /* search which slot/channel has this bit set - there should be only one */ for (mux = e->max; mux > 0; mux--) @@ -175,7 +172,6 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol, break; ucontrol->value.enumerated.item[0] = mux; - mutex_unlock(&drv->lock); dev_dbg(c->dev, "%s - %s map = %#x\n", is_tx ? "tx channel" : "rx slot", @@ -235,7 +231,7 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol, if (mux > e->max - 1) return -EINVAL; - mutex_lock(&drv->lock); + guard(mutex)(&drv->lock); /* first clear all registers of this bit */ for (i = 0; i < e->max; i++) map[i] &= ~val; @@ -244,7 +240,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol, /* kctl set to 'none' and we reset the bits so send IPC */ ret = sst_check_and_send_slot_map(drv, kcontrol); - mutex_unlock(&drv->lock); return ret; } @@ -258,7 +253,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol, ret = sst_check_and_send_slot_map(drv, kcontrol); - mutex_unlock(&drv->lock); return ret; } @@ -354,13 +348,12 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, struct sst_algo_control *bc = (void *)kcontrol->private_value; dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name); - mutex_lock(&drv->lock); + guard(mutex)(&drv->lock); switch (bc->type) { case SST_ALGO_PARAMS: memcpy(bc->params, ucontrol->value.bytes.data, bc->max); break; default: - mutex_unlock(&drv->lock); dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n", bc->type); return -EINVAL; @@ -368,7 +361,6 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, /*if pipe is enabled, need to send the algo params from here*/ if (bc->w && bc->w->power) ret = sst_send_algo_cmd(drv, bc); - mutex_unlock(&drv->lock); return ret; } @@ -475,7 +467,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; struct sst_gain_value *gv = mc->gain_val; - mutex_lock(&drv->lock); + guard(mutex)(&drv->lock); switch (mc->type) { case SST_GAIN_TLV: @@ -497,7 +489,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, break; default: - mutex_unlock(&drv->lock); dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n", mc->type); return -EINVAL; @@ -506,7 +497,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, if (mc->w && mc->w->power) ret = sst_send_gain_cmd(drv, gv, mc->task_id, mc->pipe_id | mc->instance_id, mc->module_id, 0); - mutex_unlock(&drv->lock); return ret; } @@ -521,10 +511,9 @@ static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w, struct sst_data *drv = snd_soc_component_get_drvdata(c); struct sst_ids *ids = w->priv; - mutex_lock(&drv->lock); + guard(mutex)(&drv->lock); sst_find_and_send_pipe_algo(drv, w->name, ids); sst_set_pipe_gain(ids, drv, 0); - mutex_unlock(&drv->lock); return 0; } diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 67506a718158..c757e4dcd7cf 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -33,7 +33,7 @@ int sst_register_dsp(struct sst_device *dev) return -EINVAL; if (!try_module_get(dev->dev->driver->owner)) return -ENODEV; - mutex_lock(&sst_lock); + guard(mutex)(&sst_lock); if (sst) { dev_err(dev->dev, "we already have a device %s\n", sst->name); module_put(dev->dev->driver->owner); @@ -42,7 +42,7 @@ int sst_register_dsp(struct sst_device *dev) } dev_dbg(dev->dev, "registering device %s\n", dev->name); sst = dev; - mutex_unlock(&sst_lock); + return 0; } EXPORT_SYMBOL_GPL(sst_register_dsp); @@ -54,17 +54,15 @@ int sst_unregister_dsp(struct sst_device *dev) if (dev != sst) return -EINVAL; - mutex_lock(&sst_lock); + guard(mutex)(&sst_lock); - if (!sst) { - mutex_unlock(&sst_lock); + if (!sst) return -EIO; - } module_put(sst->dev->driver->owner); dev_dbg(dev->dev, "unreg %s\n", sst->name); sst = NULL; - mutex_unlock(&sst_lock); + return 0; } EXPORT_SYMBOL_GPL(sst_unregister_dsp); @@ -104,21 +102,14 @@ static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream) void sst_set_stream_status(struct sst_runtime_stream *stream, int state) { - unsigned long flags; - spin_lock_irqsave(&stream->status_lock, flags); + guard(spinlock_irqsave)(&stream->status_lock); stream->stream_status = state; - spin_unlock_irqrestore(&stream->status_lock, flags); } static inline int sst_get_stream_status(struct sst_runtime_stream *stream) { - int state; - unsigned long flags; - - spin_lock_irqsave(&stream->status_lock, flags); - state = stream->stream_status; - spin_unlock_irqrestore(&stream->status_lock, flags); - return state; + guard(spinlock_irqsave)(&stream->status_lock); + return stream->stream_status; } static void sst_fill_alloc_params(struct snd_pcm_substream *substream, diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 0d5e71e8a5b5..6c19ab63aa4f 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -11,6 +11,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include #include @@ -180,9 +181,8 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) union interrupt_reg_mrfld isr; union interrupt_reg_mrfld imr; union ipc_header_mrfld clear_ipc; - unsigned long irq_flags; - spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); + guard(spinlock_irqsave)(&sst_drv_ctx->ipc_spin_lock); imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX); isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX); @@ -200,7 +200,6 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) /* un mask busy interrupt */ imr.part.busy_interrupt = 0; sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full); - spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); } diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 67b1ab14239f..0b0cfd70efbc 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -11,6 +11,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include #include @@ -64,9 +65,8 @@ u64 sst_shim_read64(void __iomem *addr, int offset) void sst_set_fw_state_locked( struct intel_sst_drv *sst_drv_ctx, int sst_state) { - mutex_lock(&sst_drv_ctx->sst_lock); + guard(mutex)(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = sst_state; - mutex_unlock(&sst_drv_ctx->sst_lock); } /* @@ -302,18 +302,17 @@ int sst_assign_pvt_id(struct intel_sst_drv *drv) { int local; - spin_lock(&drv->block_lock); + guard(spinlock)(&drv->block_lock); /* find first zero index from lsb */ local = ffz(drv->pvt_id); dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local); if (local >= SST_MAX_BLOCKS){ - spin_unlock(&drv->block_lock); dev_err(drv->dev, "PVT _ID error: no free id blocks "); return -EINVAL; } /* toggle the index */ change_bit(local, &drv->pvt_id); - spin_unlock(&drv->block_lock); + return local; } From 08d2d5e683e85a7dc33c1abfd50fdc380bfafb5a Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 26 Jun 2026 15:29:04 +0700 Subject: [PATCH 030/438] ASoC: Intel: atom: Use scoped_guard() for scoped locking Clean up the code using scoped_guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260626082904.32344-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 38 ++++++++++---------- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 20 ++++------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 701369349fb6..82df398237da 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -750,27 +750,29 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) return ret; } - mutex_lock(&drv->lock); - if (enable) - timer_usage++; - else - timer_usage--; - - /* - * Send the command only if this call is the first enable or last - * disable - */ - if ((enable && (timer_usage == 1)) || - (!enable && (timer_usage == 0))) { - ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD, - SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd, - sizeof(cmd.header) + cmd.header.length); - if (ret && enable) { + scoped_guard(mutex, &drv->lock) { + if (enable) + timer_usage++; + else timer_usage--; - enable = false; + + /* + * Send the command only if this call is the first enable or last + * disable + */ + if ((enable && timer_usage == 1) || + (!enable && timer_usage == 0)) { + ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD, + SST_FLAG_BLOCKED, + SST_TASK_SBA, 0, &cmd, + sizeof(cmd.header) + + cmd.header.length); + if (ret && enable) { + timer_usage--; + enable = false; + } } } - mutex_unlock(&drv->lock); if (!enable) sst->ops->power(sst->dev, false); diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index c757e4dcd7cf..9ee4d9926e06 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -304,15 +304,14 @@ static int sst_media_open(struct snd_pcm_substream *substream, spin_lock_init(&stream->status_lock); /* get the sst ops */ - mutex_lock(&sst_lock); - if (!sst || - !try_module_get(sst->dev->driver->owner)) { - dev_err(dai->dev, "no device available to run\n"); - ret_val = -ENODEV; - goto out_ops; + scoped_guard(mutex, &sst_lock) { + if (!sst || + !try_module_get(sst->dev->driver->owner)) { + dev_err(dai->dev, "no device available to run\n"); + return -ENODEV; + } + stream->ops = sst->ops; } - stream->ops = sst->ops; - mutex_unlock(&sst_lock); stream->stream_info.str_id = 0; @@ -347,11 +346,6 @@ static int sst_media_open(struct snd_pcm_substream *substream, stream = NULL; - return ret_val; - -out_ops: - mutex_unlock(&sst_lock); - return ret_val; } From 84eb7c8e59ccbcd45b2678abac56b778c97ee270 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 22 Jun 2026 17:11:39 +0800 Subject: [PATCH 031/438] ASoC: rt1321: move DSP status checking into a helper function This patch creates the rt1320_dspfw_status helper function to check DSP status. The new function can be reused by other functions and supports checking the DSP status across different amplifiers. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20260622091139.2183297-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1320-sdw.c | 117 ++++++++++++++-------------------- 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 13493b85f3c9..8d6fe2e36fc7 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -893,6 +893,42 @@ static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320) return 0; } +static int rt1320_dspfw_status(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + unsigned int fw_status_addr, fw_ready; + unsigned int dspfw_run; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + fw_status_addr = RT1320_DSPFW_STATUS_ADDR; + break; + case RT1321_DEV_ID: + fw_status_addr = RT1321_DSPFW_STATUS_ADDR; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); + fw_ready &= 0x1; + + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_read(rt1320->regmap, 0xf01e, &dspfw_run); + dspfw_run &= 0x1; + fw_ready = (!dspfw_run && fw_ready); + } + + if (fw_ready) { + dev_dbg(dev, "%s, DSP FW was already\n", __func__); + return 1; + } + + dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); + return 0; +} + static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps) { struct device *dev = &rt1320->sdw_slave->dev; @@ -1126,30 +1162,18 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) struct device *dev = &rt1320->sdw_slave->dev; struct rt1320_datafixpoint audfixpoint[2]; unsigned int reg_c5fb, reg_c570, reg_cd00; - unsigned int vol_reg[4], fw_ready; + unsigned int vol_reg[4]; unsigned long long l_meanr0, r_meanr0; - unsigned int fw_status_addr; int l_re[5], r_re[5]; int ret, tmp; unsigned long long factor = (1 << 27); unsigned short l_advancegain, r_advancegain; unsigned int delay_s = 7; /* delay seconds for the calibration */ + int dspfw_status; if (!rt1320->component) return; - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return; - } - /* set volume 0dB */ regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]); regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]); @@ -1172,9 +1196,8 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) goto _finish_; } - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (!fw_ready) { + dspfw_status = rt1320_dspfw_status(rt1320); + if (dspfw_status <= 0) { dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); goto _finish_; } @@ -1383,30 +1406,17 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320) static void rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0) { struct device *dev = &rt1320->sdw_slave->dev; - unsigned int factor = (1 << 22), fw_ready; + unsigned int factor = (1 << 22); int l_t0_data[38], r_t0_data[38]; - unsigned int fw_status_addr; - - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return; - } + int dspfw_status; regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (!fw_ready) { + dspfw_status = rt1320_dspfw_status(rt1320); + if (dspfw_status <= 0) { dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__); goto _exit_; } @@ -1599,8 +1609,7 @@ struct rt1320_dspfwheader { struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1320->component); struct device *dev = &rt1320->sdw_slave->dev; - unsigned int val, i, fw_offset, fw_ready; - unsigned int fw_status_addr; + unsigned int val, i, fw_offset; struct rt1320_dspfwheader *fwheader; struct rt1320_imageinfo *ptr_img; struct sdw_bpt_section sec[10]; @@ -1613,18 +1622,6 @@ struct rt1320_dspfwheader { int len_vendor, len_product, len_sku; char filename[512]; - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return; - } - dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR); dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME); dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU); @@ -1654,9 +1651,7 @@ struct rt1320_dspfwheader { RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (fw_ready) { + if (rt1320_dspfw_status(rt1320)) { dev_dbg(dev, "%s, DSP FW was already\n", __func__); rt1320->fw_load_done = true; goto _exit_; @@ -2327,25 +2322,12 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) { struct device *dev = regmap_get_device(rt1320->regmap); - unsigned int fw_status_addr; - unsigned int fw_ready; + int dspfw_status; int ret = 0; if (!rt1320->r0_l_reg || !rt1320->r0_r_reg) return -EINVAL; - switch (rt1320->dev_id) { - case RT1320_DEV_ID: - fw_status_addr = RT1320_DSPFW_STATUS_ADDR; - break; - case RT1321_DEV_ID: - fw_status_addr = RT1321_DSPFW_STATUS_ADDR; - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); - return -EINVAL; - } - regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); @@ -2354,9 +2336,8 @@ static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) goto _timeout_; } - regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); - fw_ready &= 0x1; - if (!fw_ready) { + dspfw_status = rt1320_dspfw_status(rt1320); + if (dspfw_status <= 0) { dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__); goto _timeout_; } From d79828f380b337a118ef93d7f4daabb41dde24bc Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 22 Jun 2026 17:11:48 +0800 Subject: [PATCH 032/438] ASoC: rt1321: add support for rt1321 VA1/VA2 This patch adds support for the RT1321 VA1 and VA2 amplifier. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20260622091149.2183334-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1320-sdw.c | 699 +++++++++++++++++++++++++++++++--- sound/soc/codecs/rt1320-sdw.h | 12 + 2 files changed, 653 insertions(+), 58 deletions(-) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 8d6fe2e36fc7..49fe100aef6e 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -411,6 +411,402 @@ static const struct reg_sequence rt1321_blind_write[] = { { 0x41001988, 0x03 }, }; +static const struct reg_sequence rt1321_va1_blind_write[] = { + { 0x0000c003, 0xf0 }, + { 0x0000c01b, 0xfc }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c2, 0x00 }, + { 0x0000c5c1, 0x10 }, + { 0x0000c5c0, 0x04 }, + { 0x0000c5c7, 0x03 }, + { 0x0000c5c6, 0x10 }, + { 0x0000c526, 0x47 }, + { 0x0000c5c4, 0x12 }, + { 0x0000c5c5, 0x60 }, + { 0x0000c520, 0x10 }, + { 0x0000c521, 0x32 }, + { 0x0000c5c7, 0x00 }, + { 0x0000c5c8, 0x03 }, + { 0x0000c5d3, 0x08 }, + { 0x0000c5d2, 0x0a }, + { 0x0000c5d1, 0x49 }, + { 0x0000c5d0, 0x0f }, + { 0x0000c580, 0x10 }, + { 0x0000c581, 0x32 }, + { 0x0000c582, 0x01 }, + { 0x0000c682, 0x60 }, + { 0x0000c019, 0x10 }, + { 0x0000c5f0, 0x01 }, + { 0x0000c5f7, 0x22 }, + { 0x0000c5f6, 0x22 }, + { 0x0000c057, 0x51 }, + { 0x0000c054, 0x55 }, + { 0x0000c053, 0x55 }, + { 0x0000c052, 0x55 }, + { 0x0000c051, 0x01 }, + { 0x0000c050, 0x15 }, + { 0x0000c060, 0x99 }, + { 0x0000c030, 0x55 }, + { 0x0000c061, 0x55 }, + { 0x0000c063, 0x55 }, + { 0x0000c065, 0xa5 }, + { 0x0000c06b, 0x0a }, + { 0x0000ca05, 0xd6 }, + { 0x0000ca06, 0x11 }, + { 0x0000ca07, 0x1e }, + { 0x0000ca25, 0xd6 }, + { 0x0000ca26, 0x11 }, + { 0x0000ca27, 0x1e }, + { 0x0000cd00, 0x05 }, + { 0x0000cd81, 0x49 }, + { 0x0000cd82, 0x49 }, + { 0x0000c604, 0x40 }, + { 0x0000c609, 0x40 }, + { 0x0000c046, 0xf7 }, + { 0x0000c045, 0xff }, + { 0x0000c044, 0xff }, + { 0x0000c043, 0xff }, + { 0x0000c042, 0xff }, + { 0x0000c041, 0xff }, + { 0x0000c040, 0xff }, + { 0x0000c049, 0xff }, + { 0x0000c028, 0x3f }, + { 0x0000c020, 0x3f }, + { 0x0000c032, 0x13 }, + { 0x0000c033, 0x01 }, + { 0x0000cc10, 0x01 }, + { 0x0000dc20, 0x03 }, + { 0x0000de03, 0x05 }, + { 0x0000dc00, 0x00 }, + { 0x0000c700, 0xf0 }, + { 0x0000c701, 0x13 }, + { 0x0000c900, 0xc3 }, + { 0x0000c570, 0x08 }, + { 0x0000c086, 0x02 }, + { 0x0000c085, 0x7f }, + { 0x0000c084, 0x00 }, + { 0x0000c081, 0xff }, + { 0x0000f084, 0x0f }, + { 0x0000f083, 0xff }, + { 0x0000f082, 0xff }, + { 0x0000f081, 0xff }, + { 0x0000f080, 0xff }, + { 0x20003003, 0x3f }, + { 0x20005818, 0x81 }, + { 0x20009018, 0x81 }, + { 0x2000301c, 0x81 }, + { 0x0000c003, 0xc0 }, + { 0x0000c047, 0x80 }, + { 0x0000d541, 0x80 }, + { 0x0000d487, 0x0b }, + { 0x0000d487, 0x3b }, + { 0x0000d486, 0xc3 }, + { 0x0000d470, 0x89 }, + { 0x0000d471, 0x3a }, + { 0x0000d472, 0x3d }, + { 0x0000d474, 0x11 }, + { 0x0000d475, 0x32 }, + { 0x0000d476, 0x64 }, + { 0x0000d477, 0x10 }, + { 0x0000d478, 0xff }, + { 0x0000d479, 0x20 }, + { 0x0000d47a, 0x10 }, + { 0x0000d73c, 0xb7 }, + { 0x0000d73d, 0xd7 }, + { 0x0000d73e, 0x00 }, + { 0x0000d73f, 0x10 }, + { 0x1000cd56, 0x00 }, + { 0x3fc2dfc0, 0x03 }, + { 0x3fc2dfc1, 0x00 }, + { 0x3fc2dfc2, 0x00 }, + { 0x3fc2dfc3, 0x00 }, + { 0x3fc2dfc4, 0x01 }, + { 0x3fc2dfc5, 0x00 }, + { 0x3fc2dfc6, 0x00 }, + { 0x3fc2dfc7, 0x00 }, + { 0x3fc2df80, 0x00 }, + { 0x3fc2df81, 0x00 }, + { 0x3fc2df82, 0x00 }, + { 0x3fc2df83, 0x00 }, + { 0x0000d541, 0x40 }, + { 0x0000d486, 0x43 }, + { 0x1000db00, 0x04 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x10 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x45 }, + { 0x1000db06, 0x0d }, + { 0x1000db07, 0x01 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0xbf }, + { 0x1000db0b, 0x0b }, + { 0x1000db0c, 0x11 }, + { 0x1000db0d, 0x00 }, + { 0x1000db0e, 0x00 }, + { 0x1000db0f, 0x00 }, + { 0x1000db10, 0x2c }, + { 0x1000db11, 0xfa }, + { 0x1000db12, 0x00 }, + { 0x1000db13, 0x00 }, + { 0x1000db14, 0x09 }, + { 0x0000d540, 0x21 }, + { 0x0000c570, 0x08 }, + { 0x0000d714, 0x17 }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c8, 0x03 }, + { 0x20009012, 0x00 }, + { 0x0000dd08, 0x17 }, + { 0x0000dd09, 0x0e }, + { 0x0000dd0a, 0x17 }, + { 0x0000dd0b, 0x0e }, + { 0x0000c570, 0x08 }, + { 0x0000d471, 0x3a }, + { 0x0000db00, 0x00 }, + { 0x0000db01, 0x00 }, + { 0x0000db02, 0x73 }, + { 0x0000db03, 0x00 }, + { 0x0000db04, 0x00 }, + { 0x0000db05, 0x00 }, + { 0x0000db06, 0x00 }, + { 0x0000db07, 0x00 }, + { 0x0000db08, 0x7f }, + { 0x0000db09, 0x00 }, + { 0x0000db1a, 0x00 }, + { 0x0000db1b, 0x00 }, + { 0x0000db19, 0x00 }, +}; + +static const struct reg_sequence rt1321_va2_blind_write[] = { + { 0x0000c003, 0xf0 }, + { 0x0000c01b, 0xfc }, + { 0x0000c5c3, 0xf2 }, + { 0x0000c5c2, 0x00 }, + { 0x0000c5c1, 0x10 }, + { 0x0000c5c0, 0x04 }, + { 0x0000c5c7, 0x03 }, + { 0x0000c5c6, 0x10 }, + { 0x0000c526, 0x47 }, + { 0x0000c5c4, 0x12 }, + { 0x0000c5c5, 0x60 }, + { 0x0000c520, 0x10 }, + { 0x0000c521, 0x32 }, + { 0x0000c5c7, 0x00 }, + { 0x0000c5c8, 0x03 }, + { 0x0000c5d3, 0x08 }, + { 0x0000c5d2, 0x0a }, + { 0x0000c5d1, 0x49 }, + { 0x0000c5d0, 0x0f }, + { 0x0000c580, 0x10 }, + { 0x0000c581, 0x32 }, + { 0x0000c582, 0x01 }, + { 0x0000c682, 0x60 }, + { 0x0000c019, 0x10 }, + { 0x0000c5f0, 0x01 }, + { 0x0000c5f7, 0x22 }, + { 0x0000c5f6, 0x22 }, + { 0x0000c057, 0x51 }, + { 0x0000c054, 0x55 }, + { 0x0000c053, 0x55 }, + { 0x0000c052, 0x55 }, + { 0x0000c051, 0x01 }, + { 0x0000c050, 0x15 }, + { 0x0000c060, 0x99 }, + { 0x0000c030, 0x55 }, + { 0x0000c061, 0x55 }, + { 0x0000c063, 0x55 }, + { 0x0000c065, 0xa5 }, + { 0x0000c06b, 0x0a }, + { 0x0000ca05, 0xd6 }, + { 0x0000ca06, 0x11 }, + { 0x0000ca07, 0x1e }, + { 0x0000ca25, 0xd6 }, + { 0x0000ca26, 0x11 }, + { 0x0000ca27, 0x1e }, + { 0x0000cd00, 0x05 }, + { 0x0000cd81, 0x49 }, + { 0x0000cd82, 0x49 }, + { 0x0000c604, 0x40 }, + { 0x0000c609, 0x40 }, + { 0x0000c046, 0xf7 }, + { 0x0000c045, 0xff }, + { 0x0000c044, 0xff }, + { 0x0000c043, 0xff }, + { 0x0000c042, 0xff }, + { 0x0000c041, 0xff }, + { 0x0000c040, 0xff }, + { 0x0000c049, 0xff }, + { 0x0000c028, 0x3f }, + { 0x0000c020, 0x3f }, + { 0x0000c032, 0x13 }, + { 0x0000c033, 0x01 }, + { 0x0000cc10, 0x01 }, + { 0x0000dc20, 0x03 }, + { 0x0000de03, 0x05 }, + { 0x0000dc00, 0x00 }, + { 0x0000c700, 0xf0 }, + { 0x0000c701, 0x13 }, + { 0x0000c900, 0xc3 }, + { 0x0000c570, 0x08 }, + { 0x0000c086, 0x02 }, + { 0x0000c085, 0x7f }, + { 0x0000c084, 0x00 }, + { 0x0000c081, 0xff }, + { 0x0000f084, 0x0f }, + { 0x0000f083, 0xff }, + { 0x0000f082, 0xff }, + { 0x0000f081, 0xff }, + { 0x0000f080, 0xff }, + { 0x20003003, 0x3f }, + { 0x20005818, 0x81 }, + { 0x20009018, 0x81 }, + { 0x2000301c, 0x81 }, + { 0x0000c003, 0xc0 }, + { 0x0000c047, 0x80 }, + { 0x0000d541, 0x80 }, + { 0x0000d487, 0x0b }, + { 0x0000d487, 0x3b }, + { 0x0000d486, 0xc3 }, + { 0x0000d470, 0x89 }, + { 0x0000d471, 0x3a }, + { 0x0000d472, 0x3d }, + { 0x0000d474, 0x11 }, + { 0x0000d475, 0x32 }, + { 0x0000d476, 0x64 }, + { 0x0000d477, 0x10 }, + { 0x0000d478, 0xff }, + { 0x0000d479, 0x20 }, + { 0x0000d47a, 0x10 }, + { 0x10008000, 0x67 }, + { 0x10008001, 0x80 }, + { 0x10008002, 0x00 }, + { 0x10008003, 0x00 }, + { 0x1000cd56, 0x00 }, + { 0x0000d486, 0x43 }, + { 0x3fc2dfc3, 0x00 }, + { 0x3fc2dfc2, 0x00 }, + { 0x3fc2dfc1, 0x00 }, + { 0x3fc2dfc0, 0x03 }, + { 0x3fc2dfc7, 0x00 }, + { 0x3fc2dfc6, 0x00 }, + { 0x3fc2dfc5, 0x00 }, + { 0x3fc2dfc4, 0x01 }, + { 0x3fc2dfa3, 0x00 }, + { 0x3fc2dfa2, 0x00 }, + { 0x3fc2dfa1, 0x00 }, + { 0x3fc2dfa0, 0x00 }, + { 0x3fc2df80, 0x10 }, + { 0x3fc2df81, 0x20 }, + { 0x3fc2df82, 0x00 }, + { 0x3fc2df83, 0x00 }, + { 0x3fc2df84, 0x50 }, + { 0x3fc2df85, 0x19 }, + { 0x3fc2df86, 0x00 }, + { 0x3fc2df87, 0x00 }, + { 0x3fc2df88, 0x52 }, + { 0x3fc2df89, 0x23 }, + { 0x3fc2df8a, 0x00 }, + { 0x3fc2df8b, 0x00 }, + { 0x3fc2df8c, 0xe0 }, + { 0x3fc2df8d, 0x2e }, + { 0x3fc2df8e, 0x00 }, + { 0x3fc2df8f, 0x00 }, + { 0x3fc2df90, 0xe0 }, + { 0x3fc2df91, 0x2e }, + { 0x3fc2df92, 0x00 }, + { 0x3fc2df93, 0x00 }, + { 0x3fc2df94, 0x01 }, + { 0x3fc2df95, 0x08 }, + { 0x3fc2df96, 0x00 }, + { 0x3fc2df97, 0x00 }, + { 0x3fc2df40, 0x80 }, + { 0x3fc2df41, 0xbb }, + { 0x3fc2df42, 0x00 }, + { 0x3fc2df43, 0x00 }, + { 0x3fc2df44, 0xc0 }, + { 0x3fc2df45, 0x99 }, + { 0x3fc2df46, 0x01 }, + { 0x3fc2df47, 0x00 }, + { 0x3fc2df48, 0x00 }, + { 0x3fc2df49, 0x00 }, + { 0x3fc2df4a, 0x00 }, + { 0x3fc2df4b, 0x00 }, + { 0x3fc2df4c, 0x00 }, + { 0x3fc2df4d, 0x00 }, + { 0x3fc2df4e, 0x00 }, + { 0x3fc2df4f, 0x00 }, + { 0x3fc2df50, 0x01 }, + { 0x3fc2df51, 0x00 }, + { 0x3fc2df52, 0x00 }, + { 0x3fc2df53, 0x00 }, + { 0x3fc2df54, 0x01 }, + { 0x3fc2df55, 0x00 }, + { 0x3fc2df56, 0x00 }, + { 0x3fc2df57, 0x00 }, + { 0x3fc2df58, 0x00 }, + { 0x3fc2df59, 0x00 }, + { 0x3fc2df5a, 0x00 }, + { 0x3fc2df5b, 0x00 }, + { 0x3fc2df5c, 0x01 }, + { 0x3fc2df5d, 0x00 }, + { 0x3fc2df5e, 0x00 }, + { 0x3fc2df5f, 0x00 }, + { 0x3fc2df60, 0x00 }, + { 0x3fc2df61, 0x00 }, + { 0x3fc2df62, 0x00 }, + { 0x3fc2df63, 0x00 }, + { 0x3fc2df64, 0x00 }, + { 0x3fc2df65, 0x00 }, + { 0x3fc2df66, 0x00 }, + { 0x3fc2df67, 0x10 }, + { 0x3fc2df68, 0x01 }, + { 0x3fc2df69, 0x00 }, + { 0x3fc2df6a, 0x00 }, + { 0x3fc2df6b, 0x00 }, + { 0x3fc2df6c, 0x01 }, + { 0x3fc2df6d, 0x00 }, + { 0x3fc2df6e, 0x00 }, + { 0x3fc2df6f, 0x00 }, + { 0x3fc2df70, 0x04 }, + { 0x3fc2df71, 0x00 }, + { 0x3fc2df72, 0x00 }, + { 0x3fc2df73, 0x00 }, + { 0x3fc2df74, 0x01 }, + { 0x3fc2df75, 0x00 }, + { 0x3fc2df76, 0x00 }, + { 0x3fc2df77, 0x00 }, + { 0x1000db00, 0x04 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x10 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x45 }, + { 0x1000db06, 0x0d }, + { 0x1000db07, 0x01 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0xbf }, + { 0x1000db0b, 0x0b }, + { 0x1000db0c, 0x11 }, + { 0x1000db0d, 0x00 }, + { 0x1000db0e, 0x00 }, + { 0x1000db0f, 0x00 }, + { 0x1000db10, 0x2c }, + { 0x1000db11, 0xfa }, + { 0x1000db12, 0x00 }, + { 0x1000db13, 0x00 }, + { 0x1000db14, 0x09 }, + { 0x0000d540, 0x21 }, + { 0x0000d714, 0x17 }, + { 0x0000dd0b, 0x0d }, + { 0x0000dd0a, 0xff }, + { 0x0000dd09, 0x0d }, + { 0x0000dd08, 0xff }, + { 0x0000c5fb, 0x12 }, + { 0x0000c570, 0x08 }, +}; + static const struct reg_default rt1320_reg_defaults[] = { { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, @@ -498,10 +894,15 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER: case 0x1000f008: case 0x1000f021: - case 0x2000300f: + case 0x20003000 ... 0x2000300f: case 0x2000301c: - case 0x2000900f: + case 0x20003040 ... 0x20003059: + case 0x20005800 ... 0x2000580f: + case 0x20005818: + case 0x20005840 ... 0x20005859: + case 0x20009000 ... 0x2000900f: case 0x20009018: + case 0x20009040 ... 0x20009059: case 0x3fc000c0 ... 0x3fc2dfc8: case 0x3fe00000 ... 0x3fe36fff: /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ @@ -597,15 +998,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0x1000c000 ... 0x1000dfff: case 0x1000f008: case 0x1000f021: - case 0x2000300f: + case 0x2000300e ... 0x2000300f: case 0x2000301c: - case 0x2000900f: + case 0x20003040 ... 0x20003059: + case 0x2000580e ... 0x2000580f: + case 0x20005818: + case 0x20005840 ... 0x20005859: + case 0x2000900e ... 0x2000900f: case 0x20009018: + case 0x20009040 ... 0x20009059: case 0x3fc2ab80 ... 0x3fc2ac4c: case 0x3fc2b780: case 0x3fc2bf80 ... 0x3fc2bf83: case 0x3fc2bfc0 ... 0x3fc2bfc8: - case 0x3fc2d300 ... 0x3fc2d354: + case 0x3fc2d300 ... 0x3fc2d3cc: case 0x3fc2dfc0 ... 0x3fc2dfc8: case 0x3fe2e000 ... 0x3fe2e003: case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): @@ -1019,6 +1425,9 @@ static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_ if (!tempbuf) return -ENOMEM; + if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) + paramid += 0x0bff0000; + paramhr.moudleid = 1; paramhr.commandtype = cmdid; /* 8 is "sizeof(paramid) + sizeof(paramlength)" */ @@ -1157,6 +1566,52 @@ static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320) l_calir0, l_calir0_lo, r_calir0, r_calir0_lo); } +static int rt1320_pilot_tone_output(struct rt1320_sdw_priv *rt1320) +{ + struct device *dev = &rt1320->sdw_slave->dev; + int l_targetpostgain, r_targetpostgain; + unsigned long long factor = (1 << 12); + int l_pilotgain[9], r_pilotgain[9]; + const int postgain_step = 234; + int targetGain; + + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + targetGain = -320000; + break; + case RT1321_DEV_ID: + targetGain = -420000; + if (rt1320->version_id == RT1321_VA0) + targetGain = -320000; + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; + } + + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 70, &l_pilotgain[0], sizeof(l_pilotgain)); + rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 71, &r_pilotgain[0], sizeof(r_pilotgain)); + dev_dbg(dev, "%s, LR pilotgain %d, %d\n", __func__, l_pilotgain[2], r_pilotgain[2]); + + /* calculate pilot tone gain */ + l_pilotgain[2] = (l_pilotgain[2] * 10000) / factor; + r_pilotgain[2] = (r_pilotgain[2] * 10000) / factor; + + /* calculate post gain to meet target gain */ + l_targetpostgain = abs(targetGain - l_pilotgain[2]) / postgain_step; + r_targetpostgain = abs(targetGain - r_pilotgain[2]) / postgain_step; + l_targetpostgain = 0xfff - l_targetpostgain; + r_targetpostgain = 0xfff - r_targetpostgain; + dev_dbg(dev, "%s, LR targetpostgain=0x%x, 0x%x\n", __func__, l_targetpostgain, r_targetpostgain); + + regmap_write(rt1320->regmap, 0xdd0b, (l_targetpostgain & 0xf00) >> 8); + regmap_write(rt1320->regmap, 0xdd0a, l_targetpostgain & 0xff); + regmap_write(rt1320->regmap, 0xdd09, (r_targetpostgain & 0xf00) >> 8); + regmap_write(rt1320->regmap, 0xdd08, r_targetpostgain & 0xff); + + return 0; +} + static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) { struct device *dev = &rt1320->sdw_slave->dev; @@ -1174,16 +1629,10 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) if (!rt1320->component) return; - /* set volume 0dB */ regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]); regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]); regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]); regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]); - regmap_write(rt1320->regmap, 0xdd0b, 0x0f); - regmap_write(rt1320->regmap, 0xdd0a, 0xff); - regmap_write(rt1320->regmap, 0xdd09, 0x0f); - regmap_write(rt1320->regmap, 0xdd08, 0xff); - regmap_read(rt1320->regmap, 0xc5fb, ®_c5fb); regmap_read(rt1320->regmap, 0xc570, ®_c570); regmap_read(rt1320->regmap, 0xcd00, ®_cd00); @@ -1208,8 +1657,19 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) goto _finish_; } - if (rt1320->dev_id == RT1320_DEV_ID) - regmap_write(rt1320->regmap, 0xc5fb, 0x00); + /* fine tune pilot tone output */ + ret = rt1320_pilot_tone_output(rt1320); + if (ret < 0) { + dev_dbg(dev, "%s, Failed to tune pilot tone output\n", __func__); + goto _finish_; + } + + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00); + regmap_write(rt1320->regmap, 0xc5c4, 0x12); + } + + regmap_write(rt1320->regmap, 0xc5fb, 0x00); regmap_write(rt1320->regmap, 0xc570, 0x0b); regmap_write(rt1320->regmap, 0xcd00, 0xc5); @@ -1270,6 +1730,11 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); + if (rt1320->dev_id == RT1321_DEV_ID) { + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80); + regmap_write(rt1320->regmap, 0xc5c4, 0x10); + } + /* advance gain will be set when R0 load, not here */ regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]); regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]); @@ -1336,6 +1801,9 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) max_addr = 0x10007fff; break; case RT1321_DEV_ID: + if (rt1320->version_id == RT1321_VA2) + return; + filename = RT1321_VA_MCU_PATCH; min_addr = 0x10008000; max_addr = 0x10008fff; @@ -1494,22 +1962,48 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) request_firmware(&rae_fw, rae_filename, dev); if (rae_fw) { - /* RAE CRC clear */ - regmap_write(rt1320->regmap, 0xe80b, 0x0f); - - /* RAE stop & CRC disable */ - regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00); - - while (--retry) { - regmap_read(rt1320->regmap, 0xe83f, &value); - if (value & 0x40) - break; - usleep_range(1000, 1100); - } - if (!retry && !(value & 0x40)) { - dev_err(dev, "%s: RAE is not ready to load\n", __func__); - release_firmware(rae_fw); - return -ETIMEDOUT; + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + /* RAE CRC clear */ + regmap_write(rt1320->regmap, 0xe80b, 0x0f); + /* RAE stop & CRC disable */ + regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00); + while (--retry) { + regmap_read(rt1320->regmap, 0xe83f, &value); + if (value & 0x40) + break; + usleep_range(1000, 1100); + } + if (!retry && !(value & 0x40)) { + dev_err(dev, "%s: RAE is not ready to load\n", __func__); + release_firmware(rae_fw); + return -ETIMEDOUT; + } + break; + case RT1321_DEV_ID: + /* RAE CRC clear */ + regmap_write(rt1320->regmap, 0x2000300e, 0xc0); + regmap_write(rt1320->regmap, 0x2000300f, 0x0f); + /* RAE stop & Phase sync & CRC disable */ + regmap_update_bits(rt1320->regmap, 0x20003003, 0xfe, 0x00); + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x00); + /* check whether write state is ready */ + while (--retry) { + regmap_read(rt1320->regmap, 0x20003043, &value); + if (value & 0x40) + break; + usleep_range(1000, 1100); + } + if (!retry && !(value & 0x40)) { + dev_err(dev, "%s: RAE is not ready to load\n", __func__); + release_firmware(rae_fw); + return -ETIMEDOUT; + } + break; + default: + dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); + return -EINVAL; } dev_dbg(dev, "%s, rae_fw size=0x%zx\n", __func__, rae_fw->size); @@ -1570,18 +2064,34 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) goto _exit_; } - /* RAE CRC enable */ - regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c); - - /* RAE update */ - regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00); - regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80); - - /* RAE run */ - regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80); - - regmap_read(rt1320->regmap, 0xe80b, &value); - dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value); + switch (rt1320->dev_id) { + case RT1320_DEV_ID: + /* RAE CRC enable */ + regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c); + /* RAE update */ + regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80); + /* RAE run */ + regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80); + regmap_read(rt1320->regmap, 0xe80b, &value); + dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value); + break; + case RT1321_DEV_ID: + /* RAE CRC enable */ + regmap_update_bits(rt1320->regmap, 0x20003003, 0x30, 0x30); + /* RAE update */ + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x80); + regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x80); + regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x00); + regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80); + /* RAE run */ + regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01); + /* Phase sync eanble */ + regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80); + break; + } rt1320->rae_update_done = true; @@ -1620,6 +2130,8 @@ struct rt1320_dspfwheader { unsigned int hdr_size = 0; const char *dmi_vendor, *dmi_product, *dmi_sku; int len_vendor, len_product, len_sku; + unsigned char boot_mode = 0; /* 0: from RAM; 1: from ROM */ + unsigned char has_0x3fc00000 = 0; char filename[512]; dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR); @@ -1657,9 +2169,6 @@ struct rt1320_dspfwheader { goto _exit_; } - /* change to IRAM */ - regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); - request_firmware(&fw, filename, dev); if (fw) { fwheader = (struct rt1320_dspfwheader *)fw->data; @@ -1705,9 +2214,11 @@ struct rt1320_dspfwheader { dev_fw_match = true; break; case RT1321_DEV_ID: - if (ptr_img->addr == 0x3fc00000) - if (fw_data[9] == '1') + if (ptr_img->addr == 0x3fc00000) { + if (fw_data[7] == '1') dev_fw_match = true; + has_0x3fc00000 = 1; + } break; default: dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); @@ -1717,6 +2228,22 @@ struct rt1320_dspfwheader { fw_offset += ptr_img->size; } + if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) { + /* + * For 1321 VA2, if the FW doesn't include the section for address 0x3fc00000, + * it means the FW will boot from ROM and force dev_fw_match to true to download FW by BRA. + */ + if (!has_0x3fc00000) { + boot_mode = 1; + dev_fw_match = true; + } + dev_dbg(dev, "%s: Boot from %s for VA2\n", __func__, (boot_mode ? "ROM" : "RAM")); + } + + /* change to IRAM */ + if (!boot_mode) + regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); + if (dev_fw_match) { dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__); rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num; @@ -1739,24 +2266,39 @@ struct rt1320_dspfwheader { goto _exit_; } - /* run RAM code */ - regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); - val |= 0x8; - regmap_write(rt1320->regmap, 0x3fc2bfc0, val); - - /* clear frame counter */ switch (rt1320->dev_id) { case RT1320_DEV_ID: + /* run RAM code */ + regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); + val |= 0x8; + regmap_write(rt1320->regmap, 0x3fc2bfc0, val); + /* clear frame counter */ regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00); regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00); regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00); regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00); break; case RT1321_DEV_ID: + if (!boot_mode) { + /* run RAM code */ + regmap_read(rt1320->regmap, 0x3fc2dfc0, &val); + val |= 0x8; + regmap_write(rt1320->regmap, 0x3fc2dfc0, val); + } + /* clear frame counter */ regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00); regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00); regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00); regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00); + /* enable handshake */ + regmap_write(rt1320->regmap, 0x3fc2dfc4, 0x00); + regmap_write(rt1320->regmap, 0xd470, 0xad); + /* minimum phase settings */ + regmap_write(rt1320->regmap, 0xc5c4, 0x10); + regmap_write(rt1320->regmap, 0x20003003, 0x31); + regmap_update_bits(rt1320->regmap, 0x20003002, 0x40, 0x00); + regmap_write(rt1320->regmap, 0xc5b3, 0x01); + regmap_write(rt1320->regmap, 0xc052, 0x11); break; } @@ -1839,14 +2381,35 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) static void rt1321_preset(struct rt1320_sdw_priv *rt1320) { + const struct reg_sequence *blindwrite; unsigned int i, reg, val, delay; + unsigned int array_size; - for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) { - reg = rt1321_blind_write[i].reg; - val = rt1321_blind_write[i].def; - delay = rt1321_blind_write[i].delay_us; + switch (rt1320->version_id) { + case RT1321_VA0: + blindwrite = rt1321_blind_write; + array_size = ARRAY_SIZE(rt1321_blind_write); + break; + case RT1321_VA1: + blindwrite = rt1321_va1_blind_write; + array_size = ARRAY_SIZE(rt1321_va1_blind_write); + break; + case RT1321_VA2: + blindwrite = rt1321_va2_blind_write; + array_size = ARRAY_SIZE(rt1321_va2_blind_write); + break; + default: + dev_err(&rt1320->sdw_slave->dev, "%s: Unknown version ID %d\n", + __func__, rt1320->version_id); + return; + } - if (reg == 0x3fc2dfc3) + for (i = 0; i < array_size; i++) { + reg = blindwrite[i].reg; + val = blindwrite[i].def; + delay = blindwrite[i].delay_us; + + if (reg == 0x1000cd56) rt1320_load_mcu_patch(rt1320); regmap_write(rt1320->regmap, reg, val); @@ -1888,6 +2451,24 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val); regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp); rt1320->dev_id = (val << 8) | tmp; + + /* This is a workaround that reads the value twice to obtain the correct result. */ + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val); + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp); + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val); + rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp); + val = (val << 8) | tmp; + + if (rt1320->dev_id == RT1321_DEV_ID) { + if (rt1320->version_id == 0x01) + rt1320->version_id = RT1321_VA2; + else if (val == RT1321_DEV_HV_VA0_ID) + rt1320->version_id = RT1321_VA0; + else if (val == RT1321_DEV_HV_VA1_ID) + rt1320->version_id = RT1321_VA1; + else + dev_err(dev, "%s: Unknown version ID 0x%x for RT1321\n", __func__, rt1320->version_id); + } } regmap_read(rt1320->regmap, @@ -2440,7 +3021,7 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, if (!rt1320->hw_init) return 0; - ret = pm_runtime_resume(component->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -2451,6 +3032,8 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, if (!ucontrol->value.integer.value[0]) rt1320->fw_load_done = false; + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); return 0; } diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index a7b573883dd0..bc0f78e03529 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -17,12 +17,17 @@ #define RT1320_DEV_ID 0x6981 #define RT1321_DEV_ID 0x7045 +#define RT1321_DEV_HV_VA0_ID 0x6997 +#define RT1321_DEV_HV_VA1_ID 0x7071 /* imp-defined registers */ #define RT1320_DEV_VERSION_ID_1 0xc404 #define RT1320_DEV_ID_1 0xc405 #define RT1320_DEV_ID_0 0xc406 +#define RT1320_HV_DEV_ID_0 0xf622 +#define RT1320_HV_DEV_ID_1 0xf623 + #define RT1320_POWER_STATE 0xc560 #define RT1321_PATCH_MAIN_VER 0x1000cffe @@ -94,6 +99,12 @@ enum rt1320_version_id { RT1320_VC, }; +enum rt1321_version_id { + RT1321_VA0, + RT1321_VA1, + RT1321_VA2, +}; + #define RT1320_VER_B_ID 0x07392238 #define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin" #define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" @@ -121,6 +132,7 @@ struct rt1320_datafixpoint { int invrs; }; +/* FW parameter id 1300 */ typedef struct FwPara_HwSwGain { unsigned int SwAdvGain; unsigned int SwBasGain; From 99e361b2a50424ffd923dc151fd605afa5b213ce Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Sat, 20 Jun 2026 15:50:58 +0200 Subject: [PATCH 033/438] ASoC: rt5677: Add GPIO .get_direction() callback Implement the get_direction callback for the GPIO controller to allow consumers to query the direction of GPIO pins. Signed-off-by: Diogo Ivo Link: https://patch.msgid.link/20260620-smaug-audio-v1-1-e318acdf5abd@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ac084ca008f3..73fc008d558a 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -6,6 +6,7 @@ * Author: Oder Chiou */ +#include #include #include #include @@ -4767,6 +4768,21 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) return rt5677_update_gpio_bits(rt5677, offset, m, v); } +static int rt5677_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct rt5677_priv *rt5677 = gpiochip_get_data(chip); + unsigned int shift = RT5677_GPIOx_DIR_SFT + (offset % 5) * 3; + unsigned int bank = offset / 5; + unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2; + int ret; + + ret = regmap_test_bits(rt5677->regmap, reg, BIT(shift)); + if (ret < 0) + return ret; + + return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; +} + /* * Configures the GPIO as * 0 - floating @@ -4834,6 +4850,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) static const struct gpio_chip rt5677_template_chip = { .label = RT5677_DRV_NAME, .owner = THIS_MODULE, + .get_direction = rt5677_gpio_get_direction, .direction_output = rt5677_gpio_direction_out, .set = rt5677_gpio_set, .direction_input = rt5677_gpio_direction_in, From a5edc45d9cf6e60be1cbd39f68e92685a91b13ac Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Sat, 20 Jun 2026 15:50:59 +0200 Subject: [PATCH 034/438] ASoC: rt5677: Enable standalone compilation for generic card use Add a prompt string to make the RT5677 driver user-selectable, allowing it to be built independently for use with generic sound card bindings. Signed-off-by: Diogo Ivo Link: https://patch.msgid.link/20260620-smaug-audio-v1-2-e318acdf5abd@bootlin.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 252f683be3c1..e9de333c5c8a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1888,7 +1888,7 @@ config SND_SOC_RT5670 depends on I2C config SND_SOC_RT5677 - tristate + tristate "Realtek RT5677 Codec" depends on I2C select REGMAP_I2C select REGMAP_IRQ From a295be8d6210ab6a6ec9710b5b146cba34f36c6f Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:25 +0200 Subject: [PATCH 035/438] ASoC: meson: gx: add gx-formatter and gx-interface These files are the basic block which allow to shape I2S in GX devices the same as the AXG ones: the DAI backend only controls the interface (i.e. clocks and pins) whereas a formatter takes care of properly formatting the data. gx-formatter and gx-interface are strongly inspired to axg-tdm-formatter and axg-tdm, respectively. The long term plan is to join the two platforms to use the same formatter solution. There is only a minor addition here compared to what has been done for AXG and it's "gx_formatter_create()" which is required in order to let already existing AIU code to make use of this formatter without making any devicetree change. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/20260610-reshape-aiu-as-axg-v2-1-cac3663a8b51@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/Makefile | 1 + sound/soc/meson/gx-formatter.c | 282 +++++++++++++++++++++++++++++++++ sound/soc/meson/gx-formatter.h | 56 +++++++ sound/soc/meson/gx-interface.h | 48 ++++++ 4 files changed, 387 insertions(+) create mode 100644 sound/soc/meson/gx-formatter.c create mode 100644 sound/soc/meson/gx-formatter.h create mode 100644 sound/soc/meson/gx-interface.h diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index 24078e4396b0..146ec81526ba 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -4,6 +4,7 @@ snd-soc-meson-aiu-y := aiu.o snd-soc-meson-aiu-y += aiu-acodec-ctrl.o snd-soc-meson-aiu-y += aiu-codec-ctrl.o snd-soc-meson-aiu-y += aiu-encoder-i2s.o +snd-soc-meson-aiu-y += gx-formatter.o snd-soc-meson-aiu-y += aiu-encoder-spdif.o snd-soc-meson-aiu-y += aiu-fifo.o snd-soc-meson-aiu-y += aiu-fifo-i2s.o diff --git a/sound/soc/meson/gx-formatter.c b/sound/soc/meson/gx-formatter.c new file mode 100644 index 000000000000..311e63affb23 --- /dev/null +++ b/sound/soc/meson/gx-formatter.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// +// Copyright (c) 2026 BayLibre, SAS. +// Author: Valerio Setti + +#include +#include +#include +#include + +#include "gx-formatter.h" + +struct gx_formatter { + struct list_head list; + struct gx_stream *stream; + const struct gx_formatter_driver *drv; + bool enabled; + struct regmap *map; +}; + +static int gx_formatter_enable(struct gx_formatter *formatter) +{ + int ret; + + /* Do nothing if the formatter is already enabled */ + if (formatter->enabled) + return 0; + + /* Setup the stream parameter in the formatter */ + if (formatter->drv->ops->prepare) { + ret = formatter->drv->ops->prepare(formatter->map, + formatter->drv->quirks, + formatter->stream); + if (ret) + return ret; + } + + /* Finally, actually enable the formatter */ + if (formatter->drv->ops->enable) + formatter->drv->ops->enable(formatter->map); + + formatter->enabled = true; + + return 0; +} + +static void gx_formatter_disable(struct gx_formatter *formatter) +{ + /* Do nothing if the formatter is already disabled */ + if (!formatter->enabled) + return; + + if (formatter->drv->ops->disable) + formatter->drv->ops->disable(formatter->map); + + formatter->enabled = false; +} + +static int gx_formatter_attach(struct gx_formatter *formatter) +{ + struct gx_stream *ts = formatter->stream; + int ret = 0; + + mutex_lock(&ts->lock); + + /* Catch up if the stream is already running when we attach */ + if (ts->ready) { + ret = gx_formatter_enable(formatter); + if (ret) { + pr_err("failed to enable formatter\n"); + goto out; + } + } + + list_add_tail(&formatter->list, &ts->formatter_list); +out: + mutex_unlock(&ts->lock); + return ret; +} + +static void gx_formatter_detach(struct gx_formatter *formatter) +{ + struct gx_stream *ts = formatter->stream; + + if (!ts) + return; + + mutex_lock(&ts->lock); + list_del(&formatter->list); + mutex_unlock(&ts->lock); + + gx_formatter_disable(formatter); +} + +static int gx_formatter_power_up(struct gx_formatter *formatter, + struct snd_soc_dapm_widget *w) +{ + struct gx_stream *ts = formatter->drv->ops->get_stream(w); + int ret; + + /* + * If we don't get a stream at this stage, it would mean that the + * widget is powering up but is not attached to any backend DAI. + * It should not happen, ever ! + */ + if (WARN_ON(!ts)) + return -ENODEV; + + formatter->stream = ts; + INIT_LIST_HEAD(&formatter->list); + ret = gx_formatter_attach(formatter); + if (ret) + return ret; + + return 0; +} + +static void gx_formatter_power_down(struct gx_formatter *formatter) +{ + gx_formatter_detach(formatter); + formatter->stream = NULL; +} + +int gx_formatter_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, + int event) +{ + struct snd_soc_component *c; + struct gx_formatter *formatter; + int ret = 0; + + c = snd_soc_dapm_to_component(w->dapm); + + if (w->priv) + formatter = w->priv; + else + formatter = snd_soc_component_get_drvdata(c); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = gx_formatter_power_up(formatter, w); + break; + + case SND_SOC_DAPM_PRE_PMD: + gx_formatter_power_down(formatter); + break; + + default: + dev_err(c->dev, "Unexpected event %d\n", event); + return -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(gx_formatter_event); + +int gx_formatter_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct gx_formatter_driver *drv; + struct gx_formatter *formatter; + void __iomem *regs; + + drv = of_device_get_match_data(dev); + if (!drv) { + dev_err(dev, "failed to match device\n"); + return -ENODEV; + } + + formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL); + if (!formatter) + return -ENOMEM; + platform_set_drvdata(pdev, formatter); + formatter->drv = drv; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg); + if (IS_ERR(formatter->map)) { + dev_err(dev, "failed to init regmap: %ld\n", + PTR_ERR(formatter->map)); + return PTR_ERR(formatter->map); + } + + return devm_snd_soc_register_component(dev, drv->component_drv, + NULL, 0); +} +EXPORT_SYMBOL_GPL(gx_formatter_probe); + +int gx_formatter_create(struct device *dev, + struct snd_soc_dapm_widget *w, + const struct gx_formatter_driver *drv, + struct regmap *regmap) +{ + struct gx_formatter *formatter; + + formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL); + if (!formatter) + return -ENOMEM; + + formatter->drv = drv; + formatter->map = regmap; + + w->priv = formatter; + + return 0; +} +EXPORT_SYMBOL_GPL(gx_formatter_create); + +int gx_stream_start(struct gx_stream *ts) +{ + struct gx_formatter *formatter; + int ret = 0; + + mutex_lock(&ts->lock); + + /* Start all the formatters attached to the stream */ + list_for_each_entry(formatter, &ts->formatter_list, list) { + ret = gx_formatter_enable(formatter); + if (ret) { + pr_err("failed to enable formatter\n"); + goto out; + } + } + + ts->ready = true; + +out: + mutex_unlock(&ts->lock); + return ret; +} +EXPORT_SYMBOL_GPL(gx_stream_start); + +void gx_stream_stop(struct gx_stream *ts) +{ + struct gx_formatter *formatter; + + mutex_lock(&ts->lock); + ts->ready = false; + + /* Stop all the formatters attached to the stream */ + list_for_each_entry(formatter, &ts->formatter_list, list) { + gx_formatter_disable(formatter); + } + + mutex_unlock(&ts->lock); +} +EXPORT_SYMBOL_GPL(gx_stream_stop); + +struct gx_stream *gx_stream_alloc(struct gx_iface *iface) +{ + struct gx_stream *ts; + + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts) { + INIT_LIST_HEAD(&ts->formatter_list); + mutex_init(&ts->lock); + ts->iface = iface; + } + + return ts; +} +EXPORT_SYMBOL_GPL(gx_stream_alloc); + +void gx_stream_free(struct gx_stream *ts) +{ + /* + * If the list is not empty, it would mean that one of the formatter + * widget is still powered and attached to the interface while we + * are removing the TDM DAI. It should not be possible + */ + WARN_ON(!list_empty(&ts->formatter_list)); + mutex_destroy(&ts->lock); + kfree(ts); +} +EXPORT_SYMBOL_GPL(gx_stream_free); + +MODULE_DESCRIPTION("Amlogic GX formatter driver"); +MODULE_AUTHOR("Valerio Setti "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/meson/gx-formatter.h b/sound/soc/meson/gx-formatter.h new file mode 100644 index 000000000000..b90b1814d79b --- /dev/null +++ b/sound/soc/meson/gx-formatter.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (c) 2026 Baylibre SAS. + * Author: Valerio Setti + */ + +#ifndef _MESON_GX_FORMATTER_H +#define _MESON_GX_FORMATTER_H + +#include "gx-interface.h" + +struct platform_device; +struct regmap; +struct snd_soc_dapm_widget; +struct snd_kcontrol; + +struct gx_formatter_hw { + unsigned int skew_offset; +}; + +struct gx_formatter_ops { + struct gx_stream *(*get_stream)(struct snd_soc_dapm_widget *w); + void (*enable)(struct regmap *map); + void (*disable)(struct regmap *map); + int (*prepare)(struct regmap *map, + const struct gx_formatter_hw *quirks, + struct gx_stream *ts); +}; + +struct gx_formatter_driver { + const struct snd_soc_component_driver *component_drv; + const struct regmap_config *regmap_cfg; + const struct gx_formatter_ops *ops; + const struct gx_formatter_hw *quirks; +}; + +int gx_formatter_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, + int event); +int gx_formatter_probe(struct platform_device *pdev); + +int gx_formatter_create(struct device *dev, + struct snd_soc_dapm_widget *w, + const struct gx_formatter_driver *drv, + struct regmap *regmap); + +/* + * Formatter data is already freed when the associated device is removed, + * so we just need to remove the pointer from the widget. + */ +static inline void gx_formatter_free(struct snd_soc_dapm_widget *w) +{ + w->priv = NULL; +} + +#endif /* _MESON_GX_FORMATTER_H */ diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h new file mode 100644 index 000000000000..65c46dcce32a --- /dev/null +++ b/sound/soc/meson/gx-interface.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (c) 2026 Baylibre SAS. + * Author: Valerio Setti + */ + +#ifndef _MESON_GX_INTERFACE_H +#define _MESON_GX_INTERFACE_H + +#include +#include +#include +#include +#include + +struct gx_iface { + struct clk *mclk; + unsigned long mclk_rate; + + /* format is common to all the DAIs of the iface */ + unsigned int fmt; + + /* For component wide symmetry */ + int rate; + + /* Only for GX platform */ + int bs_quirk; +}; + +struct gx_stream { + struct gx_iface *iface; + struct list_head formatter_list; + struct mutex lock; + unsigned int channels; + unsigned int width; + unsigned int physical_width; + bool ready; + + /* For continuous clock tracking */ + bool clk_enabled; +}; + +struct gx_stream *gx_stream_alloc(struct gx_iface *iface); +void gx_stream_free(struct gx_stream *ts); +int gx_stream_start(struct gx_stream *ts); +void gx_stream_stop(struct gx_stream *ts); + +#endif /* _MESON_GX_INTERFACE_H */ From 9335117a221a7886bb6cac8a15905cf567d3413b Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:26 +0200 Subject: [PATCH 036/438] ASoC: meson: aiu-encoder-i2s: prepare for multiple streams aiu-encoder-i2s is going to be the interface that handles both playback and capture, so this commit does all the required changes to prepare for that since so far it only handled playback: - probe/remove functions are added to allocate/free per stream data, respectively. - 'struc gx_iface' and 'struct gx_stream' are used to store interface or stream associated data, respecively. - interface wide rate symmetry is enforced. - quirks on bclk are also enforced if/when necessary. Clock-wise instead of bulk enabling all the clocks on startup and disabling them on shutdown, only the peripheral's internal ones are enabled/disabled in those functions, whereas MCLK and I2S clock divider are handled in prepare/hw_free. Finally a trigger() callback is also added to start/stop the associated I2S data formatter. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/20260610-reshape-aiu-as-axg-v2-2-cac3663a8b51@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-encoder-i2s.c | 207 +++++++++++++++++++++++++++--- sound/soc/meson/aiu.h | 3 + 2 files changed, 193 insertions(+), 17 deletions(-) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index 3b4061508c18..f50b03824ad2 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -10,6 +10,8 @@ #include #include "aiu.h" +#include "gx-formatter.h" +#include "gx-interface.h" #define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) #define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) @@ -112,6 +114,9 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, struct snd_pcm_hw_params *params, unsigned int bs) { + struct aiu *aiu = snd_soc_component_get_drvdata(component); + struct gx_iface *iface = &aiu->i2s.iface; + /* * NOTE: this HW is odd. * In most configuration, the i2s divider is 'mclk / blck'. @@ -126,6 +131,18 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, return -EINVAL; } bs += bs / 2; + iface->bs_quirk = true; + } else { + /* + * If the bs quirk is currently applied for one stream and another + * ones tries to setup a configuration for which the quirk is + * not required, then fail. + */ + if (iface->bs_quirk) { + dev_err(component->dev, + "bclk requirements are incompatible with active stream\n"); + return -EINVAL; + } } /* Use CLK_MORE for mclk to bclk divider */ @@ -145,14 +162,15 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, struct snd_pcm_hw_params *params) { struct aiu *aiu = snd_soc_component_get_drvdata(component); + struct gx_iface *iface = &aiu->i2s.iface; unsigned int srate = params_rate(params); unsigned int fs, bs; int ret; /* Get the oversampling factor */ - fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate); + fs = DIV_ROUND_CLOSEST(iface->mclk_rate, srate); - if (fs % 64) + if ((fs % 64) || (fs == 0)) return -EINVAL; /* Send data MSB first */ @@ -188,24 +206,59 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); + struct gx_iface *iface = ts->iface; struct snd_soc_component *component = dai->component; int ret; - /* Disable the clock while changing the settings */ - aiu_encoder_i2s_divider_enable(component, false); + /* + * Enforce interface wide rate symmetry only if there is more than + * 1 stream active. + */ + if (snd_soc_dai_active(dai) > 1) { + if (iface->rate && iface->rate != params_rate(params)) { + dev_err(dai->dev, "can't set iface rate (%d != %d)\n", + iface->rate, params_rate(params)); + return -EINVAL; + } + } ret = aiu_encoder_i2s_setup_desc(component, params); if (ret) { - dev_err(dai->dev, "setting i2s desc failed\n"); + dev_err(dai->dev, "setting i2s desc failed: %d\n", ret); return ret; } ret = aiu_encoder_i2s_set_clocks(component, params); if (ret) { - dev_err(dai->dev, "setting i2s clocks failed\n"); + dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); return ret; } + iface->rate = params_rate(params); + ts->physical_width = params_physical_width(params); + ts->width = params_width(params); + ts->channels = params_channels(params); + + return 0; +} + +static int aiu_encoder_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); + struct snd_soc_component *component = dai->component; + int ret; + + if (ts->clk_enabled) + return 0; + + ret = clk_prepare_enable(ts->iface->mclk); + if (ret) + return ret; + + ts->clk_enabled = true; + aiu_encoder_i2s_divider_enable(component, true); return 0; @@ -214,9 +267,24 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); + struct gx_iface *iface = ts->iface; struct snd_soc_component *component = dai->component; - aiu_encoder_i2s_divider_enable(component, false); + /* + * If this is the last substream being closed then disable the i2s + * clock divider and clear 'iface->rate'. + */ + if (snd_soc_dai_active(dai) <= 1) { + aiu_encoder_i2s_divider_enable(component, 0); + iface->rate = 0; + iface->bs_quirk = false; + } + + if (ts->clk_enabled) { + clk_disable_unprepare(ts->iface->mclk); + ts->clk_enabled = false; + } return 0; } @@ -224,6 +292,8 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; + struct aiu *aiu = snd_soc_component_get_drvdata(component); + struct gx_iface *iface = &aiu->i2s.iface; unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK; unsigned int val = 0; unsigned int skew; @@ -255,9 +325,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) skew = 0; break; default: + dev_err(dai->dev, "unsupported dai format\n"); return -EINVAL; } + iface->fmt = fmt; + val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew); snd_soc_component_update_bits(component, AIU_CLK_CTRL, AIU_CLK_CTRL_LRCLK_INVERT | @@ -272,6 +345,7 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct aiu *aiu = snd_soc_component_get_drvdata(dai->component); + struct gx_iface *iface = &aiu->i2s.iface; int ret; if (WARN_ON(clk_id != 0)) @@ -280,11 +354,15 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, if (dir == SND_SOC_CLOCK_IN) return 0; - ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq); - if (ret) - dev_err(dai->dev, "Failed to set sysclk to %uHz", freq); + ret = clk_set_rate(iface->mclk, freq); + if (ret) { + dev_err(dai->dev, "Failed to set sysclk to %uHz: %d", freq, ret); + return ret; + } - return ret; + iface->mclk_rate = freq; + + return 0; } static const unsigned int hw_channels[] = {2, 8}; @@ -305,15 +383,35 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_channel_constraints); if (ret) { - dev_err(dai->dev, "adding channels constraints failed\n"); + dev_err(dai->dev, "adding channels constraints failed: %d\n", ret); return ret; } - ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks); - if (ret) - dev_err(dai->dev, "failed to enable i2s clocks\n"); + /* + * Enable only clocks which are required for the interface internal + * logic. MCLK is enabled/disabled from the formatter and the I2S + * divider is enabled/disabled in "hw_params"/"hw_free", respectively. + */ + ret = clk_prepare_enable(aiu->i2s.clks[PCLK].clk); + if (ret) { + dev_err(dai->dev, "failed to enable PCLK: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(aiu->i2s.clks[MIXER].clk); + if (ret) { + dev_err(dai->dev, "failed to enable MIXER: %d\n", ret); + clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); + return ret; + } + ret = clk_prepare_enable(aiu->i2s.clks[AOCLK].clk); + if (ret) { + dev_err(dai->dev, "failed to enable AOCLK: %d\n", ret); + clk_disable_unprepare(aiu->i2s.clks[MIXER].clk); + clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); + return ret; + } - return ret; + return 0; } static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream, @@ -321,14 +419,89 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream, { struct aiu *aiu = snd_soc_component_get_drvdata(dai->component); - clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks); + clk_disable_unprepare(aiu->i2s.clks[AOCLK].clk); + clk_disable_unprepare(aiu->i2s.clks[MIXER].clk); + clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); +} + +static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = gx_stream_start(ts); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + gx_stream_stop(ts); + ret = 0; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int aiu_encoder_i2s_remove_dai(struct snd_soc_dai *dai) +{ + int stream; + + for_each_pcm_streams(stream) { + struct gx_stream *ts; + + ts = snd_soc_dai_dma_data_get(dai, stream); + if (ts) + gx_stream_free(ts); + + snd_soc_dai_dma_data_set(dai, stream, NULL); + } + + return 0; +} + +static int aiu_encoder_i2s_probe_dai(struct snd_soc_dai *dai) +{ + struct aiu *aiu = snd_soc_dai_get_drvdata(dai); + struct gx_iface *iface = &aiu->i2s.iface; + int stream; + + for_each_pcm_streams(stream) { + struct gx_stream *ts; + + if (!snd_soc_dai_get_widget(dai, stream)) + continue; + + ts = gx_stream_alloc(iface); + if (!ts) { + aiu_encoder_i2s_remove_dai(dai); + return -ENOMEM; + } + snd_soc_dai_dma_data_set(dai, stream, ts); + } + + iface->mclk = aiu->i2s.clks[MCLK].clk; + iface->mclk_rate = clk_get_rate(iface->mclk); + + return 0; } const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = { + .probe = aiu_encoder_i2s_probe_dai, + .remove = aiu_encoder_i2s_remove_dai, .hw_params = aiu_encoder_i2s_hw_params, + .prepare = aiu_encoder_i2s_prepare, .hw_free = aiu_encoder_i2s_hw_free, .set_fmt = aiu_encoder_i2s_set_fmt, .set_sysclk = aiu_encoder_i2s_set_sysclk, .startup = aiu_encoder_i2s_startup, .shutdown = aiu_encoder_i2s_shutdown, + .trigger = aiu_encoder_i2s_trigger, }; diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h index 0f94c8bf6081..68310de0bdf7 100644 --- a/sound/soc/meson/aiu.h +++ b/sound/soc/meson/aiu.h @@ -7,6 +7,8 @@ #ifndef _MESON_AIU_H #define _MESON_AIU_H +#include "gx-formatter.h" + struct clk; struct clk_bulk_data; struct device; @@ -25,6 +27,7 @@ struct aiu_interface { struct clk_bulk_data *clks; unsigned int clk_num; int irq; + struct gx_iface iface; }; struct aiu_platform_data { From 2cbb32d8dce0358a385760349fe19758a0d1a49e Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:27 +0200 Subject: [PATCH 037/438] ASoC: meson: aiu: introduce I2S output formatter Introduce aiu-formatter-i2s, a gx_formatter implementation for the AIU I2S playback path. This is going to replace data formatting tasks that are currently being implemented in aiu-encoder-i2s. This should ideally follow the same design pattern used on the AXG platform (see axg-tdmout), where basically the widget/formatter corresponds to a single audio component. This is not possible in the GX platform though because all the features are currently implemented in the AIU audio component and changing that would require backward incompatible device-tree changes. Therefore aiu-formatter-i2s is kept very simple and it only implements the bare minimum functionalities to provide I2S playback formatting. It's not a standalone component though because this is still belongs to AIU. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/20260610-reshape-aiu-as-axg-v2-3-cac3663a8b51@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/Makefile | 1 + sound/soc/meson/aiu-formatter-i2s.c | 104 ++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 sound/soc/meson/aiu-formatter-i2s.c diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile index 146ec81526ba..f9ec0ebb01f0 100644 --- a/sound/soc/meson/Makefile +++ b/sound/soc/meson/Makefile @@ -5,6 +5,7 @@ snd-soc-meson-aiu-y += aiu-acodec-ctrl.o snd-soc-meson-aiu-y += aiu-codec-ctrl.o snd-soc-meson-aiu-y += aiu-encoder-i2s.o snd-soc-meson-aiu-y += gx-formatter.o +snd-soc-meson-aiu-y += aiu-formatter-i2s.o snd-soc-meson-aiu-y += aiu-encoder-spdif.o snd-soc-meson-aiu-y += aiu-fifo.o snd-soc-meson-aiu-y += aiu-fifo-i2s.o diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-formatter-i2s.c new file mode 100644 index 000000000000..b4604734fe88 --- /dev/null +++ b/sound/soc/meson/aiu-formatter-i2s.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2026 BayLibre, SAS. +// Author: Valerio Setti + +#include +#include +#include + +#include "aiu.h" +#include "gx-formatter.h" + +#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) +#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) +#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) +#define AIU_RST_SOFT_I2S_FAST BIT(0) + +#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) + +static struct snd_soc_dai * +aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dai *be; + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + if (!p->connect) + continue; + + if (p->sink->id == snd_soc_dapm_dai_in) + return (struct snd_soc_dai *)p->sink->priv; + + be = aiu_formatter_i2s_get_be(p->sink); + if (be) + return be; + } + + return NULL; +} + +static struct gx_stream * +aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w); + + if (!be) + return NULL; + + return snd_soc_dai_dma_data_get_playback(be); +} + +static int aiu_formatter_i2s_prepare(struct regmap *map, + const struct gx_formatter_hw *quirks, + struct gx_stream *ts) +{ + /* Always operate in split (classic interleaved) mode */ + unsigned int desc = 0; + unsigned int tmp; + + /* Reset required to update the pipeline */ + regmap_write(map, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST); + regmap_read(map, AIU_I2S_SYNC, &tmp); + + switch (ts->physical_width) { + case 16: /* Nothing to do */ + break; + + case 32: + desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | + AIU_I2S_SOURCE_DESC_MODE_32BIT); + break; + + default: + return -EINVAL; + } + + switch (ts->channels) { + case 2: /* Nothing to do */ + break; + case 8: + desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; + break; + default: + return -EINVAL; + } + + regmap_update_bits(map, AIU_I2S_SOURCE_DESC, + AIU_I2S_SOURCE_DESC_MODE_8CH | + AIU_I2S_SOURCE_DESC_MODE_24BIT | + AIU_I2S_SOURCE_DESC_MODE_32BIT, + desc); + + /* Send data MSB first */ + regmap_update_bits(map, AIU_I2S_DAC_CFG, + AIU_I2S_DAC_CFG_MSB_FIRST, + AIU_I2S_DAC_CFG_MSB_FIRST); + + return 0; +} + +const struct gx_formatter_ops aiu_formatter_i2s_ops = { + .get_stream = aiu_formatter_i2s_get_stream, + .prepare = aiu_formatter_i2s_prepare, +}; From 83b83024cdbfdddee104f4a84c2c2f1f8e6659f3 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Wed, 10 Jun 2026 23:29:28 +0200 Subject: [PATCH 038/438] ASoC: meson: aiu: use aiu-formatter-i2s to format I2S output data Create a new DAPM widget for "I2S formatter" and place it on the path between FIFO and output DAI interface. Remove I2S output formatting code from aiu-encoder-i2s since it's now implemented from aiu-formatter-i2s. Signed-off-by: Valerio Setti Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/20260610-reshape-aiu-as-axg-v2-4-cac3663a8b51@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-encoder-i2s.c | 78 ++++++++----------------------- sound/soc/meson/aiu.c | 32 +++++++++++-- sound/soc/meson/aiu.h | 1 + 3 files changed, 48 insertions(+), 63 deletions(-) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index f50b03824ad2..83b579e98f1c 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -13,13 +13,8 @@ #include "gx-formatter.h" #include "gx-interface.h" -#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) -#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) -#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) #define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11) -#define AIU_RST_SOFT_I2S_FAST BIT(0) -#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) #define AIU_CLK_CTRL_I2S_DIV_EN BIT(0) #define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2) #define AIU_CLK_CTRL_AOCLK_INVERT BIT(6) @@ -37,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component, enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0); } -static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component, - struct snd_pcm_hw_params *params) -{ - /* Always operate in split (classic interleaved) mode */ - unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT; - - /* Reset required to update the pipeline */ - snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST); - snd_soc_component_read(component, AIU_I2S_SYNC); - - switch (params_physical_width(params)) { - case 16: /* Nothing to do */ - break; - - case 32: - desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | - AIU_I2S_SOURCE_DESC_MODE_32BIT); - break; - - default: - return -EINVAL; - } - - switch (params_channels(params)) { - case 2: /* Nothing to do */ - break; - case 8: - desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; - break; - default: - return -EINVAL; - } - - snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC, - AIU_I2S_SOURCE_DESC_MODE_8CH | - AIU_I2S_SOURCE_DESC_MODE_24BIT | - AIU_I2S_SOURCE_DESC_MODE_32BIT | - AIU_I2S_SOURCE_DESC_MODE_SPLIT, - desc); - - return 0; -} - static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component, struct snd_pcm_hw_params *params, unsigned int bs) @@ -173,11 +125,6 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, if ((fs % 64) || (fs == 0)) return -EINVAL; - /* Send data MSB first */ - snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG, - AIU_I2S_DAC_CFG_MSB_FIRST, - AIU_I2S_DAC_CFG_MSB_FIRST); - /* Set bclk to lrlck ratio */ snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL, AIU_CODEC_DAC_LRCLK_CTRL_DIV, @@ -223,12 +170,6 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, } } - ret = aiu_encoder_i2s_setup_desc(component, params); - if (ret) { - dev_err(dai->dev, "setting i2s desc failed: %d\n", ret); - return ret; - } - ret = aiu_encoder_i2s_set_clocks(component, params); if (ret) { dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); @@ -411,6 +352,25 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream, return ret; } + /* + * We're always operating in split mode for the playback stream. + * + * This setting arguably belong to the 'aiu-formatter', but it's kept + * here for backward compatibility reason. At reset the I2S encoder + * operates in normal mode which would only support 8ch, but by default + * only 2ch are enabled. If a playback stream is started without + * changing to split mode, then the I2S encoder doesn't consume audio + * samples and the playback fails. + * Moving this to 'aiu-formatter' would cause the split mode to be set + * only when the formatter is enabled, which doesn't happen at boot as + * the default value for "HDMI CTRL SRC" is "DISABLED". + */ + ret = snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC, + AIU_I2S_SOURCE_DESC_MODE_SPLIT, + AIU_I2S_SOURCE_DESC_MODE_SPLIT); + if (ret < 0) + dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret); + return 0; } diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index f2890111c1d2..64ace4d25d92 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC, static const struct snd_kcontrol_new aiu_spdif_encode_mux = SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum); -static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = { - SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0, - &aiu_spdif_encode_mux), +#define AIU_WIDGET_SPDIF_SRC_SEL 0 +#define AIU_WIDGET_I2S_FORMATTER 1 + +static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = { + [AIU_WIDGET_SPDIF_SRC_SEL] = + SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0, + &aiu_spdif_encode_mux), + [AIU_WIDGET_I2S_FORMATTER] = + SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0, + gx_formatter_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), }; static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = { - { "I2S Encoder Playback", NULL, "I2S FIFO Playback" }, + { "I2S Formatter", NULL, "I2S FIFO Playback" }, + { "I2S Encoder Playback", NULL, "I2S Formatter" }, { "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" }, { "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" }, { "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" }, @@ -172,6 +181,11 @@ static const struct regmap_config aiu_regmap_cfg = { .max_register = 0x2ac, }; +const struct gx_formatter_driver aiu_formatter_i2s_drv = { + .regmap_cfg = &aiu_regmap_cfg, + .ops = &aiu_formatter_i2s_ops, +}; + static int aiu_clk_bulk_get(struct device *dev, const char * const *ids, unsigned int num, @@ -282,6 +296,14 @@ static int aiu_probe(struct platform_device *pdev) if (ret) return ret; + /* Allocate the aiu-formatter into its widget */ + ret = gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER], + &aiu_formatter_i2s_drv, map); + if (ret) { + dev_err(dev, "Failed to allocate aiu formatter\n"); + goto err; + } + /* Register the cpu component of the aiu */ ret = snd_soc_register_component(dev, &aiu_cpu_component, aiu_cpu_dai_drv, @@ -310,12 +332,14 @@ static int aiu_probe(struct platform_device *pdev) return 0; err: + gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]); snd_soc_unregister_component(dev); return ret; } static void aiu_remove(struct platform_device *pdev) { + gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]); snd_soc_unregister_component(&pdev->dev); } diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h index 68310de0bdf7..7d0b98c1f351 100644 --- a/sound/soc/meson/aiu.h +++ b/sound/soc/meson/aiu.h @@ -61,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops; extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops; extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops; extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops; +extern const struct gx_formatter_ops aiu_formatter_i2s_ops; #define AIU_IEC958_BPF 0x000 #define AIU_958_MISC 0x010 From b2133ca33e66dafe948c5a219e7f40b2ccd07881 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jun 2026 01:08:07 +0000 Subject: [PATCH 039/438] ASoC: au1x: psc-ac97: remove unused chans chans is not used in au1xpsc_ac97_hw_params(). Remove it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87y0g2ds7c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/psc-ac97.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 94698e08a513..0f9d80883116 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -210,9 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, { struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); unsigned long r, ro, stat; - int chans, t, stype = substream->stream; - - chans = params_channels(params); + int t, stype = substream->stream; r = ro = __raw_readl(AC97_CFG(pscdata)); stat = __raw_readl(AC97_STAT(pscdata)); From c97f0bf5f705b16d150f2b0d5ce0ee24eee4f68a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jun 2026 05:45:10 +0000 Subject: [PATCH 040/438] ASoC: sdw_utils: tidyup .count_sidecar count_sidecar() is not using *card. Tidyup it. Current code makes old style / new style conversion difficult. To make future conversions easier to understand, this patch clean up the code a little. but no functional change. Signed-off-by: Kuninori Morimoto Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/87jyrlety1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc_sdw_utils.h | 28 ++++++++++---------- sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c | 4 +-- sound/soc/sdw_utils/soc_sdw_utils.c | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 79c21966220b..443d63dc6ea3 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -44,6 +44,18 @@ struct asoc_sdw_codec_info; +struct asoc_sdw_mc_private { + struct snd_soc_card card; + struct snd_soc_jack sdw_headset; + struct device *headset_codec_dev; /* only one headset per card */ + struct device *amp_dev1, *amp_dev2; + bool append_dai_type; + bool ignore_internal_dmic; + void *private; + unsigned long mc_quirk; + int codec_info_list_count; +}; + struct asoc_sdw_dai_info { const bool direction[2]; /* playback & capture support */ const char *codec_name; @@ -88,25 +100,13 @@ struct asoc_sdw_codec_info { int (*codec_card_late_probe)(struct snd_soc_card *card); - int (*count_sidecar)(struct snd_soc_card *card, + int (*count_sidecar)(struct asoc_sdw_mc_private *ctx, int *num_dais, int *num_devs); int (*add_sidecar)(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, struct snd_soc_codec_conf **codec_conf); }; -struct asoc_sdw_mc_private { - struct snd_soc_card card; - struct snd_soc_jack sdw_headset; - struct device *headset_codec_dev; /* only one headset per card */ - struct device *amp_dev1, *amp_dev2; - bool append_dai_type; - bool ignore_internal_dmic; - void *private; - unsigned long mc_quirk; - int codec_info_list_count; -}; - struct asoc_sdw_endpoint { struct list_head list; @@ -235,7 +235,7 @@ int asoc_sdw_es9356_amp_init(struct snd_soc_card *card, int asoc_sdw_es9356_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); /* CS AMP support */ -int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, +int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx, int *num_dais, int *num_devs); int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c index e0e32a279787..129a437ae397 100644 --- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c +++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c @@ -99,11 +99,9 @@ static const struct snd_soc_dai_link bridge_dai_template = { SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai), }; -int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, +int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx, int *num_dais, int *num_devs) { - struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); - if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) { (*num_dais)++; (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index d8db8fc5313e..073f3f9205a7 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -2045,7 +2045,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; if (codec_info->count_sidecar && codec_info->add_sidecar) { - ret = codec_info->count_sidecar(card, &num_dais, num_devs); + ret = codec_info->count_sidecar(ctx, &num_dais, num_devs); if (ret) return ret; From a1332be2a07090cf422507ec812ce2b9ba0a558a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jun 2026 05:45:15 +0000 Subject: [PATCH 041/438] ASoC: sdw_utils: tidyup asoc_sdw_parse_sdw_endpoints() We can avoid to use *card. Tidyup it. Current code makes old style / new style conversion difficult. To make future conversions easier to understand, this patch clean up the code a little. but no functional change. Signed-off-by: Kuninori Morimoto Reviewed-by: Cezary Rojewski Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/87ik75etxw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc_sdw_utils.h | 3 ++- sound/soc/amd/acp/acp-sdw-legacy-mach.c | 2 +- sound/soc/amd/acp/acp-sdw-sof-mach.c | 2 +- sound/soc/intel/boards/sof_sdw.c | 2 +- sound/soc/sdw_utils/soc_sdw_utils.c | 5 ++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 443d63dc6ea3..9b28e9aef4f1 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -182,7 +182,8 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks const struct snd_soc_acpi_endpoint *new); int asoc_sdw_get_dai_type(u32 type); -int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, +int asoc_sdw_parse_sdw_endpoints(struct device *dev, + struct asoc_sdw_mc_private *ctx, struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index e8b6819cc4b4..9726a9d33ec6 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -432,7 +432,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) if (!soc_aux) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs); + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs); if (ret < 0) return ret; diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index a423853f3a97..963ce6fd4012 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -303,7 +303,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!sof_aux) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs); + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs); if (ret < 0) return ret; diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d43daf9b025d..24226a387cc2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1285,7 +1285,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs); + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); if (ret < 0) goto err_end; diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 073f3f9205a7..dd2cc57059d6 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -1976,14 +1976,13 @@ static int is_sdca_endpoint_present(struct device *dev, return ret; } -int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, +int asoc_sdw_parse_sdw_endpoints(struct device *dev, + struct asoc_sdw_mc_private *ctx, struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, int *num_devs) { - struct device *dev = card->dev; - struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link; From 2f82d58a87d707c54ba649a4f71b9e7bc9c56f47 Mon Sep 17 00:00:00 2001 From: Julian Braha Date: Tue, 30 Jun 2026 09:52:49 +0100 Subject: [PATCH 042/438] ASoC: codecs: cleanup kconfig indentations Cleanup various bad indentations in the kconfig: 1. spaces instead of tabs (this file mostly uses tabs) 2. too much indentation 3. not enough indentation Signed-off-by: Julian Braha Link: https://patch.msgid.link/20260630085249.380365-1-julianbraha@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e9de333c5c8a..f90a0d4c77ea 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -615,8 +615,8 @@ config SND_SOC_AK4613 depends on I2C config SND_SOC_AK4619 - tristate "AKM AK4619 CODEC" - depends on I2C + tristate "AKM AK4619 CODEC" + depends on I2C config SND_SOC_AK4642 tristate "AKM AK4642 CODEC" @@ -1201,16 +1201,16 @@ config SND_SOC_JZ4725B_CODEC will be called snd-soc-jz4725b-codec. config SND_SOC_JZ4760_CODEC - depends on MACH_INGENIC || COMPILE_TEST - depends on OF - select REGMAP - tristate "Ingenic JZ4760 internal CODEC" - help - Enable support for the internal CODEC found in the JZ4760 SoC - from Ingenic. + depends on MACH_INGENIC || COMPILE_TEST + depends on OF + select REGMAP + tristate "Ingenic JZ4760 internal CODEC" + help + Enable support for the internal CODEC found in the JZ4760 SoC + from Ingenic. - This driver can also be built as a module. If so, the module - will be called snd-soc-jz4760-codec. + This driver can also be built as a module. If so, the module + will be called snd-soc-jz4760-codec. config SND_SOC_JZ4770_CODEC depends on MACH_INGENIC || COMPILE_TEST @@ -2296,8 +2296,8 @@ config SND_SOC_TLV320ADC3XXX depends on I2C depends on GPIOLIB help - Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 - ADCs. + Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 + ADCs. config SND_SOC_TLV320AIC23 tristate @@ -2893,7 +2893,7 @@ config SND_SOC_TPA6130A2 depends on I2C config SND_SOC_LPASS_MACRO_COMMON - tristate + tristate config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK From 3848617c64ac5bf71e02f437e1974720d78843ca Mon Sep 17 00:00:00 2001 From: Narasimharao Vadlamudi Date: Tue, 30 Jun 2026 22:43:33 +0530 Subject: [PATCH 043/438] ASoC: renesas: fsi: Propagate platform_get_irq() errors platform_get_irq() returns a positive IRQ number on success and a negative error code on failure. It no longer returns zero. The driver currently stores the return value in an unsigned int and returns -ENODEV for all failures, which loses useful errors such as -EPROBE_DEFER. Store the IRQ in an int and return the error from platform_get_irq() directly. Acked-by: Kuninori Morimoto Reviewed-by: Geert Uytterhoeven Signed-off-by: Narasimharao Vadlamudi Link: https://patch.msgid.link/20260630171333.36396-1-ahmisaranrao@gmail.com Signed-off-by: Mark Brown --- sound/soc/renesas/fsi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c index ae86014c3819..6be6587e1095 100644 --- a/sound/soc/renesas/fsi.c +++ b/sound/soc/renesas/fsi.c @@ -1992,7 +1992,7 @@ static int fsi_probe(struct platform_device *pdev) const struct fsi_core *core; struct fsi_priv *fsi; struct resource *res; - unsigned int irq; + int irq; int ret; memset(&info, 0, sizeof(info)); @@ -2007,12 +2007,15 @@ static int fsi_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { + if (!res) { dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); return -ENODEV; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); if (!master) return -ENOMEM; From ae2e2f1ff1e80f88e5720a3c642992d182adb025 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 29 Jun 2026 18:30:24 -0700 Subject: [PATCH 044/438] ASoC: mediatek: mt2701: add COMPILE_TEST Enable COMPILE_TEST for mt2701 to get extra build coverage as done with other mediatek platforms. Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260630013024.1500623-1-rosenp@gmail.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 4af7bbb58010..224746e7664f 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -7,7 +7,7 @@ config SND_SOC_MEDIATEK config SND_SOC_MT2701 tristate "ASoC support for Mediatek MT2701 chip" - depends on ARCH_MEDIATEK + depends on ARCH_MEDIATEK || COMPILE_TEST select SND_SOC_MEDIATEK help This adds ASoC driver for Mediatek MT2701 boards From bff7fad1010eea6f183fb110b54171cf8700ef8e Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Wed, 24 Jun 2026 23:10:02 +0200 Subject: [PATCH 045/438] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema Convert CS35L36 Speaker Amplifier to yaml. Changes: - maintainers email to the generic Cirrus email - Both the codec and downstream worked just fine without VP-supply provided. Align with datasheet for similar models. - add dai-common.yaml to cover for '#sound-dai-cells', 'sound-name-prefix' - updated not yet implemented: cirrus,weak-fet-delay -> cirrus,classh-wk-fet-delay-ms (in both definition and example) cirrus,weak-fet-thld -> cirrus,weak-fet-thld-millivolt (only in the example) - added two required properties: cirrus,boost-ctl-millivolt cirrus,boost-peak-milliamp Assisted-by: OpenAI:gpt-4 Reviewed-by: David Rhodes Co-developed-by: Rob Herring (Arm) Signed-off-by: Rob Herring (Arm) Signed-off-by: David Heidelberg Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260624-dt-cirrus-cs35l36-v3-1-ec451d5a2908@ixit.cz Signed-off-by: Mark Brown --- .../bindings/sound/cirrus,cs35l36.yaml | 240 ++++++++++++++++++ .../devicetree/bindings/sound/cs35l36.txt | 168 ------------ 2 files changed, 240 insertions(+), 168 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml delete mode 100644 Documentation/devicetree/bindings/sound/cs35l36.txt diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml new file mode 100644 index 000000000000..2a142b32acf5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml @@ -0,0 +1,240 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs35l36.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS35L36 Speaker Amplifier + +maintainers: + - David Rhodes + - patches@opensource.cirrus.com + +description: + CS35L36 is a boosted mono Class D amplifier + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - cirrus,cs35l36 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + VA-supply: + description: Voltage regulator of analog internal section + + VP-supply: + description: Voltage regulator of boost converter + + reset-gpios: + maxItems: 1 + + cirrus,boost-ctl-millivolt: + description: Boost converter output voltage (step 50) + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 2550 + maximum: 12000 + + cirrus,boost-peak-milliamp: + description: Boost-converter peak current limit (step 50) + $ref: /schemas/types.yaml#/definitions/uint32 + default: 4500 + minimum: 1600 + maximum: 4500 + + cirrus,boost-ind-nanohenry: + description: Initial inductor estimation reference value (1000=1μH, 1200=1.2μH) + $ref: /schemas/types.yaml#/definitions/uint32 + default: 1000 + + cirrus,multi-amp-mode: + description: Hi-Z ASP port when more than one amplifier in system + type: boolean + + cirrus,boost-ctl-select: + description: Boost converter control source selection + $ref: /schemas/types.yaml#/definitions/uint32 + default: 1 + enum: + - 0 # Control Port + - 1 # Class + - 2 # Sync + + cirrus,amp-pcm-inv: + description: Invert incoming PCM data when true + type: boolean + + cirrus,imon-pol-inv: + description: Invert polarity of outbound IMON feedback when true + type: boolean + + cirrus,vmon-pol-inv: + description: Invert polarity of outbound VMON feedback when true + type: boolean + + cirrus,dcm-mode-enable: + description: Enable boost converter automatic Discontinuous Conduction Mode + type: boolean + + cirrus,weak-fet-disable: + description: Reduce output driver strength in Weak-FET Drive Mode when true + type: boolean + + cirrus,classh-wk-fet-delay-ms: + description: Weak-FET entry delay + default: 100 + enum: [0, 5, 10, 50, 100, 200, 500, 1000] + + cirrus,classh-weak-fet-thld-millivolt: + description: Weak-FET drive threshold + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700] + + cirrus,temp-warn-threshold: + description: Overtemperature warning threshold + $ref: /schemas/types.yaml#/definitions/uint32 + default: 2 + enum: + - 0 # 105°C + - 1 # 115°C + - 2 # 125°C + - 3 # 135°C + + cirrus,irq-drive-select: + description: Interrupt output driver type + $ref: /schemas/types.yaml#/definitions/uint32 + default: 1 + enum: + - 0 # open-drain + - 1 # push-pull + + cirrus,irq-gpio-select: + description: Programmable IRQ pin selection + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # PDM_DATA/SWIRE_SD/INT + - 1 # GPIO + + cirrus,vpbr-config: + $ref: "#/$defs/vpbr-config" + +$defs: + vpbr-config: + description: Brownout prevention configuration sub-node + type: object + additionalProperties: false + + properties: + cirrus,vpbr-en: + description: VBST brownout prevention enable + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + enum: + - 0 # disabled + - 1 # enabled + + cirrus,vpbr-thld: + description: Initial VPBR threshold voltage + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 2 + maximum: 31 + + cirrus,vpbr-atk-rate: + description: Attenuation attack step rate + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + + cirrus,vpbr-atk-vol: + description: VP brownout prevention step size + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + + cirrus,vpbr-max-attn: + description: Maximum attenuation during VP brownout prevention (dB) + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + + cirrus,vpbr-wait: + description: Delay between brownout clearance and attenuation release (ms) + $ref: /schemas/types.yaml#/definitions/uint32 + default: 1 + enum: + - 0 # 10 + - 1 # 100 + - 2 # 250 + - 3 # 500 + + cirrus,vpbr-rel-rate: + description: Attenuation release step rate + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + + cirrus,vpbr-mute-en: + description: Mute audio if maximum attenuation reached + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 1 + +required: + - compatible + - reg + - interrupts + - VA-supply + - cirrus,boost-ctl-millivolt + - cirrus,boost-peak-milliamp + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@40 { + compatible = "cirrus,cs35l36"; + reg = <0x40>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + reset-gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + cirrus,boost-ind-nanohenry = <1000>; + cirrus,boost-ctl-millivolt = <10000>; + cirrus,boost-peak-milliamp = <4500>; + cirrus,boost-ctl-select = <0>; + cirrus,classh-wk-fet-delay-ms = <100>; + cirrus,classh-weak-fet-thld-millivolt = <100>; + cirrus,temp-warn-threshold = <1>; + cirrus,multi-amp-mode; + cirrus,irq-drive-select = <1>; + cirrus,irq-gpio-select = <1>; + + cirrus,vpbr-config { + cirrus,vpbr-en = <0>; + cirrus,vpbr-thld = <5>; + cirrus,vpbr-atk-rate = <2>; + cirrus,vpbr-atk-vol = <1>; + cirrus,vpbr-max-attn = <9>; + cirrus,vpbr-wait = <1>; + cirrus,vpbr-rel-rate = <5>; + cirrus,vpbr-mute-en = <0>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/cs35l36.txt b/Documentation/devicetree/bindings/sound/cs35l36.txt deleted file mode 100644 index d34117b8558e..000000000000 --- a/Documentation/devicetree/bindings/sound/cs35l36.txt +++ /dev/null @@ -1,168 +0,0 @@ -CS35L36 Speaker Amplifier - -Required properties: - - - compatible : "cirrus,cs35l36" - - - reg : the I2C address of the device for I2C - - - VA-supply, VP-supply : power supplies for the device, - as covered in - Documentation/devicetree/bindings/regulator/regulator.txt. - - - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost - converter's output voltage in mV. The range is from 2550mV to 12000mV with - increments of 50mV. - (Default) VP - - - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA. - Configures the peak current by monitoring the current through the boost FET. - Range starts at 1600mA and goes to a maximum of 4500mA with increments of - 50mA. - (Default) 4.50 Amps - - - cirrus,boost-ind-nanohenry : Inductor estimation LBST reference value. - Seeds the digital boost converter's inductor estimation block with the initial - inductance value to reference. - - 1000 = 1uH (Default) - 1200 = 1.2uH - -Optional properties: - - cirrus,multi-amp-mode : Boolean to determine if there are more than - one amplifier in the system. If more than one it is best to Hi-Z the ASP - port to prevent bus contention on the output signal - - - cirrus,boost-ctl-select : Boost converter control source selection. - Selects the source of the BST_CTL target VBST voltage for the boost - converter to generate. - 0x00 - Control Port Value - 0x01 - Class H Tracking (Default) - 0x10 - MultiDevice Sync Value - - - cirrus,amp-pcm-inv : Boolean to determine Amplifier will invert incoming - PCM data - - - cirrus,imon-pol-inv : Boolean to determine Amplifier will invert the - polarity of outbound IMON feedback data - - - cirrus,vmon-pol-inv : Boolean to determine Amplifier will invert the - polarity of outbound VMON feedback data - - - cirrus,dcm-mode-enable : Boost converter automatic DCM Mode enable. - This enables the digital boost converter to operate in a low power - (Discontinuous Conduction) mode during low loading conditions. - - - cirrus,weak-fet-disable : Boolean : The strength of the output drivers is - reduced when operating in a Weak-FET Drive Mode and must not be used to drive - a large load. - - - cirrus,classh-wk-fet-delay : Weak-FET entry delay. Controls the delay - (in ms) before the Class H algorithm switches to the weak-FET voltage - (after the audio falls and remains below the value specified in WKFET_AMP_THLD). - - 0 = 0ms - 1 = 5ms - 2 = 10ms - 3 = 50ms - 4 = 100ms (Default) - 5 = 200ms - 6 = 500ms - 7 = 1000ms - - - cirrus,classh-weak-fet-thld-millivolt : Weak-FET amplifier drive threshold. - Configures the signal threshold at which the PWM output stage enters - weak-FET operation. The range is 50mV to 700mV in 50mV increments. - - - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold. - Configures the threshold at which the overtemperature warning condition occurs. - When the threshold is met, the overtemperature warning attenuation is applied - and the TEMP_WARN_EINT interrupt status bit is set. - If TEMP_WARN_MASK = 0, INTb is asserted. - - 0 = 105C - 1 = 115C - 2 = 125C (Default) - 3 = 135C - - - cirrus,irq-drive-select : Selects the driver type of the selected interrupt - output. - - 0 = Open-drain - 1 = Push-pull (Default) - - - cirrus,irq-gpio-select : Selects the pin to serve as the programmable - interrupt output. - - 0 = PDM_DATA / SWIRE_SD / INT (Default) - 1 = GPIO - -Optional properties for the "cirrus,vpbr-config" Sub-node - - - cirrus,vpbr-en : VBST brownout prevention enable. Configures whether the - VBST brownout prevention algorithm is enabled or disabled. - - 0 = VBST brownout prevention disabled (default) - 1 = VBST brownout prevention enabled - - See Section 7.31.1 VPBR Config for configuration options & further details - - - cirrus,vpbr-thld : Initial VPBR threshold. Configures the VP brownout - threshold voltage - - - cirrus,cirrus,vpbr-atk-rate : Attenuation attack step rate. Configures the - amount delay between consecutive volume attenuation steps when a brownout - condition is present and the VP brownout condition is in an attacking state. - - - cirrus,vpbr-atk-vol : VP brownout prevention step size. Configures the VP - brownout prevention attacking attenuation step size when operating in either - digital volume or analog gain modes. - - - cirrus,vpbr-max-attn : Maximum attenuation that the VP brownout prevention - can apply to the audio signal. - - - cirrus,vpbr-wait : Configures the delay time between a brownout condition - no longer being present and the VP brownout prevention entering an attenuation - release state. - - - cirrus,vpbr-rel-rate : Attenuation release step rate. Configures the delay - between consecutive volume attenuation release steps when a brownout condition - is not longer present and the VP brownout is in an attenuation release state. - - - cirrus,vpbr-mute-en : During the attack state, if the vpbr-max-attn value - is reached, the error condition still remains, and this bit is set, the audio - is muted. - -Example: - -cs35l36: cs35l36@40 { - compatible = "cirrus,cs35l36"; - reg = <0x40>; - VA-supply = <&dummy_vreg>; - VP-supply = <&dummy_vreg>; - reset-gpios = <&gpio0 54 0>; - interrupt-parent = <&gpio8>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; - - cirrus,boost-ind-nanohenry = <1000>; - cirrus,boost-ctl-millivolt = <10000>; - cirrus,boost-peak-milliamp = <4500>; - cirrus,boost-ctl-select = <0x00>; - cirrus,weak-fet-delay = <0x04>; - cirrus,weak-fet-thld = <0x01>; - cirrus,temp-warn-threshold = <0x01>; - cirrus,multi-amp-mode; - cirrus,irq-drive-select = <0x01>; - cirrus,irq-gpio-select = <0x01>; - - cirrus,vpbr-config { - cirrus,vpbr-en = <0x00>; - cirrus,vpbr-thld = <0x05>; - cirrus,vpbr-atk-rate = <0x02>; - cirrus,vpbr-atk-vol = <0x01>; - cirrus,vpbr-max-attn = <0x09>; - cirrus,vpbr-wait = <0x01>; - cirrus,vpbr-rel-rate = <0x05>; - cirrus,vpbr-mute-en = <0x00>; - }; -}; From 7ffb66fd96ec73dd5413d27624476588beb57c30 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 1 Jul 2026 06:17:57 +0000 Subject: [PATCH 046/438] ASoC: mediatek: mt8173-rt5650: tidyup error message mt8173_rt5650_dev_probe() has strange error message => ret = device_property_read_u32(...); ^^^^^^^^^^^^^^^^^^^^^^^^ if (ret) => dev_err(... "%s snd_soc_register_card fail %d\n", ...); ^^^^^^^^^^^^^^^^^^^^^ It should be "device_property_read_u32() fail". Fix it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/875x2zcjxn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 3d6d7bc05b87..8c5096482520 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -315,7 +315,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) &mt8173_rt5650_priv.pll_from); if (ret) { dev_err(&pdev->dev, - "%s snd_soc_register_card fail %d\n", + "%s device_property_read_u32() fail %d\n", __func__, ret); } } From 882e55031187791a2b87810d4a93f866a2da6d47 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Tue, 30 Jun 2026 15:23:06 +0800 Subject: [PATCH 047/438] ASoC: codecs: ES8389: Modify volatile_register Mark some registers that are not volatile as false And modified the logic for `cache_bypass` during `8389_resume`. Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260630072311.8427-2-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 3484c87853cb..10de2143f8d8 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -50,10 +50,29 @@ static const char * const es8389_core_supplies[] = { static bool es8389_volatile_register(struct device *dev, unsigned int reg) { - if ((reg <= 0xff)) - return true; - else + switch (reg) { + case ES8389_ADCL_VOL: + case ES8389_ADCR_VOL: + case ES8389_MIC1_GAIN: + case ES8389_MIC2_GAIN: + case ES8389_DACL_VOL: + case ES8389_DACR_VOL: + case ES8389_ALC_ON: + case ES8389_ALC_CTL: + case ES8389_ALC_TARGET: + case ES8389_ALC_GAIN: + case ES8389_ADC_MUTE: + case ES8389_OSR_VOL: + case ES8389_DAC_INV: + case ES8389_MIX_VOL: + case ES8389_DAC_MIX: + case ES8389_ADC_RESET: + case ES8389_ADC_MODE: + case ES8389_DMIC_EN: return false; + default: + return true; + } } static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0); @@ -861,13 +880,13 @@ static int es8389_resume(struct snd_soc_component *component) regcache_cache_only(es8389->regmap, false); regcache_cache_bypass(es8389->regmap, true); regmap_read(es8389->regmap, ES8389_RESET, ®v); - regcache_cache_bypass(es8389->regmap, false); if (regv == 0xff) es8389_init(component); else es8389_set_bias_level(component, SND_SOC_BIAS_ON); + regcache_cache_bypass(es8389->regmap, false); regcache_sync(es8389->regmap); return 0; From cbc559dd8d46acd0781a4f183d8ec550262714ab Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Tue, 30 Jun 2026 15:23:07 +0800 Subject: [PATCH 048/438] ASoC: codecs: ES8389: Fix the issue about mclk_src Fix the issue with incorrect modifications to mclk_src When the system needs to be configured to use the MCLK from the SCLK pin, the code still sets the relevant registers to use the MCLK from the MCLK pin Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260630072311.8427-3-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 2 +- sound/soc/codecs/es8389.h | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 10de2143f8d8..890c6b4c15e2 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -609,7 +609,7 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, if (es8389->mclk_src == ES8389_SCLK_PIN) { regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK, - ES8389_MCLK_SOURCE, es8389->mclk_src); + ES8389_MCLK_MASK, ES8389_MCLK_FROM_SCLK); es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params); } diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h index d21e72f876a6..57bf7c5f8b57 100644 --- a/sound/soc/codecs/es8389.h +++ b/sound/soc/codecs/es8389.h @@ -116,9 +116,11 @@ #define ES8389_TDM_SLOT (0x70 << 0) #define ES8389_TDM_SHIFT 4 -#define ES8389_MCLK_SOURCE (1 << 6) -#define ES8389_MCLK_PIN (1 << 6) -#define ES8389_SCLK_PIN (0 << 6) +#define ES8389_MCLK_MASK (3 << 6) +#define ES8389_MCLK_FROM_SCLK (1 << 6) +#define ES8389_MCLK_SOURCE ES8389_MCLK_PIN +#define ES8389_MCLK_PIN 0 +#define ES8389_SCLK_PIN 1 /* ES8389_FMT */ #define ES8389_S24_LE (0 << 5) From 9367a244afc24e3863689bef126efa2ad01105db Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Tue, 30 Jun 2026 15:23:08 +0800 Subject: [PATCH 049/438] ASoC: codecs: ES8389: Modify the clock table Updated the configuration for certain frequencies Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260630072311.8427-4-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 46 ++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 890c6b4c15e2..9d263927d7b7 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -434,52 +434,54 @@ static const struct _coeff_div coeff_div[] = { {36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {150, 2400000, 16000, 0x02, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, + {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, {800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14, 2, 2}, {375, 12000000, 32000, 0x0E, 0x2E, 0x05, 0xC8, 0x00, 0xC2, 0x80, 0x40, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 0}, - {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2}, - {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2}, + {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, + {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, {128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25, 2, 2}, - {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, + {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, {96, 9216000, 96000, 0x02, 0x43, 0x00, 0xC0, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, {256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, {128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xBF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 2, 2}, + {64, 12288000, 192000, 0x00, 0x41, 0x00, 0xC0, 0x18, 0xC1, 0x80, 0x00, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 1, 0}, }; static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate) From 3bea836903c2b2305c2219e897b217261be8a26a Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Tue, 30 Jun 2026 15:23:09 +0800 Subject: [PATCH 050/438] ASoC: codecs: ES8389: Modify the initial configuration Modify the initial configuration Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260630072311.8427-5-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 9d263927d7b7..26a063186dc5 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -792,7 +792,7 @@ static void es8389_init(struct snd_soc_component *component) regmap_read(es8389->regmap, ES8389_MAX_REGISTER, ®); es8389->version = reg; - regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00); + regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x56); regmap_write(es8389->regmap, ES8389_RESET, 0x7E); regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38); regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64); @@ -844,7 +844,7 @@ static void es8389_init(struct snd_soc_component *component) regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04); regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01); regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00); - regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00); + regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x10); regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F); regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F); regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0); From 87592da1a490abd2adeb57a49fb200d058403cc5 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Tue, 30 Jun 2026 15:23:10 +0800 Subject: [PATCH 051/438] ASoC: codecs: ES8389: Add private members about HPF Add private members related to HPF. Add Kcontrol for HPF Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260630072311.8427-6-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 122 +++++++++++++++++++++++++++++++++++++- sound/soc/codecs/es8389.h | 3 + 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 26a063186dc5..2f9a98a513a1 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -36,6 +36,10 @@ struct es8389_private { unsigned int sysclk; int mastermode; + u8 hpfl; + u8 hpfr; + u32 hpf_freq; + u32 capture_rate; u8 mclk_src; u8 vddd; int version; @@ -82,6 +86,92 @@ static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0); static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0); static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0); +static const u32 hpf_table[10][10] = { + {1020, 754, 624, 559, 527, 511, 502, 498, 497, 496}, + {754, 495, 368, 306, 274, 259, 251, 247, 246, 244}, + {624, 368, 243, 182, 151, 136, 128, 124, 123, 121}, + {559, 306, 182, 120, 90, 75, 68, 63, 62, 60}, + {527, 274, 151, 90, 60, 45, 38, 33, 32, 31}, + {511, 259, 136, 75, 45, 30, 23, 19, 18, 17}, + {502, 251, 128, 68, 38, 23, 16, 13, 11, 11}, + {498, 247, 124, 63, 33, 19, 13, 10, 8, 8}, + {497, 246, 123, 62, 32, 18, 11, 8, 8, 0}, + {496, 244, 121, 60, 31, 17, 11, 8, 0, 0} +}; + +static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out) +{ + int best_row = -1, best_col = -1; + u32 min_diff = U32_MAX; + u32 f, diff; + int i, j; + + if ((target_hz > 1020) | (target_hz < 0)) + return false; + + for (i = 0; i < 10; i++) { + for (j = i; j < 10; j++) { + f = hpf_table[i][j]; + + diff = (target_hz > f) ? (target_hz - f) : (f - target_hz); + if (diff < min_diff) { + min_diff = diff; + best_row = i; + best_col = j; + *out = f; + } + } + } + + *hpf1 = best_col + ES8389_HPF_OFFSET; + *hpf2 = best_row + ES8389_HPF_OFFSET; + + return true; +} + +static int es8389_hpf_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = es8389->hpf_freq; + return 0; +} + +static int es8389_hpf_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); + u32 freq; + bool hpf; + + if (es8389->hpf_freq == ucontrol->value.integer.value[0]) + return 0; + + if (es8389->capture_rate) { + freq = (ucontrol->value.integer.value[0] * 48000) / es8389->capture_rate; + + hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq); + if (!hpf) + return -EBUSY; + + if (es8389->hpf_freq != ucontrol->value.integer.value[0]) + dev_dbg(component->dev, "At the %u Hz sampling rate, %ld Hz could not be obtained." + "the frequency has been set to the closest value, %u Hz\n", + es8389->capture_rate, ucontrol->value.integer.value[0], es8389->hpf_freq); + + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl); + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr); + } else { + es8389->hpf_freq = ucontrol->value.integer.value[0]; + dev_dbg(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n"); + } + + return 1; +} + static int es8389_dmic_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -259,6 +349,8 @@ static const struct snd_kcontrol_new es8389_snd_controls[] = { SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0), SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv), SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0), + SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0, + es8389_hpf_get, es8389_hpf_set), SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv), SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv), @@ -585,6 +677,8 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, int coeff, ret; u8 dmic_enable, state = 0; unsigned int regv; + u32 freq; + bool hpf; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -662,6 +756,28 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, dev_warn(component->dev, "Clock coefficients do not match"); } + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + es8389->capture_rate = params_rate(params); + freq = (es8389->hpf_freq * 48000) / params_rate(params); + hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq); + if (!hpf) { + dev_err(component->dev, "The HPF frequency is invalid\n"); + return -EINVAL; + } + } + + return 0; +} + +static int es8389_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + es8389->capture_rate = 0; + return 0; } @@ -742,8 +858,8 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction) regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE, 0x03, 0x00); } else { - regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a); - regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a); + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl); + regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr); regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE, 0x03, 0x00); } @@ -759,6 +875,7 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction) static const struct snd_soc_dai_ops es8389_ops = { .hw_params = es8389_pcm_hw_params, + .hw_free = es8389_pcm_hw_free, .set_fmt = es8389_set_dai_fmt, .set_sysclk = es8389_set_dai_sysclk, .set_tdm_slot = es8389_set_tdm_slot, @@ -934,6 +1051,7 @@ static int es8389_probe(struct snd_soc_component *component) return ret; } + es8389->hpf_freq = ES8389_HPF_DEFAULT; es8389_init(component); es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h index 57bf7c5f8b57..de39e9bf96e9 100644 --- a/sound/soc/codecs/es8389.h +++ b/sound/soc/codecs/es8389.h @@ -106,6 +106,9 @@ #define ES8389_MIC_SEL_MASK (7 << 4) #define ES8389_MIC_DEFAULT (1 << 4) +#define ES8389_HPF_DEFAULT 16 +#define ES8389_HPF_OFFSET 4 + #define ES8389_MASTER_MODE_EN (1 << 0) #define ES8389_TDM_OFF (0 << 0) From 2264927316e5312208659fe0b7efd0001c8975d9 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Tue, 30 Jun 2026 15:23:11 +0800 Subject: [PATCH 052/438] ASoC: codecs: ES8389: Add INPUTL MUX and INPUTR MUX Add INPUTL MUX and INPUTR MUX in route Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20260630072311.8427-7-zhangyi@everest-semi.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 2f9a98a513a1..0c7567e2ffc2 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -252,6 +252,16 @@ static const struct soc_enum alc_ramprate = static const struct soc_enum alc_winsize = SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize); +static const char *const es8389_adcl_mux_txt[] = { + "Normal", + "ADC2 channel to ADC1 channel", +}; + +static const char *const es8389_adcr_mux_txt[] = { + "Normal", + "ADC1 channel to ADC2 channel", +}; + static const char *const es8389_outl_mux_txt[] = { "Normal", "DAC2 channel to DAC1 channel", @@ -279,6 +289,20 @@ static const unsigned int es8389_pga_values[] = { 1, 5, 6 }; +static const struct soc_enum es8389_adcl_mux_enum = + SOC_ENUM_SINGLE(ES8389_ADC_MODE, 5, + ARRAY_SIZE(es8389_adcl_mux_txt), es8389_adcl_mux_txt); + +static const struct snd_kcontrol_new es8389_adcl_mux_controls = + SOC_DAPM_ENUM("INPUTL MUX", es8389_adcl_mux_enum); + +static const struct soc_enum es8389_adcr_mux_enum = + SOC_ENUM_SINGLE(ES8389_ADC_MODE, 4, + ARRAY_SIZE(es8389_adcr_mux_txt), es8389_adcr_mux_txt); + +static const struct snd_kcontrol_new es8389_adcr_mux_controls = + SOC_DAPM_ENUM("INPUTR MUX", es8389_adcr_mux_enum); + static const struct soc_enum es8389_outl_mux_enum = SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5, ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt); @@ -409,6 +433,8 @@ static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = { &es8389_adc_mixer_controls[0], ARRAY_SIZE(es8389_adc_mixer_controls)), SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls), + SND_SOC_DAPM_MUX("INPUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_adcl_mux_controls), + SND_SOC_DAPM_MUX("INPUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_adcr_mux_controls), SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls), SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls), @@ -422,10 +448,15 @@ static const struct snd_soc_dapm_route es8389_dapm_routes[] = { {"ADCL", NULL, "PGAL"}, {"ADCR", NULL, "PGAR"}, + {"INPUTL MUX", "Normal", "ADCL"}, + {"INPUTL MUX", "ADC2 channel to ADC1 channel", "ADCR"}, + {"INPUTR MUX", "Normal", "ADCR"}, + {"INPUTR MUX", "ADC1 channel to ADC2 channel", "ADCL"}, + {"ADC Mixer", "DACL ADCL Mixer", "DACL"}, {"ADC Mixer", "DACR ADCR Mixer", "DACR"}, - {"ADC Mixer", NULL, "ADCL"}, - {"ADC Mixer", NULL, "ADCR"}, + {"ADC Mixer", NULL, "INPUTL MUX"}, + {"ADC Mixer", NULL, "INPUTR MUX"}, {"ADC MUX", "AMIC", "ADC Mixer"}, {"ADC MUX", "DMIC", "DMIC"}, From e3653722b94df580ab8610f4f38ab43e46f083c0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jun 2026 06:04:20 +0000 Subject: [PATCH 053/438] ASoC: sof: topology: use for_each_card_rtds() We already have for_each_card_rtds(). Let's use it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87h5mpet2c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f709935593ef..6de8a6c1c127 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1102,7 +1102,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, full = NULL; partial = NULL; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { /* does stream match DAI link ? */ if (rtd->dai_link->stream_name) { if (!strcmp(rtd->dai_link->stream_name, w->sname)) { @@ -1167,7 +1167,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, else return; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { /* does stream match DAI link ? */ if (!rtd->dai_link->stream_name || !strstr(rtd->dai_link->stream_name, sname)) From 02fd694e60a7e2c581c7836f6781c01b9b419c8a Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 1 Jul 2026 11:13:09 +0700 Subject: [PATCH 054/438] ASoC: samsung: i2s: Avoid mixing goto with guard() cleanup.h recommends not mixing goto-based error handling with cleanup helpers in the same function. Remove the goto path and rely on guard(pm_runtime) for automatic cleanup instead. Fixes: 3d08517b5c67 ("ASoC: samsung: i2s: Use guard() for spin locks") Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260701041310.230725-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f80f697a5d55..f80e8d498156 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -512,7 +513,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, u32 mod, mask, val = 0; int ret = 0; - pm_runtime_get_sync(dai->dev); + guard(pm_runtime_active)(dai->dev); scoped_guard(spinlock_irqsave, &priv->lock) mod = readl(priv->addr + I2SMOD); @@ -537,8 +538,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, && (mod & cdcon_mask))))) { dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); - ret = -EAGAIN; - goto err; + return -EAGAIN; } if (dir == SND_SOC_CLOCK_IN) @@ -566,7 +566,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, } else { priv->rclk_srcrate = clk_get_rate(priv->op_clk); - goto done; + return 0; } } @@ -580,14 +580,14 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, if (WARN_ON(IS_ERR(priv->op_clk))) { ret = PTR_ERR(priv->op_clk); priv->op_clk = NULL; - goto err; + return ret; } ret = clk_prepare_enable(priv->op_clk); if (ret) { clk_put(priv->op_clk); priv->op_clk = NULL; - goto err; + return ret; } priv->rclk_srcrate = clk_get_rate(priv->op_clk); @@ -595,11 +595,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, || (clk_id && !(mod & rsrc_mask))) { dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); - ret = -EAGAIN; - goto err; + return -EAGAIN; } else { /* Call can't be on the active DAI */ - goto done; + return 0; } if (clk_id == 1) @@ -607,8 +606,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, break; default: dev_err(&i2s->pdev->dev, "We don't serve that!\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } scoped_guard(spinlock_irqsave, &priv->lock) { @@ -616,13 +614,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, mod = (mod & ~mask) | val; writel(mod, priv->addr + I2SMOD); } -done: - pm_runtime_put(dai->dev); return 0; -err: - pm_runtime_put(dai->dev); - return ret; } static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) From 47a0dde9a3bdd01359ce3a5f0b59a9de33b73dce Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 1 Jul 2026 11:13:10 +0700 Subject: [PATCH 055/438] ASoC: ti: j721e-evm: Avoid mixing goto with guard() The previous guard(mutex) conversion mixed cleanup helpers with goto-based error handling, which is discouraged by the cleanup.h guidelines. Restore mutex_lock()/mutex_unlock() instead. Fixes: 6f4cf77320ae ("ASoC: ti: j721e-evm: Use guard() for mutex locks") Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260701041310.230725-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/j721e-evm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c index c214ae0d7b95..312298e0b004 100644 --- a/sound/soc/ti/j721e-evm.c +++ b/sound/soc/ti/j721e-evm.c @@ -4,6 +4,7 @@ * Author: Peter Ujfalusi */ +#include #include #include #include @@ -263,7 +264,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream) int ret = 0; int i; - guard(mutex)(&priv->mutex); + mutex_lock(&priv->mutex); domain->active++; @@ -303,6 +304,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream) out: if (ret) domain->active--; + mutex_unlock(&priv->mutex); return ret; } From fb5d1b1c5f8a920ee697545fa6dee16825085717 Mon Sep 17 00:00:00 2001 From: WenTao Liang Date: Sat, 27 Jun 2026 11:52:51 +0800 Subject: [PATCH 056/438] ASoC: samsung: aries_audio_probe: double of_node_put due to direct assignment without of_node_get In aries_audio_probe(), aries_dai[0].platforms->of_node is assigned the same pointer as aries_dai[0].cpus->of_node (from of_parse_phandle) without calling of_node_get(). When the sound card is deregistered, the ASoC framework calls of_node_put() on both cpus->of_node and platforms->of_node, causing a double put on the same node and a refcount underflow. Add of_node_get(aries_dai[0].cpus->of_node) before the assignment. Cc: stable@vger.kernel.org Fixes: 7a3a7671fa6c ("ASoC: samsung: Add driver for Aries boards") Signed-off-by: WenTao Liang Link: https://patch.msgid.link/20260627035251.60172-1-vulab@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/samsung/aries_wm8994.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 48ccc1d1854b..6db91b73f25c 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -658,6 +658,7 @@ static int aries_audio_probe(struct platform_device *pdev) goto out; } + of_node_get(aries_dai[0].cpus->of_node); aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node; /* Set CPU of_node for BT DAI */ From bb7c62fdbfecfe15c98c83567f6e1de7d02e52fc Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 1 Jul 2026 15:05:17 +0700 Subject: [PATCH 057/438] ASoC: samsung: spdif: Preserve the original clock acquisition error devm_clk_get() may return different error codes, including -EPROBE_DEFER. The current code overwrites the original error with -ENOENT, preventing deferred probing from working correctly. Replace dev_err() with dev_err_probe() so the original error code is preserved and propagated to the caller. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260701080517.298294-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/spdif.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 7fc46d55c522..53eaabaf8956 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -380,8 +380,8 @@ static int spdif_probe(struct platform_device *pdev) spdif->pclk = devm_clk_get(&pdev->dev, "spdif"); if (IS_ERR(spdif->pclk)) { - dev_err(&pdev->dev, "failed to get peri-clock\n"); - ret = -ENOENT; + ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->pclk), + "failed to get peri-clock\n"); goto err0; } ret = clk_prepare_enable(spdif->pclk); @@ -390,8 +390,8 @@ static int spdif_probe(struct platform_device *pdev) spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif"); if (IS_ERR(spdif->sclk)) { - dev_err(&pdev->dev, "failed to get internal source clock\n"); - ret = -ENOENT; + ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->sclk), + "failed to get internal source clock\n"); goto err1; } ret = clk_prepare_enable(spdif->sclk); From 0eb0e3c623ac1da8b85d518043fef7660af7805d Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:03 +0800 Subject: [PATCH 058/438] ASoC: loongson: Fix error handling in ACPI property parsing In loongson_card_parse_acpi(), the return value of device_property_read_string() for the `codec-dai-name` property was ignored. If the property is missing or invalid, an uninitialized pointer would be used later, potentially leading to undefined behavior. Fix this by checking the return value and propagating the error appropriately. Cc: stable@vger.kernel.org Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/cover.1780538113.git.zhoubinbin@loongson.cn?part=5 Fixes: ddb538a3004b ("ASoC: loongson: Factor out loongson_card_acpi_find_device() function") Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/08e44a54708eae053be148524346bb8dfcd55b03.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index 7910d5d9ac4f..ea895fe6b5e9 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -91,7 +91,7 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data) const char *codec_dai_name; struct acpi_device *adev; struct device *phy_dev; - int i; + int i, ret; /* fixup platform name based on reference node */ adev = loongson_card_acpi_find_device(card, "cpu"); @@ -108,7 +108,9 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data) return -ENOENT; snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); - device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name); + ret = device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name); + if (ret) + return ret; for (i = 0; i < card->num_links; i++) { loongson_dai_links[i].platforms->name = dev_name(phy_dev); From 914e95aaec0df7dc2f3e3e5a774b09f92f37cd91 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:04 +0800 Subject: [PATCH 059/438] ASoC: dt-bindings: loongson,ls2k1000-i2s: Document Loongson-2K0300 compatible Add a new compatible string `loongson,ls2k0300-i2s` for the I2S controller found on Loongson-2K0300 SoC. Unlike Loongson-2K1000, Loongson-2K0300 does not require the second register region for APB DMA configuration, so update the binding to allow a single reg entry. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/af092f9eabdc170c3d7951b29eee6512f748eb48.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- .../bindings/sound/loongson,ls2k1000-i2s.yaml | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml index da79510bb2d9..51e23c189f7a 100644 --- a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml @@ -14,9 +14,12 @@ allOf: properties: compatible: - const: loongson,ls2k1000-i2s + enum: + - loongson,ls2k0300-i2s + - loongson,ls2k1000-i2s reg: + minItems: 1 items: - description: Loongson I2S controller Registers. - description: APB DMA config register for Loongson I2S controller. @@ -49,6 +52,23 @@ required: unevaluatedProperties: false +if: + properties: + compatible: + contains: + enum: + - loongson,ls2k1000-i2s + +then: + properties: + reg: + minItems: 2 + +else: + properties: + reg: + maxItems: 1 + examples: - | #include From 41ab1f8a0edaa98d59162fbe801c1f162fc6cf9a Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:05 +0800 Subject: [PATCH 060/438] ASoC: loongson: Add Loongson-2K0300 I2S controller support The Loongson-2K0300 I2S interface differs significantly from the Loongson-2K1000. Although both utilize external DMA controllers, the Loongson-2K0300 does not require additional registers for routing configuration. Due to hardware design flaw, an extra controller reset sequence is required during probe. Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/4d3caa62d4275e1495505387198408f4d30d453c.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_i2s_plat.c | 42 +++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c index ac054b6ce632..82d95c6644ef 100644 --- a/sound/soc/loongson/loongson_i2s_plat.c +++ b/sound/soc/loongson/loongson_i2s_plat.c @@ -2,7 +2,7 @@ // // Loongson I2S controller master mode dirver(platform device) // -// Copyright (C) 2023-2024 Loongson Technology Corporation Limited +// Copyright (C) 2023-2026 Loongson Technology Corporation Limited // // Author: Yingkun Meng // Binbin Zhou @@ -21,6 +21,7 @@ #include "loongson_i2s.h" #include "loongson_dma.h" +/* Loongson-2K1000 APBDMA routing */ #define LOONGSON_I2S_RX_DMA_OFFSET 21 #define LOONGSON_I2S_TX_DMA_OFFSET 18 @@ -30,6 +31,11 @@ #define LOONGSON_DMA3_CONF 0x3 #define LOONGSON_DMA4_CONF 0x4 +struct loongson_i2s_plat_config { + int rev_id; + int (*i2s_dma_config)(struct platform_device *pdev); +}; + static int loongson_i2s_apbdma_config(struct platform_device *pdev) { int val; @@ -47,8 +53,18 @@ static int loongson_i2s_apbdma_config(struct platform_device *pdev) return 0; } +static const struct loongson_i2s_plat_config ls2k0300_i2s_plat_config = { + .rev_id = 1, +}; + +static const struct loongson_i2s_plat_config ls2k1000_i2s_plat_config = { + .rev_id = 0, + .i2s_dma_config = loongson_i2s_apbdma_config, +}; + static int loongson_i2s_plat_probe(struct platform_device *pdev) { + const struct loongson_i2s_plat_config *plat_config; struct device *dev = &pdev->dev; struct loongson_i2s *i2s; struct resource *res; @@ -59,12 +75,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev) if (!i2s) return -ENOMEM; - ret = loongson_i2s_apbdma_config(pdev); - if (ret) - return ret; + plat_config = device_get_match_data(dev); + if (!plat_config) + return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (plat_config->i2s_dma_config) { + ret = plat_config->i2s_dma_config(pdev); + if (ret) + return ret; + } + + i2s->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2s->reg_base)) return dev_err_probe(dev, PTR_ERR(i2s->reg_base), "devm_ioremap_resource failed\n"); @@ -87,11 +108,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev) if (IS_ERR(i2s_clk)) return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n"); i2s->clk_rate = clk_get_rate(i2s_clk); + i2s->rev_id = plat_config->rev_id; dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); dev_set_name(dev, LS_I2S_DRVNAME); dev_set_drvdata(dev, i2s); + if (i2s->rev_id == 1) { + regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET, I2S_CTRL_RESET); + fsleep(200); + } + ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component, &loongson_i2s_dai, 1); if (ret) @@ -102,7 +129,8 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev) } static const struct of_device_id loongson_i2s_ids[] = { - { .compatible = "loongson,ls2k1000-i2s" }, + { .compatible = "loongson,ls2k0300-i2s", .data = &ls2k0300_i2s_plat_config }, + { .compatible = "loongson,ls2k1000-i2s", .data = &ls2k1000_i2s_plat_config }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, loongson_i2s_ids); From 95133a9ac817242dded1d15643a2aa5faaa289d8 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:25 +0800 Subject: [PATCH 061/438] ASoC: dt-bindings: loongson,ls-audio-card: Use common sound card Reference the common sound card properties. This allows removing the `model` property and directly using the common `audio-routing` property later on. Acked-by: Rob Herring (Arm) Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/fa72a429a9d076d381f7d514184f19d5a35ffa51.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- .../bindings/sound/loongson,ls-audio-card.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml index 61e8babed402..e1b7445a8b22 100644 --- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml +++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml @@ -8,20 +8,20 @@ title: Loongson 7axxx/2kxxx ASoC audio sound card driver maintainers: - Yingkun Meng + - Binbin Zhou description: The binding describes the sound card present in loongson 7axxx/2kxxx platform. The sound card is an ASoC component which uses Loongson I2S controller to transfer the audio data. +allOf: + - $ref: sound-card-common.yaml# + properties: compatible: const: loongson,ls-audio-card - model: - $ref: /schemas/types.yaml#/definitions/string - description: User specified audio sound card name - mclk-fs: $ref: simple-card.yaml#/definitions/mclk-fs @@ -47,12 +47,11 @@ properties: required: - compatible - - model - mclk-fs - cpu - codec -additionalProperties: false +unevaluatedProperties: false examples: - | From 5460b4ddc76a04eb4ad05333f904bad67f1730e2 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:26 +0800 Subject: [PATCH 062/438] ASoC: dt-bindings: loongson,ls-audio-card: Add ctcisz forever pi compatible Add a new compatible string `loongson,ls2k0300-forever-pi-audio-card` for the audio card on Loongson-2K0300 ctcisz forever pi SoC. It uses a different DAI format compared to existing Loongson platforms. The existing "loongson,ls-audio-card" remains valid for LS7A, Loongson-2K1000 and Loongson-2K2000. Signed-off-by: Binbin Zhou Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/183d809cd51874bcb78743273e4b7617f120fedb.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/loongson,ls-audio-card.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml index e1b7445a8b22..8c214e5d04b1 100644 --- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml +++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml @@ -20,7 +20,9 @@ allOf: properties: compatible: - const: loongson,ls-audio-card + enum: + - loongson,ls-audio-card # Loongson-2K1000/Loongson-2K2000/LS7A + - loongson,ls2k0300-forever-pi-audio-card # CTCISZ Forever Pi mclk-fs: $ref: simple-card.yaml#/definitions/mclk-fs From da659805e0b055f8f12de022e28a9983d2f3923f Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:27 +0800 Subject: [PATCH 063/438] ASoC: loongson: Add Loongson-2K0300 CTCISZ Forever Pi sound card support The Loongson-2K0300 audio card uses a different DAI format compared to existing Loongson platforms. Move the dai_fmt setting from the static DAI link to runtime hw_params via snd_soc_runtime_set_dai_fmt(), and pass the correct format through driver match data. Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/ed1314e1d3275fd20aff47397345a88fad6e9368.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_card.c | 34 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index ea895fe6b5e9..0e63cbcad57a 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -2,8 +2,9 @@ // // Loongson ASoC Audio Machine driver // -// Copyright (C) 2023 Loongson Technology Corporation Limited +// Copyright (C) 2023-2026 Loongson Technology Corporation Limited // Author: Yingkun Meng +// Binbin Zhou // #include @@ -18,6 +19,19 @@ static char codec_name[SND_ACPI_I2C_ID_LEN]; struct loongson_card_data { struct snd_soc_card snd_card; unsigned int mclk_fs; + const struct loongson_card_config *cfg; +}; + +struct loongson_card_config { + unsigned int fmt; +}; + +static const struct loongson_card_config ls2k1000_card_config = { + .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC, +}; + +static const struct loongson_card_config ls2k0300_forever_pi_card_config = { + .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, }; static int loongson_card_hw_params(struct snd_pcm_substream *substream, @@ -45,7 +59,7 @@ static int loongson_card_hw_params(struct snd_pcm_substream *substream, return ret; } - return 0; + return snd_soc_runtime_set_dai_fmt(rtd, ls_card->cfg->fmt); } static const struct snd_soc_ops loongson_ops = { @@ -61,8 +75,6 @@ static struct snd_soc_dai_link loongson_dai_links[] = { { .name = "Loongson Audio Port", .stream_name = "Loongson Audio", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF - | SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(analog), .ops = &loongson_ops, }, @@ -177,6 +189,10 @@ static int loongson_asoc_card_probe(struct platform_device *pdev) if (!ls_priv) return -ENOMEM; + ls_priv->cfg = (const struct loongson_card_config *)device_get_match_data(dev); + if (!ls_priv->cfg) + return -EINVAL; + card = &ls_priv->snd_card; card->dev = dev; @@ -202,7 +218,15 @@ static int loongson_asoc_card_probe(struct platform_device *pdev) } static const struct of_device_id loongson_asoc_dt_ids[] = { - { .compatible = "loongson,ls-audio-card" }, + /* Loongson-2K1000/Loongson-2K2000/LS7A */ + { + .compatible = "loongson,ls-audio-card", + .data = &ls2k1000_card_config + }, + { + .compatible = "loongson,ls2k0300-forever-pi-audio-card", + .data = &ls2k0300_forever_pi_card_config + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, loongson_asoc_dt_ids); From 3ddae79479f6c96c4083951c7c4511d7236e7982 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:28 +0800 Subject: [PATCH 064/438] ASoC: dt-bindings: loongson,ls-audio-card: Add ATK-DL2K0300B compatible Add new compatible for the ATK-DL2K0300B development board based on Loongson-2K0300. Unlike others, this board features GPIO-controlled headphone detection, headphone control, and speaker enable. Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/71430fcee5951fb7a7d52e2091a87707db85e06c.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- .../sound/loongson,ls-audio-card.yaml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml index 8c214e5d04b1..dc7f4afbb777 100644 --- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml +++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml @@ -23,6 +23,7 @@ properties: enum: - loongson,ls-audio-card # Loongson-2K1000/Loongson-2K2000/LS7A - loongson,ls2k0300-forever-pi-audio-card # CTCISZ Forever Pi + - loongson,ls2k0300-dl2k0300b-audio-card # ATK-DL2K0300B mclk-fs: $ref: simple-card.yaml#/definitions/mclk-fs @@ -47,6 +48,18 @@ properties: required: - sound-dai + spkr-en-gpios: + maxItems: 1 + description: The GPIO that enables the speakers + + hp-ctl-gpios: + maxItems: 1 + description: The GPIO that control the headphones + + hp-det-gpios: + maxItems: 1 + description: The GPIO that detect headphones are plugged in + required: - compatible - mclk-fs @@ -69,3 +82,28 @@ examples: sound-dai = <&es8323>; }; }; + + - | + #include + + sound { + compatible = "loongson,ls2k0300-dl2k0300b-audio-card"; + model = "loongson-audio"; + mclk-fs = <512>; + hp-det-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>; + spkr-en-gpios = <&gpio 86 GPIO_ACTIVE_HIGH>; + hp-ctl-gpios = <&gpio 87 GPIO_ACTIVE_HIGH>; + audio-routing = + "Headphone", "LOUT1", + "Headphone", "ROUT1", + "Speaker", "LOUT2", + "Speaker", "ROUT2"; + + cpu { + sound-dai = <&i2s>; + }; + + codec { + sound-dai = <&es8388>; + }; + }; From dde4064a4913319cf9b19e745af3417a35f0f738 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:48 +0800 Subject: [PATCH 065/438] ASoC: loongson: Add headphone jack detection and DAPM routing Extend the Loongson audio machine driver with jack detection, DAPM widgets support, enabling proper switching between headphones and speakers on the Loongson-2K0300 ATK-DL2K0300B board. Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/c4b1503220b6fb433ecdcb881556827579041c3d.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- sound/soc/loongson/loongson_card.c | 131 ++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c index 0e63cbcad57a..25cd12eab4b1 100644 --- a/sound/soc/loongson/loongson_card.c +++ b/sound/soc/loongson/loongson_card.c @@ -7,33 +7,126 @@ // Binbin Zhou // +#include +#include #include +#include +#include +#include #include #include -#include -#include -#include static char codec_name[SND_ACPI_I2C_ID_LEN]; struct loongson_card_data { struct snd_soc_card snd_card; unsigned int mclk_fs; + struct gpio_desc *gpiod_hp_det; + struct gpio_desc *gpiod_hp_ctl; + struct gpio_desc *gpiod_spkr_en; const struct loongson_card_config *cfg; }; struct loongson_card_config { unsigned int fmt; + bool add_hp_jack; + bool add_dapm_widgets; + bool add_dapm_routes; }; static const struct loongson_card_config ls2k1000_card_config = { .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC, + .add_hp_jack = false, + .add_dapm_widgets = false, + .add_dapm_routes = false, }; static const struct loongson_card_config ls2k0300_forever_pi_card_config = { .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, + .add_hp_jack = false, + .add_dapm_widgets = false, + .add_dapm_routes = false, }; +static const struct loongson_card_config ls2k0300_dl2k0300b_card_config = { + .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, + .add_hp_jack = true, + .add_dapm_widgets = true, + .add_dapm_routes = true, +}; + +static int tegra_machine_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); + struct loongson_card_data *priv = snd_soc_card_get_drvdata(card); + + if (!snd_soc_dapm_widget_name_cmp(w, "Speaker")) + gpiod_set_value_cansleep(priv->gpiod_spkr_en, + SND_SOC_DAPM_EVENT_ON(event)); + + if (!snd_soc_dapm_widget_name_cmp(w, "Headphone")) + gpiod_set_value_cansleep(priv->gpiod_hp_ctl, + SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static const struct snd_soc_dapm_widget loongson_aosc_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", tegra_machine_event), + SND_SOC_DAPM_SPK("Speaker", tegra_machine_event), +}; + +/* Headphones Jack */ + +static struct snd_soc_jack loongson_asoc_hp_jack; + +static struct snd_soc_jack_pin loongson_asoc_hp_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE + }, + { + .pin = "Speaker", + .mask = SND_JACK_HEADPHONE, + .invert = 1 + }, +}; + +static struct snd_soc_jack_gpio loongson_asoc_hp_jack_gpio = { + .name = "Headphones detection", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +static int loongson_asoc_machine_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct loongson_card_data *ls_priv = snd_soc_card_get_drvdata(card); + int ret = 0; + + if (!ls_priv->cfg->add_hp_jack || !ls_priv->gpiod_hp_det) + return 0; + + ret = snd_soc_card_jack_new_pins(card, "Headphones Jack", + SND_JACK_HEADPHONE, + &loongson_asoc_hp_jack, + loongson_asoc_hp_jack_pins, + ARRAY_SIZE(loongson_asoc_hp_jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headphones Jack creation failed: %d\n", ret); + return ret; + } + + loongson_asoc_hp_jack_gpio.desc = ls_priv->gpiod_hp_det; + + ret = snd_soc_jack_add_gpios(&loongson_asoc_hp_jack, 1, &loongson_asoc_hp_jack_gpio); + if (ret) + dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret); + + return ret; +} + static int loongson_card_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -75,6 +168,7 @@ static struct snd_soc_dai_link loongson_dai_links[] = { { .name = "Loongson Audio Port", .stream_name = "Loongson Audio", + .init = loongson_asoc_machine_init, SND_SOC_DAILINK_REG(analog), .ops = &loongson_ops, }, @@ -135,16 +229,35 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data) static int loongson_card_parse_of(struct loongson_card_data *data) { - struct device_node *cpu, *codec; struct snd_soc_card *card = &data->snd_card; + struct device_node *cpu, *codec; struct device *dev = card->dev; int ret, i; + data->gpiod_hp_det = devm_gpiod_get_optional(dev, "hp-det", GPIOD_IN); + if (IS_ERR(data->gpiod_hp_det)) + return PTR_ERR(data->gpiod_hp_det); + + data->gpiod_hp_ctl = devm_gpiod_get_optional(dev, "hp-ctl", GPIOD_OUT_LOW); + if (IS_ERR(data->gpiod_hp_ctl)) + return PTR_ERR(data->gpiod_hp_ctl); + + data->gpiod_spkr_en = devm_gpiod_get_optional(dev, "spkr-en", GPIOD_OUT_LOW); + if (IS_ERR(data->gpiod_spkr_en)) + return PTR_ERR(data->gpiod_spkr_en); + + if (data->cfg->add_dapm_routes) { + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) + return ret; + } + cpu = of_get_child_by_name(dev->of_node, "cpu"); if (!cpu) { dev_err(dev, "platform property missing or invalid\n"); return -EINVAL; } + codec = of_get_child_by_name(dev->of_node, "codec"); if (!codec) { dev_err(dev, "audio-codec property missing or invalid\n"); @@ -199,6 +312,12 @@ static int loongson_asoc_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dai_link = loongson_dai_links; card->num_links = ARRAY_SIZE(loongson_dai_links); + + if (ls_priv->cfg->add_dapm_widgets) { + card->dapm_widgets = loongson_aosc_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(loongson_aosc_dapm_widgets); + } + snd_soc_card_set_drvdata(card, ls_priv); ret = device_property_read_string(dev, "model", &card->name); @@ -227,6 +346,10 @@ static const struct of_device_id loongson_asoc_dt_ids[] = { .compatible = "loongson,ls2k0300-forever-pi-audio-card", .data = &ls2k0300_forever_pi_card_config }, + { + .compatible = "loongson,ls2k0300-dl2k0300b-audio-card", + .data = &ls2k0300_dl2k0300b_card_config + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, loongson_asoc_dt_ids); From 5f988d622318e5f485c60a8be661a81ed9f74c53 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 26 Jun 2026 10:27:49 +0800 Subject: [PATCH 066/438] ASoC: es8328: Add DAPM routes from MIC inputs to Mic Bias The ES8328 codec has differential/single-ended microphone inputs (LINPUT1/RINPUT1, LINPUT2/RINPUT2) that require connection to the internal Mic Bias generator for proper operation. Currently, these routes are missing, which can cause microphone recording to fail. Add the missing DAPM routes to link the input pins to the Mic Bias supply, ensuring the microphone bias voltage is correctly applied. Signed-off-by: Binbin Zhou Link: https://patch.msgid.link/dcf1f8ae4f1f192a1d63e9fe7044b0218119b5eb.1782439646.git.zhoubinbin@loongson.cn Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 9838fe42cb6f..aaa6646ad4c5 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -405,6 +405,11 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = { { "Mic Bias", NULL, "Mic Bias Gen" }, + { "LINPUT1", NULL, "Mic Bias" }, + { "RINPUT1", NULL, "Mic Bias" }, + { "LINPUT2", NULL, "Mic Bias" }, + { "RINPUT2", NULL, "Mic Bias" }, + { "Left Mixer", NULL, "Left DAC" }, { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, { "Left Mixer", "Right Playback Switch", "Right DAC" }, From 380d6b549d5aa96a2c485d91e1a978abd7567f65 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 1 Jul 2026 02:36:19 +0000 Subject: [PATCH 067/438] ASoC: sof: nocodec: tidyup sof_nocodec_bes_setup() It has only 1 card (= sof_nocodec_card). No need to use parameter to get it. Current code makes old style / new style conversion difficult. To make future conversions easier to understand, this patch clean up the code a little. but no functional change. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87h5mjcu70.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/nocodec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 11a95dba3c9c..fae36595b81a 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -21,12 +21,13 @@ static struct snd_soc_card sof_nocodec_card = { static int sof_nocodec_bes_setup(struct device *dev, struct snd_soc_dai_driver *drv, struct snd_soc_dai_link *links, - int link_num, struct snd_soc_card *card) + int link_num) { + struct snd_soc_card *card = &sof_nocodec_card; struct snd_soc_dai_link_component *dlc; int i; - if (!drv || !links || !card) + if (!drv || !links) return -EINVAL; /* set up BE dai_links */ @@ -78,7 +79,7 @@ static int sof_nocodec_setup(struct device *dev, if (!links) return -ENOMEM; - return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, &sof_nocodec_card); + return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers); } static int sof_nocodec_probe(struct platform_device *pdev) From 39222ca2ff2b233d09b363e7d227de8c1bf0b91b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 1 Jul 2026 02:36:23 +0000 Subject: [PATCH 068/438] ASoC: sof: nocodec: tidyup sof_nocodec_setup() We can get necessary info from mach. Let's cleanup sof_nocodec_setup(). Current code makes old style / new style conversion difficult. To make future conversions easier to understand, this patch clean up the code a little. but no functional change. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87fr23cu6w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sof/nocodec.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index fae36595b81a..34744f8ae34a 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -68,10 +68,10 @@ static int sof_nocodec_bes_setup(struct device *dev, return 0; } -static int sof_nocodec_setup(struct device *dev, - u32 num_dai_drivers, - struct snd_soc_dai_driver *dai_drivers) +static int sof_nocodec_setup(struct device *dev, struct snd_soc_acpi_mach *mach) { + u32 num_dai_drivers = mach->mach_params.num_dai_drivers; + struct snd_soc_dai_driver *dai_drivers = mach->mach_params.dai_drivers; struct snd_soc_dai_link *links; /* create dummy BE dai_links */ @@ -93,8 +93,7 @@ static int sof_nocodec_probe(struct platform_device *pdev) snd_soc_card_set_topology_name(card, "sof"); - ret = sof_nocodec_setup(card->dev, mach->mach_params.num_dai_drivers, - mach->mach_params.dai_drivers); + ret = sof_nocodec_setup(card->dev, mach); if (ret < 0) return ret; From 406e181cb32546db0867f4c44bdbe5e23a56dbde Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 1 Jul 2026 15:43:36 +0700 Subject: [PATCH 069/438] ASoC: samsung: i2s: Use dev_err_probe() for iis clock error Switch the iis clock error path to dev_err_probe(). This folds the dev_err() and return into a single statement and, when devm_clk_get() returns -EPROBE_DEFER, avoids logging a spurious error on every probe retry while still recording the reason in the deferred-probe debugfs. No functional change other than the demoted log level on deferred probe; the returned error code is unchanged. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260701084336.308886-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f80e8d498156..56d11741dabd 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1441,10 +1441,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) regs_base = res->start; priv->clk = devm_clk_get(&pdev->dev, "iis"); - if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "Failed to get iis clock\n"); - return PTR_ERR(priv->clk); - } + if (IS_ERR(priv->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), + "Failed to get iis clock\n"); + ret = clk_prepare_enable(priv->clk); if (ret != 0) { From cd054a6e272caa97ab808ef6f5588749a1429108 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Thu, 2 Jul 2026 00:14:57 +0530 Subject: [PATCH 070/438] ASoC: codecs: lpass-wsa-macro: Switch to PM clock framework for runtime PM Convert the LPASS WSA macro codec driver to runtime PM clock management by using the PM clock framework. Replace manual macro/dcodec/mclk/npl/fsgen clock toggling with PM clock helpers and runtime PM callbacks. Keep the SWR gate runtime PM reference from SWR clock enable until disable so autosuspend does not gate clocks while SWR is still prepared. Set autosuspend delay to 100 ms so PM-clock-managed votes are dropped soon after idle while still avoiding suspend/resume churn on short gaps. Add a PM_CLK dependency to SND_SOC_LPASS_WSA_MACRO since this patch introduces PM clock APIs. Tighten error unwind by checking pm_runtime_put_sync_suspend() in probe and by restoring regcache state if pm_clk_resume()/regcache_sync() fails. Suggested-by: Mark Brown Signed-off-by: Ajay Kumar Nandam Reviewed-by: Srinivas Kandagatla Tested-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260702-xo-sd-codec-v7-b4-v8-1-d39d0fdb7859@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/lpass-wsa-macro.c | 137 ++++++++++++----------------- 2 files changed, 56 insertions(+), 82 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 252f683be3c1..92cfa623782c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2897,6 +2897,7 @@ config SND_SOC_LPASS_MACRO_COMMON config SND_SOC_LPASS_WSA_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 5ad0448af649..718564ee381e 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2529,15 +2530,13 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = { static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) { struct regmap *regmap = wsa->regmap; + int ret; if (enable) { - int ret; - - ret = clk_prepare_enable(wsa->mclk); - if (ret) { - dev_err(wsa->dev, "failed to enable mclk\n"); + ret = pm_runtime_resume_and_get(wsa->dev); + if (ret < 0) return ret; - } + wsa_macro_mclk_enable(wsa, true); regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, @@ -2548,7 +2547,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, CDC_WSA_SWR_CLK_EN_MASK, 0); wsa_macro_mclk_enable(wsa, false); - clk_disable_unprepare(wsa->mclk); + + ret = pm_runtime_put_autosuspend(wsa->dev); + if (ret < 0) + dev_warn(wsa->dev, "runtime PM put failed: %d\n", ret); } return 0; @@ -2774,25 +2776,23 @@ static int wsa_macro_probe(struct platform_device *pdev) clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); - ret = clk_prepare_enable(wsa->macro); + ret = devm_pm_clk_create(dev); if (ret) - goto err; + return ret; - ret = clk_prepare_enable(wsa->dcodec); - if (ret) - goto err_dcodec; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + return ret; - ret = clk_prepare_enable(wsa->mclk); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_mclk; + return ret; - ret = clk_prepare_enable(wsa->npl); - if (ret) - goto err_npl; - - ret = clk_prepare_enable(wsa->fsgen); - if (ret) - goto err_fsgen; + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; /* reset swr ip */ regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, @@ -2809,56 +2809,37 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa_macro_dai, ARRAY_SIZE(wsa_macro_dai)); if (ret) - goto err_clkout; - - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + goto err_rpm_put; ret = wsa_macro_register_mclk_output(wsa); if (ret) - goto err_clkout; + goto err_rpm_put; + + ret = pm_runtime_put_autosuspend(dev); + if (ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); return 0; - -err_clkout: - clk_disable_unprepare(wsa->fsgen); -err_fsgen: - clk_disable_unprepare(wsa->npl); -err_npl: - clk_disable_unprepare(wsa->mclk); -err_mclk: - clk_disable_unprepare(wsa->dcodec); -err_dcodec: - clk_disable_unprepare(wsa->macro); -err: +err_rpm_put: + if (pm_runtime_put_sync_suspend(dev) < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); return ret; - -} - -static void wsa_macro_remove(struct platform_device *pdev) -{ - struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(wsa->macro); - clk_disable_unprepare(wsa->dcodec); - clk_disable_unprepare(wsa->mclk); - clk_disable_unprepare(wsa->npl); - clk_disable_unprepare(wsa->fsgen); } static int wsa_macro_runtime_suspend(struct device *dev) { struct wsa_macro *wsa = dev_get_drvdata(dev); + int ret; regcache_cache_only(wsa->regmap, true); - regcache_mark_dirty(wsa->regmap); - clk_disable_unprepare(wsa->fsgen); - clk_disable_unprepare(wsa->npl); - clk_disable_unprepare(wsa->mclk); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(wsa->regmap, false); + return ret; + } + + regcache_mark_dirty(wsa->regmap); return 0; } @@ -2866,36 +2847,29 @@ static int wsa_macro_runtime_suspend(struct device *dev) static int wsa_macro_runtime_resume(struct device *dev) { struct wsa_macro *wsa = dev_get_drvdata(dev); - int ret; + int ret, sret; - ret = clk_prepare_enable(wsa->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(dev, "unable to prepare mclk\n"); + regcache_cache_only(wsa->regmap, true); + regcache_mark_dirty(wsa->regmap); + return ret; + } + regcache_cache_only(wsa->regmap, false); + + ret = regcache_sync(wsa->regmap); + if (ret) { + regcache_cache_only(wsa->regmap, true); + regcache_mark_dirty(wsa->regmap); + sret = pm_clk_suspend(dev); + if (sret) + dev_err(dev, + "failed to suspend clocks after regcache sync failure: %d\n", + sret); return ret; } - ret = clk_prepare_enable(wsa->npl); - if (ret) { - dev_err(dev, "unable to prepare mclkx2\n"); - goto err_npl; - } - - ret = clk_prepare_enable(wsa->fsgen); - if (ret) { - dev_err(dev, "unable to prepare fsgen\n"); - goto err_fsgen; - } - - regcache_cache_only(wsa->regmap, false); - regcache_sync(wsa->regmap); - return 0; -err_fsgen: - clk_disable_unprepare(wsa->npl); -err_npl: - clk_disable_unprepare(wsa->mclk); - - return ret; } static const struct dev_pm_ops wsa_macro_pm_ops = { @@ -2929,7 +2903,6 @@ static struct platform_driver wsa_macro_driver = { .pm = pm_ptr(&wsa_macro_pm_ops), }, .probe = wsa_macro_probe, - .remove = wsa_macro_remove, }; module_platform_driver(wsa_macro_driver); From eb667d0fbdd38d5a800b9e7aafc9a6c14530b9bf Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Thu, 2 Jul 2026 00:14:58 +0530 Subject: [PATCH 071/438] ASoC: codecs: lpass-va-macro: Switch to PM clock framework for runtime PM Convert the LPASS VA macro codec driver to runtime PM clock management by using the PM clock framework. Replace manual macro/dcodec/mclk/npl clock handling with PM clock helpers and runtime PM callbacks, and keep runtime PM references around fsgen clock gating so PM-clock-managed clocks remain active while fsgen is enabled. Set autosuspend delay to 100 ms so PM-clock-managed votes are dropped soon after idle while still avoiding suspend/resume churn on short gaps. Add a PM_CLK dependency to SND_SOC_LPASS_VA_MACRO since this patch introduces PM clock APIs. Improve failure unwind paths: handle runtime PM put errors in probe/fsgen paths and restore regcache state correctly on resume failure. Suggested-by: Mark Brown Signed-off-by: Ajay Kumar Nandam Reviewed-by: Srinivas Kandagatla Tested-by: Srinivas Kandagatla Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260702-xo-sd-codec-v7-b4-v8-2-d39d0fdb7859@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/lpass-va-macro.c | 131 ++++++++++++++++-------------- 2 files changed, 69 insertions(+), 63 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 92cfa623782c..030bb902fdef 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2904,6 +2904,7 @@ config SND_SOC_LPASS_WSA_MACRO config SND_SOC_LPASS_VA_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)" diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 528d5b167ecf..814a14f0d117 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1346,34 +1347,43 @@ static int fsgen_gate_enable(struct clk_hw *hw) { struct va_macro *va = to_va_macro(hw); struct regmap *regmap = va->regmap; - int ret; + int ret, rpm_ret; - if (va->has_swr_master) { - ret = clk_prepare_enable(va->mclk); - if (ret) - return ret; - } + ret = pm_runtime_resume_and_get(va->dev); + if (ret < 0) + return ret; ret = va_macro_mclk_enable(va, true); + if (ret) { + rpm_ret = pm_runtime_put_autosuspend(va->dev); + if (rpm_ret < 0) + dev_warn(va->dev, + "runtime PM put failed in fsgen enable unwind: %d\n", + rpm_ret); + return ret; + } if (va->has_swr_master) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE); - return ret; + return 0; } static void fsgen_gate_disable(struct clk_hw *hw) { struct va_macro *va = to_va_macro(hw); struct regmap *regmap = va->regmap; + int ret; if (va->has_swr_master) regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, CDC_VA_SWR_CLK_EN_MASK, 0x0); va_macro_mclk_enable(va, false); - if (va->has_swr_master) - clk_disable_unprepare(va->mclk); + + ret = pm_runtime_put_autosuspend(va->dev); + if (ret < 0) + dev_warn(va->dev, "runtime PM put failed in fsgen disable: %d\n", ret); } static int fsgen_gate_is_enabled(struct clk_hw *hw) @@ -1534,6 +1544,7 @@ static int va_macro_probe(struct platform_device *pdev) void __iomem *base; u32 sample_rate = 0; int ret; + int rpm_ret; va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL); if (!va) @@ -1601,22 +1612,24 @@ static int va_macro_probe(struct platform_device *pdev) clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); } - ret = clk_prepare_enable(va->macro); + ret = devm_pm_clk_create(dev); if (ret) goto err; - ret = clk_prepare_enable(va->dcodec); - if (ret) - goto err_dcodec; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + goto err; - ret = clk_prepare_enable(va->mclk); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_mclk; + goto err; - if (va->has_npl_clk) { - ret = clk_prepare_enable(va->npl); - if (ret) - goto err_npl; + rpm_ret = pm_runtime_resume_and_get(dev); + if (rpm_ret < 0) { + ret = rpm_ret; + goto err; } /** @@ -1629,7 +1642,7 @@ static int va_macro_probe(struct platform_device *pdev) /* read version from register */ ret = va_macro_set_lpass_codec_version(va); if (ret) - goto err_clkout; + goto err_rpm_put; } if (va->has_swr_master) { @@ -1659,35 +1672,28 @@ static int va_macro_probe(struct platform_device *pdev) va_macro_dais, ARRAY_SIZE(va_macro_dais)); if (ret) - goto err_clkout; - - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + goto err_rpm_put; ret = va_macro_register_fsgen_output(va); if (ret) - goto err_clkout; + goto err_rpm_put; va->fsgen = devm_clk_hw_get_clk(dev, &va->hw, "fsgen"); if (IS_ERR(va->fsgen)) { ret = PTR_ERR(va->fsgen); - goto err_clkout; + goto err_rpm_put; } + rpm_ret = pm_runtime_put_autosuspend(dev); + if (rpm_ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", rpm_ret); + return 0; -err_clkout: - if (va->has_npl_clk) - clk_disable_unprepare(va->npl); -err_npl: - clk_disable_unprepare(va->mclk); -err_mclk: - clk_disable_unprepare(va->dcodec); -err_dcodec: - clk_disable_unprepare(va->macro); +err_rpm_put: + rpm_ret = pm_runtime_put_sync_suspend(dev); + if (rpm_ret < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind: %d\n", rpm_ret); err: lpass_macro_pds_exit(va->pds); @@ -1698,53 +1704,52 @@ static void va_macro_remove(struct platform_device *pdev) { struct va_macro *va = dev_get_drvdata(&pdev->dev); - if (va->has_npl_clk) - clk_disable_unprepare(va->npl); - - clk_disable_unprepare(va->mclk); - clk_disable_unprepare(va->dcodec); - clk_disable_unprepare(va->macro); - lpass_macro_pds_exit(va->pds); } static int va_macro_runtime_suspend(struct device *dev) { struct va_macro *va = dev_get_drvdata(dev); + int ret; regcache_cache_only(va->regmap, true); + + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(va->regmap, false); + return ret; + } + regcache_mark_dirty(va->regmap); - if (va->has_npl_clk) - clk_disable_unprepare(va->npl); - - clk_disable_unprepare(va->mclk); - return 0; } static int va_macro_runtime_resume(struct device *dev) { struct va_macro *va = dev_get_drvdata(dev); - int ret; + int ret, sret; - ret = clk_prepare_enable(va->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(va->dev, "unable to prepare mclk\n"); + regcache_cache_only(va->regmap, true); + regcache_mark_dirty(va->regmap); return ret; } - if (va->has_npl_clk) { - ret = clk_prepare_enable(va->npl); - if (ret) { - clk_disable_unprepare(va->mclk); - dev_err(va->dev, "unable to prepare npl\n"); - return ret; - } - } - regcache_cache_only(va->regmap, false); - regcache_sync(va->regmap); + + ret = regcache_sync(va->regmap); + if (ret) { + regcache_cache_only(va->regmap, true); + regcache_mark_dirty(va->regmap); + sret = pm_clk_suspend(dev); + if (sret) + dev_err(va->dev, + "failed to suspend clocks after regcache sync failure: %d\n", + sret); + return ret; + } return 0; } From 541735571578b84987868c5662089f73bac36895 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Thu, 2 Jul 2026 00:14:59 +0530 Subject: [PATCH 072/438] ASoC: codecs: lpass-wsa-macro: Use devm_clk_hw_register() for MCLK output Switch WSA MCLK output registration to devm_clk_hw_register() so the clk hw is automatically unregistered on probe failure and remove. Reviewed-by: Konrad Dybcio Signed-off-by: Ajay Kumar Nandam Reviewed-by: Srinivas Kandagatla Tested-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260702-xo-sd-codec-v7-b4-v8-3-d39d0fdb7859@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 718564ee381e..f511816aa4a0 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2658,7 +2658,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa) init.num_parents = 1; wsa->hw.init = &init; hw = &wsa->hw; - ret = clk_hw_register(wsa->dev, hw); + ret = devm_clk_hw_register(wsa->dev, hw); if (ret) return ret; From e08d63e63ac09826b0e78c55cb7faa2eb16872a1 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Thu, 2 Jul 2026 15:29:18 +0800 Subject: [PATCH 073/438] ASoC: codecs: max98390: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during resume. max98390_resume() currently ignores that failure and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260702072918.85779-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98390.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 2bbedf84ee5d..66309e87fdbd 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -952,11 +952,17 @@ static int max98390_suspend(struct device *dev) static int max98390_resume(struct device *dev) { struct max98390_priv *max98390 = dev_get_drvdata(dev); + int ret; dev_dbg(dev, "%s:Enter\n", __func__); regcache_cache_only(max98390->regmap, false); - regcache_sync(max98390->regmap); + ret = regcache_sync(max98390->regmap); + if (ret) { + regcache_cache_only(max98390->regmap, true); + regcache_mark_dirty(max98390->regmap); + return ret; + } return 0; } From 8aa079a408d0732b1bab9930d327bccf77cf7d0a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Jun 2026 05:37:45 +0000 Subject: [PATCH 074/438] ASoC: mediatek: mt8365-mt6357: tidyup mach_priv It sets soc_card_data (1) in Card private data at (A), but the function (z) after that gets it as priv (2) at (B). These are different data (*). (z) static int mt8365_mt6357_gpio_probe(...) { (B) struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card); ... ^^^^(2) ^^^^^^^^^^^ } static int mt8365_mt6357_dev_probe(*soc_card_data, ...) { ^^^^^^^^^^^^^(1) ... struct mt8365_mt6357_priv *mach_priv; ... ^^^^^^^^^(2) (*) soc_card_data->mach_priv = mach_priv; ^^^^^^^^^^^^^(1) ^^^^^^^^^(2) (A) snd_soc_card_set_drvdata(card, soc_card_data); ^^^^^^^^^^^ ^^^^^^^^^^^^^(1) (z) mt8365_mt6357_gpio_probe(card); ... } Depending on the defined order in the struct (s), they may be the same pointer, but mach_priv (2) is not top of soc_card_data (1), thus the function (z) is getting wrong pointer. Fix it. (1) (s) struct mtk_soc_card_data { const struct mtk_sof_priv *sof_priv; ... void *mach_priv; }; (2) Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87qzlteuae.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8365/mt8365-mt6357.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c index 10f9ef73c130..38bd86b67ecc 100644 --- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -71,7 +71,8 @@ static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = { static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv; int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -102,7 +103,8 @@ static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream) static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv; int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -246,7 +248,8 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card) { - struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card); + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); + struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv; struct device *dev = card->dev; int ret, i; From ec2332472f587a32d4f90970efaf5acfdf58ce48 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:02 +0530 Subject: [PATCH 075/438] ASoC: amd: acp: add ACPI machine table for ACP7.B/7.F SOF driver Add snd_soc_acpi_amd_acp7x_sof_machines[] ACPI machine table for ACP7.B and ACP7.F PCI revision based platforms. Add the extern declaration to mach-config.h so that it can be referenced from the SOF PCI driver. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-2-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-config.c | 12 ++++++++++++ sound/soc/amd/mach-config.h | 1 + 2 files changed, 13 insertions(+) diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 0d977f4f758d..93a2182d4e86 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -360,5 +360,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[] = { + { + .id = "AMDI1010", + .drv_name = "acp7x-dsp", + .pdata = &acp_quirk_data, + .fw_filename = "sof-acp7x.ri", + .sof_tplg_filename = "sof-acp7x.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp7x_sof_machines); + MODULE_DESCRIPTION("AMD ACP Machine Configuration Module"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 5b6362103ca0..b602a983feb7 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -28,6 +28,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[]; struct config_entry { u32 flags; From 0ec5afad9d31c4f2b92933d20261e4095e26ad9b Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:03 +0530 Subject: [PATCH 076/438] ASoC: SOF: amd: add base platform support for ACP7.B/7.F Add SOF support for ACP7.B and ACP7.F PCI revision based platforms. This covers Kconfig/Makefile entries, register offset definitions, DMA descriptor/channel/status paths, PGFSM power-on handling, PCI device driver, I2S/DMIC DAI definitions, and IPC SW interrupt trigger offset selection for ACP7.B/7.F. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-3-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 10 ++ sound/soc/sof/amd/Makefile | 2 + sound/soc/sof/amd/acp-dsp-offset.h | 17 ++++ sound/soc/sof/amd/acp-ipc.c | 13 ++- sound/soc/sof/amd/acp.c | 23 ++++- sound/soc/sof/amd/acp.h | 9 ++ sound/soc/sof/amd/acp7x.c | 142 +++++++++++++++++++++++++++++ sound/soc/sof/amd/pci-acp7x.c | 116 +++++++++++++++++++++++ 8 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 sound/soc/sof/amd/acp7x.c create mode 100644 sound/soc/sof/amd/pci-acp7x.c diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 05faf1c6d6fc..7413bfdb0943 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -103,5 +103,15 @@ config SND_SOC_SOF_AMD_ACP70 Select this option for SOF support on AMD ACP7.0/ACP7.1 version based platforms. Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms. +config SND_SOC_SOF_AMD_ACP7X + tristate "SOF support for ACP7.B/7.F platforms" + depends on SND_SOC_SOF_PCI + depends on AMD_NODE + select SND_SOC_SOF_AMD_COMMON + help + Select this option for SOF support on AMD ACP7.B and ACP7.F PCI + revision based platforms. + Say Y if you want to enable SOF on ACP7.B/7.F based platforms. + If unsure select "N". endif diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile index 6ae39fd5a836..bb1c0ddef69d 100644 --- a/sound/soc/sof/amd/Makefile +++ b/sound/soc/sof/amd/Makefile @@ -11,6 +11,7 @@ snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o snd-sof-amd-acp63-y := pci-acp63.o acp63.o snd-sof-amd-acp70-y := pci-acp70.o acp70.o +snd-sof-amd-acp7x-y := pci-acp7x.o acp7x.o obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) += snd-sof-amd-renoir.o @@ -18,3 +19,4 @@ obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o +obj-$(CONFIG_SND_SOC_SOF_AMD_ACP7X) += snd-sof-amd-acp7x.o diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h index 08583a91afbc..bea1bd3afa70 100644 --- a/sound/soc/sof/amd/acp-dsp-offset.h +++ b/sound/soc/sof/amd/acp-dsp-offset.h @@ -68,12 +68,14 @@ #define ACP5X_PGFSM_BASE 0x1424 #define ACP6X_PGFSM_BASE 0x1024 #define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE +#define ACP7X_PGFSM_BASE ACP6X_PGFSM_BASE #define PGFSM_CONTROL_OFFSET 0x0 #define PGFSM_STATUS_OFFSET 0x4 #define ACP3X_CLKMUX_SEL 0x1424 #define ACP5X_CLKMUX_SEL 0x142C #define ACP6X_CLKMUX_SEL 0x102C #define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL +#define ACP7X_CLKMUX_SEL ACP6X_CLKMUX_SEL /* Registers from ACP_INTR block */ #define ACP3X_EXT_INTR_STAT 0x1808 @@ -86,21 +88,31 @@ #define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL #define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT #define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1 +#define ACP7X_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB +#define ACP7X_EXTERNAL_INTR_CNTL 0x1A04 +#define ACP7X_EXT_INTR_STAT 0x1A1C +#define ACP7X_EXTERNAL_INTR_CNTL1 0x1A08 +#define ACP7X_EXT_INTR_STAT1 0x1A20 #define ACP3X_DSP_SW_INTR_BASE 0x1814 #define ACP5X_DSP_SW_INTR_BASE 0x1814 #define ACP6X_DSP_SW_INTR_BASE 0x1808 #define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE +#define ACP7X_DSP_SW_INTR_BASE 0x1860 #define DSP_SW_INTR_CNTL_OFFSET 0x0 #define DSP_SW_INTR_STAT_OFFSET 0x4 +#define ACP7X_DSP_SW_INTR_STAT (ACP7X_DSP_SW_INTR_BASE + DSP_SW_INTR_STAT_OFFSET) #define DSP_SW_INTR_TRIG_OFFSET 0x8 +#define ACP7X_DSP_SW_INTR_TRIG_OFFSET 0x30 #define ACP3X_ERROR_STATUS 0x18C4 #define ACP6X_ERROR_STATUS 0x1A4C #define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS +#define ACP7X_ERROR_STATUS 0x1A88 #define ACP3X_AXI2DAGB_SEM_0 0x1880 #define ACP5X_AXI2DAGB_SEM_0 0x1884 #define ACP6X_AXI2DAGB_SEM_0 0x1874 #define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0 +#define ACP7X_AXI2DAGB_SEM_0 0x18F4 /* ACP common registers to report errors related to I2S & SoundWire interfaces */ #define ACP3X_SW_I2S_ERROR_REASON 0x18C8 @@ -123,6 +135,7 @@ #define ACP_SCRATCH_REG_0 0x10000 #define ACP6X_DSP_FUSION_RUNSTALL 0x0644 #define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL +#define ACP7X_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL /* Cache window registers */ #define ACP_DSP0_CACHE_OFFSET0 0x0420 @@ -139,5 +152,9 @@ #define ACP70_SDW1_HOST_WAKE_STAT BIT(25) #define ACP70_SDW0_PME_STAT BIT(26) #define ACP70_SDW1_PME_STAT BIT(27) +#define ACP7X_DSP0_IDMA_ERROR_MASK 0x4B0 +#define ACP7X_IDMA_ERROR_MASK 0x1FF9FF +#define ACP7X_ZSC_DSP_CTRL 0x001014 +#define ACP7X_PME_EN ACP70_PME_EN #endif diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index 94025bc799ea..494f9cb0c06f 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -32,11 +32,20 @@ static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) struct snd_sof_dev *sdev = adata->dev; const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); u32 swintr_trigger; + unsigned int swintr_trigger_reg_offset; + switch (adata->pci_rev) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + swintr_trigger_reg_offset = ACP7X_DSP_SW_INTR_TRIG_OFFSET; + break; + default: + swintr_trigger_reg_offset = DSP_SW_INTR_TRIG_OFFSET; + } swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base + - DSP_SW_INTR_TRIG_OFFSET); + swintr_trigger_reg_offset); swintr_trigger |= 0x01; - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET, + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + swintr_trigger_reg_offset, swintr_trigger); } diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index e6af8927baa0..bb3766aacf0e 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -60,6 +60,8 @@ static void init_dma_descriptor(struct acp_dev_data *adata) case ACP70_PCI_ID: case ACP71_PCI_ID: case ACP72_PCI_ID: + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR; acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR; break; @@ -101,6 +103,8 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch, case ACP70_PCI_ID: case ACP71_PCI_ID: case ACP72_PCI_ID: + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: acp_dma_cntl_0 = ACP70_DMA_CNTL_0; acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS; acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0; @@ -342,6 +346,8 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch) case ACP70_PCI_ID: case ACP71_PCI_ID: case ACP72_PCI_ID: + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: acp_dma_ch_sts = ACP70_DMA_CH_STS; break; default: @@ -595,6 +601,11 @@ static int acp_power_on(struct snd_sof_dev *sdev) acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK; acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK; break; + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + acp_pgfsm_status_mask = ACP7X_PGFSM_STATUS_MASK; + acp_pgfsm_cntl_mask = ACP7X_PGFSM_CNTL_POWER_ON_MASK; + break; default: return -EINVAL; } @@ -604,7 +615,8 @@ static int acp_power_on(struct snd_sof_dev *sdev) acp_pgfsm_cntl_mask); ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val, - !val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); + !val, ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n"); @@ -703,6 +715,13 @@ static int acp_init(struct snd_sof_dev *sdev) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1); break; + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK, + ACP7X_IDMA_ERROR_MASK); + break; } return 0; } @@ -749,6 +768,8 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) case ACP72_PCI_ID: enable = true; break; + default: + break; } snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 7bcb76676a98..063aa41dd237 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -76,6 +76,12 @@ #define ACP70_PCI_ID 0x70 #define ACP71_PCI_ID 0x71 #define ACP72_PCI_ID 0x72 +#define ACP7B_PCI_ID 0x7B +#define ACP7F_PCI_ID 0x7F + +#define ACP7X_PGFSM_CNTL_POWER_ON_MASK 0x7F +#define ACP7X_PGFSM_STATUS_MASK 0xFFF +#define ACP7X_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET #define HOST_BRIDGE_CZN 0x1630 #define HOST_BRIDGE_VGH 0x1645 @@ -344,6 +350,9 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_acp70_ops; int sof_acp70_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_acp7x_ops; +int sof_acp7x_ops_init(struct snd_sof_dev *sdev); + struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c new file mode 100644 index 000000000000..87c70014d777 --- /dev/null +++ b/sound/soc/sof/amd/acp7x.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2025 Advanced Micro Devices, Inc. +// +// Authors: Vijendar Mukunda + +/* + * Hardware interface for Audio DSP on ACP7.B/7.F platforms + */ + +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-audio.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define I2S_TDM0_INSTANCE 0 +#define I2S_TDM1_INSTANCE 1 +#define I2S_TDM2_INSTANCE 2 +#define PDM0_DMIC_INSTANCE 3 +#define PDM1_DMIC_INSTANCE 4 + +static struct snd_soc_dai_driver acp7x_sof_dai[] = { + [I2S_TDM0_INSTANCE] = { + .id = I2S_TDM0_INSTANCE, + .name = "acp-sof-i2s0", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S HS controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_TDM1_INSTANCE] = { + .id = I2S_TDM1_INSTANCE, + .name = "acp-sof-i2s1", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S BT controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [I2S_TDM2_INSTANCE] = { + .id = I2S_TDM2_INSTANCE, + .name = "acp-sof-i2s2", + .playback = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 96000, + }, + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, + /* Supporting only stereo for I2S SP controller capture */ + .channels_min = 2, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [PDM0_DMIC_INSTANCE] = { + .id = PDM0_DMIC_INSTANCE, + .name = "acp-sof-dmic0", + .capture = { + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + }, + }, + + [PDM1_DMIC_INSTANCE] = { + .id = PDM1_DMIC_INSTANCE, + .name = "acp-sof-dmic1", + .capture = { + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 96000, + }, + }, +}; + +struct snd_sof_dsp_ops sof_acp7x_ops; +EXPORT_SYMBOL_NS(sof_acp7x_ops, "SND_SOC_SOF_AMD_COMMON"); + +int sof_acp7x_ops_init(struct snd_sof_dev *sdev) +{ + /* common defaults */ + memcpy(&sof_acp7x_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); + + sof_acp7x_ops.drv = acp7x_sof_dai; + sof_acp7x_ops.num_drv = ARRAY_SIZE(acp7x_sof_dai); + + return 0; +} diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c new file mode 100644 index 000000000000..532e15313795 --- /dev/null +++ b/sound/soc/sof/amd/pci-acp7x.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2025 Advanced Micro Devices, Inc. All rights reserved. +// +// Authors: Vijendar Mukunda + +/* + * PCI interface for ACP7.B/7.F devices + */ + +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-pci-dev.h" +#include "../../amd/mach-config.h" +#include "acp.h" +#include "acp-dsp-offset.h" + +#define ACP7X_FUTURE_REG_ACLK_0 0x18e0 +#define ACP7X_REG_START 0x1240000 +#define ACP7X_REG_END 0x125C000 + +static const struct sof_amd_acp_desc acp7x_chip_info = { + .name = "acp7x", + .pgfsm_base = ACP7X_PGFSM_BASE, + .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB, + .ext_intr_cntl = ACP7X_EXTERNAL_INTR_CNTL, + .ext_intr_stat = ACP7X_EXT_INTR_STAT, + .ext_intr_stat1 = ACP7X_EXT_INTR_STAT1, + .dsp_intr_base = ACP7X_DSP_SW_INTR_BASE, + .acp_error_stat = ACP7X_ERROR_STATUS, + .sram_pte_offset = ACP7X_SRAM_PTE_OFFSET, + .hw_semaphore_offset = ACP7X_AXI2DAGB_SEM_0, + .fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL, + .probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0, + .reg_start_addr = ACP7X_REG_START, + .reg_end_addr = ACP7X_REG_END, +}; + +static const struct sof_dev_desc acp7x_desc = { + .machines = snd_soc_acpi_amd_acp7x_sof_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &acp7x_chip_info, + .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), + .ipc_default = SOF_IPC_TYPE_3, + .default_fw_path = { + [SOF_IPC_TYPE_3] = "amd/sof", + }, + .default_tplg_path = { + [SOF_IPC_TYPE_3] = "amd/sof-tplg", + }, + .default_fw_filename = { + [SOF_IPC_TYPE_3] = "sof-acp7x.ri", + }, + .nocodec_tplg_filename = "sof-acp.tplg", + .ops = &sof_acp7x_ops, + .ops_init = sof_acp7x_ops_init, +}; + +static int acp7x_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + unsigned int flag; + + switch (pci->revision) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + break; + default: + return -ENODEV; + } + + flag = snd_amd_acp_find_config(pci); + if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) + return -ENODEV; + + return sof_pci_probe(pci, pci_id); +} + +static void acp7x_pci_remove(struct pci_dev *pci) +{ + sof_pci_remove(pci); +} + +/* PCI IDs */ +static const struct pci_device_id acp7x_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), + .driver_data = (unsigned long)&acp7x_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, acp7x_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_amd_acp7x_driver = { + .name = KBUILD_MODNAME, + .id_table = acp7x_pci_ids, + .probe = acp7x_pci_probe, + .remove = acp7x_pci_remove, + .driver = { + .pm = pm_ptr(&sof_pci_pm), + }, +}; +module_pci_driver(snd_sof_pci_amd_acp7x_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("ACP7X SOF Driver"); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); From 237efba38c4f93d049299eca45b6ab9a643331d7 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:04 +0530 Subject: [PATCH 077/438] ASoC: SOF: amd: mask ACP7x PGFSM status poll For ACP7.B/7.F, poll only the PGFSM tile status bits (P0-P4) and consider the tiles powered on when the masked status becomes 0. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-4-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index bb3766aacf0e..f7b22f9979f6 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -577,6 +577,7 @@ static int acp_power_on(struct snd_sof_dev *sdev) unsigned int base = desc->pgfsm_base; unsigned int val; unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask; + bool use_masked_status = false; int ret; val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET); @@ -605,6 +606,7 @@ static int acp_power_on(struct snd_sof_dev *sdev) case ACP7F_PCI_ID: acp_pgfsm_status_mask = ACP7X_PGFSM_STATUS_MASK; acp_pgfsm_cntl_mask = ACP7X_PGFSM_CNTL_POWER_ON_MASK; + use_masked_status = true; break; default: return -EINVAL; @@ -614,9 +616,17 @@ static int acp_power_on(struct snd_sof_dev *sdev) snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET, acp_pgfsm_cntl_mask); - ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val, - !val, ACP_REG_POLL_INTERVAL, - ACP_REG_POLL_TIMEOUT_US); + if (use_masked_status) + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, + base + PGFSM_STATUS_OFFSET, val, + !(val & acp_pgfsm_status_mask), + ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); + else + ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, + base + PGFSM_STATUS_OFFSET, val, + !val, ACP_REG_POLL_INTERVAL, + ACP_REG_POLL_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n"); From 571464f543f681f7b6f0014adc9fb18a120785e9 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:05 +0530 Subject: [PATCH 078/438] ASoC: SOF: amd: refactor SW1 I2S error reason clear in acp_irq_handler Replace the open-coded pci_rev comparison with a switch statement for clearing ACP_SW1_I2S_ERROR_REASON. This makes the per-platform control explicit and easier to extend. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-5-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index f7b22f9979f6..1f0fc052ea1a 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -540,8 +540,17 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0); /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */ - if (adata->pci_rev >= ACP_RMB_PCI_ID) + switch (adata->pci_rev) { + case ACP_RMB_PCI_ID: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: + case ACP72_PCI_ID: snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0); + break; + default: + break; + } snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); irq_flag = 1; } From 78d99c2c5eee0f6cd1adfe33dd0c266baac50fb8 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:06 +0530 Subject: [PATCH 079/438] ASoC: SOF: amd: add ACP7x probe and remove Add amd_sof_acp7x_probe() and amd_sof_acp7x_remove() for ACP7.B/7.F. Wire probe and remove into sof_acp7x_ops_init(). Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-6-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 102 ++++++++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 4 ++ sound/soc/sof/amd/acp7x.c | 2 + 3 files changed, 108 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 1f0fc052ea1a..b2c319857ad8 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -12,6 +12,7 @@ * Hardware interface for generic AMD ACP processor */ +#include #include #include #include @@ -1030,6 +1031,107 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON"); +int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct acp_dev_data *adata; + const struct sof_amd_acp_desc *chip; + const union acpi_object *obj; + struct acpi_device *adev; + unsigned int addr; + int ret; + + chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device); + return -EIO; + } + adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL); + if (!adata) + return -ENOMEM; + + adata->dev = sdev; + adata->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec", + PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(adata->dmic_dev)) { + dev_err(sdev->dev, "failed to register platform for dmic codec\n"); + return PTR_ERR(adata->dmic_dev); + } + + addr = pci_resource_start(pci, ACP_DSP_BAR); + sdev->bar[ACP_DSP_BAR] = devm_ioremap(sdev->dev, addr, pci_resource_len(pci, ACP_DSP_BAR)); + if (!sdev->bar[ACP_DSP_BAR]) { + dev_err(sdev->dev, "ioremap error\n"); + ret = -ENXIO; + goto unregister_dev; + } + + pci_set_master(pci); + adata->addr = addr; + adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; + adata->pci_rev = pci->revision; + mutex_init(&adata->acp_lock); + sdev->pdata->hw_pdata = adata; + + ret = acp_init(sdev); + if (ret < 0) + goto unregister_dev; + + adev = ACPI_COMPANION(&pci->dev); + + if (adev) { + if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image", + ACPI_TYPE_INTEGER, &obj)) + adata->acp_sof_signed_firmware_image = obj->integer.value; + } + + sdev->dsp_box.offset = 0; + sdev->dsp_box.size = BOX_SIZE_512; + + sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; + sdev->host_box.size = BOX_SIZE_512; + + sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; + sdev->debug_box.size = BOX_SIZE_1024; + + if (adata->acp_sof_signed_firmware_image) { + adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-code.bin", chip->name); + if (!adata->fw_code_bin) { + ret = -ENOMEM; + goto unregister_dev; + } + adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, + "sof-%s-data.bin", chip->name); + if (!adata->fw_data_bin) { + ret = -ENOMEM; + goto unregister_dev; + } + } + + adata->enable_fw_debug = enable_fw_debug; + acp_memory_init(sdev); + acp_dsp_stream_init(sdev); + + return 0; + +unregister_dev: + platform_device_unregister(adata->dmic_dev); + return ret; +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_probe, "SND_SOC_SOF_AMD_COMMON"); + +void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *adata = sdev->pdata->hw_pdata; + + if (adata->dmic_dev) + platform_device_unregister(adata->dmic_dev); + + acp_reset(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("AMD ACP sof driver"); MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 063aa41dd237..46b946132de8 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -277,6 +277,7 @@ struct acp_dev_data { /* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */ bool acp70_sdw1_wake_event; unsigned int pci_rev; + int acp_sof_signed_firmware_image; }; void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); @@ -353,6 +354,9 @@ int sof_acp70_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_acp7x_ops; int sof_acp7x_ops_init(struct snd_sof_dev *sdev); +int amd_sof_acp7x_probe(struct snd_sof_dev *sdev); +void amd_sof_acp7x_remove(struct snd_sof_dev *sdev); + struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c index 87c70014d777..3366e1b638af 100644 --- a/sound/soc/sof/amd/acp7x.c +++ b/sound/soc/sof/amd/acp7x.c @@ -137,6 +137,8 @@ int sof_acp7x_ops_init(struct snd_sof_dev *sdev) sof_acp7x_ops.drv = acp7x_sof_dai; sof_acp7x_ops.num_drv = ARRAY_SIZE(acp7x_sof_dai); + sof_acp7x_ops.probe = amd_sof_acp7x_probe; + sof_acp7x_ops.remove = amd_sof_acp7x_remove; return 0; } From a3674345f90226758b1dfd55c594cc3d4cdf80f6 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:07 +0530 Subject: [PATCH 080/438] ASoC: SOF: amd: add ACP7x IRQ handler for DSP IPC Add acp7x_irq_handler() and register it from amd_sof_acp7x_probe() for DSP doorbell IPC interrupts on ACP7.B/7.F. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-7-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 49 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index b2c319857ad8..5df984b93dec 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -580,6 +580,35 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) return IRQ_NONE; } +static irqreturn_t acp7x_irq_handler(int irq, void *dev_id) +{ + struct snd_sof_dev *sdev = dev_id; + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); + unsigned int base = desc->dsp_intr_base; + unsigned int val; + unsigned int ext_intr_stat; + int irq_flag = 0; + + val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); + if (val & ACP_DSP_TO_HOST_IRQ) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, + ACP_DSP_TO_HOST_IRQ); + return IRQ_WAKE_THREAD; + } + + ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); + if (ext_intr_stat & ACP_ERROR_IRQ_MASK) { + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); + irq_flag = 1; + } + + if (irq_flag) + return IRQ_HANDLED; + + return IRQ_NONE; +} + static int acp_power_on(struct snd_sof_dev *sdev) { const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); @@ -1039,6 +1068,7 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) const union acpi_object *obj; struct acpi_device *adev; unsigned int addr; + unsigned int irqflags; int ret; chip = get_chip_info(sdev->pdata); @@ -1079,6 +1109,16 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) adev = ACPI_COMPANION(&pci->dev); + sdev->ipc_irq = pci->irq; + irqflags = IRQF_SHARED; + + ret = request_threaded_irq(pci->irq, acp7x_irq_handler, acp_irq_thread, + irqflags, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); + goto unregister_dev; + } + if (adev) { if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image", ACPI_TYPE_INTEGER, &obj)) @@ -1099,13 +1139,13 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) "sof-%s-code.bin", chip->name); if (!adata->fw_code_bin) { ret = -ENOMEM; - goto unregister_dev; + goto free_ipc_irq; } adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, "sof-%s-data.bin", chip->name); if (!adata->fw_data_bin) { ret = -ENOMEM; - goto unregister_dev; + goto free_ipc_irq; } } @@ -1115,6 +1155,8 @@ int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) return 0; +free_ipc_irq: + free_irq(sdev->ipc_irq, sdev); unregister_dev: platform_device_unregister(adata->dmic_dev); return ret; @@ -1125,6 +1167,9 @@ void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) { struct acp_dev_data *adata = sdev->pdata->hw_pdata; + if (sdev->ipc_irq) + free_irq(sdev->ipc_irq, sdev); + if (adata->dmic_dev) platform_device_unregister(adata->dmic_dev); From cbdafd2acdee72f698edd4ab9429bf1f7613ff94 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:08 +0530 Subject: [PATCH 081/438] ASoC: SOF: amd: extend signed firmware pre-run for ACP7x Parse SizeFWSigned from the ACP image header when loading signed firmware on ACP7.B/7.F platforms. Keep the legacy ACP_FIRMWARE_SIGNATURE subtraction for pre-7B platforms using quirks. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-8-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 14 ++++++++++++-- sound/soc/sof/amd/acp.h | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 98324bbade15..af04f053fd65 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "../ops.h" #include "acp-dsp-offset.h" @@ -173,10 +174,19 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) adata = sdev->pdata->hw_pdata; - if (adata->quirks && adata->quirks->signed_fw_image) + if (adata->pci_rev >= ACP7B_PCI_ID) { + if (adata->acp_sof_signed_firmware_image) { + size_fw = get_unaligned_le32(adata->bin_buf + + ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF); + size_fw += ACP_IMAGE_HEADER_SIZE; + } else { + size_fw = adata->fw_bin_size; + } + } else if (adata->quirks && adata->quirks->signed_fw_image) { size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; - else + } else { size_fw = adata->fw_bin_size; + } page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; adata->fw_bin_page_count = page_count; diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 46b946132de8..c2f3add05d0c 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -113,6 +113,9 @@ #define PROBE_STATUS_BIT BIT(31) #define ACP_FIRMWARE_SIGNATURE 0x100 +#define ACP_IMAGE_HEADER_SIZE ACP_FIRMWARE_SIGNATURE +#define ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF 0x14 + #define ACP_ERROR_IRQ_MASK BIT(29) #define ACP_SDW0_IRQ_MASK BIT(21) #define ACP_SDW1_IRQ_MASK BIT(2) From d6869ae07d21acc6bab7aa0bc068c1c74b03926d Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:09 +0530 Subject: [PATCH 082/438] ASoC: SOF: amd: require full ACP header for ACP7 signed firmware ACP7.B/7.F signed images read SizeFWSigned from a fixed offset inside the ACP header. Reject firmware buffers shorter than the header so we never read past the end of the supplied image. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-9-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index af04f053fd65..e4a17e6656c0 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -176,6 +176,11 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) if (adata->pci_rev >= ACP7B_PCI_ID) { if (adata->acp_sof_signed_firmware_image) { + if (adata->fw_bin_size <= ACP_IMAGE_HEADER_SIZE) { + dev_err(sdev->dev, "Invalid signed firmware size %u\n", + adata->fw_bin_size); + return -EINVAL; + } size_fw = get_unaligned_le32(adata->bin_buf + ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF); size_fw += ACP_IMAGE_HEADER_SIZE; From c04de2d88c0b2807b71480916a10adea83c85f02 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:10 +0530 Subject: [PATCH 083/438] ASoC: SOF: amd: validate SizeFWSigned before signed FW length on ACP7x The ACP7.B/7.F ACPI signed path already reads SizeFWSigned from the image header into size_fw. Before adding ACP_IMAGE_HEADER_SIZE for SHA DMA, reject payload size zero or any size_fw with size_fw > fw_bin_size - ACP_IMAGE_HEADER_SIZE, so size_fw + ACP_IMAGE_HEADER_SIZE cannot exceed the supplied firmware buffer. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-10-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index e4a17e6656c0..76335c78255f 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -183,6 +183,13 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) } size_fw = get_unaligned_le32(adata->bin_buf + ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF); + if (!size_fw || + size_fw > adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE) { + dev_err(sdev->dev, + "Invalid signed firmware payload size %u (max %u)\n", + size_fw, adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE); + return -EINVAL; + } size_fw += ACP_IMAGE_HEADER_SIZE; } else { size_fw = adata->fw_bin_size; From 7a81f54a0483edc6cbdb2fb066ccf2dc3e258ac7 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:11 +0530 Subject: [PATCH 084/438] ASoC: SOF: amd: add post-firmware-run delay for ACP7x Add sof_acp7x_post_fw_run_delay() to introduce a small delay after firmware boot completion on resume to avoid DSP entering an unrecoverable state. Register it as post_fw_run callback only when the ACPI property acp-sof-post_fw_run_delay is set, following the same pattern used by the Vangogh platform. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-11-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp7x.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c index 3366e1b638af..c1b9c623bc39 100644 --- a/sound/soc/sof/amd/acp7x.c +++ b/sound/soc/sof/amd/acp7x.c @@ -11,6 +11,7 @@ * Hardware interface for Audio DSP on ACP7.B/7.F platforms */ +#include #include #include #include @@ -127,11 +128,29 @@ static struct snd_soc_dai_driver acp7x_sof_dai[] = { }, }; +static int sof_acp7x_post_fw_run_delay(struct snd_sof_dev *sdev) +{ + /* + * Resuming from suspend in some cases may cause the DSP firmware + * to enter an unrecoverable faulty state. Delaying a bit any host + * to DSP transmission right after firmware boot completion seems + * to resolve the issue. + */ + if (!sdev->first_boot) + usleep_range(100, 150); + + return 0; +} + struct snd_sof_dsp_ops sof_acp7x_ops; EXPORT_SYMBOL_NS(sof_acp7x_ops, "SND_SOC_SOF_AMD_COMMON"); int sof_acp7x_ops_init(struct snd_sof_dev *sdev) { + struct acpi_device *adev = ACPI_COMPANION(&to_pci_dev(sdev->dev)->dev); + const union acpi_object *obj; + int acp_sof_post_fw_run_delay = 0; + /* common defaults */ memcpy(&sof_acp7x_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); @@ -140,5 +159,14 @@ int sof_acp7x_ops_init(struct snd_sof_dev *sdev) sof_acp7x_ops.probe = amd_sof_acp7x_probe; sof_acp7x_ops.remove = amd_sof_acp7x_remove; + if (adev) { + if (!acpi_dev_get_property(adev, "acp-sof-post_fw_run_delay", + ACPI_TYPE_INTEGER, &obj)) + acp_sof_post_fw_run_delay = obj->integer.value; + } + + if (acp_sof_post_fw_run_delay) + sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay; + return 0; } From d0c32fdc1907b95e57b26467052f5f4bea9f4273 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:12 +0530 Subject: [PATCH 085/438] ASoC: SOF: amd: extend configure_and_run_sha_dma for ACPI signed FW flag Check adata->acp_sof_signed_firmware_image alongside the existing quirk flag so that ACP7.B/7.F platforms configured through ACPI also get the SHA DMA header included during signed firmware loading. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-12-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 5df984b93dec..c2143821fb83 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -288,7 +288,8 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, } } - if (adata->quirks && adata->quirks->signed_fw_image) + if ((adata->quirks && adata->quirks->signed_fw_image) || + adata->acp_sof_signed_firmware_image) snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); From 7af6ac41cd470b04ebd1d2ee972159f2dd5be7cd Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:13 +0530 Subject: [PATCH 086/438] ASoC: SOF: amd: wire signed firmware load callback for ACP7x via ACPI Read ACPI property acp-sof-signed-firmware-image in sof_acp7x_ops_init() and register acp_sof_load_signed_firmware as the load_firmware callback only when the property is set. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-13-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp7x.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c index c1b9c623bc39..94b7ea08b309 100644 --- a/sound/soc/sof/amd/acp7x.c +++ b/sound/soc/sof/amd/acp7x.c @@ -149,6 +149,7 @@ int sof_acp7x_ops_init(struct snd_sof_dev *sdev) { struct acpi_device *adev = ACPI_COMPANION(&to_pci_dev(sdev->dev)->dev); const union acpi_object *obj; + int acp_sof_signed_firmware_image = 0; int acp_sof_post_fw_run_delay = 0; /* common defaults */ @@ -160,11 +161,18 @@ int sof_acp7x_ops_init(struct snd_sof_dev *sdev) sof_acp7x_ops.remove = amd_sof_acp7x_remove; if (adev) { + if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image", + ACPI_TYPE_INTEGER, &obj)) + acp_sof_signed_firmware_image = obj->integer.value; + if (!acpi_dev_get_property(adev, "acp-sof-post_fw_run_delay", ACPI_TYPE_INTEGER, &obj)) acp_sof_post_fw_run_delay = obj->integer.value; } + if (acp_sof_signed_firmware_image) + sof_acp7x_ops.load_firmware = acp_sof_load_signed_firmware; + if (acp_sof_post_fw_run_delay) sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay; From deb631c3f387d0530a7c10de5e71b8c6cbe8c732 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:14 +0530 Subject: [PATCH 087/438] ASoC: SOF: amd: load ACP7.B/7.F signed data firmware to SRAM ACP7.B and ACP7.F signed firmware data blocks must be written to SRAM instead of DRAM. Select SOF_FW_BLK_TYPE_SRAM for PCI revision 0x7B and above in acp_sof_load_signed_firmware(). Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-14-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp-loader.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 76335c78255f..f1ec85694323 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -334,9 +334,14 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) } kfree(fw_filename); - ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, - (void *)adata->fw_dbin->data, - adata->fw_dbin->size); + if (adata->pci_rev >= ACP7B_PCI_ID) + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_SRAM, 0, + (void *)adata->fw_dbin->data, + adata->fw_dbin->size); + else + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, + (void *)adata->fw_dbin->data, + adata->fw_dbin->size); return ret; } EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON"); From 08c5e98b7b5ff5aa0c2774bf58a5a71e2741f603 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:15 +0530 Subject: [PATCH 088/438] ASoC: SOF: amd: add ACP I2S format field and topology token Add format field to sof_ipc_dai_acp_params for ACP I2S format selection. Add SOF_TKN_AMD_ACPI2S_FORMAT (1703) to the existing SOF_ACPI2S_TOKENS tuple and wire it into acpi2s_tokens[] so integrators continue using the same ACPI2S token group as earlier ACP I2S topologies, not a separate ACPTDM-specific token set. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-15-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- include/sound/sof/dai-amd.h | 1 + include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/ipc3-topology.c | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h index 59cd014392c1..e2107da6558f 100644 --- a/include/sound/sof/dai-amd.h +++ b/include/sound/sof/dai-amd.h @@ -18,6 +18,7 @@ struct sof_ipc_dai_acp_params { uint32_t fsync_rate; /* FSYNC frequency in Hz */ uint32_t tdm_slots; uint32_t tdm_mode; + uint32_t format; } __packed; /* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index f4a7baadb44d..cc694a397987 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -223,6 +223,7 @@ #define SOF_TKN_AMD_ACPI2S_RATE 1700 #define SOF_TKN_AMD_ACPI2S_CH 1701 #define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702 +#define SOF_TKN_AMD_ACPI2S_FORMAT 1703 /* MICFIL PDM */ #define SOF_TKN_IMX_MICFIL_RATE 2000 diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 4e066bbded91..9eb8335a3c07 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -281,7 +281,10 @@ static const struct sof_topology_token acpdmic_tokens[] = { offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)}, }; -/* ACPI2S */ +/* + * ACPI2S tokens fill struct sof_ipc_dai_acp_params; SOF_DAI_AMD_I2S (ACPTDM + * on ACP7.B/7.F) reuses this tuple group rather than defining a parallel set. + */ static const struct sof_topology_token acpi2s_tokens[] = { {SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_dai_acp_params, fsync_rate)}, @@ -289,6 +292,8 @@ static const struct sof_topology_token acpi2s_tokens[] = { offsetof(struct sof_ipc_dai_acp_params, tdm_slots)}, {SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_dai_acp_params, tdm_mode)}, + {SOF_TKN_AMD_ACPI2S_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acp_params, format)}, }; /* MICFIL PDM */ From 3805b8e6f932fbf9bfe5803b6a85328cc468b75d Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:16 +0530 Subject: [PATCH 089/438] ASoC: SOF: amd: add ACP7x I2S DAI type and topology support Add SOF_DAI_AMD_I2S DAI type for ACP7.B/7.F I2S/TDM interfaces. Register the ACPTDM topology DAI name and map it to SOF_DAI_AMD_I2S; IPC3 continues to parse ACP I2S link parameters through SOF_ACPI2S_TOKENS (including the format token from the prior commit), not a new token group named after ACPTDM. Add sof_link_acp_i2s_load() and the SOF_DAI_AMD_I2S PCM dai link fixup path. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-16-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- include/sound/sof/dai.h | 2 ++ sound/soc/sof/ipc3-pcm.c | 6 ++++++ sound/soc/sof/ipc3-topology.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 3 ++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 0b6a6ba6489a..e3fe492e78f5 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -91,6 +91,7 @@ enum sof_ipc_dai_type { SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */ SOF_DAI_AMD_SDW, /**< AMD ACP SDW */ SOF_DAI_INTEL_UAOL, /**< Intel UAOL */ + SOF_DAI_AMD_I2S, /**< AMD ACP I2S */ }; /* general purpose DAI configuration */ @@ -122,6 +123,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_mtk_afe_params afe; struct sof_ipc_dai_micfil_params micfil; struct sof_ipc_dai_acp_sdw_params acp_sdw; + struct sof_ipc_dai_acp_params acp_i2s; }; } __packed; diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 90ef5d99f626..143bf0fe8dd9 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -421,6 +421,12 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_AMD_I2S: + rate->min = private->dai_config->acp_i2s.fsync_rate; + rate->max = private->dai_config->acp_i2s.fsync_rate; + channels->min = private->dai_config->acp_i2s.tdm_slots; + channels->max = private->dai_config->acp_i2s.tdm_slots; + break; default: dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type); break; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 9eb8335a3c07..26d85ca9be26 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -1368,6 +1368,35 @@ static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof return 0; } +static int sof_link_acp_i2s_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, + struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) +{ + struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; + struct sof_dai_private_data *private = dai->private; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->acp_i2s, 0, sizeof(config->acp_i2s)); + config->hdr.size = size; + + ret = sof_update_ipc_object(scomp, &config->acp_i2s, SOF_ACPI2S_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; + + dai->number_configs = 1; + dai->current_config = 0; + private->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!private->dai_config) + return -ENOMEM; + + return 0; +} + static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { @@ -1697,6 +1726,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) case SOF_DAI_AMD_SDW: ret = sof_link_acp_sdw_load(scomp, slink, config, dai); break; + case SOF_DAI_AMD_I2S: + ret = sof_link_acp_i2s_load(scomp, slink, config, dai); + break; default: break; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6de8a6c1c127..6fd69ba11c41 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -309,7 +309,7 @@ static const struct sof_dai_types sof_dais[] = { {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL}, {"MICFIL", SOF_DAI_IMX_MICFIL}, {"ACP_SDW", SOF_DAI_AMD_SDW}, - + {"ACPTDM", SOF_DAI_AMD_I2S}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -1994,6 +1994,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ case SOF_DAI_AMD_HS: case SOF_DAI_AMD_SP_VIRTUAL: case SOF_DAI_AMD_HS_VIRTUAL: + case SOF_DAI_AMD_I2S: token_id = SOF_ACPI2S_TOKENS; num_tuples += token_list[SOF_ACPI2S_TOKENS].count; break; From 1c9646f3180ea0256b4f93d9585cdde1f1bac65d Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 1 Jul 2026 15:25:17 +0530 Subject: [PATCH 090/438] ASoC: SOF: amd: add system and runtime PM ops for ACP7x Add amd_sof_acp7x_suspend() and amd_sof_acp7x_resume() for ACP7.B/7.F platforms power management. Signed-off-by: Vijendar Mukunda Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260701095759.1012929-17-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/acp.c | 71 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/amd/acp.h | 4 +++ sound/soc/sof/amd/acp7x.c | 5 +++ 3 files changed, 80 insertions(+) diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index c2143821fb83..f89ad86260b4 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -1178,6 +1178,77 @@ void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON"); +int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + struct acp_dev_data *acp_data; + int ret; + bool enable = false; + + acp_data = sdev->pdata->hw_pdata; + + ret = acp_reset(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Reset failed\n"); + return ret; + } + switch (acp_data->pci_rev) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + enable = true; + break; + default: + break; + } + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1); + + return 0; +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_resume(struct snd_sof_dev *sdev) +{ + struct acp_dev_data *acp_data; + int ret; + + acp_data = sdev->pdata->hw_pdata; + + ret = acp_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Init failed\n"); + return ret; + } + ret = acp_memory_init(sdev); + if (ret) { + dev_err(sdev->dev, "ACP Memory init failed\n"); + return ret; + } + + switch (acp_data->pci_rev) { + case ACP7B_PCI_ID: + case ACP7F_PCI_ID: + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev) +{ + return amd_sof_acp7x_suspend(sdev, 0); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON"); + +int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev) +{ + return amd_sof_acp7x_resume(sdev); +} +EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("AMD ACP sof driver"); MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index c2f3add05d0c..16d66b2eaa70 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -359,6 +359,10 @@ int sof_acp7x_ops_init(struct snd_sof_dev *sdev); int amd_sof_acp7x_probe(struct snd_sof_dev *sdev); void amd_sof_acp7x_remove(struct snd_sof_dev *sdev); +int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state); +int amd_sof_acp7x_resume(struct snd_sof_dev *sdev); +int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev); +int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev); struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); /* Machine configuration */ diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c index 94b7ea08b309..b6722d11168c 100644 --- a/sound/soc/sof/amd/acp7x.c +++ b/sound/soc/sof/amd/acp7x.c @@ -176,5 +176,10 @@ int sof_acp7x_ops_init(struct snd_sof_dev *sdev) if (acp_sof_post_fw_run_delay) sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay; + sof_acp7x_ops.suspend = amd_sof_acp7x_suspend; + sof_acp7x_ops.resume = amd_sof_acp7x_resume; + sof_acp7x_ops.runtime_suspend = amd_sof_acp7x_suspend_runtime; + sof_acp7x_ops.runtime_resume = amd_sof_acp7x_resume_runtime; + return 0; } From a118fea777a2c04da7c5ccf1141d317838a79a46 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:27:12 +0800 Subject: [PATCH 091/438] ASoC: codecs: cs42l42-sdw: Propagate regcache_sync() errors cs42l42_sdw_runtime_resume() first syncs LATCH_TO_VP and then syncs the full regmap, but currently ignores both return values and can report success after a failed replay. Check both sync operations, return the first error, and restore cache- only/dirty state on failure. Signed-off-by: Pengpeng Hou Reviewed-by: Richard Fitzgerald Link: https://patch.msgid.link/20260704072712.91035-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42-sdw.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index b8256ce0b8fb..f1efbc2b532b 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -482,10 +482,20 @@ static int cs42l42_sdw_runtime_resume(struct device *dev) regcache_cache_only(cs42l42->regmap, false); /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ - regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); - regcache_sync(cs42l42->regmap); + ret = regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); + if (ret) + goto err_sync; + + ret = regcache_sync(cs42l42->regmap); + if (ret) + goto err_sync; return 0; + +err_sync: + regcache_cache_only(cs42l42->regmap, true); + regcache_mark_dirty(cs42l42->regmap); + return ret; } static int cs42l42_sdw_resume(struct device *dev) From e074c12c428c633e079154301207a6079a208583 Mon Sep 17 00:00:00 2001 From: Runyu Xiao Date: Fri, 12 Jun 2026 00:15:52 +0800 Subject: [PATCH 092/438] ASoC: cs35l33: drain threaded IRQ before runtime suspend cs35l33_runtime_suspend() currently switches the codec into regcache_cache_only(true) and powers it down without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l33_irq_thread() can still run after suspend has closed off live register access. A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1/2 after cache_only has been enabled, ignores the regmap_read() failures, and can still drive the AMP_SHORT_RLS, CAL_ERR_RLS, OTE_RLS, and OTW_RLS release paths. Use disable_irq() before entering cache_only/power-off so any in-flight threaded handler is drained and no new IRQ thread can run during the suspended state. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only warns if devm_request_threaded_irq() fails, track whether the IRQ was actually installed before disabling or re-enabling it. Fixes: 3333cb7187b9 ("ASoC: cs35l33: Initial commit of the cs35l33 CODEC driver.") Cc: stable@vger.kernel.org Signed-off-by: Runyu Xiao Link: https://patch.msgid.link/20260611161553.3378721-2-runyu.xiao@seu.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l33.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index f49edb9ea1f2..e217da124549 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -40,6 +40,7 @@ struct cs35l33_private { struct regmap *regmap; struct gpio_desc *reset_gpio; bool amp_cal; + bool irq_requested; int mclk_int; struct regulator_bulk_data core_supplies[2]; int num_core_supplies; @@ -881,6 +882,9 @@ static int cs35l33_runtime_resume(struct device *dev) goto err; } + if (cs35l33->irq_requested) + enable_irq(to_i2c_client(dev)->irq); + return 0; err: @@ -900,6 +904,10 @@ static int cs35l33_runtime_suspend(struct device *dev) /* redo the calibration in next power up */ cs35l33->amp_cal = false; + /* Drain and block the threaded IRQ before cache_only/power-off. */ + if (cs35l33->irq_requested) + disable_irq(to_i2c_client(dev)->irq); + regcache_cache_only(cs35l33->regmap, true); regcache_mark_dirty(cs35l33->regmap); regulator_bulk_disable(cs35l33->num_core_supplies, @@ -1154,10 +1162,12 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client) } ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, - cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs35l33", cs35l33); + cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l33", cs35l33); if (ret != 0) dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + else + cs35l33->irq_requested = true; /* We could issue !RST or skip it based on AMP topology */ cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, From 4105a4c0678b2808fc8046b60321b4f1cc7dae75 Mon Sep 17 00:00:00 2001 From: Runyu Xiao Date: Fri, 12 Jun 2026 00:15:53 +0800 Subject: [PATCH 093/438] ASoC: cs35l34: drain threaded IRQ before runtime suspend cs35l34_runtime_suspend() currently switches the codec into regcache_cache_only(true), asserts reset low, and powers the device off without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l34_irq_thread() can still run after suspend has removed live hardware access. A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1..4 after cache_only has been enabled, ignores the regmap_read() failures, and can still execute the PROT_RELEASE_CTL release sequence or the BST fault power-down writes. Use disable_irq() before entering cache_only/reset-low/power-off so any in-flight threaded handler is drained and no new IRQ thread can run while the device is suspended. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only logs request_threaded_irq() failures and keeps going, track whether the IRQ was actually installed before disabling or re-enabling it. Fixes: c1124c09e103 ("ASoC: cs35l34: Initial commit of the cs35l34 CODEC driver.") Cc: stable@vger.kernel.org Signed-off-by: Runyu Xiao Link: https://patch.msgid.link/20260611161553.3378721-3-runyu.xiao@seu.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index e80984b22159..3f265bd760f7 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -45,6 +45,7 @@ struct cs35l34_private { int num_core_supplies; int mclk_int; bool tdm_mode; + bool irq_requested; struct gpio_desc *reset_gpio; /* Active-low reset GPIO */ }; @@ -1032,10 +1033,12 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client) } ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, - cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs35l34", cs35l34); + cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l34", cs35l34); if (ret != 0) dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + else + cs35l34->irq_requested = true; cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW); @@ -1140,6 +1143,9 @@ static int cs35l34_runtime_resume(struct device *dev) dev_err(dev, "Failed to restore register cache\n"); goto err; } + + if (cs35l34->irq_requested) + enable_irq(to_i2c_client(dev)->irq); return 0; err: regcache_cache_only(cs35l34->regmap, true); @@ -1153,6 +1159,10 @@ static int cs35l34_runtime_suspend(struct device *dev) { struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + /* Drain and block the threaded IRQ before cache_only/power-off. */ + if (cs35l34->irq_requested) + disable_irq(to_i2c_client(dev)->irq); + regcache_cache_only(cs35l34->regmap, true); regcache_mark_dirty(cs35l34->regmap); From 6943ea99422ed840ee15dc546db1cdbd0b325620 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Tue, 7 Jul 2026 11:39:00 +0530 Subject: [PATCH 094/438] ASoC: SOF: amd: add missing blank line between Kconfig entries Add a missing blank line between SND_SOC_SOF_AMD_ACP70 and SND_SOC_SOF_AMD_ACP7X config entries to conform to Kconfig formatting convention. Signed-off-by: Vijendar Mukunda Link: https://patch.msgid.link/20260707060918.2535962-1-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/sof/amd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index 7413bfdb0943..903e7ec3b3ba 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -103,6 +103,7 @@ config SND_SOC_SOF_AMD_ACP70 Select this option for SOF support on AMD ACP7.0/ACP7.1 version based platforms. Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms. + config SND_SOC_SOF_AMD_ACP7X tristate "SOF support for ACP7.B/7.F platforms" depends on SND_SOC_SOF_PCI From cb63976eac60a3dd0da07b771a8ecdf061872027 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 8 Jul 2026 06:48:27 +0000 Subject: [PATCH 095/438] ASoC: amd: acp6x-mach: tidyup strange alignment yc_acp_quirk_table[] has strange alignment item. Tidyup it. Signed-off-by: Kuninori Morimoto Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/874iiageo4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-mach.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index d6df7de70b27..8b121593f26a 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -753,12 +753,12 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { } }, { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"), - } - }, + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"), + } + }, { .driver_data = &acp6x_card, .matches = { From 7ccad56689576e874a271d8dcb322952da605878 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Tue, 7 Jul 2026 15:57:20 +0900 Subject: [PATCH 096/438] ASoC: dt-bindings: wlf,wm8524: Add audio-graph port support Add port property referencing audio-graph-port.yaml to allow WM8524 to be used with audio-graph-card and audio-graph-card2. Signed-off-by: Chancel Liu Link: https://patch.msgid.link/20260707065725.312450-2-chancel.liu@oss.nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wlf,wm8524.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml index 4d951ece394e..dffc41d5f7de 100644 --- a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml +++ b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml @@ -24,6 +24,10 @@ properties: description: a GPIO spec for the MUTE pin. + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - wlf,mute-gpios From 28017bf7f76246ffbbd2710b5057e407003eabc9 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Tue, 7 Jul 2026 15:57:21 +0900 Subject: [PATCH 097/438] ASoC: dt-bindings: fsl,micfil: Add audio-graph port support Add port property referencing audio-graph-port.yaml to allow MICFIL to be used with audio-graph-card and audio-graph-card2. Signed-off-by: Chancel Liu Link: https://patch.msgid.link/20260707065725.312450-3-chancel.liu@oss.nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,micfil.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml index c47b7a097490..4c7dadb310de 100644 --- a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml @@ -66,6 +66,10 @@ properties: "#sound-dai-cells": const: 0 + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - reg From cf3bd20c43f77b4cce57ea2a738de8055aa12c97 Mon Sep 17 00:00:00 2001 From: Chancel Liu Date: Tue, 7 Jul 2026 15:57:22 +0900 Subject: [PATCH 098/438] ASoC: dt-bindings: dmic-codec: Add audio-graph port support Add port property referencing audio-graph-port.yaml to allow DMIC to be used with audio-graph-card and audio-graph-card2. Signed-off-by: Chancel Liu Link: https://patch.msgid.link/20260707065725.312450-4-chancel.liu@oss.nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/dmic-codec.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/dmic-codec.yaml b/Documentation/devicetree/bindings/sound/dmic-codec.yaml index cc3c84dd4c26..83c23e029ea4 100644 --- a/Documentation/devicetree/bindings/sound/dmic-codec.yaml +++ b/Documentation/devicetree/bindings/sound/dmic-codec.yaml @@ -39,6 +39,10 @@ properties: wakeup-delay-ms: description: Delay (in ms) after enabling the DMIC + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible From 907e6a701029bc2cd27b821ec25615c5215a6133 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 8 Jul 2026 11:58:40 +0200 Subject: [PATCH 099/438] ASoC: pm4125: Switch to irq_domain_create_linear() irq_domain_add_linear() is going away as being obsolete now. Switch to the preferred irq_domain_create_linear(). That differs in the first parameter: It takes more generic struct fwnode_handle instead of struct device_node. Therefore, of_fwnode_handle() is added around the parameter. Note some of the users can likely use dev->fwnode directly instead of indirect of_fwnode_handle(dev->of_node). But dev->fwnode is not guaranteed to be set for all, so this has to be investigated on case to case basis (by people who can actually test with the HW). Signed-off-by: Jiri Slaby (SUSE) Cc: Thomas Gleixner Cc: Srinivas Kandagatla Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260708095840.385526-1-jirislaby@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/pm4125.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c index 29655175ea28..674a2fbc4eda 100644 --- a/sound/soc/codecs/pm4125.c +++ b/sound/soc/codecs/pm4125.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -1295,7 +1296,7 @@ static const struct irq_domain_ops pm4125_domain_ops = { static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev) { - pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL); + pm4125->virq = irq_domain_create_linear(NULL, 1, &pm4125_domain_ops, NULL); if (!(pm4125->virq)) { dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); return -EINVAL; From ed1d19d37f5bc8de9f516891b42b4e9a63e8856e Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:18:48 +0800 Subject: [PATCH 100/438] ASoC: codecs: max98927: Propagate regcache_sync() errors max98927_resume() leaves cache-only mode and replays cached register state into the device. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704071848.47928-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 65e6fdb30eec..524300d8fb0b 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -742,11 +742,17 @@ static int max98927_suspend(struct device *dev) static int max98927_resume(struct device *dev) { struct max98927_priv *max98927 = dev_get_drvdata(dev); + int ret; regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); regcache_cache_only(max98927->regmap, false); - regcache_sync(max98927->regmap); + ret = regcache_sync(max98927->regmap); + if (ret) { + regcache_cache_only(max98927->regmap, true); + regcache_mark_dirty(max98927->regmap); + return ret; + } return 0; } From 29da72e58fde87e632f2fa43e448fcd1e3ab31b0 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:21:40 +0800 Subject: [PATCH 101/438] ASoC: codecs: uda1342: Leave cache-only mode before syncing uda1342_suspend() puts the regmap into cache-only mode. uda1342_resume() marks the cache dirty and syncs it, but does not first leave cache-only mode and ignores sync failures. Leave cache-only mode before syncing the dirty cache, propagate sync failures, and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704072140.67222-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/uda1342.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c index 12f5757f4210..4e2d6240a869 100644 --- a/sound/soc/codecs/uda1342.c +++ b/sound/soc/codecs/uda1342.c @@ -308,9 +308,16 @@ static int uda1342_suspend(struct device *dev) static int uda1342_resume(struct device *dev) { struct uda1342_priv *uda1342 = dev_get_drvdata(dev); + int ret; + regcache_cache_only(uda1342->regmap, false); regcache_mark_dirty(uda1342->regmap); - regcache_sync(uda1342->regmap); + ret = regcache_sync(uda1342->regmap); + if (ret) { + regcache_cache_only(uda1342->regmap, true); + regcache_mark_dirty(uda1342->regmap); + return ret; + } return 0; } From b2a06f7c9514092862021081d59eeb123d3554a5 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:40:00 +0800 Subject: [PATCH 102/438] ASoC: codecs: max98363: Propagate regcache_sync() errors max98363_resume() waits for SoundWire initialization, leaves cache-only mode, and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074000.42578-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98363.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 099dc5bf6195..0e32b7a94cb0 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -100,7 +100,12 @@ static int max98363_resume(struct device *dev) return ret; regcache_cache_only(max98363->regmap, false); - regcache_sync(max98363->regmap); + ret = regcache_sync(max98363->regmap); + if (ret) { + regcache_cache_only(max98363->regmap, true); + regcache_mark_dirty(max98363->regmap); + return ret; + } return 0; } From b64317ec00741a572fd6801cac176e34ffba0e0a Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:40:44 +0800 Subject: [PATCH 103/438] ASoC: codecs: max98373-sdw: Propagate regcache_sync() errors max98373_resume() waits for SoundWire initialization, leaves cache-only mode, and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074044.45520-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98373-sdw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 8fe9c58e1a62..638ef343813b 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -277,7 +277,12 @@ static int max98373_resume(struct device *dev) } regcache_cache_only(max98373->regmap, false); - regcache_sync(max98373->regmap); + ret = regcache_sync(max98373->regmap); + if (ret) { + regcache_cache_only(max98373->regmap, true); + regcache_mark_dirty(max98373->regmap); + return ret; + } return 0; } From 808d65f3fb42222a7816ca1509e177447417d447 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:19:33 +0800 Subject: [PATCH 104/438] ASoC: codecs: pm4125-sdw: Propagate regcache_sync() errors pm4125_sdw_runtime_resume() leaves cache-only mode and replays cached register state when a regmap is present. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704071933.52450-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/pm4125-sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c index 1c612ae4a4b2..307b66025426 100644 --- a/sound/soc/codecs/pm4125-sdw.c +++ b/sound/soc/codecs/pm4125-sdw.c @@ -464,10 +464,16 @@ static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev) static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev) { struct pm4125_sdw_priv *priv = dev_get_drvdata(dev); + int ret; if (priv->regmap) { regcache_cache_only(priv->regmap, false); - regcache_sync(priv->regmap); + ret = regcache_sync(priv->regmap); + if (ret) { + regcache_cache_only(priv->regmap, true); + regcache_mark_dirty(priv->regmap); + return ret; + } } return 0; From ca571406c52186eb5068e36d6a46512adf1b3a79 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:20:31 +0800 Subject: [PATCH 105/438] ASoC: codecs: rt5645: Propagate regcache_sync() errors Both rt5645_resume() and rt5645_sys_resume() leave cache-only mode and replay cached register state, but both paths ignore regcache_sync() failures and can report success. Check both sync operations, return the error, and restore cache- only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704072031.60768-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index e9819653b30d..93a4148ccccd 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3518,9 +3518,15 @@ static int rt5645_suspend(struct snd_soc_component *component) static int rt5645_resume(struct snd_soc_component *component) { struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); + int ret; regcache_cache_only(rt5645->regmap, false); - regcache_sync(rt5645->regmap); + ret = regcache_sync(rt5645->regmap); + if (ret) { + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + return ret; + } return 0; } @@ -4331,9 +4337,15 @@ static int rt5645_sys_suspend(struct device *dev) static int rt5645_sys_resume(struct device *dev) { struct rt5645_priv *rt5645 = dev_get_drvdata(dev); + int ret; regcache_cache_only(rt5645->regmap, false); - regcache_sync(rt5645->regmap); + ret = regcache_sync(rt5645->regmap); + if (ret) { + regcache_cache_only(rt5645->regmap, true); + regcache_mark_dirty(rt5645->regmap); + return ret; + } if (rt5645->hp_jack) { rt5645->jack_type = 0; From a1d01870b45d77c25e719235e5c8d67d7bf545d2 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:22:36 +0800 Subject: [PATCH 106/438] ASoC: codecs: wcd937x-sdw: Propagate regcache_sync() errors wcd937x_sdw_runtime_resume() leaves cache-only mode and replays cached register state when a regmap is present. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704072236.70862-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x-sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c index 7a18bed7f347..1ad75c226060 100644 --- a/sound/soc/codecs/wcd937x-sdw.c +++ b/sound/soc/codecs/wcd937x-sdw.c @@ -1084,10 +1084,16 @@ static int wcd937x_sdw_runtime_suspend(struct device *dev) static int wcd937x_sdw_runtime_resume(struct device *dev) { struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); + int ret; if (wcd->regmap) { regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); + ret = regcache_sync(wcd->regmap); + if (ret) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + return ret; + } } return 0; From 495d266f67f46e4ef0497c98a1588be43a39f95e Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:23:47 +0800 Subject: [PATCH 107/438] ASoC: codecs: wcd939x-sdw: Propagate regcache_sync() errors wcd939x_sdw_runtime_resume() leaves cache-only mode and replays cached register state when a regmap is present. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704072347.76000-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x-sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c index 95f4be287e79..69b9b08118f0 100644 --- a/sound/soc/codecs/wcd939x-sdw.c +++ b/sound/soc/codecs/wcd939x-sdw.c @@ -1431,10 +1431,16 @@ static int wcd939x_sdw_runtime_suspend(struct device *dev) static int wcd939x_sdw_runtime_resume(struct device *dev) { struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); + int ret; if (wcd->regmap) { regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); + ret = regcache_sync(wcd->regmap); + if (ret) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + return ret; + } } return 0; From cc5c698bbca05d0467239c5d7aa7ec8697b77ab2 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:24:54 +0800 Subject: [PATCH 108/438] ASoC: codecs: wsa883x: Propagate regcache_sync() errors wsa883x_runtime_resume() leaves cache-only mode and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704072454.80981-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 468d2b38a22a..24a5904d8e6c 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -1696,9 +1696,15 @@ static int wsa883x_runtime_suspend(struct device *dev) static int wsa883x_runtime_resume(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); + int ret; regcache_cache_only(regmap, false); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + return ret; + } return 0; } From 6ed25217ae6925bc9f511328a7c39e9f1a795298 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:26:16 +0800 Subject: [PATCH 109/438] ASoC: codecs: wsa884x: Propagate regcache_sync() errors wsa884x_runtime_resume() leaves cache-only mode and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704072616.88634-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wsa884x.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 6c6b497657d0..567861dd42ad 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -2147,9 +2147,15 @@ static int wsa884x_runtime_suspend(struct device *dev) static int wsa884x_runtime_resume(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); + int ret; regcache_cache_only(regmap, false); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + return ret; + } return 0; } From f814f9dfdc6151788b3aa937ddbb18a07d16d032 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:35:24 +0800 Subject: [PATCH 110/438] ASoC: codecs: rt712-sdca-dmic: Propagate regcache_sync() errors rt712_sdca_dmic_dev_resume() clears cache-only mode for both regmaps and replays cached register state. Both regcache_sync() calls currently ignore their return values. Check both sync operations, return the first error, and restore both regmaps to cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704073524.27201-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-dmic.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 85779547653e..8860d81134e7 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -916,10 +916,23 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev) } regcache_cache_only(rt712->regmap, false); - regcache_sync(rt712->regmap); + ret = regcache_sync(rt712->regmap); + if (ret) + goto err_sync; + regcache_cache_only(rt712->mbq_regmap, false); - regcache_sync(rt712->mbq_regmap); + ret = regcache_sync(rt712->mbq_regmap); + if (ret) + goto err_sync; + return 0; + +err_sync: + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + regcache_mark_dirty(rt712->regmap); + regcache_mark_dirty(rt712->mbq_regmap); + return ret; } static const struct dev_pm_ops rt712_sdca_dmic_pm = { From ba8c728e7566193e3b7ad0a91e751f6d441d5596 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:36:46 +0800 Subject: [PATCH 111/438] ASoC: codecs: rt712-sdca-sdw: Propagate regcache_sync() errors rt712_sdca_dev_resume() clears cache-only mode for both regmaps and replays cached register state. Both regcache_sync() calls currently ignore their return values. Check both sync operations, return the first error, and restore both regmaps to cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704073646.33065-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 70d661ce2ef2..ebdf7b308331 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -472,10 +472,23 @@ static int rt712_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt712->regmap, false); - regcache_sync(rt712->regmap); + ret = regcache_sync(rt712->regmap); + if (ret) + goto err_sync; + regcache_cache_only(rt712->mbq_regmap, false); - regcache_sync(rt712->mbq_regmap); + ret = regcache_sync(rt712->mbq_regmap); + if (ret) + goto err_sync; + return 0; + +err_sync: + regcache_cache_only(rt712->regmap, true); + regcache_cache_only(rt712->mbq_regmap, true); + regcache_mark_dirty(rt712->regmap); + regcache_mark_dirty(rt712->mbq_regmap); + return ret; } static const struct dev_pm_ops rt712_sdca_pm = { From 7a0886826308cb07ce9056bf656f7282b959062d Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:37:58 +0800 Subject: [PATCH 112/438] ASoC: codecs: rt721-sdca-sdw: Propagate regcache_sync() errors rt721_sdca_dev_resume() clears cache-only mode for both regmaps and replays cached register state. Both regcache_sync() calls currently ignore their return values. Check both sync operations, return the first error, and restore both regmaps to cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704073758.37156-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt721-sdca-sdw.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index 041b381e582b..6e27e761afb6 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -510,10 +510,23 @@ static int rt721_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt721->regmap, false); - regcache_sync(rt721->regmap); + ret = regcache_sync(rt721->regmap); + if (ret) + goto err_sync; + regcache_cache_only(rt721->mbq_regmap, false); - regcache_sync(rt721->mbq_regmap); + ret = regcache_sync(rt721->mbq_regmap); + if (ret) + goto err_sync; + return 0; + +err_sync: + regcache_cache_only(rt721->regmap, true); + regcache_cache_only(rt721->mbq_regmap, true); + regcache_mark_dirty(rt721->regmap); + regcache_mark_dirty(rt721->mbq_regmap); + return ret; } static const struct dev_pm_ops rt721_sdca_pm = { From 439f04ca429b819d481c24ff6da1923ab29d4830 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:41:37 +0800 Subject: [PATCH 113/438] ASoC: codecs: rt1017-sdca-sdw: Propagate regcache_sync() errors rt1017_sdca_dev_resume() waits for SoundWire initialization, leaves cache-only mode, and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074137.47606-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt1017-sdca-sdw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index 95405cea8143..caf75e5657ef 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -784,7 +784,12 @@ static int rt1017_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt1017->regmap, false); - regcache_sync(rt1017->regmap); + ret = regcache_sync(rt1017->regmap); + if (ret) { + regcache_cache_only(rt1017->regmap, true); + regcache_mark_dirty(rt1017->regmap); + return ret; + } return 0; } From c9ad95acabb2f117d4dfa9b3ca4888851256bb73 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:42:38 +0800 Subject: [PATCH 114/438] ASoC: codecs: rt1316-sdw: Propagate regcache_sync() errors rt1316_dev_resume() waits for SoundWire initialization, leaves cache- only mode, and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074238.50145-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt1316-sdw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index ca318dbd946e..359b52ba1ef9 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -756,7 +756,12 @@ static int rt1316_dev_resume(struct device *dev) } regcache_cache_only(rt1316->regmap, false); - regcache_sync(rt1316->regmap); + ret = regcache_sync(rt1316->regmap); + if (ret) { + regcache_cache_only(rt1316->regmap, true); + regcache_mark_dirty(rt1316->regmap); + return ret; + } return 0; } From f047e6a0f93ae3994abc4622486aeb992429f38b Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:43:50 +0800 Subject: [PATCH 115/438] ASoC: codecs: rt722-sdca-sdw: Propagate regcache_sync() errors rt722_sdca_dev_resume() waits for SoundWire initialization, leaves cache-only mode, and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074350.53023-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt722-sdca-sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index e68aa0350a5b..d2db33b4f684 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -557,7 +557,13 @@ static int rt722_sdca_dev_resume(struct device *dev) } regcache_cache_only(rt722->regmap, false); - regcache_sync(rt722->regmap); + ret = regcache_sync(rt722->regmap); + if (ret) { + regcache_cache_only(rt722->regmap, true); + regcache_mark_dirty(rt722->regmap); + return ret; + } + return 0; } From e857b163c8f441d477db36f0aca1cf6e258a4be7 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:44:34 +0800 Subject: [PATCH 116/438] ASoC: codecs: wsa881x: Propagate regcache_sync() errors wsa881x_runtime_resume() powers the device up, waits for SoundWire initialization, leaves cache-only mode, and replays cached register state. It currently ignores regcache_sync() failures and returns success. Propagate sync failures, restore cache-only/dirty state, and undo the shutdown GPIO state acquired by resume. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074434.54200-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wsa881x.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 5174614c3e83..47ac3e4985a5 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1178,7 +1178,13 @@ static int wsa881x_runtime_resume(struct device *dev) } regcache_cache_only(regmap, false); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + gpiod_direction_output(wsa881x->sd_n, 1); + return ret; + } return 0; } From abe8ddff80fdfce5255ab9f5931aaed5b058bb65 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 15:45:50 +0800 Subject: [PATCH 117/438] ASoC: codecs: rt5514: Propagate bias restore errors rt5514_set_bias_level() restores normal recording settings when leaving the DSP-enabled state, but ignores both the patch write and regcache_sync() failures. The bias transition can therefore report success even when the restore did not complete. Propagate the write and sync errors from the bias-level restore path. Only clear dsp_enabled after both restore operations succeed, so a failed restore keeps the internal state retryable. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704074550.57755-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 00a4a208d2fa..58aecd4c83a6 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1073,12 +1073,18 @@ static int rt5514_set_bias_level(struct snd_soc_component *component, * settings to make sure recording properly. */ if (rt5514->dsp_enabled) { - rt5514->dsp_enabled = 0; - regmap_multi_reg_write(rt5514->i2c_regmap, - rt5514_i2c_patch, - ARRAY_SIZE(rt5514_i2c_patch)); + ret = regmap_multi_reg_write(rt5514->i2c_regmap, + rt5514_i2c_patch, + ARRAY_SIZE(rt5514_i2c_patch)); + if (ret) + return ret; + regcache_mark_dirty(rt5514->regmap); - regcache_sync(rt5514->regmap); + ret = regcache_sync(rt5514->regmap); + if (ret) + return ret; + + rt5514->dsp_enabled = 0; } } break; From e38cbb75248a4027389c8a3d0bbd27bb760ba992 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:49:46 +0800 Subject: [PATCH 118/438] ASoC: codecs: lpass-rx-macro: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state. The RX macro MCLK helper and runtime resume path currently ignore that failure and report success. Propagate the error from the MCLK helper users and from runtime resume. If runtime resume fails after enabling clocks, restore cache-only/dirty state and unwind the clocks acquired by the resume path. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704034946.20369-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 6233aa9f5bc6..550fc76109c6 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -2030,9 +2030,10 @@ static struct snd_soc_dai_driver rx_macro_dai[] = { }, }; -static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) +static int rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) { struct regmap *regmap = rx->regmap; + int ret; if (mclk_enable) { if (rx->rx_mclk_users == 0) { @@ -2047,14 +2048,16 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) CDC_RX_FS_MCLK_CNT_EN_MASK, CDC_RX_FS_MCLK_CNT_ENABLE); regcache_mark_dirty(regmap); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) + return ret; } rx->rx_mclk_users++; } else { if (rx->rx_mclk_users <= 0) { dev_err(rx->dev, "%s: clock already disabled\n", __func__); rx->rx_mclk_users = 0; - return; + return 0; } rx->rx_mclk_users--; if (rx->rx_mclk_users == 0) { @@ -2068,6 +2071,8 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) CDC_RX_CLK_MCLK2_EN_MASK, 0x0); } } + + return 0; } static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w, @@ -2079,11 +2084,9 @@ static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - rx_macro_mclk_enable(rx, true); - break; + return rx_macro_mclk_enable(rx, true); case SND_SOC_DAPM_POST_PMD: - rx_macro_mclk_enable(rx, false); - break; + return rx_macro_mclk_enable(rx, false); default: dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event); ret = -EINVAL; @@ -3677,7 +3680,11 @@ static int swclk_gate_enable(struct clk_hw *hw) return ret; } - rx_macro_mclk_enable(rx, true); + ret = rx_macro_mclk_enable(rx, true); + if (ret) { + clk_disable_unprepare(rx->mclk); + return ret; + } regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, CDC_RX_SWR_CLK_EN_MASK, 1); @@ -4003,9 +4010,15 @@ static int rx_macro_runtime_resume(struct device *dev) goto err_fsgen; } regcache_cache_only(rx->regmap, false); - regcache_sync(rx->regmap); + ret = regcache_sync(rx->regmap); + if (ret) + goto err_sync; return 0; +err_sync: + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); + clk_disable_unprepare(rx->fsgen); err_fsgen: clk_disable_unprepare(rx->npl); err_npl: From ea70ad6ac28809f238d054b375cbe218f713deee Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:50:52 +0800 Subject: [PATCH 119/438] ASoC: codecs: lpass-tx-macro: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state. The TX macro MCLK helper and runtime resume path currently ignore that failure and report success. Propagate the error from the MCLK helper users and from runtime resume. If runtime resume fails after enabling clocks, restore cache-only/dirty state and unwind the clocks acquired by the resume path. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035052.29804-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index f7d168f557dd..b6b5ef802035 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -614,6 +614,7 @@ static int tx_macro_mclk_enable(struct tx_macro *tx, bool mclk_enable) { struct regmap *regmap = tx->regmap; + int ret; if (mclk_enable) { if (tx->tx_mclk_users == 0) { @@ -626,7 +627,9 @@ static int tx_macro_mclk_enable(struct tx_macro *tx, CDC_TX_FS_CNT_EN_MASK, CDC_TX_FS_CNT_ENABLE); regcache_mark_dirty(regmap); - regcache_sync(regmap); + ret = regcache_sync(regmap); + if (ret) + return ret; } tx->tx_mclk_users++; } else { @@ -739,11 +742,9 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - tx_macro_mclk_enable(tx, true); - break; + return tx_macro_mclk_enable(tx, true); case SND_SOC_DAPM_POST_PMD: - tx_macro_mclk_enable(tx, false); - break; + return tx_macro_mclk_enable(tx, false); default: break; } @@ -2155,7 +2156,11 @@ static int swclk_gate_enable(struct clk_hw *hw) return ret; } - tx_macro_mclk_enable(tx, true); + ret = tx_macro_mclk_enable(tx, true); + if (ret) { + clk_disable_unprepare(tx->mclk); + return ret; + } regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, CDC_TX_SWR_CLK_EN_MASK, @@ -2437,9 +2442,15 @@ static int tx_macro_runtime_resume(struct device *dev) } regcache_cache_only(tx->regmap, false); - regcache_sync(tx->regmap); + ret = regcache_sync(tx->regmap); + if (ret) + goto err_sync; return 0; +err_sync: + regcache_cache_only(tx->regmap, true); + regcache_mark_dirty(tx->regmap); + clk_disable_unprepare(tx->fsgen); err_fsgen: clk_disable_unprepare(tx->npl); err_npl: From 83cc6d88e37754f6ef3d7ce4a5c335688bab22b8 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:52:04 +0800 Subject: [PATCH 120/438] ASoC: codecs: max98373: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state after resume. max98373_resume() currently ignores that failure and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035204.39073-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98373-i2c.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index 8805bd01153c..cbd7ebffa6d6 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -488,10 +488,17 @@ static int max98373_suspend(struct device *dev) static int max98373_resume(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); + int ret; regcache_cache_only(max98373->regmap, false); max98373_reset(max98373, dev); - regcache_sync(max98373->regmap); + ret = regcache_sync(max98373->regmap); + if (ret) { + regcache_cache_only(max98373->regmap, true); + regcache_mark_dirty(max98373->regmap); + return ret; + } + return 0; } From 49ea357ea779ed24530e402655500c89d484b1db Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:53:16 +0800 Subject: [PATCH 121/438] ASoC: codecs: max98388: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state after resume. max98388_resume() currently ignores that failure and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035316.47011-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98388.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c index a4c57152d25f..d97dab41bf0f 100644 --- a/sound/soc/codecs/max98388.c +++ b/sound/soc/codecs/max98388.c @@ -863,10 +863,16 @@ static int max98388_suspend(struct device *dev) static int max98388_resume(struct device *dev) { struct max98388_priv *max98388 = dev_get_drvdata(dev); + int ret; regcache_cache_only(max98388->regmap, false); max98388_reset(max98388, dev); - regcache_sync(max98388->regmap); + ret = regcache_sync(max98388->regmap); + if (ret) { + regcache_cache_only(max98388->regmap, true); + regcache_mark_dirty(max98388->regmap); + return ret; + } return 0; } From 2c5e237e7e2a4256d080b44ec39a60a3d8e6d355 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:54:37 +0800 Subject: [PATCH 122/438] ASoC: codecs: rt1318-sdw: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state after the SoundWire slave has reinitialized. rt1318_dev_resume() currently ignores that failure and returns success. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035437.57792-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt1318-sdw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index c038ac0e3b76..ef18cd63d461 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -830,7 +830,12 @@ static int rt1318_dev_resume(struct device *dev) return ret; regcache_cache_only(rt1318->regmap, false); - regcache_sync(rt1318->regmap); + ret = regcache_sync(rt1318->regmap); + if (ret) { + regcache_cache_only(rt1318->regmap, true); + regcache_mark_dirty(rt1318->regmap); + return ret; + } return 0; } From aeb606a6437dfed9a98a6c2b056f9086a881f210 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:55:48 +0800 Subject: [PATCH 123/438] ASoC: codecs: rt9120: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state after runtime resume. rt9120_runtime_resume() currently ignores that failure and returns success. Propagate the error, restore cache-only/dirty state, and power the device back down on sync failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035548.67713-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt9120.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c index 97f56af25577..e51cd4a31894 100644 --- a/sound/soc/codecs/rt9120.c +++ b/sound/soc/codecs/rt9120.c @@ -606,12 +606,19 @@ static int rt9120_runtime_suspend(struct device *dev) static int rt9120_runtime_resume(struct device *dev) { struct rt9120_data *data = dev_get_drvdata(dev); + int ret; if (data->pwdnn_gpio) { gpiod_set_value(data->pwdnn_gpio, 1); msleep(RT9120_CHIPON_WAITMS); regcache_cache_only(data->regmap, false); - regcache_sync(data->regmap); + ret = regcache_sync(data->regmap); + if (ret) { + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + gpiod_set_value(data->pwdnn_gpio, 0); + return ret; + } } return 0; From 70f88374e4e40d851a8a36bc2a6138697bbfcb5a Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:57:05 +0800 Subject: [PATCH 124/438] ASoC: codecs: tas2552: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state after runtime resume. tas2552_runtime_resume() currently ignores that failure and returns success. Propagate the error, restore cache-only/dirty state, and put the amplifier back into shutdown on sync failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035705.77946-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 1a7650b9b2a7..22f93e29454f 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -495,13 +495,21 @@ static int tas2552_runtime_suspend(struct device *dev) static int tas2552_runtime_resume(struct device *dev) { struct tas2552_data *tas2552 = dev_get_drvdata(dev); + int ret; gpiod_set_value_cansleep(tas2552->enable_gpio, 1); tas2552_sw_shutdown(tas2552, 0); regcache_cache_only(tas2552->regmap, false); - regcache_sync(tas2552->regmap); + ret = regcache_sync(tas2552->regmap); + if (ret) { + regcache_cache_only(tas2552->regmap, true); + regcache_mark_dirty(tas2552->regmap); + tas2552_sw_shutdown(tas2552, 1); + gpiod_set_value_cansleep(tas2552->enable_gpio, 0); + return ret; + } return 0; } From 0d6b2d6f93a6715827a9b3c027cd8448d76e0e47 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:57:46 +0800 Subject: [PATCH 125/438] ASoC: codecs: tas2783-sdw: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state after SoundWire resume or attach handling. tas2783 currently ignores that failure. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035746.82560-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/tas2783-sdw.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 3d0b116544cc..db58c50e8a83 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -1099,7 +1099,13 @@ static s32 tas2783_sdca_dev_resume(struct device *dev) } regcache_cache_only(tas_dev->regmap, false); - regcache_sync(tas_dev->regmap); + ret = regcache_sync(tas_dev->regmap); + if (ret) { + regcache_cache_only(tas_dev->regmap, true); + regcache_mark_dirty(tas_dev->regmap); + return ret; + } + return 0; } @@ -1210,6 +1216,7 @@ static s32 tas_update_status(struct sdw_slave *slave, { struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev); struct device *dev = &slave->dev; + int ret; dev_dbg(dev, "Peripheral status = %s", status == SDW_SLAVE_UNATTACHED ? "unattached" : @@ -1227,7 +1234,12 @@ static s32 tas_update_status(struct sdw_slave *slave, /* updated the cache data to device */ regcache_cache_only(tas_dev->regmap, false); - regcache_sync(tas_dev->regmap); + ret = regcache_sync(tas_dev->regmap); + if (ret) { + regcache_cache_only(tas_dev->regmap, true); + regcache_mark_dirty(tas_dev->regmap); + return ret; + } /* perform I/O transfers required for Slave initialization */ return tas_io_init(&slave->dev, slave); From 72f1d7d21fbfea6bc2c09032044acfa372306fc0 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:58:57 +0800 Subject: [PATCH 126/438] ASoC: codecs: wcd938x-sdw: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during runtime resume. wcd938x_sdw_runtime_resume() currently ignores that failure. Propagate the error and restore cache-only/dirty state on failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035857.90264-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x-sdw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index 0f0cc0ac3056..e5ad368418a2 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -1245,10 +1245,16 @@ static int wcd938x_sdw_runtime_suspend(struct device *dev) static int wcd938x_sdw_runtime_resume(struct device *dev) { struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev); + int ret; if (wcd->regmap) { regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); + ret = regcache_sync(wcd->regmap); + if (ret) { + regcache_cache_only(wcd->regmap, true); + regcache_mark_dirty(wcd->regmap); + return ret; + } } pm_runtime_mark_last_busy(dev); From 5e5ea96e68c7751a3d38827f8d11b68810872e8f Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 11:59:57 +0800 Subject: [PATCH 127/438] ASoC: codecs: cs35l32: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during runtime resume. cs35l32_runtime_resume() currently ignores that failure. Propagate the error, restore cache-only/dirty state, and unwind the reset and supply state acquired by runtime resume. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704035957.97236-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index c835088de578..8288fb6d50be 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -538,7 +538,15 @@ static int cs35l32_runtime_resume(struct device *dev) gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); regcache_cache_only(cs35l32->regmap, false); - regcache_sync(cs35l32->regmap); + ret = regcache_sync(cs35l32->regmap); + if (ret) { + regcache_cache_only(cs35l32->regmap, true); + regcache_mark_dirty(cs35l32->regmap); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + return ret; + } return 0; } From 9497ea79d71916c2e782b20cbcf9047a58c74a98 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:00:44 +0800 Subject: [PATCH 128/438] ASoC: codecs: wm2200: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during runtime resume. wm2200_runtime_resume() currently ignores that failure. Propagate the error, restore cache-only/dirty state, and unwind the LDO and core supplies acquired by runtime resume. Signed-off-by: Pengpeng Hou Reviewed-by: Richard Fitzgerald Link: https://patch.msgid.link/20260704040044.2402-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index ba8ce2e6e615..bc78b553b6cb 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2461,7 +2461,15 @@ static int wm2200_runtime_resume(struct device *dev) } regcache_cache_only(wm2200->regmap, false); - regcache_sync(wm2200->regmap); + ret = regcache_sync(wm2200->regmap); + if (ret) { + regcache_cache_only(wm2200->regmap, true); + regcache_mark_dirty(wm2200->regmap); + gpiod_set_value_cansleep(wm2200->ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); + return ret; + } return 0; } From d5f4c137844ff1366916f96932b033279340a8b2 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:01:32 +0800 Subject: [PATCH 129/438] ASoC: codecs: wm5100: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during runtime resume. wm5100_runtime_resume() currently ignores that failure. Propagate the error, restore cache-only/dirty state, and unwind the LDO and core supplies acquired by runtime resume. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040132.8278-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wm5100.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index bd94fa53c362..2fe937a93026 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2659,7 +2659,15 @@ static int wm5100_runtime_resume(struct device *dev) } regcache_cache_only(wm5100->regmap, false); - regcache_sync(wm5100->regmap); + ret = regcache_sync(wm5100->regmap); + if (ret) { + regcache_cache_only(wm5100->regmap, true); + regcache_mark_dirty(wm5100->regmap); + gpiod_set_value_cansleep(wm5100->ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), + wm5100->core_supplies); + return ret; + } return 0; } From 56ce50099e64e78dd6152edb02adf90f6471af78 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:02:20 +0800 Subject: [PATCH 130/438] ASoC: codecs: wm8962: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during runtime resume. wm8962_runtime_resume() currently ignores that failure and continues programming the device. Propagate the error, restore cache-only/dirty state, and unwind the supplies and clock acquired by runtime resume. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040220.12045-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index de18b1f85a32..2db822fc1de7 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3937,7 +3937,9 @@ static int wm8962_runtime_resume(struct device *dev) WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, 0); - regcache_sync(wm8962->regmap); + ret = regcache_sync(wm8962->regmap); + if (ret) + goto cache_sync_err; regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA, @@ -3955,6 +3957,11 @@ static int wm8962_runtime_resume(struct device *dev) return 0; +cache_sync_err: + regcache_cache_only(wm8962->regmap, true); + regcache_mark_dirty(wm8962->regmap); + regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), + wm8962->supplies); disable_clock: clk_disable_unprepare(wm8962->pdata.mclk); return ret; From a407338ca621abe7fbc8feba2a4f432d8818b876 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:03:30 +0800 Subject: [PATCH 131/438] ASoC: codecs: cs4349: Propagate regcache_sync() errors regcache_sync() can fail while replaying cached register state during runtime resume. cs4349_runtime_resume() currently ignores that failure and returns success. Propagate the error, restore cache-only/dirty state, and hold reset low again on sync failure. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040330.23616-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 6ac6d306b054..9a7f70175717 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -340,7 +340,13 @@ static int cs4349_runtime_resume(struct device *dev) gpiod_set_value_cansleep(cs4349->reset_gpio, 1); regcache_cache_only(cs4349->regmap, false); - regcache_sync(cs4349->regmap); + ret = regcache_sync(cs4349->regmap); + if (ret) { + regcache_cache_only(cs4349->regmap, true); + regcache_mark_dirty(cs4349->regmap); + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + return ret; + } return 0; } From 39dadd459c88d1eb5dc7ccbfc605cf078c162b96 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:04:18 +0800 Subject: [PATCH 132/438] ASoC: codecs: rt1320-sdw: Propagate regcache_sync() errors rt1320_dev_resume() clears cache-only mode for both regmaps and replays cached register state into the device. Both regcache_sync() calls currently ignore their return values, so resume can report success even if either replay failed. Check both sync operations and return the first error. On failure, restore both regmaps to cache-only mode and mark both caches dirty, so a later successful resume attempt starts from a coherent suspended cache state instead of a partially live pair of regmaps. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040418.28181-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt1320-sdw.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 18d7ebff505f..a30fb575918d 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -3626,10 +3626,23 @@ static int rt1320_dev_resume(struct device *dev) return ret; regcache_cache_only(rt1320->regmap, false); - regcache_sync(rt1320->regmap); + ret = regcache_sync(rt1320->regmap); + if (ret) + goto err_sync; + regcache_cache_only(rt1320->mbq_regmap, false); - regcache_sync(rt1320->mbq_regmap); + ret = regcache_sync(rt1320->mbq_regmap); + if (ret) + goto err_sync; + return 0; + +err_sync: + regcache_cache_only(rt1320->regmap, true); + regcache_cache_only(rt1320->mbq_regmap, true); + regcache_mark_dirty(rt1320->regmap); + regcache_mark_dirty(rt1320->mbq_regmap); + return ret; } static const struct dev_pm_ops rt1320_pm = { From 446a8b7a03a4d666fb66fbf63163e0245e6c087e Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:05:30 +0800 Subject: [PATCH 133/438] ASoC: codecs: rt5682-sdw: Propagate regcache_sync() errors rt5682_io_init() and rt5682_dev_resume() both leave cache-only mode before replaying cached register state with regcache_sync(). Both paths ignore the sync result, which can hide a failed hardware restore. Propagate regcache_sync() failures from both paths. The first hardware init path now has a dedicated sync-failure cleanup that restores cache bypass, cache-only, and dirty-cache state before balancing the runtime PM reference. The resume path restores both regmaps to cache-only mode and marks the main cache dirty before returning the error. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040530.40047-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-sdw.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index dec8c2147d68..e49ec28b6103 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -410,7 +410,9 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) if (rt5682->first_hw_init) { regcache_cache_bypass(rt5682->regmap, false); regcache_mark_dirty(rt5682->regmap); - regcache_sync(rt5682->regmap); + ret = regcache_sync(rt5682->regmap); + if (ret) + goto err_sync; /* volatile registers */ regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2, @@ -472,8 +474,16 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt5682->hw_init = true; rt5682->first_hw_init = true; + goto out; + +err_sync: + regcache_cache_bypass(rt5682->regmap, false); + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + regcache_mark_dirty(rt5682->regmap); err_nodev: +out: pm_runtime_put_autosuspend(&slave->dev); dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret); @@ -776,7 +786,13 @@ static int rt5682_dev_resume(struct device *dev) regcache_cache_only(rt5682->sdw_regmap, false); regcache_cache_only(rt5682->regmap, false); - regcache_sync(rt5682->regmap); + ret = regcache_sync(rt5682->regmap); + if (ret) { + regcache_cache_only(rt5682->sdw_regmap, true); + regcache_cache_only(rt5682->regmap, true); + regcache_mark_dirty(rt5682->regmap); + return ret; + } return 0; } From d20de7409dfa8e3341af7f157cd42130bd4ba3a7 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:06:51 +0800 Subject: [PATCH 134/438] ASoC: codecs: max98396: Unwind supplies on resume failure max98396_resume() enables the core, pvdd, and vbat supplies before leaving cache-only mode, resetting the device, and replaying cached register state. The function currently ignores regcache_sync() failures, and the optional pvdd/vbat enable failures return without unwinding supplies that were already enabled in this resume attempt. Rework the function to use common error labels. This propagates sync failures, restores cache-only/dirty state on failed cache replay, and disables each supply acquired by this resume path before returning the error. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040651.47558-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98396.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index 9c1d7213410c..e5a2fe824c03 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -1600,19 +1600,37 @@ static int max98396_resume(struct device *dev) if (max98396->pvdd) { ret = regulator_enable(max98396->pvdd); if (ret < 0) - return ret; + goto err_core_supplies; } if (max98396->vbat) { ret = regulator_enable(max98396->vbat); if (ret < 0) - return ret; + goto err_pvdd; } regcache_cache_only(max98396->regmap, false); max98396_reset(max98396, dev); - regcache_sync(max98396->regmap); + ret = regcache_sync(max98396->regmap); + if (ret < 0) { + regcache_cache_only(max98396->regmap, true); + regcache_mark_dirty(max98396->regmap); + goto err_vbat; + } + return 0; + +err_vbat: + if (max98396->vbat) + regulator_disable(max98396->vbat); +err_pvdd: + if (max98396->pvdd) + regulator_disable(max98396->pvdd); +err_core_supplies: + regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, + max98396->core_supplies); + + return ret; } static const struct dev_pm_ops max98396_pm = { From 181bce73427cff76d280f14d691a7d7b95baa919 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sat, 4 Jul 2026 12:07:47 +0800 Subject: [PATCH 135/438] ASoC: codecs: max98090: Propagate runtime regcache_sync() errors max98090_runtime_suspend() puts the regmap into cache-only mode. Runtime resume clears cache-only mode, resets the device, and replays cached register state with regcache_sync(), but currently ignores a failed replay. Return the sync error and restore cache-only/dirty state before failing runtime resume. This deliberately leaves the separate system-resume sync call unchanged because the source does not provide an equally strong paired system suspend/cache-only proof for that path. Signed-off-by: Pengpeng Hou Link: https://patch.msgid.link/20260704040747.56587-1-pengpeng@iscas.ac.cn Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index bccce322ccc3..60da518b0e57 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2646,12 +2646,18 @@ static void max98090_i2c_remove(struct i2c_client *client) static int max98090_runtime_resume(struct device *dev) { struct max98090_priv *max98090 = dev_get_drvdata(dev); + int ret; regcache_cache_only(max98090->regmap, false); max98090_reset(max98090); - regcache_sync(max98090->regmap); + ret = regcache_sync(max98090->regmap); + if (ret < 0) { + regcache_cache_only(max98090->regmap, true); + regcache_mark_dirty(max98090->regmap); + return ret; + } return 0; } From 5f195b1ae6ca401fb372eb2c3a2604f8bee31f9d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 23 Jun 2026 01:53:55 +0000 Subject: [PATCH 136/438] ASoC: amd: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/87ldc6hvil.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-i2s.c | 6 ++++++ sound/soc/amd/raven/acp3x-i2s.c | 6 ++++++ sound/soc/amd/vangogh/acp5x-i2s.c | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 283a674c7e2c..bb58a9d34993 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -686,6 +686,10 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d return 0; } +static const u64 acp_i2s_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A; + const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { .startup = acp_i2s_startup, .hw_params = acp_i2s_hwparams, @@ -693,6 +697,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { .trigger = acp_i2s_trigger, .set_fmt = acp_i2s_set_fmt, .set_tdm_slot = acp_i2s_set_tdm_slot, + .auto_selectable_formats = &acp_i2s_selectable_formats, + .num_auto_selectable_formats = 1, }; EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON"); diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index 352485dd98b1..b0147e88ba54 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -250,11 +250,17 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, return ret; } +static const u64 acp3x_i2s_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A; + static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = { .hw_params = acp3x_i2s_hwparams, .trigger = acp3x_i2s_trigger, .set_fmt = acp3x_i2s_set_fmt, .set_tdm_slot = acp3x_i2s_set_tdm_slot, + .auto_selectable_formats = &acp3x_i2s_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_component_driver acp3x_dai_component = { diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c index bf719f628617..dbfb87e2fe92 100644 --- a/sound/soc/amd/vangogh/acp5x-i2s.c +++ b/sound/soc/amd/vangogh/acp5x-i2s.c @@ -337,11 +337,17 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream, return ret; } +static const u64 acp5x_i2s_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A; + static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = { .hw_params = acp5x_i2s_hwparams, .trigger = acp5x_i2s_trigger, .set_fmt = acp5x_i2s_set_fmt, .set_tdm_slot = acp5x_i2s_set_tdm_slot, + .auto_selectable_formats = &acp5x_i2s_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_component_driver acp5x_dai_component = { From 946ddf03d0a2ee23f6884a66bfdec3cce07d9011 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 23 Jun 2026 01:54:02 +0000 Subject: [PATCH 137/438] ASoC: codecs: pcm*: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Reviewed-by: Kirill Marinushkin Link: https://patch.msgid.link/87jyrqhvid.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm1681.c | 7 +++++++ sound/soc/codecs/pcm1754.c | 6 ++++++ sound/soc/codecs/pcm1789.c | 7 +++++++ sound/soc/codecs/pcm179x.c | 6 ++++++ sound/soc/codecs/pcm186x.c | 9 +++++++++ sound/soc/codecs/pcm3060.c | 8 ++++++++ sound/soc/codecs/pcm512x.c | 9 +++++++++ 7 files changed, 52 insertions(+) diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index cb923cecb47f..60fdbe5c4e05 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -199,10 +199,17 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream, return pcm1681_set_deemph(component); } +static const u64 pcm1681_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J; + static const struct snd_soc_dai_ops pcm1681_dai_ops = { .set_fmt = pcm1681_set_dai_fmt, .hw_params = pcm1681_hw_params, .mute_stream = pcm1681_mute, + .auto_selectable_formats = &pcm1681_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c index b68a528000be..bb15da1c24aa 100644 --- a/sound/soc/codecs/pcm1754.c +++ b/sound/soc/codecs/pcm1754.c @@ -78,10 +78,16 @@ static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return 0; } +static const u64 pcm1754_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J; + static const struct snd_soc_dai_ops pcm1754_dai_ops = { .set_fmt = pcm1754_set_dai_fmt, .hw_params = pcm1754_hw_params, .mute_stream = pcm1754_mute_stream, + .auto_selectable_formats = &pcm1754_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_dai_driver pcm1754_dai = { diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c index 3ab381e9a856..f06e353743aa 100644 --- a/sound/soc/codecs/pcm1789.c +++ b/sound/soc/codecs/pcm1789.c @@ -164,11 +164,18 @@ static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static const u64 pcm1789_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J; + static const struct snd_soc_dai_ops pcm1789_dai_ops = { .set_fmt = pcm1789_set_dai_fmt, .hw_params = pcm1789_hw_params, .mute_stream = pcm1789_mute, .trigger = pcm1789_trigger, + .auto_selectable_formats = &pcm1789_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index f52ff66b6e64..cb70927872aa 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c @@ -142,10 +142,16 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream, return 0; } +static const u64 pcm179x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J; + static const struct snd_soc_dai_ops pcm179x_dai_ops = { .set_fmt = pcm179x_set_dai_fmt, .hw_params = pcm179x_hw_params, .mute_stream = pcm179x_mute, + .auto_selectable_formats = &pcm179x_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 0d1103fe4e04..461ec74e8752 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -473,11 +473,20 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static const u64 pcm186x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops pcm186x_dai_ops = { .set_sysclk = pcm186x_set_dai_sysclk, .set_tdm_slot = pcm186x_set_tdm_slot, .set_fmt = pcm186x_set_fmt, .hw_params = pcm186x_hw_params, + .auto_selectable_formats = &pcm186x_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver pcm1863_dai = { diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 8974200652e7..f01c46583e89 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -164,10 +164,18 @@ static int pcm3060_hw_params(struct snd_pcm_substream *substream, return 0; } +static const u64 pcm3060_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops pcm3060_dai_ops = { .set_sysclk = pcm3060_set_sysclk, .set_fmt = pcm3060_set_fmt, .hw_params = pcm3060_hw_params, + .auto_selectable_formats = &pcm3060_selectable_formats, + .num_auto_selectable_formats = 1, }; #define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \ diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index fdef98ce52f1..12163ca7899a 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1505,12 +1505,21 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) return ret; } +static const u64 pcm512x_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B; + static const struct snd_soc_dai_ops pcm512x_dai_ops = { .startup = pcm512x_dai_startup, .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, .mute_stream = pcm512x_mute, .set_bclk_ratio = pcm512x_set_bclk_ratio, + .auto_selectable_formats = &pcm512x_selectable_formats, + .num_auto_selectable_formats = 1, .no_capture_mute = 1, }; From 2b7f2b7a2a36c35fdee1496365ff6a23c22e336f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 23 Jun 2026 01:54:06 +0000 Subject: [PATCH 138/438] ASoC: meson: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/87ik7ahvi9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/t9015.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index da1a93946d67..085f771eb244 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -78,8 +78,14 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static const u64 t9015_dai_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J; + static const struct snd_soc_dai_ops t9015_dai_ops = { .set_fmt = t9015_dai_set_fmt, + .auto_selectable_formats = &t9015_dai_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver t9015_dai = { From 5e6f8ad0008a498cbb70a30d4736fd562da73188 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 23 Jun 2026 01:54:10 +0000 Subject: [PATCH 139/438] ASoC: spacemit: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Reviewed-by: Troy Mitchell Link: https://patch.msgid.link/87h5muhvi6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/spacemit/k1_i2s.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c index 8871fc15b29c..cd461f2aa756 100644 --- a/sound/soc/spacemit/k1_i2s.c +++ b/sound/soc/spacemit/k1_i2s.c @@ -335,6 +335,11 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai) return 0; } +static const u64 spacemit_i2s_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B; + static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { .probe = spacemit_i2s_dai_probe, .remove = spacemit_i2s_dai_remove, @@ -343,6 +348,8 @@ static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { .set_sysclk = spacemit_i2s_set_sysclk, .set_fmt = spacemit_i2s_set_fmt, .trigger = spacemit_i2s_trigger, + .auto_selectable_formats = &spacemit_i2s_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver spacemit_i2s_dai = { From 92aa9c7b1d9d318709b3cd769b894844cc6e9a9d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 9 Jul 2026 11:37:40 +0700 Subject: [PATCH 140/438] ASoC: xtensa: Use dev_err_probe() and drop redundant error handling Convert error paths with messages to dev_err_probe(), which combines dev_err() and the return statement while also handling -EPROBE_DEFER for the clock path. Remove the redundant "err:" label and return errors directly. Paths such as platform_get_irq() already log failures in the callee, so they simply return the error code without printing an additional message. Inline the pm_runtime_disable() cleanup at its only call site. No functional change. Signed-off-by: bui duc phuc Reviewed-by: Max Filippov Link: https://patch.msgid.link/20260709043740.329504-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/xtensa/xtfpga-i2s.c | 60 +++++++++++++---------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 9ad86c54e3ea..fd0990201b40 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -533,34 +533,25 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) int err, irq; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); - if (!i2s) { - err = -ENOMEM; - goto err; - } + if (!i2s) + return -ENOMEM; + platform_set_drvdata(pdev, i2s); i2s->dev = &pdev->dev; dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s); i2s->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(i2s->regs)) { - err = PTR_ERR(i2s->regs); - goto err; - } + if (IS_ERR(i2s->regs)) + return PTR_ERR(i2s->regs); i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs, &xtfpga_i2s_regmap_config); - if (IS_ERR(i2s->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); - err = PTR_ERR(i2s->regmap); - goto err; - } + if (IS_ERR(i2s->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), "regmap init failed\n"); i2s->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(i2s->clk)) { - dev_err(&pdev->dev, "couldn't get clock\n"); - err = PTR_ERR(i2s->clk); - goto err; - } + if (IS_ERR(i2s->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->clk), "couldn't get clock\n"); regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG, (0x1 << XTFPGA_I2S_CONFIG_CHANNEL_BASE)); @@ -568,41 +559,34 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, XTFPGA_I2S_INT_UNDERRUN); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err = irq; - goto err; - } + if (irq < 0) + return irq; + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, xtfpga_i2s_threaded_irq_handler, IRQF_SHARED | IRQF_ONESHOT, pdev->name, i2s); - if (err < 0) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto err; - } + if (err < 0) + return err; err = devm_snd_soc_register_component(&pdev->dev, &xtfpga_i2s_component, xtfpga_i2s_dai, ARRAY_SIZE(xtfpga_i2s_dai)); - if (err < 0) { - dev_err(&pdev->dev, "couldn't register component\n"); - goto err; - } + if (err < 0) + return err; + pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { err = xtfpga_i2s_runtime_resume(&pdev->dev); - if (err) - goto err_pm_disable; + if (err) { + pm_runtime_disable(&pdev->dev); + return err; + } } - return 0; -err_pm_disable: - pm_runtime_disable(&pdev->dev); -err: - dev_err(&pdev->dev, "%s: err = %d\n", __func__, err); - return err; + return 0; } static void xtfpga_i2s_remove(struct platform_device *pdev) From 14b68141bcffafde22848c18569e821675afe9e6 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 10 Jul 2026 17:21:36 +0700 Subject: [PATCH 141/438] ASoC: xilinx: xlnx_i2s: Use dev_err_probe() and drop redundant error handling Use dev_err_probe() for probe error handling where appropriate to simplify the code and properly handle deferred probe. Also remove redundant error messages when the called helper already reports failures, returning the error directly to avoid duplicate logging. Reviewed-by: Michal Simek Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260710102138.29347-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_i2s.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c index ca915a001ad5..0676da122edd 100644 --- a/sound/soc/xilinx/xlnx_i2s.c +++ b/sound/soc/xilinx/xlnx_i2s.c @@ -185,17 +185,15 @@ static int xlnx_i2s_probe(struct platform_device *pdev) return PTR_ERR(drv_data->base); ret = of_property_read_u32(node, "xlnx,num-channels", &drv_data->channels); - if (ret < 0) { - dev_err(dev, "cannot get supported channels\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "cannot get supported channels\n"); + drv_data->channels *= 2; ret = of_property_read_u32(node, "xlnx,dwidth", &drv_data->data_width); - if (ret < 0) { - dev_err(dev, "cannot get data width\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "cannot get data width\n"); + switch (drv_data->data_width) { case 16: format = SNDRV_PCM_FMTBIT_S16_LE; @@ -233,10 +231,8 @@ static int xlnx_i2s_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component, &drv_data->dai_drv, 1); - if (ret) { - dev_err(&pdev->dev, "i2s component registration failed\n"); + if (ret) return ret; - } dev_info(&pdev->dev, "%s DAI registered\n", drv_data->dai_drv.name); From cb32e3acb1036b2c2d5a5df1e19986ccd1fff9ed Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 10 Jul 2026 17:21:37 +0700 Subject: [PATCH 142/438] ASoC: xilinx: xlnx_spdif: Preserve devm_request_irq() error codes devm_request_irq() can return various error codes, such as -EINVAL, -ENOTCONN, -ENOMEM, -ENOSYS, and -EBUSY. However, the driver overwrites all of them with -ENODEV, which hides the actual cause of the failure. Also, devm_request_irq() already reports failures internally, so the additional dev_err() call is redundant. Return the original error code and remove the duplicate error message. Signed-off-by: bui duc phuc Reviewed-by: Michal Simek Link: https://patch.msgid.link/20260710102138.29347-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_spdif.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c index 017a64ab9f1e..deb7225c1b4b 100644 --- a/sound/soc/xilinx/xlnx_spdif.c +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -274,10 +274,8 @@ static int xlnx_spdif_probe(struct platform_device *pdev) ret = devm_request_irq(dev, ret, xlnx_spdifrx_irq_handler, 0, "XLNX_SPDIF_RX", ctx); - if (ret) { - dev_err(dev, "spdif rx irq request failed\n"); - return -ENODEV; - } + if (ret) + return ret; init_waitqueue_head(&ctx->chsts_q); dai_drv = &xlnx_spdif_rx_dai; From f9620327ba7ebe3a3d374bbb0d55a74e4860bc50 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 10 Jul 2026 17:21:38 +0700 Subject: [PATCH 143/438] ASoC: xilinx: xlnx_spdif: Use dev_err_probe() and drop redundant error handling Use dev_err_probe() for probe error handling where appropriate to simplify the code and properly handle deferred probe. Also remove redundant error messages when the called helper already reports failures, returning the error directly to avoid duplicate logging. Signed-off-by: bui duc phuc Reviewed-by: Michal Simek Link: https://patch.msgid.link/20260710102138.29347-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_spdif.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c index deb7225c1b4b..ae05818ba064 100644 --- a/sound/soc/xilinx/xlnx_spdif.c +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -249,21 +249,18 @@ static int xlnx_spdif_probe(struct platform_device *pdev) return -ENOMEM; ctx->axi_clk = devm_clk_get_enabled(dev, "s_axi_aclk"); - if (IS_ERR(ctx->axi_clk)) { - ret = PTR_ERR(ctx->axi_clk); - dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret); - return ret; - } + if (IS_ERR(ctx->axi_clk)) + return dev_err_probe(dev, PTR_ERR(ctx->axi_clk), + "failed to get s_axi_aclk\n"); ctx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctx->base)) return PTR_ERR(ctx->base); ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode); - if (ret < 0) { - dev_err(dev, "cannot get SPDIF mode\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "cannot get SPDIF mode\n"); + if (ctx->mode) { dai_drv = &xlnx_spdif_tx_dai; } else { @@ -282,19 +279,15 @@ static int xlnx_spdif_probe(struct platform_device *pdev) } ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk); - if (ret < 0) { - dev_err(dev, "cannot get aud_clk_i value\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "cannot get aud_clk_i value\n"); dev_set_drvdata(dev, ctx); ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component, dai_drv, 1); - if (ret) { - dev_err(dev, "SPDIF component registration failed\n"); + if (ret) return ret; - } writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG); dev_info(dev, "%s DAI registered\n", dai_drv->name); From dd79f1926436ebfebf57b540d21eae5d1773297a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:44:39 +0000 Subject: [PATCH 144/438] ASoC: simple-card: move simple_parse_of() Move simple_parse_of() position. No functional change. This is preparation for code cleanup. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87h5mixj09.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 76 ++++++++++++++++----------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b4957e025211..456b7ebeb068 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -517,44 +517,6 @@ static int simple_populate_aux(struct simple_util_priv *priv) return simple_ret(priv, ret); } -static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) -{ - struct snd_soc_card *card = simple_priv_to_card(priv); - int ret; - - ret = simple_util_parse_widgets(card, PREFIX); - if (ret < 0) - goto end; - - ret = simple_util_parse_routing(card, PREFIX); - if (ret < 0) - goto end; - - ret = simple_util_parse_pin_switches(card, PREFIX); - if (ret < 0) - goto end; - - /* Single/Muti DAI link(s) & New style of DT node */ - memset(li, 0, sizeof(*li)); - ret = simple_for_each_link(priv, li, - simple_dai_link_of, - simple_dai_link_of_dpcm); - if (ret < 0) - goto end; - - ret = simple_util_parse_card_name(priv, PREFIX); - if (ret < 0) - goto end; - - ret = simple_populate_aux(priv); - if (ret < 0) - goto end; - - ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); -end: - return simple_ret(priv, ret); -} - static int simple_count_noml(struct simple_util_priv *priv, struct device_node *np, struct device_node *codec, @@ -704,6 +666,44 @@ static int simple_soc_probe(struct snd_soc_card *card) return simple_ret(priv, ret); } +static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) +{ + struct snd_soc_card *card = simple_priv_to_card(priv); + int ret; + + ret = simple_util_parse_widgets(card, PREFIX); + if (ret < 0) + goto end; + + ret = simple_util_parse_routing(card, PREFIX); + if (ret < 0) + goto end; + + ret = simple_util_parse_pin_switches(card, PREFIX); + if (ret < 0) + goto end; + + /* Single/Muti DAI link(s) & New style of DT node */ + memset(li, 0, sizeof(*li)); + ret = simple_for_each_link(priv, li, + simple_dai_link_of, + simple_dai_link_of_dpcm); + if (ret < 0) + goto end; + + ret = simple_util_parse_card_name(priv, PREFIX); + if (ret < 0) + goto end; + + ret = simple_populate_aux(priv); + if (ret < 0) + goto end; + + ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); +end: + return simple_ret(priv, ret); +} + static int simple_probe(struct platform_device *pdev) { struct simple_util_priv *priv; From 7f20b9b05b3abb619b6c951dfb7303525efc13c0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:44:48 +0000 Subject: [PATCH 145/438] ASoC: simple-card: merge extra method into simple_parse_of() Current simple_probe() calls many code before/after simple_parse_of(). This is because it had supported platform style probe, but is no longer exist. We can merge all into simple_parse_of(), same as Audio Graph Card/Cars2. No functional change. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87fr22xizz.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 82 ++++++++++++++++----------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 456b7ebeb068..20e6edd1d7d3 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -666,10 +666,31 @@ static int simple_soc_probe(struct snd_soc_card *card) return simple_ret(priv, ret); } -static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) +static int simple_parse_of(struct simple_util_priv *priv) { struct snd_soc_card *card = simple_priv_to_card(priv); - int ret; + struct device *dev = card->dev; + int ret = -EINVAL; + + if (!dev) + goto end; + + ret = -ENOMEM; + struct link_info *li __free(kfree) = kzalloc_obj(*li); + if (!li) + goto end; + + ret = simple_get_dais_count(priv, li); + if (ret < 0) + goto end; + + ret = -EINVAL; + if (!li->link) + goto end; + + ret = simple_util_init_priv(priv, li); + if (ret < 0) + goto end; ret = simple_util_parse_widgets(card, PREFIX); if (ret < 0) @@ -689,17 +710,30 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) simple_dai_link_of, simple_dai_link_of_dpcm); if (ret < 0) - goto end; + goto err; ret = simple_util_parse_card_name(priv, PREFIX); if (ret < 0) - goto end; + goto err; ret = simple_populate_aux(priv); if (ret < 0) - goto end; + goto err; ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); + if (ret < 0) + goto err; + + snd_soc_card_set_drvdata(card, priv); + + simple_util_debug_info(priv); + + ret = devm_snd_soc_register_card(dev, card); +err: + if (ret < 0) { + simple_util_clean_reference(card); + return dev_err_probe(dev, ret, "parse error\n"); + } end: return simple_ret(priv, ret); } @@ -709,7 +743,6 @@ static int simple_probe(struct platform_device *pdev) struct simple_util_priv *priv; struct device *dev = &pdev->dev; struct snd_soc_card *card; - int ret; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -722,42 +755,7 @@ static int simple_probe(struct platform_device *pdev) card->probe = simple_soc_probe; card->driver_name = "simple-card"; - ret = -ENOMEM; - struct link_info *li __free(kfree) = kzalloc_obj(*li); - if (!li) - goto end; - - ret = simple_get_dais_count(priv, li); - if (ret < 0) - goto end; - - ret = -EINVAL; - if (!li->link) - goto end; - - ret = simple_util_init_priv(priv, li); - if (ret < 0) - goto end; - - ret = simple_parse_of(priv, li); - if (ret < 0) { - dev_err_probe(dev, ret, "parse error\n"); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - simple_util_debug_info(priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - simple_util_clean_reference(card); -end: - return dev_err_probe(dev, ret, "parse error\n"); + return simple_parse_of(priv); } static const struct of_device_id simple_of_match[] = { From aa7fe27fda3241d33cd3af5cdeef4094c162cabb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:44:57 +0000 Subject: [PATCH 146/438] ASoC: audio-graph-card2: Tidyup audio_graph2_parse_of() around error audio_graph2_parse_of() have not been calling simple_util_clean_reference(). Call it. And it is already calling dev_err_probe() in error case, no need to call graph_ret() in success case. Tidyup it. Let's keep same style with simple-card/audio-graph-card. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87echmxizq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 0202ed0ee78e..c5ada1f83881 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1303,11 +1303,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, struct graph2_custom_hooks *hooks) { struct snd_soc_card *card = simple_priv_to_card(priv); - int ret; + int ret = -ENOMEM; struct link_info *li __free(kfree) = kzalloc_obj(*li); if (!li) - return -ENOMEM; + goto end; card->probe = graph_util_card_probe; card->owner = THIS_MODULE; @@ -1316,33 +1316,33 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, if ((hooks) && (hooks)->hook_pre) { ret = (hooks)->hook_pre(priv); if (ret < 0) - goto err; + goto end; } ret = graph_for_each_link(priv, hooks, li, graph_count); if (!li->link) ret = -EINVAL; if (ret < 0) - goto err; + goto end; ret = simple_util_init_priv(priv, li); if (ret < 0) - goto err; + goto end; priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); if (IS_ERR(priv->pa_gpio)) { ret = PTR_ERR(priv->pa_gpio); dev_err(dev, "failed to get amplifier gpio: %d\n", ret); - goto err; + goto end; } ret = simple_util_parse_widgets(card, NULL); if (ret < 0) - goto err; + goto end; ret = simple_util_parse_routing(card, NULL); if (ret < 0) - goto err; + goto end; memset(li, 0, sizeof(*li)); ret = graph_for_each_link(priv, hooks, li, graph_link); @@ -1369,9 +1369,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, ret = devm_snd_soc_register_card(dev, card); err: - if (ret < 0) - dev_err_probe(dev, ret, "parse error\n"); - + if (ret < 0) { + simple_util_clean_reference(card); + return dev_err_probe(dev, ret, "parse error\n"); + } +end: return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_parse_of); From 30bb98d530d0c04893d516cf65204d0086e08970 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:45:06 +0000 Subject: [PATCH 147/438] ASoC: audio-graph-card: Tidyup audio_graph_parse_of() around error It is already calling dev_err_probe() in error case, no need to call graph_ret() in success case. Tidyup it. Let's keep same style with simple-card/audio-graph-card2. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87cxx6xizh.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 18ce4ee06350..42e1b77fa65e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -603,14 +603,13 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) simple_util_debug_info(priv); ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; err: - simple_util_clean_reference(card); + if (ret < 0) { + simple_util_clean_reference(card); + return dev_err_probe(dev, ret, "parse error\n"); + } end: - return dev_err_probe(dev, ret, "parse error\n"); + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph_parse_of); From 7ad9d917e251be70cfa9733f990cfa5f7c49f9b5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:45:14 +0000 Subject: [PATCH 148/438] ASoC: simple_card_utils: add simple_util_parse_property() We have simple_util_parse_{routing/widgets/pin_switches}(). These are doing almost same things, but has each own implementation. Les't adds new simple_util_parse_property() and share the code. To be more easy cleanup later, change the required parameter from "card" to "priv". Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87bjcqxiza.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 27 +++++++--- sound/soc/generic/audio-graph-card.c | 4 +- sound/soc/generic/audio-graph-card2.c | 4 +- sound/soc/generic/simple-card-utils.c | 72 ++++++++------------------- sound/soc/generic/simple-card.c | 6 +-- 5 files changed, 49 insertions(+), 64 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 915e6ae5f68d..dfa1b5fb7aa8 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -189,12 +189,27 @@ bool simple_util_is_convert_required(const struct simple_util_data *data); int simple_util_get_sample_fmt(struct simple_util_data *data); -int simple_util_parse_routing(struct snd_soc_card *card, - char *prefix); -int simple_util_parse_widgets(struct snd_soc_card *card, - char *prefix); -int simple_util_parse_pin_switches(struct snd_soc_card *card, - char *prefix); +int simple_util_parse_property(struct simple_util_priv *priv, + int (*func)(struct snd_soc_card *card, const char *propname), + char *prefix, char *property); +static inline int simple_util_parse_routing(struct simple_util_priv *priv, char *prefix) +{ + return simple_util_parse_property(priv, snd_soc_of_parse_audio_routing, + prefix, "routing"); +} + +static inline int simple_util_parse_widgets(struct simple_util_priv *priv, char *prefix) +{ + return simple_util_parse_property(priv, snd_soc_of_parse_audio_simple_widgets, + prefix, "widgets"); +} + +static inline int simple_util_parse_pin_switches(struct simple_util_priv *priv, char *prefix) +{ + return simple_util_parse_property(priv, snd_soc_of_parse_pin_switches, + prefix, "pin-switches"); +} + int simple_util_init_jack(struct snd_soc_card *card, struct simple_util_jack *sjack, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 42e1b77fa65e..273b0c82ebea 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -579,11 +579,11 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) goto end; } - ret = simple_util_parse_widgets(card, NULL); + ret = simple_util_parse_widgets(priv, NULL); if (ret < 0) goto end; - ret = simple_util_parse_routing(card, NULL); + ret = simple_util_parse_routing(priv, NULL); if (ret < 0) goto end; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index c5ada1f83881..b4ae9bb860a1 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1336,11 +1336,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, goto end; } - ret = simple_util_parse_widgets(card, NULL); + ret = simple_util_parse_widgets(priv, NULL); if (ret < 0) goto end; - ret = simple_util_parse_routing(card, NULL); + ret = simple_util_parse_routing(priv, NULL); if (ret < 0) goto end; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index e5cb602fd248..522dd1e3c96a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -216,6 +216,27 @@ int simple_util_set_dailink_name(struct simple_util_priv *priv, } EXPORT_SYMBOL_GPL(simple_util_set_dailink_name); +int simple_util_parse_property(struct simple_util_priv *priv, + int (*func)(struct snd_soc_card *card, const char *propname), + char *prefix, char *property) +{ + struct snd_soc_card *card = simple_priv_to_card(priv); + struct device_node *node = card->dev->of_node; + char prop[128]; + + if (!prefix) + prefix = ""; + + snprintf(prop, sizeof(prop), "%s%s", prefix, property); + + /* no property is not error */ + if (!of_property_present(node, prop)) + return 0; + + return func(card, prop); +} +EXPORT_SYMBOL_GPL(simple_util_parse_property); + int simple_util_parse_card_name(struct simple_util_priv *priv, char *prefix) { @@ -747,57 +768,6 @@ void simple_util_clean_reference(struct snd_soc_card *card) } EXPORT_SYMBOL_GPL(simple_util_clean_reference); -int simple_util_parse_routing(struct snd_soc_card *card, - char *prefix) -{ - struct device_node *node = card->dev->of_node; - char prop[128]; - - if (!prefix) - prefix = ""; - - snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); - - if (!of_property_present(node, prop)) - return 0; - - return snd_soc_of_parse_audio_routing(card, prop); -} -EXPORT_SYMBOL_GPL(simple_util_parse_routing); - -int simple_util_parse_widgets(struct snd_soc_card *card, - char *prefix) -{ - struct device_node *node = card->dev->of_node; - char prop[128]; - - if (!prefix) - prefix = ""; - - snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets"); - - if (of_property_present(node, prop)) - return snd_soc_of_parse_audio_simple_widgets(card, prop); - - /* no widgets is not error */ - return 0; -} -EXPORT_SYMBOL_GPL(simple_util_parse_widgets); - -int simple_util_parse_pin_switches(struct snd_soc_card *card, - char *prefix) -{ - char prop[128]; - - if (!prefix) - prefix = ""; - - snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); - - return snd_soc_of_parse_pin_switches(card, prop); -} -EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches); - int simple_util_init_jack(struct snd_soc_card *card, struct simple_util_jack *sjack, int is_hp, char *prefix, diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 20e6edd1d7d3..6e432733649f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -692,15 +692,15 @@ static int simple_parse_of(struct simple_util_priv *priv) if (ret < 0) goto end; - ret = simple_util_parse_widgets(card, PREFIX); + ret = simple_util_parse_widgets(priv, PREFIX); if (ret < 0) goto end; - ret = simple_util_parse_routing(card, PREFIX); + ret = simple_util_parse_routing(priv, PREFIX); if (ret < 0) goto end; - ret = simple_util_parse_pin_switches(card, PREFIX); + ret = simple_util_parse_pin_switches(priv, PREFIX); if (ret < 0) goto end; From d0ab37b02826fc4b2b78cb3f47416cc2dbbd9e7e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:45:32 +0000 Subject: [PATCH 149/438] ASoC: simple_card_utils: add simple_util_parse_aux_devs() We are using snd_soc_of_parse_aux_devs() directly, but can use simple_util_parse_property(). use it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/878q7uxiyr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 5 +++++ sound/soc/generic/audio-graph-card2.c | 2 +- sound/soc/generic/simple-card.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index dfa1b5fb7aa8..ff9747c6aa49 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -210,6 +210,11 @@ static inline int simple_util_parse_pin_switches(struct simple_util_priv *priv, prefix, "pin-switches"); } +static inline int simple_util_parse_aux_devs(struct simple_util_priv *priv, char *prefix) +{ + return simple_util_parse_property(priv, snd_soc_of_parse_aux_devs, + prefix, "aux-devs"); +} int simple_util_init_jack(struct snd_soc_card *card, struct simple_util_jack *sjack, diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index b4ae9bb860a1..4dee28276671 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1363,7 +1363,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, simple_util_debug_info(priv); - ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); + ret = simple_util_parse_aux_devs(priv, NULL); if (ret < 0) goto err; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6e432733649f..4dd05e726213 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -720,7 +720,7 @@ static int simple_parse_of(struct simple_util_priv *priv) if (ret < 0) goto err; - ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); + ret = simple_util_parse_aux_devs(priv, PREFIX); if (ret < 0) goto err; From 27ecf4da5ad3845b773508917e71f5a07b149077 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:45:40 +0000 Subject: [PATCH 150/438] ASoC: simple-card: tidyup simple_util_parse_xxx() in simple_parse_of() simple_parse_of() calls simple_util_parse_xxx(), but are random. Let's gather them all in one place. Let's keep same style with audio-graph-card/audio-graph-card2. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/877bnexiyj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 4dd05e726213..a67f4aad0188 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -704,6 +704,14 @@ static int simple_parse_of(struct simple_util_priv *priv) if (ret < 0) goto end; + ret = simple_util_parse_card_name(priv, PREFIX); + if (ret < 0) + goto err; + + ret = simple_util_parse_aux_devs(priv, PREFIX); + if (ret < 0) + goto err; + /* Single/Muti DAI link(s) & New style of DT node */ memset(li, 0, sizeof(*li)); ret = simple_for_each_link(priv, li, @@ -712,18 +720,10 @@ static int simple_parse_of(struct simple_util_priv *priv) if (ret < 0) goto err; - ret = simple_util_parse_card_name(priv, PREFIX); - if (ret < 0) - goto err; - ret = simple_populate_aux(priv); if (ret < 0) goto err; - ret = simple_util_parse_aux_devs(priv, PREFIX); - if (ret < 0) - goto err; - snd_soc_card_set_drvdata(card, priv); simple_util_debug_info(priv); From b8081307f5c9d662ed5afbf42e809273dd9af8be Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:45:48 +0000 Subject: [PATCH 151/438] ASoC: audio-graph-card: tidyup simple_util_parse_xxx() in audio_graph_parse_of() audio_graph_parse_of() calls simple_util_parse_xxx(), but are random. Let's gather them all in one place. Let's keep same style with simple-card/audio-graph-card2. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/875x2yxiyc.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 273b0c82ebea..f5e36c777ac6 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -587,6 +587,10 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto end; + ret = simple_util_parse_card_name(priv, NULL); + if (ret < 0) + goto err; + memset(li, 0, sizeof(*li)); ret = graph_for_each_link(priv, li, graph_dai_link_of, @@ -594,10 +598,6 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto err; - ret = simple_util_parse_card_name(priv, NULL); - if (ret < 0) - goto err; - snd_soc_card_set_drvdata(card, priv); simple_util_debug_info(priv); From fa6222d5e1219468301370c8b316f9b729ee600b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:45:55 +0000 Subject: [PATCH 152/438] ASoC: audio-graph-card2: tidyup simple_util_parse_xxx() in audio_graph2_parse_of() audio_graph2_parse_of() calls simple_util_parse_xxx(), but are random. Let's gather them all in one place. Let's keep same style with simple-card/audio-graph-card. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/874iiixiy5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card2.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 4dee28276671..9ef7373a6ca6 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1344,12 +1344,16 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, if (ret < 0) goto end; - memset(li, 0, sizeof(*li)); - ret = graph_for_each_link(priv, hooks, li, graph_link); + ret = simple_util_parse_card_name(priv, NULL); if (ret < 0) goto err; - ret = simple_util_parse_card_name(priv, NULL); + ret = simple_util_parse_aux_devs(priv, NULL); + if (ret < 0) + goto err; + + memset(li, 0, sizeof(*li)); + ret = graph_for_each_link(priv, hooks, li, graph_link); if (ret < 0) goto err; @@ -1363,10 +1367,6 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, simple_util_debug_info(priv); - ret = simple_util_parse_aux_devs(priv, NULL); - if (ret < 0) - goto err; - ret = devm_snd_soc_register_card(dev, card); err: if (ret < 0) { From 279bfbb150aef95a3ee281cdd9ebefdddfb43a1e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:46:02 +0000 Subject: [PATCH 153/438] ASoC: simple-card-utils: tidyup simple_util_init_aux_jacks() Current code makes old style / new style conversion difficult. To make future conversions easier to understand, this patch clean up the code a little. but no functional change. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/8733y2xixy.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 3 +-- sound/soc/generic/simple-card-utils.c | 4 ++-- sound/soc/generic/simple-card.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ff9747c6aa49..5e2e91578bf5 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -219,8 +219,7 @@ static inline int simple_util_parse_aux_devs(struct simple_util_priv *priv, char int simple_util_init_jack(struct snd_soc_card *card, struct simple_util_jack *sjack, int is_hp, char *prefix, char *pin); -int simple_util_init_aux_jacks(struct simple_util_priv *priv, - char *prefix); +int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix); int simple_util_init_priv(struct simple_util_priv *priv, struct link_info *li); void simple_util_remove(struct platform_device *pdev); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 522dd1e3c96a..44632759b185 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -824,9 +824,9 @@ int simple_util_init_jack(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(simple_util_init_jack); -int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix) +int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix) { - struct snd_soc_card *card = simple_priv_to_card(priv); + struct simple_util_priv *priv = snd_soc_card_get_drvdata(card); struct snd_soc_component *component; int found_jack_index = 0; int type = 0; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index a67f4aad0188..49289cd655ea 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -661,7 +661,7 @@ static int simple_soc_probe(struct snd_soc_card *card) if (ret < 0) goto end; - ret = simple_util_init_aux_jacks(priv, PREFIX); + ret = simple_util_init_aux_jacks(card, PREFIX); end: return simple_ret(priv, ret); } From 6f5c4f6ffa8bd87803145d03b1ad36d4fa50d562 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 2 Jul 2026 01:46:09 +0000 Subject: [PATCH 154/438] ASoC: simple-card-utils: tidyup simple_util_clean_reference() Current code makes old style / new style conversion difficult. To make future conversions easier to understand, this patch clean up the code a little. but no functional change. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/871pdmxixq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/generic/audio-graph-card2.c | 2 +- sound/soc/generic/simple-card-utils.c | 6 ++++-- sound/soc/generic/simple-card.c | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 5e2e91578bf5..bd8c3a033577 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -181,7 +181,7 @@ void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platfo void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, int is_single_links); -void simple_util_clean_reference(struct snd_soc_card *card); +void simple_util_clean_reference(struct simple_util_priv *priv); void simple_util_parse_convert(struct device_node *np, char *prefix, struct simple_util_data *data); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index f5e36c777ac6..73ea562ce52b 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -605,7 +605,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) ret = devm_snd_soc_register_card(dev, card); err: if (ret < 0) { - simple_util_clean_reference(card); + simple_util_clean_reference(priv); return dev_err_probe(dev, ret, "parse error\n"); } end: diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 9ef7373a6ca6..e3e92025b317 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1370,7 +1370,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, ret = devm_snd_soc_register_card(dev, card); err: if (ret < 0) { - simple_util_clean_reference(card); + simple_util_clean_reference(priv); return dev_err_probe(dev, ret, "parse error\n"); } end: diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 44632759b185..42019daa5e04 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -752,11 +752,12 @@ void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, } EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu); -void simple_util_clean_reference(struct snd_soc_card *card) +void simple_util_clean_reference(struct simple_util_priv *priv) { struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link_component *cpu; struct snd_soc_dai_link_component *codec; + struct snd_soc_card *card = simple_priv_to_card(priv); int i, j; for_each_card_prelinks(card, i, dai_link) { @@ -996,8 +997,9 @@ EXPORT_SYMBOL_GPL(simple_util_init_priv); void simple_util_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); + struct simple_util_priv *priv = snd_soc_card_get_drvdata(card); - simple_util_clean_reference(card); + simple_util_clean_reference(priv); } EXPORT_SYMBOL_GPL(simple_util_remove); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 49289cd655ea..abfbc9fd7c6d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -731,7 +731,7 @@ static int simple_parse_of(struct simple_util_priv *priv) ret = devm_snd_soc_register_card(dev, card); err: if (ret < 0) { - simple_util_clean_reference(card); + simple_util_clean_reference(priv); return dev_err_probe(dev, ret, "parse error\n"); } end: From af58a647f9c9674535f62aa1d04b681317da0a26 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 5 Jul 2026 19:23:26 +0200 Subject: [PATCH 155/438] ASoC: renesas: adg: Drop redundant NULL check on clk_get and clk_register_fixed_rate devm_clk_get() and clk_register_fixed_rate() do not return NULL (only valid clock or ERR pointer), so simplify the code to drop redundant IS_ERR_OR_NULL(). Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260705172325.118926-3-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/renesas/rcar/adg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c index 53efd1be5139..2a74d89ba39d 100644 --- a/sound/soc/renesas/rcar/adg.c +++ b/sound/soc/renesas/rcar/adg.c @@ -565,7 +565,7 @@ static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, struct clk *clk; clk = clk_register_fixed_rate(dev, name, parent, 0, 0); - if (IS_ERR_OR_NULL(clk)) { + if (IS_ERR(clk)) { dev_err(dev, "create null clk error\n"); return ERR_CAST(clk); } @@ -618,7 +618,7 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv) * No "adg" is not error */ clk = devm_clk_get(dev, "adg"); - if (IS_ERR_OR_NULL(clk)) + if (IS_ERR(clk)) clk = rsnd_adg_null_clk_get(priv); adg->adg = clk; @@ -626,9 +626,9 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv) for (i = 0; i < clkin_size; i++) { clk = devm_clk_get(dev, clkin_name[i]); - if (IS_ERR_OR_NULL(clk)) + if (IS_ERR(clk)) clk = rsnd_adg_null_clk_get(priv); - if (IS_ERR_OR_NULL(clk)) + if (IS_ERR(clk)) goto err; adg->clkin[i] = clk; From 6ef98181eac3ed8f4d96170d7115fc4dc1e0d43d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 5 Jul 2026 19:23:27 +0200 Subject: [PATCH 156/438] ASoC: codecs: es9356: Constify regmap_sdw_mbq_cfg Static 'struct regmap_sdw_mbq_cfg' is not modified so can be changed to const for more safety. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260705172325.118926-4-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/es9356.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c index 1122455aab77..f574b3d6cb3c 100644 --- a/sound/soc/codecs/es9356.c +++ b/sound/soc/codecs/es9356.c @@ -671,7 +671,7 @@ static int es9356_sdca_mbq_size(struct device *dev, unsigned int reg) } } -static struct regmap_sdw_mbq_cfg es9356_mbq_config = { +static const struct regmap_sdw_mbq_cfg es9356_mbq_config = { .mbq_size = es9356_sdca_mbq_size, }; From b9b23e72abef91ab4689f1467cefc2517042ab26 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Tue, 7 Jul 2026 15:13:11 +0530 Subject: [PATCH 157/438] ASoC: codecs: lpass-tx-macro: switch to PM clock framework for runtime PM Convert the LPASS TX macro codec driver to runtime PM clock management using the PM clock framework. Replace manual macro/dcodec/mclk/npl/fsgen clock toggling with PM clock helpers and runtime PM callbacks. Keep the SWR gate runtime PM reference from SWR clock enable until disable so autosuspend does not gate clocks while SWR is still prepared. Set autosuspend delay to 100 ms so PM-clock-managed votes are dropped soon after idle while still avoiding suspend/resume churn on short gaps. Add a PM_CLK dependency to SND_SOC_LPASS_TX_MACRO since this patch introduces PM clock APIs. Tighten error unwind by checking pm_runtime_put_sync_suspend() in probe and by restoring regcache state if pm_clk_resume()/regcache_sync() fails. Co-developed-by: Ravi Hothi Signed-off-by: Ravi Hothi Signed-off-by: Ajay Kumar Nandam Link: https://patch.msgid.link/20260707-xo-sd-codec-tx-rx-v2-1-f61b4622f97f@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 + sound/soc/codecs/lpass-tx-macro.c | 114 ++++++++++++------------------ 2 files changed, 49 insertions(+), 67 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 252f683be3c1..160c52258d95 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2909,12 +2909,14 @@ config SND_SOC_LPASS_VA_MACRO config SND_SOC_LPASS_RX_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)" config SND_SOC_LPASS_TX_MACRO depends on COMMON_CLK + depends on PM_CLK select REGMAP_MMIO select SND_SOC_LPASS_MACRO_COMMON tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index f7d168f557dd..fc073a556fb5 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -2149,17 +2150,20 @@ static int swclk_gate_enable(struct clk_hw *hw) struct regmap *regmap = tx->regmap; int ret; - ret = clk_prepare_enable(tx->mclk); + ret = pm_runtime_resume_and_get(tx->dev); + if (ret < 0) + return ret; + + ret = tx_macro_mclk_enable(tx, true); if (ret) { - dev_err(tx->dev, "failed to enable mclk\n"); + pm_runtime_put_autosuspend(tx->dev); return ret; } - tx_macro_mclk_enable(tx, true); - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, CDC_TX_SWR_CLK_EN_MASK, CDC_TX_SWR_CLK_ENABLE); + return 0; } @@ -2172,7 +2176,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_TX_SWR_CLK_EN_MASK, 0x0); tx_macro_mclk_enable(tx, false); - clk_disable_unprepare(tx->mclk); + pm_runtime_put_autosuspend(tx->dev); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -2318,25 +2322,23 @@ static int tx_macro_probe(struct platform_device *pdev) clk_set_rate(tx->mclk, MCLK_FREQ); clk_set_rate(tx->npl, MCLK_FREQ); - ret = clk_prepare_enable(tx->macro); + ret = devm_pm_clk_create(dev); if (ret) goto err; - ret = clk_prepare_enable(tx->dcodec); - if (ret) - goto err_dcodec; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + goto err; - ret = clk_prepare_enable(tx->mclk); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_mclk; + goto err; - ret = clk_prepare_enable(tx->npl); - if (ret) - goto err_npl; - - ret = clk_prepare_enable(tx->fsgen); - if (ret) - goto err_fsgen; + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto err; /* reset soundwire block */ @@ -2356,30 +2358,21 @@ static int tx_macro_probe(struct platform_device *pdev) tx_macro_dai, ARRAY_SIZE(tx_macro_dai)); if (ret) - goto err_clkout; - - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + goto err_rpm_put; ret = tx_macro_register_mclk_output(tx); if (ret) - goto err_clkout; + goto err_rpm_put; + + ret = pm_runtime_put_autosuspend(dev); + if (ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); return 0; -err_clkout: - clk_disable_unprepare(tx->fsgen); -err_fsgen: - clk_disable_unprepare(tx->npl); -err_npl: - clk_disable_unprepare(tx->mclk); -err_mclk: - clk_disable_unprepare(tx->dcodec); -err_dcodec: - clk_disable_unprepare(tx->macro); +err_rpm_put: + if (pm_runtime_put_sync_suspend(dev) < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); err: lpass_macro_pds_exit(tx->pds); @@ -2390,25 +2383,23 @@ static void tx_macro_remove(struct platform_device *pdev) { struct tx_macro *tx = dev_get_drvdata(&pdev->dev); - clk_disable_unprepare(tx->macro); - clk_disable_unprepare(tx->dcodec); - clk_disable_unprepare(tx->mclk); - clk_disable_unprepare(tx->npl); - clk_disable_unprepare(tx->fsgen); - lpass_macro_pds_exit(tx->pds); } static int tx_macro_runtime_suspend(struct device *dev) { struct tx_macro *tx = dev_get_drvdata(dev); + int ret; regcache_cache_only(tx->regmap, true); - regcache_mark_dirty(tx->regmap); - clk_disable_unprepare(tx->fsgen); - clk_disable_unprepare(tx->npl); - clk_disable_unprepare(tx->mclk); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(tx->regmap, false); + return ret; + } + + regcache_mark_dirty(tx->regmap); return 0; } @@ -2418,34 +2409,23 @@ static int tx_macro_runtime_resume(struct device *dev) struct tx_macro *tx = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(tx->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(dev, "unable to prepare mclk\n"); + regcache_cache_only(tx->regmap, true); + regcache_mark_dirty(tx->regmap); return ret; } - ret = clk_prepare_enable(tx->npl); - if (ret) { - dev_err(dev, "unable to prepare npl\n"); - goto err_npl; - } - - ret = clk_prepare_enable(tx->fsgen); - if (ret) { - dev_err(dev, "unable to prepare fsgen\n"); - goto err_fsgen; - } - regcache_cache_only(tx->regmap, false); - regcache_sync(tx->regmap); + ret = regcache_sync(tx->regmap); + if (ret) { + regcache_cache_only(tx->regmap, true); + regcache_mark_dirty(tx->regmap); + pm_clk_suspend(dev); + return ret; + } return 0; -err_fsgen: - clk_disable_unprepare(tx->npl); -err_npl: - clk_disable_unprepare(tx->mclk); - - return ret; } static const struct dev_pm_ops tx_macro_pm_ops = { From b05482e7ce1b110f86b08a99768ac41e4c9e4dfa Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Tue, 7 Jul 2026 15:13:12 +0530 Subject: [PATCH 158/438] ASoC: codecs: lpass-rx-macro: switch to PM clock framework for runtime PM Convert the LPASS RX macro codec driver to runtime PM clock management using the PM clock framework. Replace manual macro/dcodec/mclk/npl/fsgen clock toggling with PM clock helpers and runtime PM callbacks. Keep the SWR gate runtime PM reference from SWR clock enable until disable so autosuspend does not gate clocks while SWR is still prepared. Set autosuspend delay to 100 ms so PM-clock-managed votes are dropped soon after idle while still avoiding suspend/resume churn on short gaps. Add a PM_CLK dependency to SND_SOC_LPASS_RX_MACRO since this patch introduces PM clock APIs. Tighten error unwind by checking pm_runtime_put_sync_suspend() in probe and by restoring regcache state if pm_clk_resume()/regcache_sync() fails. Drop the now-empty rx_macro_remove() callback since all clock cleanup is handled by PM clock framework and devm. Co-developed-by: Ravi Hothi Signed-off-by: Ravi Hothi Signed-off-by: Ajay Kumar Nandam Link: https://patch.msgid.link/20260707-xo-sd-codec-tx-rx-v2-2-f61b4622f97f@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 113 +++++++++++------------------- 1 file changed, 41 insertions(+), 72 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 6233aa9f5bc6..927f75050c0f 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -3671,11 +3672,9 @@ static int swclk_gate_enable(struct clk_hw *hw) struct rx_macro *rx = to_rx_macro(hw); int ret; - ret = clk_prepare_enable(rx->mclk); - if (ret) { - dev_err(rx->dev, "unable to prepare mclk\n"); + ret = pm_runtime_resume_and_get(rx->dev); + if (ret < 0) return ret; - } rx_macro_mclk_enable(rx, true); @@ -3693,7 +3692,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_RX_SWR_CLK_EN_MASK, 0); rx_macro_mclk_enable(rx, false); - clk_disable_unprepare(rx->mclk); + pm_runtime_put_autosuspend(rx->dev); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -3867,25 +3866,23 @@ static int rx_macro_probe(struct platform_device *pdev) clk_set_rate(rx->mclk, MCLK_FREQ); clk_set_rate(rx->npl, MCLK_FREQ); - ret = clk_prepare_enable(rx->macro); + ret = devm_pm_clk_create(dev); if (ret) return ret; - ret = clk_prepare_enable(rx->dcodec); - if (ret) - goto err_dcodec; + ret = of_pm_clk_add_clks(dev); + if (ret < 0) + return ret; - ret = clk_prepare_enable(rx->mclk); + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - goto err_mclk; + return ret; - ret = clk_prepare_enable(rx->npl); + ret = pm_runtime_resume_and_get(dev); if (ret) - goto err_npl; - - ret = clk_prepare_enable(rx->fsgen); - if (ret) - goto err_fsgen; + return ret; /* reset swr block */ regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, @@ -3902,46 +3899,25 @@ static int rx_macro_probe(struct platform_device *pdev) rx_macro_dai, ARRAY_SIZE(rx_macro_dai)); if (ret) - goto err_clkout; - - - pm_runtime_set_autosuspend_delay(dev, 3000); - pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + goto err_rpm_put; ret = rx_macro_register_mclk_output(rx); if (ret) - goto err_clkout; + goto err_rpm_put; + + ret = pm_runtime_put_autosuspend(dev); + if (ret < 0) + dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); return 0; -err_clkout: - clk_disable_unprepare(rx->fsgen); -err_fsgen: - clk_disable_unprepare(rx->npl); -err_npl: - clk_disable_unprepare(rx->mclk); -err_mclk: - clk_disable_unprepare(rx->dcodec); -err_dcodec: - clk_disable_unprepare(rx->macro); +err_rpm_put: + if (pm_runtime_put_sync_suspend(dev) < 0) + dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); return ret; } -static void rx_macro_remove(struct platform_device *pdev) -{ - struct rx_macro *rx = dev_get_drvdata(&pdev->dev); - - clk_disable_unprepare(rx->mclk); - clk_disable_unprepare(rx->npl); - clk_disable_unprepare(rx->fsgen); - clk_disable_unprepare(rx->macro); - clk_disable_unprepare(rx->dcodec); -} - static const struct of_device_id rx_macro_dt_match[] = { { .compatible = "qcom,sc7280-lpass-rx-macro", @@ -3969,13 +3945,17 @@ MODULE_DEVICE_TABLE(of, rx_macro_dt_match); static int rx_macro_runtime_suspend(struct device *dev) { struct rx_macro *rx = dev_get_drvdata(dev); + int ret; regcache_cache_only(rx->regmap, true); - regcache_mark_dirty(rx->regmap); - clk_disable_unprepare(rx->fsgen); - clk_disable_unprepare(rx->npl); - clk_disable_unprepare(rx->mclk); + ret = pm_clk_suspend(dev); + if (ret) { + regcache_cache_only(rx->regmap, false); + return ret; + } + + regcache_mark_dirty(rx->regmap); return 0; } @@ -3985,33 +3965,23 @@ static int rx_macro_runtime_resume(struct device *dev) struct rx_macro *rx = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(rx->mclk); + ret = pm_clk_resume(dev); if (ret) { - dev_err(dev, "unable to prepare mclk\n"); + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); return ret; } - ret = clk_prepare_enable(rx->npl); - if (ret) { - dev_err(dev, "unable to prepare mclkx2\n"); - goto err_npl; - } - - ret = clk_prepare_enable(rx->fsgen); - if (ret) { - dev_err(dev, "unable to prepare fsgen\n"); - goto err_fsgen; - } regcache_cache_only(rx->regmap, false); - regcache_sync(rx->regmap); + ret = regcache_sync(rx->regmap); + if (ret) { + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); + pm_clk_suspend(dev); + return ret; + } return 0; -err_fsgen: - clk_disable_unprepare(rx->npl); -err_npl: - clk_disable_unprepare(rx->mclk); - - return ret; } static const struct dev_pm_ops rx_macro_pm_ops = { @@ -4026,7 +3996,6 @@ static struct platform_driver rx_macro_driver = { .pm = pm_ptr(&rx_macro_pm_ops), }, .probe = rx_macro_probe, - .remove = rx_macro_remove, }; module_platform_driver(rx_macro_driver); From b8ca90fafe6adc401601f91d1394ba76bacf67ed Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Tue, 7 Jul 2026 15:13:13 +0530 Subject: [PATCH 159/438] ASoC: codecs: lpass-{tx,rx}-macro: check clk_set_rate() return value clk_set_rate() returns 0 on success or a negative errno on failure but the TX and RX macro probe functions were ignoring it. Check the return value and bail out of probe on failure. Suggested-by: Konrad Dybcio Co-developed-by: Ravi Hothi Signed-off-by: Ravi Hothi Signed-off-by: Ajay Kumar Nandam Link: https://patch.msgid.link/20260707-xo-sd-codec-tx-rx-v2-3-f61b4622f97f@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 9 +++++++-- sound/soc/codecs/lpass-tx-macro.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 927f75050c0f..388cebf461a3 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3863,8 +3863,13 @@ static int rx_macro_probe(struct platform_device *pdev) rx->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(rx->mclk, MCLK_FREQ); - clk_set_rate(rx->npl, MCLK_FREQ); + ret = clk_set_rate(rx->mclk, MCLK_FREQ); + if (ret) + return ret; + + ret = clk_set_rate(rx->npl, MCLK_FREQ); + if (ret) + return ret; ret = devm_pm_clk_create(dev); if (ret) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index fc073a556fb5..b56605639a24 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -2319,8 +2319,13 @@ static int tx_macro_probe(struct platform_device *pdev) tx->active_decimator[TX_MACRO_AIF3_CAP] = -1; /* set MCLK and NPL rates */ - clk_set_rate(tx->mclk, MCLK_FREQ); - clk_set_rate(tx->npl, MCLK_FREQ); + ret = clk_set_rate(tx->mclk, MCLK_FREQ); + if (ret) + goto err; + + ret = clk_set_rate(tx->npl, MCLK_FREQ); + if (ret) + goto err; ret = devm_pm_clk_create(dev); if (ret) From cccd721e5aab03e92234faee72b363c9ba60611c Mon Sep 17 00:00:00 2001 From: James Calligeros Date: Sat, 11 Jul 2026 11:11:19 +1000 Subject: [PATCH 160/438] ASoC: apple: mca: increase SERDES reset delay The SERDES clusters in this peripheral take a long time to warm up. We tried polling the reset bit until cleared, however this is not a reliable signal of readiness to be configured. Only waiting ~25 us to give the cluster a chance to settle makes it work reliably. Increase the 2 us delay to 25 us and hope we never have to do this again. Fixes: d8b3e396088d ("ASoC: apple: mca: Fix SERDES reset sequence") Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-1-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 492165c0e1ea..ebe116f32661 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -210,10 +210,10 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd, SERDES_STATUS_EN | SERDES_STATUS_RST, SERDES_STATUS_RST); /* - * Experiments suggest that it takes at most ~1 us - * for the bit to clear, so wait 2 us for good measure. + * The SERDES cluster needs a bit of time to reset itself + * and settle before we start poking it. This is... slow... */ - udelay(2); + udelay(25); WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) & SERDES_STATUS_RST); mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, From 108d4b654d82c04c4b74db2cf9b1a947b19a5e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 11 Jul 2026 11:11:20 +1000 Subject: [PATCH 161/438] ASoC: apple: mca: Separate data & clock port setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up until now FEs were always the clock providers -- feeding the clocks on any ports (BEs) they are attached to. This will soon change and FEs will be allowed to be clock consumers. Once that happens, the routing of clocks and data will to some degree decouple. In advance of the change, make preparations: * Narrow down semantics of what was formerly the 'port_driver' field to refer to clocks only. * On 'startup' of BEs, separate the clock and data aspects of the port setup. Signed-off-by: Martin Povišer Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-2-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 67 +++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index ebe116f32661..55cdb4e0f0b4 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -133,8 +133,8 @@ struct mca_cluster { struct clk *clk_parent; struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1]; - bool port_started[SNDRV_PCM_STREAM_LAST + 1]; - int port_driver; /* The cluster driving this cluster's port */ + bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1]; + int port_clk_driver; /* The cluster driving this cluster's port */ bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1]; struct device_link *pd_link; @@ -157,7 +157,7 @@ struct mca_data { struct reset_control *rstc; struct device_link *pd_link; - /* Mutex for accessing port_driver of foreign clusters */ + /* Mutex for accessing port_clk_driver of foreign clusters */ struct mutex port_mutex; int nclusters; @@ -311,7 +311,7 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) for (i = 0; i < mca->nclusters; i++) { be_cl = &mca->clusters[i]; - if (be_cl->port_driver != cl->no) + if (be_cl->port_clk_driver != cl->no) continue; for_each_pcm_streams(stream) { @@ -331,10 +331,10 @@ static int mca_be_prepare(struct snd_pcm_substream *substream, struct mca_cluster *fe_cl; int ret; - if (cl->port_driver < 0) + if (cl->port_clk_driver < 0) return -EINVAL; - fe_cl = &mca->clusters[cl->port_driver]; + fe_cl = &mca->clusters[cl->port_clk_driver]; /* * Typically the CODECs we are paired with will require clocks @@ -360,7 +360,7 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, struct mca_data *mca = cl->host; struct mca_cluster *fe_cl; - if (cl->port_driver < 0) + if (cl->port_clk_driver < 0) return -EINVAL; /* @@ -368,7 +368,7 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, * belong to the same PCM, accesses should have been * synchronized at ASoC level. */ - fe_cl = &mca->clusters[cl->port_driver]; + fe_cl = &mca->clusters[cl->port_clk_driver]; if (!mca_fe_clocks_in_use(fe_cl)) return 0; /* Nothing to do */ @@ -708,12 +708,15 @@ static const struct snd_soc_dai_ops mca_fe_ops = { .trigger = mca_fe_trigger, }; -static bool mca_be_started(struct mca_cluster *cl) +/* + * Is there a FE attached which will be feeding this port's clocks? + */ +static bool mca_be_clk_started(struct mca_cluster *cl) { int stream; for_each_pcm_streams(stream) - if (cl->port_started[stream]) + if (cl->port_clk_started[stream]) return true; return false; } @@ -744,28 +747,38 @@ static int mca_be_startup(struct snd_pcm_substream *substream, fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); - if (mca_be_started(cl)) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), + cl->base + REG_PORT_DATA_SEL); + mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, + PORT_ENABLES_TX_DATA); + } + + if (mca_be_clk_started(cl)) { /* * Port is already started in the other direction. * Make sure there isn't a conflict with another cluster - * driving the port. + * driving the port clocks. */ - if (cl->port_driver != fe_cl->no) + if (cl->port_clk_driver != fe_cl->no) return -EINVAL; - cl->port_started[substream->stream] = true; + cl->port_clk_started[substream->stream] = true; return 0; } - writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA, - cl->base + REG_PORT_ENABLES); writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1), cl->base + REG_PORT_CLOCK_SEL); + writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), cl->base + REG_PORT_DATA_SEL); + + mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, + PORT_ENABLES_CLOCKS); + scoped_guard(mutex, &mca->port_mutex) - cl->port_driver = fe_cl->no; - cl->port_started[substream->stream] = true; + cl->port_clk_driver = fe_cl->no; + cl->port_clk_started[substream->stream] = true; return 0; } @@ -776,17 +789,21 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream, struct mca_cluster *cl = mca_dai_to_cluster(dai); struct mca_data *mca = cl->host; - cl->port_started[substream->stream] = false; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0); + writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); + } - if (!mca_be_started(cl)) { + cl->port_clk_started[substream->stream] = false; + if (!mca_be_clk_started(cl)) { /* * Were we the last direction to shutdown? - * Turn off the lights. + * Turn off the lights (clocks). */ - writel_relaxed(0, cl->base + REG_PORT_ENABLES); - writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); + mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, 0); + writel_relaxed(0, cl->base + REG_PORT_CLOCK_SEL); scoped_guard(mutex, &mca->port_mutex) - cl->port_driver = -1; + cl->port_clk_driver = -1; } } @@ -1092,7 +1109,7 @@ static int apple_mca_probe(struct platform_device *pdev) cl->host = mca; cl->no = i; cl->base = base + CLUSTER_STRIDE * i; - cl->port_driver = -1; + cl->port_clk_driver = -1; cl->clk_parent = of_clk_get(pdev->dev.of_node, i); if (IS_ERR(cl->clk_parent)) { dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n", From 2aab6230f8d81c47cd3cc0617d1ef93b7f66f974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 11 Jul 2026 11:11:21 +1000 Subject: [PATCH 162/438] ASoC: apple: mca: Factor out mca_be_get_fe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a function that we also want to use from within mca_be_shutdown, so factor it out. Signed-off-by: Martin Povišer Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-3-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 55cdb4e0f0b4..1e9a5c9cfc54 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -721,30 +721,35 @@ static bool mca_be_clk_started(struct mca_cluster *cl) return false; } -static int mca_be_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be, + int stream) { - struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); - struct snd_soc_pcm_runtime *fe; - struct mca_cluster *cl = mca_dai_to_cluster(dai); - struct mca_cluster *fe_cl; - struct mca_data *mca = cl->host; + struct snd_soc_pcm_runtime *fe = NULL; struct snd_soc_dpcm *dpcm; - fe = NULL; - - for_each_dpcm_fe(be, substream->stream, dpcm) { + for_each_dpcm_fe(be, stream, dpcm) { if (fe && dpcm->fe != fe) { - dev_err(mca->dev, "many FE per one BE unsupported\n"); - return -EINVAL; + dev_err(be->dev, "many FE per one BE unsupported\n"); + return NULL; } fe = dpcm->fe; } + return fe; +} + +static int mca_be_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_cluster *fe_cl; + struct mca_data *mca = cl->host; + if (!fe) return -EINVAL; - fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { From 00309bfb1f54558a06b8aeeaedb2e54956b5182a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 11 Jul 2026 11:11:22 +1000 Subject: [PATCH 163/438] ASoC: apple: mca: Support FEs being clock consumers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support FEs being I2S clock consumers. This does not mean we support accepting clocks from outside the SoC (although it paves the way for that support in the future), but it means multiple FEs can attach to one BE, one being clock producer and the rest clock consumers. This is useful for grabbing I/V sense data on some machines, since in such a scenario the format of the sense data on the I2S bus differs from that of the audio data (the two formats differing in slot width). With two FEs attached to the bus, we can split the responsibilities and command different slot widths to the two. Signed-off-by: Martin Povišer Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-4-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 124 +++++++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 21 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 1e9a5c9cfc54..92c9f8df50d6 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -133,12 +133,17 @@ struct mca_cluster { struct clk *clk_parent; struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1]; + bool clk_provider; + bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1]; int port_clk_driver; /* The cluster driving this cluster's port */ bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1]; struct device_link *pd_link; + /* In case of clock consumer FE */ + int syncgen_in_use; + unsigned int bclk_ratio; /* Masks etc. picked up via the set_tdm_slot method */ @@ -256,11 +261,32 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } +static int mca_fe_get_port(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *be; + struct snd_soc_dpcm *dpcm; + + be = NULL; + for_each_dpcm_be(fe, substream->stream, dpcm) { + be = dpcm->be; + break; + } + + if (!be) + return -EINVAL; + + return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no; +} + static int mca_fe_enable_clocks(struct mca_cluster *cl) { struct mca_data *mca = cl->host; int ret; + if (!cl->clk_provider) + return -EINVAL; + ret = clk_prepare_enable(cl->clk_parent); if (ret) { dev_err(mca->dev, @@ -332,7 +358,7 @@ static int mca_be_prepare(struct snd_pcm_substream *substream, int ret; if (cl->port_clk_driver < 0) - return -EINVAL; + return 0; fe_cl = &mca->clusters[cl->port_clk_driver]; @@ -380,6 +406,56 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, return 0; } +static int mca_fe_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + + if (cl->clk_provider) + return 0; + + /* Turn on the cluster power domain if not already in use */ + if (!cl->syncgen_in_use) { + int port = mca_fe_get_port(substream); + + cl->pd_link = device_link_add(mca->dev, cl->pd_dev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!cl->pd_link) { + dev_err(mca->dev, + "cluster %d: unable to prop-up power domain\n", cl->no); + return -EINVAL; + } + + mca_modify(cl, REG_SYNCGEN_MCLK_SEL, SYNCGEN_MCLK_SEL, BIT(port)); + mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, + SYNCGEN_STATUS_EN); + } + cl->syncgen_in_use |= 1 << substream->stream; + + return 0; +} + +static int mca_fe_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mca_cluster *cl = mca_dai_to_cluster(dai); + + if (cl->clk_provider) + return 0; + + cl->syncgen_in_use &= ~(1 << substream->stream); + if (cl->syncgen_in_use) + return 0; + + mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0); + if (cl->pd_link) + device_link_del(cl->pd_link); + + return 0; +} + static unsigned int mca_crop_mask(unsigned int mask, int nchans) { while (hweight32(mask) > nchans) @@ -505,9 +581,18 @@ static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) u32 serdes_conf = 0; u32 bitstart; - if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != - SND_SOC_DAIFMT_BP_FP) + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: + cl->clk_provider = true; + break; + + case SND_SOC_DAIFMT_BC_FC: + cl->clk_provider = false; + break; + + default: goto err; + } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -564,24 +649,6 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) return 0; } -static int mca_fe_get_port(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); - struct snd_soc_pcm_runtime *be; - struct snd_soc_dpcm *dpcm; - - be = NULL; - for_each_dpcm_be(fe, substream->stream, dpcm) { - be = dpcm->be; - break; - } - - if (!be) - return -EINVAL; - - return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no; -} - static int mca_fe_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -706,6 +773,8 @@ static const struct snd_soc_dai_ops mca_fe_ops = { .set_tdm_slot = mca_fe_set_tdm_slot, .hw_params = mca_fe_hw_params, .trigger = mca_fe_trigger, + .prepare = mca_fe_prepare, + .hw_free = mca_fe_hw_free, }; /* @@ -759,6 +828,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream, PORT_ENABLES_TX_DATA); } + if (!fe_cl->clk_provider) + return 0; + if (mca_be_clk_started(cl)) { /* * Port is already started in the other direction. @@ -791,14 +863,24 @@ static int mca_be_startup(struct snd_pcm_substream *substream, static void mca_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_cluster *fe_cl; struct mca_data *mca = cl->host; + if (!fe) + return; + fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0); writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); } + if (!fe_cl->clk_provider) + return; + cl->port_clk_started[substream->stream] = false; if (!mca_be_clk_started(cl)) { /* From 108a14b20f958ad5cbb8f8bfaf4932dfd69bb0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Sat, 11 Jul 2026 11:11:23 +1000 Subject: [PATCH 164/438] ASoC: apple: mca: Support capture on multiples BEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When multiple BEs are linked to a FE, the former behavior was to source the data line from the DIN pin of the first BE only. Change this to ORing the DIN inputs of all linked BEs. As long as the unused slots on each BE's line are zeroed out and the slots on the BEs don't overlap, this will work out well. Signed-off-by: Martin Povišer Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-5-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 92c9f8df50d6..d8973e5611dd 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -261,22 +261,19 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int mca_fe_get_port(struct snd_pcm_substream *substream) +static int mca_fe_get_portmask(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); - struct snd_soc_pcm_runtime *be; struct snd_soc_dpcm *dpcm; + int mask = 0; - be = NULL; for_each_dpcm_be(fe, substream->stream, dpcm) { - be = dpcm->be; - break; + int no = mca_dai_to_cluster(snd_soc_rtd_to_cpu(dpcm->be, 0))->no; + + mask |= 1 << no; } - if (!be) - return -EINVAL; - - return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no; + return mask; } static int mca_fe_enable_clocks(struct mca_cluster *cl) @@ -417,7 +414,7 @@ static int mca_fe_prepare(struct snd_pcm_substream *substream, /* Turn on the cluster power domain if not already in use */ if (!cl->syncgen_in_use) { - int port = mca_fe_get_port(substream); + int port = ffs(mca_fe_get_portmask(substream)); cl->pd_link = device_link_add(mca->dev, cl->pd_dev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | @@ -466,7 +463,7 @@ static unsigned int mca_crop_mask(unsigned int mask, int nchans) static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit, unsigned int mask, int slots, int nchans, - int slot_width, bool is_tx, int port) + int slot_width, bool is_tx, int portmask) { __iomem void *serdes_base = cl->base + serdes_unit; u32 serdes_conf, serdes_conf_mask; @@ -525,7 +522,7 @@ static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit, serdes_base + REG_RX_SERDES_SLOTMASK); writel_relaxed(~((u32)mca_crop_mask(mask, nchans)), serdes_base + REG_RX_SERDES_SLOTMASK + 0x4); - writel_relaxed(1 << port, + writel_relaxed(portmask, serdes_base + REG_RX_SERDES_PORT); } @@ -662,7 +659,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, unsigned long bclk_ratio; unsigned int tdm_slots, tdm_slot_width, tdm_mask; u32 regval, pad; - int ret, port, nchans_ceiled; + int ret, portmask, nchans_ceiled; if (!cl->tdm_slot_width) { /* @@ -711,13 +708,13 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, tdm_mask = (1 << tdm_slots) - 1; } - port = mca_fe_get_port(substream); - if (port < 0) - return port; + portmask = mca_fe_get_portmask(substream); + if (!portmask) + return -EINVAL; ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF, tdm_mask, tdm_slots, params_channels(params), - tdm_slot_width, is_tx, port); + tdm_slot_width, is_tx, portmask); if (ret) return ret; From 889c26cfb98dd40f8e7bab721bc11a82dd592c33 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sat, 11 Jul 2026 11:11:24 +1000 Subject: [PATCH 165/438] ASoC: apple: mca: Do not mark clocks in use for non-providers On the speakers PCM, this sequence: 1. Open playback 2. Open sense 3. Close playback 4. Close sense would result in the sense FE being marked as clocks in use at (2), since there is a clock provider (playback FE). Then at (4) this would WARN since there is no driver any more when closing the in use clocks. If (1) and (2) are reversed this does not happen, since the sense PCM is not marked as using the clocks when there is no provider yet. So, check explicitly whether the substream FE is a clock provider in be_prepare, and skip everything if it isn't. Signed-off-by: Hector Martin Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-6-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 67 ++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index d8973e5611dd..322dd8771111 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -346,36 +346,6 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) return false; } -static int mca_be_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct mca_cluster *cl = mca_dai_to_cluster(dai); - struct mca_data *mca = cl->host; - struct mca_cluster *fe_cl; - int ret; - - if (cl->port_clk_driver < 0) - return 0; - - fe_cl = &mca->clusters[cl->port_clk_driver]; - - /* - * Typically the CODECs we are paired with will require clocks - * to be present at time of unmute with the 'mute_stream' op - * or at time of DAPM widget power-up. We need to enable clocks - * here at the latest (frontend prepare would be too late). - */ - if (!mca_fe_clocks_in_use(fe_cl)) { - ret = mca_fe_enable_clocks(fe_cl); - if (ret < 0) - return ret; - } - - cl->clocks_in_use[substream->stream] = true; - - return 0; -} - static int mca_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -805,6 +775,43 @@ static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be, return fe; } +static int mca_be_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); + struct mca_cluster *cl = mca_dai_to_cluster(dai); + struct mca_data *mca = cl->host; + struct mca_cluster *fe_cl, *fe_clk_cl; + int ret; + + fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); + + if (!fe_cl->clk_provider) + return 0; + + if (cl->port_clk_driver < 0) + return 0; + + fe_clk_cl = &mca->clusters[cl->port_clk_driver]; + + /* + * Typically the CODECs we are paired with will require clocks + * to be present at time of unmute with the 'mute_stream' op + * or at time of DAPM widget power-up. We need to enable clocks + * here at the latest (frontend prepare would be too late). + */ + if (!mca_fe_clocks_in_use(fe_clk_cl)) { + ret = mca_fe_enable_clocks(fe_clk_cl); + if (ret < 0) + return ret; + } + + cl->clocks_in_use[substream->stream] = true; + + return 0; +} + static int mca_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { From 8dd595bca51a4c1f775cfcca8c10753c58b7a969 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sat, 11 Jul 2026 11:11:25 +1000 Subject: [PATCH 166/438] ASoC: apple: mca: Add delay after configuring clock Right after the early FE setup, ADMAC gets told to start the DMA. This can end up in a weird "slip" state with the channels transposed. Waiting a bit fixes this; presumably this allows the clock to stabilize. Signed-off-by: Hector Martin Signed-off-by: James Calligeros Link: https://patch.msgid.link/20260711-apple-audio-redux-v4-7-2994d87c2f24@gmail.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 322dd8771111..afb3754a8883 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -225,6 +225,12 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd, FIELD_PREP(SERDES_CONF_SYNC_SEL, 0)); mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1)); + /* + * ADMAC gets started right after this. This delay seems + * to be needed for that to be reliable, e.g. ensure the + * clock is stable? + */ + udelay(100); break; default: break; From a9a2c8c44b30f15596d5b1a0982d13b0c79911f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jul 2026 17:04:04 +0100 Subject: [PATCH 167/438] ASoC: simple-card: Fix clang build Jumping over the allocation of the link_info for a missing dev breaks the build: /tmp/next/build/sound/soc/generic/simple-card.c:676:3: error: cannot jump from this goto statement to its label 676 | goto end; | ^ /tmp/next/build/sound/soc/generic/simple-card.c:679:20: note: jump bypasses initialization of variable with __attribute__((cleanup)) 679 | struct link_info *li __free(kfree) = kzalloc_obj(*li); | ^ Fixes: 7f20b9b05b3a ("ASoC: simple-card: merge extra method into simple_parse_of()") Link: https://patch.msgid.link/20260713-asoc-fix-simple-card-build-v1-1-671ad44ad1a0@kernel.org Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index abfbc9fd7c6d..6e98e973e525 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -673,7 +673,7 @@ static int simple_parse_of(struct simple_util_priv *priv) int ret = -EINVAL; if (!dev) - goto end; + return simple_ret(priv, ret); ret = -ENOMEM; struct link_info *li __free(kfree) = kzalloc_obj(*li); From 552d9559cae2b6344228da1b8f7205d6e537ba38 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 13 Jul 2026 16:46:49 +0800 Subject: [PATCH 168/438] ASoC: SOF: Intel: reset spib_addr before disabling SPIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spib_addr register will indicate to the host DMA where the position is in the buffer currently processed by host SW. The register is ignored by the host DMA if SPIB is disabled. Reset it to 0 before disabling SPIB. Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://patch.msgid.link/20260713084650.4138172-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 5c1f3b427cdb..4a46e35c3eac 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -198,13 +198,18 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, mask = (1 << hstream->index); + /* Reset the spib_addr before disabling SPIB */ + if (!enable) + sof_io_write(sdev, hstream->spib_addr, 0); + /* enable/disable SPIB for the stream */ snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR, SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask, enable << hstream->index); /* set the SPIB value */ - sof_io_write(sdev, hstream->spib_addr, size); + if (enable) + sof_io_write(sdev, hstream->spib_addr, size); return 0; } From 0507d956c4ce91f2bca63ef99d2f0a30817ea7db Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 13 Jul 2026 16:46:50 +0800 Subject: [PATCH 169/438] ASoC: SOF: Intel: Disable SPIB in non ICCMAX stream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing code disable SPIB in the playback direction only because previously the hda data stream is only used for SOF firmware download and we prepare capture stream for ICCMAX and prepare playback stream for non ICCMAX case. But now the hda data stream is also used for SoundWire BPT which will use both directions. The SPIB is enabled in non ICCMAX cases and we should disable in clean up. Add a is_iccmax flag in the hda_data_stream_cleanup() function to align with the hda_data_stream_prepare() function to enable/disable the SPIB. Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Link: https://patch.msgid.link/20260713084650.4138172-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 11 ++++++----- sound/soc/sof/intel/hda-sdw-bpt.c | 2 +- sound/soc/sof/intel/hda-stream.c | 8 +++++--- sound/soc/sof/intel/hda.h | 5 +++-- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 2b3abcf75d55..4347e71337f9 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -216,9 +216,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - bool persistent_buffer, struct hdac_ext_stream *hext_stream) + bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax) { - return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, false); + return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, + is_iccmax, false); } EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON"); @@ -302,7 +303,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) * If the cleanup also fails, we return the initial error */ ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab, - persistent_cl_buffer, iccmax_stream); + persistent_cl_buffer, iccmax_stream, true); if (ret1 < 0) { dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); @@ -458,7 +459,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) * If the cleanup also fails, we return the initial error */ ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, - persistent_cl_buffer, hext_stream); + persistent_cl_buffer, hext_stream, false); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); @@ -587,7 +588,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, cleanup: /* clean up even in case of error and return the first error */ ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer, - hext_stream); + hext_stream, false); if (ret1 < 0) { dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c index 728ffe7ae54d..c10648f56f23 100644 --- a/sound/soc/sof/intel/hda-sdw-bpt.c +++ b/sound/soc/sof/intel/hda-sdw-bpt.c @@ -163,7 +163,7 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream u32 mask; int ret; - ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, true); + ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, false, true); if (ret < 0) { dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n", __func__); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 4a46e35c3eac..0778002e2bd6 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -1328,16 +1328,18 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si EXPORT_SYMBOL_NS(hda_data_stream_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair) + bool persistent_buffer, struct hdac_ext_stream *hext_stream, + bool is_iccmax, bool pair) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct hdac_stream *hstream = hdac_stream(hext_stream); int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret = 0; - if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) + if (!is_iccmax) ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0); - else + + if (hstream->direction == SNDRV_PCM_STREAM_CAPTURE) snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_SD_CTL_DMA_START, 0); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3f0966477ace..799e49539b4a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -739,7 +739,7 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - bool persistent_buffer, struct hdac_ext_stream *hext_stream); + bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax); int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); #define HDA_CL_STREAM_FORMAT 0x40 @@ -911,7 +911,8 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si bool is_iccmax, bool pair); int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair); + bool persistent_buffer, struct hdac_ext_stream *hext_stream, + bool is_iccmax, bool pair); /* common dai driver */ extern struct snd_soc_dai_driver skl_dai[]; From 06b6f1245567a4be862c3e1cc74577922ceb05fb Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sat, 4 Jul 2026 21:28:57 +0200 Subject: [PATCH 170/438] ASoC: codecs: aw88261: only check PLL and clock state at power-up The SYSST check performed during device start requires SWS (amplifier switching, bit 8) and BSTS (boost finished, bit 9) on top of PLL lock and clock stability. Those bits cannot be asserted at this point in the sequence: the check runs after amppd release but before the hmute/ULS-hmute release, and the amplifier neither switches nor finishes ramping its boost converter while it is still muted. With the Fairphone (Gen. 6) firmware profile, aw88261_dev_start() therefore always fails with check sysst fail, reg_val=0x0011, check:0x311 and playback aborts, even though the amplifier is fine and PLL lock and stable clocks are present. Check only PLL lock and clock stability, for which a definition already exists; this still re-validates the clocks after amppd release (aw88261_dev_check_syspll() checked them before it). This matches the vendor aw882xx driver, which only validates PLL lock and clock stability at this stage, and the in-tree aw88399 driver, which skips the SWS check whenever the amplifier may legitimately not be switching (AW88399_BIT_SYSST_NOSWS_CHECK). Fixes: 028a2ae25691 ("ASoC: codecs: Add aw88261 amplifier driver") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-fable-5 Signed-off-by: Jorijn van der Graaf Link: https://patch.msgid.link/20260704192857.88366-1-jorijnvdgraaf@catcrafts.net Signed-off-by: Mark Brown --- sound/soc/codecs/aw88261.c | 6 +++--- sound/soc/codecs/aw88261.h | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index 549783d3e75e..dbdf51188cf5 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -206,10 +206,10 @@ static int aw88261_dev_check_sysst(struct aw_device *aw_dev) return ret; check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK) - & AW88261_BIT_SYSST_CHECK; - if (check_val != AW88261_BIT_SYSST_CHECK) { + & AW88261_BIT_PLL_CHECK; + if (check_val != AW88261_BIT_PLL_CHECK) { dev_dbg(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", - reg_val, AW88261_BIT_SYSST_CHECK); + reg_val, AW88261_BIT_PLL_CHECK); usleep_range(AW88261_2000_US, AW88261_2000_US + 10); } else { return 0; diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h index 270ccf375f36..f16f9f8c40a2 100644 --- a/sound/soc/codecs/aw88261.h +++ b/sound/soc/codecs/aw88261.h @@ -194,12 +194,6 @@ AW88261_OTHS_OT_VALUE | \ AW88261_PLLS_LOCKED_VALUE)) -#define AW88261_BIT_SYSST_CHECK \ - (AW88261_BSTS_FINISHED_VALUE | \ - AW88261_SWS_SWITCHING_VALUE | \ - AW88261_CLKS_STABLE_VALUE | \ - AW88261_PLLS_LOCKED_VALUE) - #define AW88261_ULS_HMUTE_START_BIT (14) #define AW88261_ULS_HMUTE_BITS_LEN (1) #define AW88261_ULS_HMUTE_MASK \ From 350b7eae8e8b2bd3885a3e2424381494d6bde038 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:38 +0700 Subject: [PATCH 171/438] ASoC: codecs: ab8500: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 6e8ef9cd1b31..2cf96cbdd294 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -14,6 +14,7 @@ * for ST-Ericsson. */ +#include #include #include #include @@ -989,9 +990,8 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev); - mutex_lock(&drvdata->ctrl_lock); + guard(mutex)(&drvdata->ctrl_lock); ucontrol->value.enumerated.item[0] = drvdata->sid_status; - mutex_unlock(&drvdata->ctrl_lock); return 0; } @@ -1014,7 +1014,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, return -EIO; } - mutex_lock(&drvdata->ctrl_lock); + guard(mutex)(&drvdata->ctrl_lock); sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF); if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { @@ -1025,7 +1025,8 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, } else { status = -EBUSY; } - goto out; + dev_dbg(component->dev, "%s: Exit\n", __func__); + return status; } snd_soc_component_write(component, AB8500_SIDFIRADR, 0); @@ -1043,9 +1044,6 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, drvdata->sid_status = SID_FIR_CONFIGURED; -out: - mutex_unlock(&drvdata->ctrl_lock); - dev_dbg(component->dev, "%s: Exit\n", __func__); return status; From da41b1716fad3ce1b4b617fd2155fb0347d7a1ba Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:39 +0700 Subject: [PATCH 172/438] ASoC: codecs: ak4613: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4613.c | 77 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 3e0696b5abf5..be5306d07d40 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -95,6 +95,7 @@ * see * AK4613_ENABLE_TDM_TEST */ +#include #include #include #include @@ -384,7 +385,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); struct device *dev = component->dev; - mutex_lock(&priv->lock); + guard(mutex)(&priv->lock); priv->cnt--; if (priv->cnt < 0) { dev_err(dev, "unexpected counter error\n"); @@ -392,7 +393,6 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, } if (!priv->cnt) priv->ctrl1 = 0; - mutex_unlock(&priv->lock); } static void ak4613_hw_constraints(struct ak4613_priv *priv, @@ -507,10 +507,9 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->lock); + guard(mutex)(&priv->lock); ak4613_hw_constraints(priv, substream); priv->cnt++; - mutex_unlock(&priv->lock); return 0; } @@ -599,45 +598,47 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, */ ret = -EINVAL; - mutex_lock(&priv->lock); - if (priv->cnt > 1) { - /* - * If it was already working, use current priv->ctrl1 - */ - ret = 0; - } else { - /* - * It is not yet working, - */ - unsigned int channel = params_channels(params); - u8 tdm; + scoped_guard(mutex, &priv->lock) { + if (priv->cnt > 1) { + /* + * If it was already working, use current priv->ctrl1 + */ + ret = 0; + } else { + /* + * It is not yet working, + */ + unsigned int channel = params_channels(params); + u8 tdm; - /* STEREO or TDM */ - if (channel == 2) - tdm = AK4613_CONFIG_MODE_STEREO; - else - tdm = AK4613_CONFIG_GET(priv, MODE); + /* STEREO or TDM */ + if (channel == 2) + tdm = AK4613_CONFIG_MODE_STEREO; + else + tdm = AK4613_CONFIG_GET(priv, MODE); - for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { - const struct ak4613_interface *iface = ak4613_iface + i; + for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { + const struct ak4613_interface *iface = ak4613_iface + i; - if ((iface->fmt == fmt) && (iface->width == width)) { - /* - * Ctrl1 - * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | - * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| - * < tdm > < iface->dif > - */ - priv->ctrl1 = (tdm << 6) | (iface->dif << 3); - ret = 0; - break; + if (iface->fmt == fmt && iface->width == width) { + /* + * Ctrl1 + * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | + * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| + * < tdm > < iface->dif > + */ + priv->ctrl1 = (tdm << 6) | (iface->dif << 3); + ret = 0; + break; + } } } } - mutex_unlock(&priv->lock); - if (ret < 0) - goto hw_params_end; + if (ret < 0) { + dev_warn(dev, "unsupported data width/format combination\n"); + return ret; + } snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1); snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2); @@ -645,10 +646,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic); snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc); -hw_params_end: - if (ret < 0) - dev_warn(dev, "unsupported data width/format combination\n"); - return ret; } From d46421aeac5a923ea76ad8922e285280fddc16da Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:40 +0700 Subject: [PATCH 173/438] ASoC: codecs: arizona-jack: Use guard() cleanup helpers Clean up the code using guard() helpers for mutex locking and PM runtime management. No functional change intended. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona-jack.c | 121 +++++++++++++++----------------- 1 file changed, 55 insertions(+), 66 deletions(-) diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index a9063bac2752..819d080b1188 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -5,6 +5,7 @@ * Copyright (C) 2012-2014 Wolfson Microelectronics plc */ +#include #include #include #include @@ -707,15 +708,13 @@ static void arizona_micd_timeout_work(struct work_struct *work) struct arizona_priv, micd_timeout_work.work); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n"); info->detecting = false; arizona_identify_headphone(info); - - mutex_unlock(&info->lock); } static int arizona_micd_adc_read(struct arizona_priv *info) @@ -921,12 +920,11 @@ static void arizona_micd_detect(struct work_struct *work) cancel_delayed_work_sync(&info->micd_timeout_work); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); /* If the cable was removed while measuring ignore the result */ if (!(info->jack->status & SND_JACK_MECHANICAL)) { dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); - mutex_unlock(&info->lock); return; } @@ -936,7 +934,6 @@ static void arizona_micd_detect(struct work_struct *work) arizona_button_reading(info); pm_runtime_mark_last_busy(arizona->dev); - mutex_unlock(&info->lock); } static irqreturn_t arizona_micdet(int irq, void *data) @@ -948,10 +945,10 @@ static irqreturn_t arizona_micdet(int irq, void *data) cancel_delayed_work_sync(&info->micd_detect_work); cancel_delayed_work_sync(&info->micd_timeout_work); - mutex_lock(&info->lock); - if (!info->detecting) - debounce = 0; - mutex_unlock(&info->lock); + scoped_guard(mutex, &info->lock) { + if (!info->detecting) + debounce = 0; + } if (debounce) queue_delayed_work(system_power_efficient_wq, @@ -969,9 +966,8 @@ static void arizona_hpdet_work(struct work_struct *work) struct arizona_priv, hpdet_work.work); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); arizona_start_hpdet_acc_id(info); - mutex_unlock(&info->lock); } static int arizona_hpdet_wait(struct arizona_priv *info) @@ -1018,9 +1014,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data) cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); - pm_runtime_get_sync(arizona->dev); + guard(pm_runtime_active_auto)(arizona->dev); - mutex_lock(&info->lock); + guard(mutex)(&info->lock); if (info->micd_clamp) { mask = ARIZONA_MICD_CLAMP_STS; @@ -1036,8 +1032,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data) ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); if (ret) { dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); - mutex_unlock(&info->lock); - pm_runtime_put_autosuspend(arizona->dev); return IRQ_NONE; } @@ -1056,62 +1050,61 @@ static irqreturn_t arizona_jackdet(int irq, void *data) &info->micd_timeout_work, msecs_to_jiffies(micd_timeout)); } + } else { + info->last_jackdet = val; - goto out; - } - info->last_jackdet = val; + if (info->last_jackdet == present) { + dev_dbg(arizona->dev, "Detected jack\n"); + snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); - if (info->last_jackdet == present) { - dev_dbg(arizona->dev, "Detected jack\n"); - snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); + info->detecting = true; + info->mic = false; + info->jack_flips = 0; - info->detecting = true; - info->mic = false; - info->jack_flips = 0; + if (!arizona->pdata.hpdet_acc_id) { + arizona_start_mic(info); + } else { + queue_delayed_work(system_power_efficient_wq, + &info->hpdet_work, + msecs_to_jiffies(HPDET_DEBOUNCE)); + } - if (!arizona->pdata.hpdet_acc_id) { - arizona_start_mic(info); + if (info->micd_clamp || !arizona->pdata.jd_invert) + regmap_update_bits(arizona->regmap, + ARIZONA_JACK_DETECT_DEBOUNCE, + ARIZONA_MICD_CLAMP_DB | + ARIZONA_JD1_DB, 0); } else { - queue_delayed_work(system_power_efficient_wq, - &info->hpdet_work, - msecs_to_jiffies(HPDET_DEBOUNCE)); - } + dev_dbg(arizona->dev, "Detected jack removal\n"); + + arizona_stop_mic(info); + + info->num_hpdet_res = 0; + for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) + info->hpdet_res[i] = 0; + info->mic = false; + info->hpdet_done = false; + info->hpdet_retried = false; + + snd_soc_jack_report(info->jack, 0, + ARIZONA_JACK_MASK | info->micd_button_mask); + + /* + * If the jack was removed during a headphone detection we + * need to wait for the headphone detection to finish, as + * it can not be aborted. We don't want to be able to start + * a new headphone detection from a fresh insert until this + * one is finished. + */ + arizona_hpdet_wait(info); - if (info->micd_clamp || !arizona->pdata.jd_invert) regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, - ARIZONA_MICD_CLAMP_DB | - ARIZONA_JD1_DB, 0); - } else { - dev_dbg(arizona->dev, "Detected jack removal\n"); - - arizona_stop_mic(info); - - info->num_hpdet_res = 0; - for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) - info->hpdet_res[i] = 0; - info->mic = false; - info->hpdet_done = false; - info->hpdet_retried = false; - - snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask); - - /* - * If the jack was removed during a headphone detection we - * need to wait for the headphone detection to finish, as - * it can not be aborted. We don't want to be able to start - * a new headphone detection from a fresh insert until this - * one is finished. - */ - arizona_hpdet_wait(info); - - regmap_update_bits(arizona->regmap, - ARIZONA_JACK_DETECT_DEBOUNCE, - ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, - ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, + ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); + } } -out: /* Clear trig_sts to make sure DCVDD is not forced up */ regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, ARIZONA_MICD_CLAMP_FALL_TRIG_STS | @@ -1119,10 +1112,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data) ARIZONA_JD1_FALL_TRIG_STS | ARIZONA_JD1_RISE_TRIG_STS); - mutex_unlock(&info->lock); - - pm_runtime_put_autosuspend(arizona->dev); - return IRQ_HANDLED; } From fa58edfcce1c9f86353960700905dbeae512b419 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:41 +0700 Subject: [PATCH 174/438] ASoC: codecs: arizona: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 8c683b0bb74c..4411165c3734 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -7,6 +7,7 @@ * Author: Mark Brown */ +#include #include #include #include @@ -1158,17 +1159,16 @@ int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags) struct arizona_priv *priv = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&priv->dvfs_lock); + guard(mutex)(&priv->dvfs_lock); if (!priv->dvfs_cached && !priv->dvfs_reqs) { ret = arizona_dvfs_enable(component); if (ret) - goto err; + return ret; } priv->dvfs_reqs |= flags; -err: - mutex_unlock(&priv->dvfs_lock); + return ret; } EXPORT_SYMBOL_GPL(arizona_dvfs_up); @@ -1179,7 +1179,7 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags) unsigned int old_reqs; int ret = 0; - mutex_lock(&priv->dvfs_lock); + guard(mutex)(&priv->dvfs_lock); old_reqs = priv->dvfs_reqs; priv->dvfs_reqs &= ~flags; @@ -1187,7 +1187,6 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags) if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs) ret = arizona_dvfs_disable(component); - mutex_unlock(&priv->dvfs_lock); return ret; } EXPORT_SYMBOL_GPL(arizona_dvfs_down); @@ -1199,7 +1198,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, struct arizona_priv *priv = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&priv->dvfs_lock); + guard(mutex)(&priv->dvfs_lock); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1222,7 +1221,6 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, break; } - mutex_unlock(&priv->dvfs_lock); return ret; } EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev); @@ -1657,13 +1655,11 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component, { 0x80, 0x0 }, }; - mutex_lock(&arizona->dac_comp_lock); - - dac_comp[1].def = arizona->dac_comp_coeff; - if (rate >= 176400) - dac_comp[2].def = arizona->dac_comp_enabled; - - mutex_unlock(&arizona->dac_comp_lock); + scoped_guard(mutex, &arizona->dac_comp_lock) { + dac_comp[1].def = arizona->dac_comp_coeff; + if (rate >= 176400) + dac_comp[2].def = arizona->dac_comp_enabled; + } regmap_multi_reg_write(arizona->regmap, dac_comp, From 95cc462fe4212e0cf64546da1ecfbd88d7f6cac4 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:42 +0700 Subject: [PATCH 175/438] ASoC: codecs: aw87390: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw87390.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c index 020213e0ca4b..8150670fde2d 100644 --- a/sound/soc/codecs/aw87390.c +++ b/sound/soc/codecs/aw87390.c @@ -7,6 +7,7 @@ // Author: Weidong Wang // +#include #include #include #include @@ -225,11 +226,10 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol, struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); int ret; - mutex_lock(&aw87390->lock); + guard(mutex)(&aw87390->lock); ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change\n"); - mutex_unlock(&aw87390->lock); return 0; } @@ -238,8 +238,6 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol, aw87390_power_on(aw87390->aw_pa); } - mutex_unlock(&aw87390->lock); - return 1; } @@ -280,14 +278,12 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390) return ret; } - mutex_lock(&aw87390->lock); + guard(mutex)(&aw87390->lock); ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg); if (ret) dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n"); - mutex_unlock(&aw87390->lock); - return ret; } From 9c3035088593abcf44900c5f218f5f8bd290be63 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:43 +0700 Subject: [PATCH 176/438] ASoC: codecs: aw88081: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-7-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88081.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c index d5e886a8f106..a3cc027de606 100644 --- a/sound/soc/codecs/aw88081.c +++ b/sound/soc/codecs/aw88081.c @@ -7,6 +7,7 @@ // Author: Weidong Wang // +#include #include #include #include @@ -763,9 +764,8 @@ static void aw88081_startup_work(struct work_struct *work) struct aw88081 *aw88081 = container_of(work, struct aw88081, start_work.work); - mutex_lock(&aw88081->lock); + guard(mutex)(&aw88081->lock); aw88081_start_pa(aw88081); - mutex_unlock(&aw88081->lock); } static void aw88081_start(struct aw88081 *aw88081, bool sync_start) @@ -942,11 +942,10 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol, int ret; /* pa stop or stopping just set profile */ - mutex_lock(&aw88081->lock); + guard(mutex)(&aw88081->lock); ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88081->lock); return 0; } @@ -955,8 +954,6 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol, aw88081_start(aw88081, AW88081_SYNC_START); } - mutex_unlock(&aw88081->lock); - return 1; } @@ -1165,11 +1162,9 @@ static int aw88081_request_firmware_file(struct aw88081 *aw88081) if (ret) return ret; - mutex_lock(&aw88081->lock); - ret = aw88081_dev_init(aw88081, aw88081->aw_cfg); - mutex_unlock(&aw88081->lock); + guard(mutex)(&aw88081->lock); - return ret; + return aw88081_dev_init(aw88081, aw88081->aw_cfg); } static int aw88081_playback_event(struct snd_soc_dapm_widget *w, @@ -1178,7 +1173,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88081->lock); + guard(mutex)(&aw88081->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88081_start(aw88081, AW88081_ASYNC_START); @@ -1189,7 +1184,6 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88081->lock); return 0; } From a0c8cd0ecfe7b017a442943f23989d01c4dcc6a7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:44 +0700 Subject: [PATCH 177/438] ASoC: codecs: aw88166: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-8-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88166.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c index 3f15f4ac51f7..b72f87f677dd 100644 --- a/sound/soc/codecs/aw88166.c +++ b/sound/soc/codecs/aw88166.c @@ -7,6 +7,7 @@ // Author: Weidong Wang // +#include #include #include #include @@ -1173,9 +1174,8 @@ static void aw88166_startup_work(struct work_struct *work) struct aw88166 *aw88166 = container_of(work, struct aw88166, start_work.work); - mutex_lock(&aw88166->lock); + guard(mutex)(&aw88166->lock); aw88166_start_pa(aw88166); - mutex_unlock(&aw88166->lock); } static void aw88166_start(struct aw88166 *aw88166, bool sync_start) @@ -1413,11 +1413,10 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol, struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); int ret; - mutex_lock(&aw88166->lock); + guard(mutex)(&aw88166->lock); ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88166->lock); return 0; } @@ -1426,8 +1425,6 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol, aw88166_start(aw88166, AW88166_SYNC_START); } - mutex_unlock(&aw88166->lock); - return 1; } @@ -1607,12 +1604,12 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166) return ret; } - mutex_lock(&aw88166->lock); - /* aw device init */ - ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); - if (ret) - dev_err(aw88166->aw_pa->dev, "dev init failed\n"); - mutex_unlock(&aw88166->lock); + scoped_guard(mutex, &aw88166->lock) { + /* aw device init */ + ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); + if (ret) + dev_err(aw88166->aw_pa->dev, "dev init failed\n"); + } return ret; } @@ -1639,7 +1636,7 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88166->lock); + guard(mutex)(&aw88166->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88166_start(aw88166, AW88166_ASYNC_START); @@ -1650,7 +1647,6 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88166->lock); return 0; } From 9d8e98091f5a9aee81b8f758f31cd70f5c948b7b Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:45 +0700 Subject: [PATCH 178/438] ASoC: codecs: aw88261: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-9-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88261.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index 549783d3e75e..b931b8602566 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -8,6 +8,7 @@ // Author: Weidong Wang // +#include #include #include #include @@ -960,11 +961,10 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, int ret; /* pa stop or stopping just set profile */ - mutex_lock(&aw88261->lock); + guard(mutex)(&aw88261->lock); ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88261->lock); return 0; } @@ -973,8 +973,6 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, aw88261_start(aw88261); } - mutex_unlock(&aw88261->lock); - return 1; } @@ -1038,7 +1036,7 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88261->lock); + guard(mutex)(&aw88261->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88261_start(aw88261); @@ -1049,7 +1047,6 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88261->lock); return 0; } @@ -1188,12 +1185,12 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261) return ret; } - mutex_lock(&aw88261->lock); - /* aw device init */ - ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); - if (ret) - dev_err(aw88261->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88261->lock); + scoped_guard(mutex, &aw88261->lock) { + /* aw device init */ + ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); + if (ret) + dev_err(aw88261->aw_pa->dev, "dev init failed"); + } return ret; } From 6699b73f0080a87af8d1e052e912bef06587c426 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:46 +0700 Subject: [PATCH 179/438] ASoC: codecs: aw88395: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-10-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88395/aw88395.c | 24 ++++++-------- sound/soc/codecs/aw88395/aw88395_device.c | 40 ++++++++--------------- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c index ee0e8bd8c54c..e9ff2c79ac15 100644 --- a/sound/soc/codecs/aw88395/aw88395.c +++ b/sound/soc/codecs/aw88395/aw88395.c @@ -8,6 +8,7 @@ // Author: Weidong Wang // +#include #include #include #include @@ -51,9 +52,8 @@ static void aw88395_startup_work(struct work_struct *work) struct aw88395 *aw88395 = container_of(work, struct aw88395, start_work.work); - mutex_lock(&aw88395->lock); + guard(mutex)(&aw88395->lock); aw88395_start_pa(aw88395); - mutex_unlock(&aw88395->lock); } static void aw88395_start(struct aw88395 *aw88395, bool sync_start) @@ -224,11 +224,10 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol, int ret; /* pa stop or stopping just set profile */ - mutex_lock(&aw88395->lock); + guard(mutex)(&aw88395->lock); ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]); if (ret < 0) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88395->lock); return 0; } @@ -237,8 +236,6 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol, aw88395_start(aw88395, AW88395_SYNC_START); } - mutex_unlock(&aw88395->lock); - return 1; } @@ -366,7 +363,7 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88395->lock); + guard(mutex)(&aw88395->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88395_start(aw88395, AW88395_ASYNC_START); @@ -377,7 +374,6 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88395->lock); return 0; } @@ -495,12 +491,12 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395) dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__); - mutex_lock(&aw88395->lock); - /* aw device init */ - ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); - if (ret < 0) - dev_err(aw88395->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88395->lock); + scoped_guard(mutex, &aw88395->lock) { + /* aw device init */ + ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); + if (ret < 0) + dev_err(aw88395->aw_pa->dev, "dev init failed"); + } return ret; } diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c index 79c3135a4110..12d42d27560d 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.c +++ b/sound/soc/codecs/aw88395/aw88395_device.c @@ -8,6 +8,7 @@ // Author: Ben Yi // +#include #include #include #include @@ -70,7 +71,7 @@ int aw_dev_dsp_write(struct aw_device *aw_dev, u32 reg_value; int ret; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); switch (data_type) { case AW_DSP_16_DATA: ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data); @@ -93,7 +94,6 @@ int aw_dev_dsp_write(struct aw_device *aw_dev, /* clear dsp chip select state*/ if (regmap_read(aw_dev->regmap, AW88395_ID_REG, ®_value)) dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); - mutex_unlock(&aw_dev->dsp_lock); return ret; } @@ -156,7 +156,7 @@ int aw_dev_dsp_read(struct aw_device *aw_dev, u32 reg_value; int ret; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); switch (data_type) { case AW_DSP_16_DATA: ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data); @@ -179,7 +179,6 @@ int aw_dev_dsp_read(struct aw_device *aw_dev, /* clear dsp chip select state*/ if (regmap_read(aw_dev->regmap, AW88395_ID_REG, ®_value)) dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); - mutex_unlock(&aw_dev->dsp_lock); return ret; } @@ -1110,42 +1109,36 @@ static int aw_dev_dsp_update_container(struct aw_device *aw_dev, #ifdef AW88395_DSP_I2C_WRITES u32 tmp_len; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base); if (ret) - goto error_operation; + return ret; for (i = 0; i < len; i += AW88395_MAX_RAM_WRITE_BYTE_SIZE) { tmp_len = min(len - i, AW88395_MAX_RAM_WRITE_BYTE_SIZE); ret = regmap_raw_write(aw_dev->regmap, AW88395_DSPMDAT_REG, &data[i], tmp_len); if (ret) - goto error_operation; + return ret; } - mutex_unlock(&aw_dev->dsp_lock); #else __be16 reg_val; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); /* i2c write */ ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base); if (ret) - goto error_operation; + return ret; for (i = 0; i < len; i += 2) { reg_val = cpu_to_be16p((u16 *)(data + i)); ret = regmap_write(aw_dev->regmap, AW88395_DSPMDAT_REG, (u16)reg_val); if (ret) - goto error_operation; + return ret; } - mutex_unlock(&aw_dev->dsp_lock); #endif return 0; - -error_operation: - mutex_unlock(&aw_dev->dsp_lock); - return ret; } static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, @@ -1231,14 +1224,14 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) { unsigned int reg_val; - mutex_lock(&aw_dev->dsp_lock); + guard(mutex)(&aw_dev->dsp_lock); /* check the odd bits of reg 0x40 */ regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, AW88395_DSP_ODD_NUM_BIT_TEST); regmap_read(aw_dev->regmap, AW88395_DSPMADD_REG, ®_val); if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check reg 0x40 odd bit failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_ODD_NUM_BIT_TEST); - goto error; + return -EPERM; } /* check the even bits of reg 0x40 */ @@ -1247,7 +1240,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check reg 0x40 even bit failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST); - goto error; + return -EPERM; } /* check dsp_fw_base_addr */ @@ -1256,7 +1249,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check dsp fw addr failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST); - goto error; + return -EPERM; } /* check dsp_cfg_base_addr */ @@ -1265,15 +1258,10 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) { dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", reg_val, AW88395_DSP_ODD_NUM_BIT_TEST); - goto error; + return -EPERM; } - mutex_unlock(&aw_dev->dsp_lock); return 0; - -error: - mutex_unlock(&aw_dev->dsp_lock); - return -EPERM; } int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en) From 49204ed803502f13f63ec515144ad656b3381d38 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:47 +0700 Subject: [PATCH 180/438] ASoC: codecs: aw88399: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-11-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88399.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index b2ec3503f7e2..67ea073abdb7 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -7,6 +7,7 @@ // Author: Weidong Wang // +#include #include #include #include @@ -1140,9 +1141,8 @@ static void aw88399_startup_work(struct work_struct *work) struct aw88399 *aw88399 = container_of(work, struct aw88399, start_work.work); - mutex_lock(&aw88399->lock); + guard(mutex)(&aw88399->lock); aw88399_start_pa(aw88399); - mutex_unlock(&aw88399->lock); } static void aw88399_start(struct aw88399 *aw88399, bool sync_start) @@ -1702,11 +1702,10 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol, struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec); int ret; - mutex_lock(&aw88399->lock); + guard(mutex)(&aw88399->lock); ret = aw88399_dev_set_profile_index(aw88399->aw_pa, ucontrol->value.integer.value[0]); if (ret) { dev_dbg(codec->dev, "profile index does not change"); - mutex_unlock(&aw88399->lock); return 0; } @@ -1715,8 +1714,6 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol, aw88399_start(aw88399, AW88399_SYNC_START); } - mutex_unlock(&aw88399->lock); - return 1; } @@ -1939,12 +1936,11 @@ static int aw88399_request_firmware_file(struct aw88399 *aw88399) return ret; } - mutex_lock(&aw88399->lock); + guard(mutex)(&aw88399->lock); /* aw device init */ ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); if (ret) dev_err(aw88399->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88399->lock); return ret; } @@ -1975,7 +1971,7 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component); - mutex_lock(&aw88399->lock); + guard(mutex)(&aw88399->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: aw88399_start(aw88399, AW88399_ASYNC_START); @@ -1986,7 +1982,6 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w, default: break; } - mutex_unlock(&aw88399->lock); return 0; } From 35150d26cb41ac4f5de6480ee468745e39fbf114 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:48 +0700 Subject: [PATCH 181/438] ASoC: codecs: cros_ec_codec: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Tzung-Bi Shih Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-12-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 7dc5a7c3ca96..fd2d5d7f9276 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -608,10 +609,10 @@ static void wov_copy_work(struct work_struct *w) container_of(w, struct cros_ec_codec_priv, wov_copy_work.work); int ret; - mutex_lock(&priv->wov_dma_lock); + guard(mutex)(&priv->wov_dma_lock); if (!priv->wov_substream) { dev_warn(priv->dev, "no pcm substream\n"); - goto leave; + return; } if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) @@ -624,8 +625,6 @@ static void wov_copy_work(struct work_struct *w) msecs_to_jiffies(10)); else if (ret) dev_err(priv->dev, "failed to read audio data\n"); -leave: - mutex_unlock(&priv->wov_dma_lock); } static int wov_enable_get(struct snd_kcontrol *kcontrol, @@ -895,12 +894,11 @@ static int wov_pcm_hw_params(struct snd_soc_component *component, struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->wov_dma_lock); + guard(mutex)(&priv->wov_dma_lock); priv->wov_substream = substream; priv->wov_rp = priv->wov_wp = 0; priv->wov_dma_offset = 0; priv->wov_burst_read = true; - mutex_unlock(&priv->wov_dma_lock); return 0; } @@ -911,10 +909,10 @@ static int wov_pcm_hw_free(struct snd_soc_component *component, struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->wov_dma_lock); - wov_queue_dequeue(priv, wov_queue_size(priv)); - priv->wov_substream = NULL; - mutex_unlock(&priv->wov_dma_lock); + scoped_guard(mutex, &priv->wov_dma_lock) { + wov_queue_dequeue(priv, wov_queue_size(priv)); + priv->wov_substream = NULL; + } cancel_delayed_work_sync(&priv->wov_copy_work); From 53651103db9291c240f0b48e16004c63075215ec Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:49 +0700 Subject: [PATCH 182/438] ASoC: codecs: cs-amp-lib: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-13-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs-amp-lib.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c index 371e99205b58..41a9a5b005c6 100644 --- a/sound/soc/codecs/cs-amp-lib.c +++ b/sound/soc/codecs/cs-amp-lib.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -83,10 +84,12 @@ static int cs_amp_write_cal_coeff(struct cs_dsp *dsp, KUNIT_STATIC_STUB_REDIRECT(cs_amp_write_cal_coeff, dsp, controls, ctl_name, val); if (IS_REACHABLE(CONFIG_FW_CS_DSP)) { - mutex_lock(&dsp->pwr_lock); - cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval)); - mutex_unlock(&dsp->pwr_lock); + scoped_guard(mutex, &dsp->pwr_lock) { + cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, + controls->mem_region, + controls->alg_id); + ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval)); + } if (ret < 0) { dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret); From fa08036d5d5b4777d9ef7942bf13b3071ee5ffe7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:50 +0700 Subject: [PATCH 183/438] ASoC: codecs: cs35l56: Use guard() and PM runtime scope helpers Convert the interrupt handler to use guard(mutex) for automatic mutex unlocking and PM_RUNTIME_ACQUIRE_IF_ENABLED() to manage the runtime PM reference through scope-based cleanup. This removes the explicit cleanup paths while preserving the existing behavior. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-14-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-shared.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index f14e2eaaa4ee..d5817e420847 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -640,23 +640,22 @@ irqreturn_t cs35l56_irq(int irq, void *data) unsigned int val; int rv; - irqreturn_t ret = IRQ_NONE; - if (!cs35l56_base->init_done) return IRQ_NONE; - mutex_lock(&cs35l56_base->irq_lock); + guard(mutex)(&cs35l56_base->irq_lock); - rv = pm_runtime_resume_and_get(cs35l56_base->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED(cs35l56_base->dev, pm); + rv = PM_RUNTIME_ACQUIRE_ERR(&pm); if (rv < 0) { dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); - goto err_unlock; + return IRQ_NONE; } regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); if ((val & CS35L56_IRQ1_STS_MASK) == 0) { dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); - goto err; + return IRQ_NONE; } /* Ack interrupts */ @@ -680,7 +679,7 @@ irqreturn_t cs35l56_irq(int irq, void *data) /* Check to see if unmasked bits are active */ if (!status1 && !status8 && !status20) - goto err; + return IRQ_NONE; if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) dev_crit(cs35l56_base->dev, "Amp short error\n"); @@ -688,14 +687,7 @@ irqreturn_t cs35l56_irq(int irq, void *data) if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) dev_crit(cs35l56_base->dev, "Overtemp error\n"); - ret = IRQ_HANDLED; - -err: - pm_runtime_put(cs35l56_base->dev); -err_unlock: - mutex_unlock(&cs35l56_base->irq_lock); - - return ret; + return IRQ_HANDLED; } EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED"); From 6e982e8f5a23e027e757712b750be4e4dd9d4950 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:51 +0700 Subject: [PATCH 184/438] ASoC: codecs: cs42l42: Use guard() cleanup helpers Clean up the code using guard() helpers for mutex locking and PM runtime management. No functional change intended. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-15-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 56 +++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 2652a639a79a..fadf68860601 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -9,6 +9,7 @@ * Author: Michael White */ +#include #include #include #include @@ -565,7 +566,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); /* Prevent race with interrupt handler */ - mutex_lock(&cs42l42->irq_lock); + guard(mutex)(&cs42l42->irq_lock); cs42l42->jack = jk; if (jk) { @@ -581,7 +582,6 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ break; } } - mutex_unlock(&cs42l42->irq_lock); return 0; } @@ -1668,13 +1668,10 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) unsigned int current_button_status; unsigned int i; - pm_runtime_get_sync(cs42l42->dev); - mutex_lock(&cs42l42->irq_lock); - if (cs42l42->suspended || !cs42l42->init_done) { - mutex_unlock(&cs42l42->irq_lock); - pm_runtime_put_autosuspend(cs42l42->dev); + guard(pm_runtime_active_auto)(cs42l42->dev); + guard(mutex)(&cs42l42->irq_lock); + if (cs42l42->suspended || !cs42l42->init_done) return IRQ_NONE; - } /* Read sticky registers to clear interurpt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { @@ -1774,9 +1771,6 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) } } - mutex_unlock(&cs42l42->irq_lock); - pm_runtime_put_autosuspend(cs42l42->dev); - return IRQ_HANDLED; } EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE"); @@ -2163,23 +2157,23 @@ int cs42l42_suspend(struct device *dev) * future interrupts. This ensures a safe disable if the interrupt * is shared. */ - mutex_lock(&cs42l42->irq_lock); - cs42l42->suspended = true; + scoped_guard(mutex, &cs42l42->irq_lock) { + cs42l42->suspended = true; - /* Save register values that will be overwritten by shutdown sequence */ - for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { - regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); - save_regs[i] = (u8)reg; + /* Save register values that will be overwritten by shutdown sequence */ + for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { + regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); + save_regs[i] = (u8)reg; + } + + /* Shutdown codec */ + regmap_multi_reg_write(cs42l42->regmap, + cs42l42_shutdown_seq, + ARRAY_SIZE(cs42l42_shutdown_seq)); + + /* All interrupt sources are now disabled */ } - /* Shutdown codec */ - regmap_multi_reg_write(cs42l42->regmap, - cs42l42_shutdown_seq, - ARRAY_SIZE(cs42l42_shutdown_seq)); - - /* All interrupt sources are now disabled */ - mutex_unlock(&cs42l42->irq_lock); - /* Wait for power-down complete */ msleep(CS42L42_PDN_DONE_TIME_MS); ret = regmap_read_poll_timeout(cs42l42->regmap, @@ -2250,13 +2244,13 @@ void cs42l42_resume_restore(struct device *dev) regcache_cache_only(cs42l42->regmap, false); regcache_mark_dirty(cs42l42->regmap); - mutex_lock(&cs42l42->irq_lock); - /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ - regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); - regcache_sync(cs42l42->regmap); + scoped_guard(mutex, &cs42l42->irq_lock) { + /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ + regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); + regcache_sync(cs42l42->regmap); - cs42l42->suspended = false; - mutex_unlock(&cs42l42->irq_lock); + cs42l42->suspended = false; + } dev_dbg(dev, "System resumed\n"); } From d1b5d20f53df626521a90e3aa63876d47518253c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:52 +0700 Subject: [PATCH 185/438] ASoC: codecs: cs42l43: Use guard() and PM runtime scope helpers Convert mutex locking to guard(mutex) and replace explicit runtime PM handling with runtime PM scope helpers. This simplifies the control flow by removing explicit cleanup paths and unnecessary 'goto' labels. Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-16-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l43-jack.c | 138 ++++++++++++++------------------ sound/soc/codecs/cs42l43.c | 16 ++-- 2 files changed, 65 insertions(+), 89 deletions(-) diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c index 934666295ee3..1f0a5c5cac8a 100644 --- a/sound/soc/codecs/cs42l43-jack.c +++ b/sound/soc/codecs/cs42l43-jack.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. #include +#include #include #include #include @@ -67,6 +68,21 @@ static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const pro return -EINVAL; } +static void cs42l43_apply_accdet_config(struct cs42l43_codec *priv, + unsigned int autocontrol, + unsigned int pdncntl) +{ + struct cs42l43 *cs42l43 = priv->core; + + regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, + CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | + CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); + regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, + CS42L43_RING_SENSE_EN_MASK, pdncntl); + + dev_dbg(priv->dev, "Successfully configured accessory detect\n"); +} + int cs42l43_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *d) { @@ -80,31 +96,34 @@ int cs42l43_set_jack(struct snd_soc_component *component, dev_dbg(priv->dev, "Configure accessory detect\n"); - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret); return ret; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); priv->jack_hp = jack; - if (!jack) - goto done; + if (!jack) { + cs42l43_apply_accdet_config(priv, autocontrol, pdncntl); + return 0; + } ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms"); if (ret != -EINVAL) { if (ret < 0) { dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n", ret); - goto error; + return ret; } if (ret > CS42L43_N_BUTTONS) { ret = -EINVAL; dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n"); - goto error; + return ret; } ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms", @@ -112,7 +131,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, if (ret < 0) { dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n", ret); - goto error; + return ret; } } else { priv->buttons[0] = 70; @@ -124,7 +143,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, 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; + return ret; hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT; @@ -134,7 +153,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms, ARRAY_SIZE(cs42l43_accdet_ramp_ms)); if (ret < 0) - goto error; + return ret; hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT; @@ -142,7 +161,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->bias_sense_ua, cs42l43_accdet_bias_sense, ARRAY_SIZE(cs42l43_accdet_bias_sense)); if (ret < 0) - goto error; + return ret; if (priv->bias_sense_ua) autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT; @@ -154,7 +173,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->tip_debounce_ms); if (ret < 0 && ret != -EINVAL) { dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret); - goto error; + return ret; } /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */ @@ -170,7 +189,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->tip_fall_db_ms, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT; @@ -178,7 +197,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, &priv->tip_rise_db_ms, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT; @@ -199,7 +218,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, NULL, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT; @@ -207,7 +226,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, NULL, cs42l43_accdet_db_ms, ARRAY_SIZE(cs42l43_accdet_db_ms)); if (ret < 0) - goto error; + return ret; ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT; pdncntl |= CS42L43_RING_SENSE_EN_MASK; @@ -228,23 +247,9 @@ int cs42l43_set_jack(struct snd_soc_component *component, CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK | CS42L43_AUTO_HSDET_TIME_MASK, hs2); -done: - ret = 0; + cs42l43_apply_accdet_config(priv, autocontrol, pdncntl); - regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, - CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | - CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); - regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, - CS42L43_RING_SENSE_EN_MASK, pdncntl); - - dev_dbg(priv->dev, "Successfully configured accessory detect\n"); - -error: - mutex_unlock(&priv->jack_lock); - - pm_runtime_put_autosuspend(priv->dev); - - return ret; + return 0; } static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect) @@ -369,22 +374,22 @@ irqreturn_t cs42l43_button_press(int irq, void *data) { struct cs42l43_codec *priv = data; struct cs42l43 *cs42l43 = priv->core; - irqreturn_t iret = IRQ_NONE; unsigned int buttons = 0; unsigned int val = 0; int i, ret; - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for button press: %d\n", ret); - return iret; + return IRQ_NONE; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); if (!priv->button_detect_running) { dev_dbg(priv->dev, "Spurious button press IRQ\n"); - goto error; + return IRQ_NONE; } // Wait for 2 full cycles of comb filter to ensure good reading @@ -395,12 +400,12 @@ irqreturn_t cs42l43_button_press(int irq, void *data) /* Bail if jack removed, the button is irrelevant and likely invalid */ if (!cs42l43_jack_present(priv)) { dev_dbg(priv->dev, "Button ignored due to removal\n"); - goto error; + return IRQ_NONE; } if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) { dev_dbg(priv->dev, "Button ignored due to bias sense\n"); - goto error; + return IRQ_NONE; } val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT; @@ -423,45 +428,32 @@ irqreturn_t cs42l43_button_press(int irq, void *data) snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS); - iret = IRQ_HANDLED; - -error: - mutex_unlock(&priv->jack_lock); - - pm_runtime_put_autosuspend(priv->dev); - - return iret; + return IRQ_HANDLED; } irqreturn_t cs42l43_button_release(int irq, void *data) { struct cs42l43_codec *priv = data; - irqreturn_t iret = IRQ_NONE; int ret; - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for button release: %d\n", ret); - return iret; + return IRQ_NONE; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); - if (priv->button_detect_running) { - dev_dbg(priv->dev, "Button release IRQ\n"); - - snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); - - iret = IRQ_HANDLED; - } else { + if (!priv->button_detect_running) { dev_dbg(priv->dev, "Spurious button release IRQ\n"); + return IRQ_NONE; } - mutex_unlock(&priv->jack_lock); + dev_dbg(priv->dev, "Button release IRQ\n"); + snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); - pm_runtime_put_autosuspend(priv->dev); - - return iret; + return IRQ_HANDLED; } void cs42l43_bias_sense_timeout(struct work_struct *work) @@ -471,13 +463,14 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) struct cs42l43 *cs42l43 = priv->core; int ret; - ret = pm_runtime_resume_and_get(priv->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); if (ret) { dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret); return; } - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); if (cs42l43_jack_present(priv) && priv->button_detect_running) { dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n"); @@ -490,10 +483,6 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); } - - mutex_unlock(&priv->jack_lock); - - pm_runtime_put_autosuspend(priv->dev); } static const struct reg_sequence cs42l43_3pole_patch[] = { @@ -895,9 +884,8 @@ int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); ucontrol->value.integer.value[0] = priv->jack_override; - mutex_unlock(&priv->jack_lock); return 0; } @@ -913,17 +901,13 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u if (override >= e->items) return -EINVAL; - mutex_lock(&priv->jack_lock); + guard(mutex)(&priv->jack_lock); - if (!cs42l43_jack_present(priv)) { - mutex_unlock(&priv->jack_lock); + if (!cs42l43_jack_present(priv)) return -EBUSY; - } - if (override == priv->jack_override) { - mutex_unlock(&priv->jack_lock); + if (override == priv->jack_override) return 0; - } priv->jack_override = override; @@ -983,7 +967,5 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u cs42l43_jack_override_modes[override].report); } - mutex_unlock(&priv->jack_lock); - return 1; } diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 1d133577702e..47308cd870fb 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1207,14 +1208,12 @@ static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv) { struct cs42l43 *cs42l43 = priv->core; - mutex_lock(&priv->spk_vu_lock); + guard(mutex)(&priv->spk_vu_lock); regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK); regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, CS42L43_AMP1_2_VU_MASK, 0); - - mutex_unlock(&priv->spk_vu_lock); } static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift) @@ -1601,7 +1600,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, struct cs42l43 *cs42l43 = priv->core; int ret; - mutex_lock(&cs42l43->pll_lock); + guard(mutex)(&cs42l43->pll_lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1626,8 +1625,6 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, break; } - mutex_unlock(&cs42l43->pll_lock); - return ret; } @@ -2565,13 +2562,10 @@ static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id, { struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); struct cs42l43 *cs42l43 = priv->core; - int ret; - mutex_lock(&cs42l43->pll_lock); - ret = cs42l43_set_pll(priv, src, freq); - mutex_unlock(&cs42l43->pll_lock); + guard(mutex)(&cs42l43->pll_lock); - return ret; + return cs42l43_set_pll(priv, src, freq); } static int cs42l43_component_probe(struct snd_soc_component *component) From 2f952d2ff5f2c23d1f0083f6d2196bdc12a73820 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:53 +0700 Subject: [PATCH 186/438] ASoC: codecs: cs42l84: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-17-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l84.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c index f2a58163de0e..36533a13319d 100644 --- a/sound/soc/codecs/cs42l84.c +++ b/sound/soc/codecs/cs42l84.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -281,10 +282,9 @@ static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_ struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); /* Prevent race with interrupt handler */ - mutex_lock(&cs42l84->irq_lock); + guard(mutex)(&cs42l84->irq_lock); cs42l84->jack = jk; snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET); - mutex_unlock(&cs42l84->irq_lock); return 0; } @@ -831,7 +831,7 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) u8 current_ring_state; int i; - mutex_lock(&cs42l84->irq_lock); + guard(mutex)(&cs42l84->irq_lock); /* Read sticky registers to clear interrupt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { regmap_read(cs42l84->regmap, irq_params_table[i].status_addr, @@ -902,8 +902,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) break; } - mutex_unlock(&cs42l84->irq_lock); - return IRQ_HANDLED; } @@ -919,8 +917,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) } } - mutex_unlock(&cs42l84->irq_lock); - return IRQ_HANDLED; } From e6eb5e269d88d2d8622c070c865a12d65d494b43 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:54 +0700 Subject: [PATCH 187/438] ASoC: codecs: cs43130: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Charles Keepax Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-18-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs43130.c | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index e7b06f962790..48d88dad4ceb 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -6,6 +6,7 @@ * * Authors: Li Xu */ +#include #include #include #include @@ -818,26 +819,26 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, unsigned int required_clk; u8 dsd_speed; - mutex_lock(&cs43130->clk_mutex); - if (!cs43130->clk_req) { - /* no DAI is currently using clk */ - if (!(CS43130_MCLK_22M % params_rate(params))) - required_clk = CS43130_MCLK_22M; - else - required_clk = CS43130_MCLK_24M; + scoped_guard(mutex, &cs43130->clk_mutex) { + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + if (!(CS43130_MCLK_22M % params_rate(params))) + required_clk = CS43130_MCLK_22M; + else + required_clk = CS43130_MCLK_24M; - cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); - if (cs43130->pll_bypass) - cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); - else - cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); + if (cs43130->pll_bypass) + cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + } + + cs43130->clk_req++; + if (cs43130->clk_req == 2) + cs43130_pcm_dsd_mix(true, cs43130->regmap); } - cs43130->clk_req++; - if (cs43130->clk_req == 2) - cs43130_pcm_dsd_mix(true, cs43130->regmap); - mutex_unlock(&cs43130->clk_mutex); - switch (params_rate(params)) { case 176400: dsd_speed = 0; @@ -881,26 +882,26 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, unsigned int required_clk; u8 dsd_speed; - mutex_lock(&cs43130->clk_mutex); - if (!cs43130->clk_req) { - /* no DAI is currently using clk */ - if (!(CS43130_MCLK_22M % params_rate(params))) - required_clk = CS43130_MCLK_22M; - else - required_clk = CS43130_MCLK_24M; + scoped_guard(mutex, &cs43130->clk_mutex) { + if (!cs43130->clk_req) { + /* no DAI is currently using clk */ + if (!(CS43130_MCLK_22M % params_rate(params))) + required_clk = CS43130_MCLK_22M; + else + required_clk = CS43130_MCLK_24M; - cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); - if (cs43130->pll_bypass) - cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); - else - cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); + if (cs43130->pll_bypass) + cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); + else + cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); + } + + cs43130->clk_req++; + if (cs43130->clk_req == 2) + cs43130_pcm_dsd_mix(true, cs43130->regmap); } - cs43130->clk_req++; - if (cs43130->clk_req == 2) - cs43130_pcm_dsd_mix(true, cs43130->regmap); - mutex_unlock(&cs43130->clk_mutex); - switch (dai->id) { case CS43130_ASP_DOP_DAI: case CS43130_XSP_DOP_DAI: @@ -988,14 +989,13 @@ static int cs43130_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); - mutex_lock(&cs43130->clk_mutex); + guard(mutex)(&cs43130->clk_mutex); cs43130->clk_req--; if (!cs43130->clk_req) { /* no DAI is currently using clk */ cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO); cs43130_pcm_dsd_mix(false, cs43130->regmap); } - mutex_unlock(&cs43130->clk_mutex); return 0; } From a97c200c2fed53e698e8f99cb2cf584f33246696 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:55 +0700 Subject: [PATCH 188/438] ASoC: codecs: cs47l15: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-19-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l15.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index da64e0a1db28..2f30dd834709 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include #include #include #include @@ -1285,9 +1286,8 @@ static int cs47l15_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -1317,9 +1317,8 @@ static void cs47l15_component_remove(struct snd_soc_component *component) struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); struct madera *madera = cs47l15->core.madera; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; wm_adsp2_component_remove(&cs47l15->core.adsp[0], component); } From db698e37213b29ccd680950593484652ae9f527a Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:56 +0700 Subject: [PATCH 189/438] ASoC: codecs: cs47l35: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-20-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l35.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index a8fe5a99a8bb..e77ac7bc8466 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include #include #include #include @@ -1566,9 +1567,8 @@ static int cs47l35_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -1600,9 +1600,8 @@ static void cs47l35_component_remove(struct snd_soc_component *component) struct madera *madera = cs47l35->core.madera; int i; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; for (i = 0; i < CS47L35_NUM_ADSP; i++) wm_adsp2_component_remove(&cs47l35->core.adsp[i], component); From cea70877a2a191a6149544da7efeb12da2509cc8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:57 +0700 Subject: [PATCH 190/438] ASoC: codecs: cs47l85: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-21-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l85.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index 42fafb0b392c..9ee60616c04c 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include #include #include #include @@ -2504,9 +2505,8 @@ static int cs47l85_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -2537,9 +2537,8 @@ static void cs47l85_component_remove(struct snd_soc_component *component) struct madera *madera = cs47l85->core.madera; int i; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; for (i = 0; i < CS47L85_NUM_ADSP; i++) wm_adsp2_component_remove(&cs47l85->core.adsp[i], component); From 1b681fda5e51d4ff8b7c39a30e7069e780ec304f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:58 +0700 Subject: [PATCH 191/438] ASoC: codecs: cs47l90: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-22-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l90.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index 77e8aabb241a..6ce603bfd500 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include #include #include #include @@ -2423,9 +2424,8 @@ static int cs47l90_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -2456,9 +2456,8 @@ static void cs47l90_component_remove(struct snd_soc_component *component) struct madera *madera = cs47l90->core.madera; int i; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; for (i = 0; i < CS47L90_NUM_ADSP; i++) wm_adsp2_component_remove(&cs47l90->core.adsp[i], component); From f452b00f97ced4ad14913a3e6de4f3086a3f6c4c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:49:59 +0700 Subject: [PATCH 192/438] ASoC: codecs: cs47l92: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-23-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l92.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index 868237bd6d91..07bc303d9797 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include #include #include #include @@ -1892,9 +1893,8 @@ static int cs47l92_component_probe(struct snd_soc_component *component) snd_soc_component_init_regmap(component, madera->regmap); - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = snd_soc_component_to_dapm(component); - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = snd_soc_component_to_dapm(component); ret = madera_init_inputs(component); if (ret) @@ -1922,9 +1922,8 @@ static void cs47l92_component_remove(struct snd_soc_component *component) struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); struct madera *madera = cs47l92->core.madera; - mutex_lock(&madera->dapm_ptr_lock); - madera->dapm = NULL; - mutex_unlock(&madera->dapm_ptr_lock); + scoped_guard(mutex, &madera->dapm_ptr_lock) + madera->dapm = NULL; wm_adsp2_component_remove(&cs47l92->core.adsp[0], component); } From 6ced86b1e21b951d33031910606219fb6a496d4f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:50:00 +0700 Subject: [PATCH 193/438] ASoC: codecs: cs48l32: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-24-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs48l32.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c index 086ed0f57a85..a9967771124e 100644 --- a/sound/soc/codecs/cs48l32.c +++ b/sound/soc/codecs/cs48l32.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -236,15 +237,13 @@ static int cs48l32_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v int ret; /* Prevent any mixer mux changes while we do this */ - mutex_lock(&cs48l32_codec->rate_lock); + guard(mutex)(&cs48l32_codec->rate_lock); /* The write must be guarded by a number of SYSCLK cycles */ cs48l32_spin_sysclk(cs48l32_codec); ret = snd_soc_put_enum_double(kcontrol, ucontrol); cs48l32_spin_sysclk(cs48l32_codec); - mutex_unlock(&cs48l32_codec->rate_lock); - return ret; } @@ -2242,7 +2241,6 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai, struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1]; unsigned int base = dai->driver->base; unsigned int current_asp_rate, target_asp_rate; - bool change_rate_domain = false; int ret; if (clk_id == dai_priv->clk) @@ -2284,19 +2282,15 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai, if ((current_asp_rate & CS48L32_ASP_RATE_MASK) != (target_asp_rate & CS48L32_ASP_RATE_MASK)) { - change_rate_domain = true; - - mutex_lock(&cs48l32_codec->rate_lock); /* Guard the rate change with SYSCLK cycles */ - cs48l32_spin_sysclk(cs48l32_codec); - } - - snd_soc_component_update_bits(component, base + CS48L32_ASP_CONTROL1, - CS48L32_ASP_RATE_MASK, target_asp_rate); - - if (change_rate_domain) { - cs48l32_spin_sysclk(cs48l32_codec); - mutex_unlock(&cs48l32_codec->rate_lock); + scoped_guard(mutex, &cs48l32_codec->rate_lock) { + cs48l32_spin_sysclk(cs48l32_codec); + snd_soc_component_update_bits(component, + base + CS48L32_ASP_CONTROL1, + CS48L32_ASP_RATE_MASK, + target_asp_rate); + cs48l32_spin_sysclk(cs48l32_codec); + } } } From 1b302f955ecb2831f7fcc626fa6e35dc8d80d9d7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 8 Jul 2026 19:50:01 +0700 Subject: [PATCH 194/438] ASoC: codecs: cx2072x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Cezary Rojewski Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260708125002.202515-25-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 83c6cbd40804..908344ee5892 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -9,6 +9,7 @@ // #include +#include #include #include #include @@ -1408,7 +1409,7 @@ static int cx2072x_jack_status_check(void *data) unsigned int type = 0; int state = 0; - mutex_lock(&cx2072x->lock); + guard(mutex)(&cx2072x->lock); regmap_read(cx2072x->regmap, CX2072X_PORTA_PIN_SENSE, &jack); jack = jack >> 24; @@ -1434,8 +1435,6 @@ static int cx2072x_jack_status_check(void *data) /* clear interrupt */ regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24); - mutex_unlock(&cx2072x->lock); - dev_dbg(codec->dev, "CX2072X_HSDETECT type=0x%X,Jack state = %x\n", type, state); return state; From 72fe2ef11df581a36b4134107eb792eedd4bc35e Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Thu, 2 Jul 2026 23:31:46 +0200 Subject: [PATCH 195/438] ASoC: meson: aiu-formatter-i2s: remove pipeline reset from prepare 'aiu-fifo-i2s' (DAI FE) already resets the I2S pipeline in 'aiu_fifo_i2s_trigger' for all relevant trigger scenarios, right before starting the FIFO. Since the DAI triggering order is the default one (FE before BE), the reset performed in 'aiu_formatter_i2s_prepare' happens after the FIFO has already been reset and started, which corrupts playback in 24-bit mode. Remove the duplicated reset from the formatter. Signed-off-by: Valerio Setti Link: https://patch.msgid.link/20260702-fix-24-bit-i2s-playback-v2-1-9c008ff0b211@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-formatter-i2s.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-formatter-i2s.c index b4604734fe88..cb554c2e7ce4 100644 --- a/sound/soc/meson/aiu-formatter-i2s.c +++ b/sound/soc/meson/aiu-formatter-i2s.c @@ -13,7 +13,6 @@ #define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) #define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) #define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) -#define AIU_RST_SOFT_I2S_FAST BIT(0) #define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) @@ -55,11 +54,11 @@ static int aiu_formatter_i2s_prepare(struct regmap *map, { /* Always operate in split (classic interleaved) mode */ unsigned int desc = 0; - unsigned int tmp; - /* Reset required to update the pipeline */ - regmap_write(map, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST); - regmap_read(map, AIU_I2S_SYNC, &tmp); + /* + * Pipeline reset is already implemented in aiu_fifo_i2s_trigger() at + * trigger time. + */ switch (ts->physical_width) { case 16: /* Nothing to do */ From eceeb7a564f8422a6b8fbfdcc34f6f1c340bc247 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 14 Jul 2026 23:19:49 +0800 Subject: [PATCH 196/438] ASoC: sun4i-codec: Sort sound related #include statements Some of the sound related #include statements are not ordered in alphabetic order. Sort them. This results in no functional change. Signed-off-by: Chen-Yu Tsai Acked-by: Jernej Skrabec Link: https://patch.msgid.link/20260714151950.316035-1-wens@kernel.org Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index f4e22af594fa..b45010875518 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -22,13 +22,13 @@ #include #include +#include +#include #include #include #include #include #include -#include -#include /* Codec DAC digital controls and FIFO registers */ #define SUN4I_CODEC_DAC_DPC (0x00) From 70d0d7b24d8606effdcbc0b0dec6955759ed36c7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 12:11:12 +0700 Subject: [PATCH 197/438] ASoC: tegra: tegra20_das: Use dev_err_probe() for error handling Replace the existing dev_err() and PTR_ERR() sequence with dev_err_probe(), preserving the original error code while simplifying the error handling. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260715051115.17385-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_das.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index b48cc4a6967b..ea8bc9bcfa67 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -167,10 +167,9 @@ static int tegra20_das_probe(struct platform_device *pdev) das->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &tegra20_das_regmap_config); - if (IS_ERR(das->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); - return PTR_ERR(das->regmap); - } + if (IS_ERR(das->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(das->regmap), + "regmap init failed\n"); tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_1, TEGRA20_DAS_DAP_SEL_DAC1); From b82384bffb27467e2e3966831d83eff3a6e1fbbb Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 12:11:13 +0700 Subject: [PATCH 198/438] ASoC: tegra: tegra210_adx: Return the original error directly snd_soc_add_component_controls() already reports failures internally. Return its error code directly instead of logging the error again in the component probe callback. Also remove the now unnecessary local error variable. Signed-off-by: bui duc phuc Reviewed-by: Thierry Reding Link: https://patch.msgid.link/20260715051115.17385-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_adx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 15a94196ee1a..e75bf50f8fb0 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -496,16 +496,12 @@ static struct snd_kcontrol_new tegra264_adx_controls[] = { static int tegra210_adx_component_probe(struct snd_soc_component *component) { struct tegra210_adx *adx = snd_soc_component_get_drvdata(component); - int err = 0; - if (adx->soc_data->num_controls) { - err = snd_soc_add_component_controls(component, adx->soc_data->controls, - adx->soc_data->num_controls); - if (err) - dev_err(component->dev, "can't add ADX controls, err: %d\n", err); - } + if (adx->soc_data->num_controls) + return snd_soc_add_component_controls(component, adx->soc_data->controls, + adx->soc_data->num_controls); - return err; + return 0; } static const struct snd_soc_component_driver tegra210_adx_cmpnt = { From f7cbc51424cd22098b0e6c09cbe338d7cd6137a7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 12:11:14 +0700 Subject: [PATCH 199/438] ASoC: tegra: tegra210_amx: Return the original error directly snd_soc_add_component_controls() already reports failures internally. Return its error code directly instead of logging the error again in the component probe callback. Also remove the now unnecessary local error variable. Signed-off-by: bui duc phuc Reviewed-by: Thierry Reding Link: https://patch.msgid.link/20260715051115.17385-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_amx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index cc1f9c158191..6a67ce6128b4 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -504,16 +504,12 @@ static struct snd_kcontrol_new tegra264_amx_controls[] = { static int tegra210_amx_component_probe(struct snd_soc_component *component) { struct tegra210_amx *amx = snd_soc_component_get_drvdata(component); - int err = 0; - if (amx->soc_data->num_controls) { - err = snd_soc_add_component_controls(component, amx->soc_data->controls, - amx->soc_data->num_controls); - if (err) - dev_err(component->dev, "can't add AMX controls, err: %d\n", err); - } + if (amx->soc_data->num_controls) + return snd_soc_add_component_controls(component, amx->soc_data->controls, + amx->soc_data->num_controls); - return err; + return 0; } static const struct snd_soc_component_driver tegra210_amx_cmpnt = { From 226791fa6dbb1e1c6d4c8ac4d10b6c73f0dc32e1 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 12:11:15 +0700 Subject: [PATCH 200/438] ASoC: tegra: tegra210: Use devm_clk_get_optional() for sync_input clock The existing comment states that the sync_input clock is only needed when another I/O is configured to use the current I2S instance as its input clock, and the current code does not treat its absence as an error. Use devm_clk_get_optional() to match the existing behaviour while still reporting real failures via dev_err_probe(). Update the comment to describe the optional nature of the clock rather than the previous error handling. Signed-off-by: bui duc phuc Reviewed-by: Thierry Reding Link: https://patch.msgid.link/20260715051115.17385-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_i2s.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index ff8c72fc38c5..e7e26e917291 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -1078,13 +1078,13 @@ static int tegra210_i2s_probe(struct platform_device *pdev) "can't retrieve I2S bit clock\n"); /* - * Not an error, as this clock is needed only when some other I/O - * requires input clock from current I2S instance, which is - * configurable from DT. + * This clock is optional and is only needed when another I/O uses + * the current I2S instance as its input clock, as configured in DT. */ - i2s->clk_sync_input = devm_clk_get(dev, "sync_input"); + i2s->clk_sync_input = devm_clk_get_optional(dev, "sync_input"); if (IS_ERR(i2s->clk_sync_input)) - dev_dbg(dev, "can't retrieve I2S sync input clock\n"); + return dev_err_probe(dev, PTR_ERR(i2s->clk_sync_input), + "can't retrieve I2S sync input clock\n"); regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) From 3330b5f6d8dea66df51c07362f01a39ad9845aad Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 15 Jul 2026 13:01:33 +0100 Subject: [PATCH 201/438] ASoC: cs35l56: Add support for CS35L62 for SoundWire CS35L62 uses the same control and regmap interface as CS35L63 so support for it can be added into the CS35L56 driver. Signed-off-by: Stefan Binding Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260715120135.939280-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-sdw.c | 2 ++ sound/soc/codecs/cs35l56-shared.c | 4 ++++ sound/soc/codecs/cs35l56.c | 1 + 3 files changed, 7 insertions(+) diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 0a55b93b96f9..1e442f43b306 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -457,6 +457,7 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi regmap_config = &cs35l56_regmap_sdw; break; case 0x3563: + case 0x3562: regmap_config = &cs35l63_regmap_sdw; break; default: @@ -510,6 +511,7 @@ static const struct sdw_device_id cs35l56_sdw_id[] = { SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556), SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557), SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563), + SDW_SLAVE_ENTRY(0x01FA, 0x3562, 0x3562), {}, }; MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index f14e2eaaa4ee..ab811f95f935 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -96,6 +96,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) ARRAY_SIZE(cs35l56_patch_fw)); break; case 0x63: + case 0x62: ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw, ARRAY_SIZE(cs35l63_patch_fw)); break; @@ -389,6 +390,7 @@ static void cs35l56_set_fw_reg_table(struct cs35l56_base *cs35l56_base) } break; case 0x63: + case 0x62: cs35l56_base->fw_reg = &cs35l63_fw_reg; break; } @@ -595,6 +597,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) } break; case 0x63: + case 0x62: regmap_multi_reg_write_bypassed(cs35l56_base->regmap, cs35l63_system_reset_seq, ARRAY_SIZE(cs35l63_system_reset_seq)); @@ -1470,6 +1473,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) cs35l56_base->calibration_controls = &cs35l56_calibration_controls; break; case 0x35A630: + case 0x35A620: cs35l56_base->calibration_controls = &cs35l63_calibration_controls; devid = devid >> 4; break; diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 570a68829ccd..f365f76ce56c 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1402,6 +1402,7 @@ static int _cs35l56_component_probe(struct snd_soc_component *component) ARRAY_SIZE(cs35l56_controls)); break; case 0x63: + case 0x62: ret = snd_soc_add_component_controls(component, cs35l63_controls, ARRAY_SIZE(cs35l63_controls)); break; From 0306d211558196e051b83e067ee4c30e1b6f94a8 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 15 Jul 2026 13:01:34 +0100 Subject: [PATCH 202/438] ASoC: sdw_utils: Add codec info for CS35L62 CS35L62 is very similar to CS35L63, and uses the same driver, so we can use the same configuration. Signed-off-by: Stefan Binding Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260715120135.939280-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdw_utils/soc_sdw_utils.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index d8db8fc5313e..e490f37448b1 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -834,6 +834,35 @@ struct asoc_sdw_codec_info codec_info_list[] = { }, .dai_num = 2, }, + { + .vendor_id = 0x01fa, + .part_id = 0x3562, + .name_prefix = "AMP", + .is_amp = true, + .dais = { + { + .direction = {true, false}, + .dai_name = "cs35l56-sdw1", + .component_name = "cs35l56", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_cs_amp_init, + .rtd_init = asoc_sdw_cs_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + { + .direction = {false, true}, + .dai_name = "cs35l56-sdw1c", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, + }, + }, + .dai_num = 2, + }, { .vendor_id = 0x01fa, .part_id = 0x3563, From 73080a7976edde1c61f3654308ffe77c428ad6a2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2026 02:13:15 +0000 Subject: [PATCH 203/438] ASoC: generic: Card name parsing should be called after xxx_for_each_link() "tidyup simple_util_parse_xxx() in xxx_parse_of()" commit changed the function call order. But simple_util_parse_card_name() should be called after dai_link settings, because it might use dai_link->name as card->name. Fixes: fa6222d5e121 ("ASoC: audio-graph-card2: tidyup simple_util_parse_xxx() in audio_graph2_parse_of()") Fixes: b8081307f5c9 ("ASoC: audio-graph-card: tidyup simple_util_parse_xxx() in audio_graph_parse_of()") Fixes: 27ecf4da5ad3 ("ASoC: simple-card: tidyup simple_util_parse_xxx() in simple_parse_of()") Reported-by: Mark Brown Link: https://lore.kernel.org/r/b81ebfa2-6a35-4ff0-9d04-b867233eda4d@sirena.org.uk Reported-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20260714103428.2318895-1-geert+renesas@glider.be Signed-off-by: Kuninori Morimoto Tested-by: Geert Uytterhoeven Link: https://patch.msgid.link/87zezt0zlw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 9 +++++---- sound/soc/generic/audio-graph-card2.c | 9 +++++---- sound/soc/generic/simple-card.c | 9 +++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 73ea562ce52b..0a8a6d891d1f 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -587,10 +587,6 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto end; - ret = simple_util_parse_card_name(priv, NULL); - if (ret < 0) - goto err; - memset(li, 0, sizeof(*li)); ret = graph_for_each_link(priv, li, graph_dai_link_of, @@ -598,6 +594,11 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto err; + /* Card name should be set after graph_for_each_link() */ + ret = simple_util_parse_card_name(priv, NULL); + if (ret < 0) + goto err; + snd_soc_card_set_drvdata(card, priv); simple_util_debug_info(priv); diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index e3e92025b317..9fb3d3df5cf6 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -1344,10 +1344,6 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, if (ret < 0) goto end; - ret = simple_util_parse_card_name(priv, NULL); - if (ret < 0) - goto err; - ret = simple_util_parse_aux_devs(priv, NULL); if (ret < 0) goto err; @@ -1357,6 +1353,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, if (ret < 0) goto err; + /* Card name should be set after graph_for_each_link() */ + ret = simple_util_parse_card_name(priv, NULL); + if (ret < 0) + goto err; + snd_soc_card_set_drvdata(card, priv); if ((hooks) && (hooks)->hook_post) { diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6e98e973e525..e7ad7af04714 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -704,10 +704,6 @@ static int simple_parse_of(struct simple_util_priv *priv) if (ret < 0) goto end; - ret = simple_util_parse_card_name(priv, PREFIX); - if (ret < 0) - goto err; - ret = simple_util_parse_aux_devs(priv, PREFIX); if (ret < 0) goto err; @@ -720,6 +716,11 @@ static int simple_parse_of(struct simple_util_priv *priv) if (ret < 0) goto err; + /* Card name should be set after simple_for_each_link() */ + ret = simple_util_parse_card_name(priv, PREFIX); + if (ret < 0) + goto err; + ret = simple_populate_aux(priv); if (ret < 0) goto err; From 6173e18dd47cce430506c2f642e0b8d8db51ff1e Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Wed, 15 Jul 2026 17:25:13 +0530 Subject: [PATCH 204/438] ASoC: codecs: lpass-wsa-macro: check clk_set_rate() return value clk_set_rate() returns 0 on success or a negative errno on failure but the WSA macro probe function is ignoring it. Check the return value and bail out of probe on failure. Reviewed-by: Konrad Dybcio Signed-off-by: Ajay Kumar Nandam Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260715-xo-sd-codec-wsa-va-clk-set-rate-v2-1-16ca64c2b929@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index f511816aa4a0..fc9e0a37c042 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2773,8 +2773,13 @@ static int wsa_macro_probe(struct platform_device *pdev) wsa->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); - clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); + ret = clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); + if (ret) + return ret; + + ret = clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); + if (ret) + return ret; ret = devm_pm_clk_create(dev); if (ret) From 4fddda16f939b6ee53c6946ad71a2ea1fabf43c5 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Nandam Date: Wed, 15 Jul 2026 17:25:14 +0530 Subject: [PATCH 205/438] ASoC: codecs: lpass-va-macro: check clk_set_rate() return value clk_set_rate() returns 0 on success or a negative errno on failure but the VA macro probe function is ignoring it. Check the return value and bail out of probe on failure. Reviewed-by: Konrad Dybcio Signed-off-by: Ajay Kumar Nandam Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260715-xo-sd-codec-wsa-va-clk-set-rate-v2-2-16ca64c2b929@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 946051698420..dbc5795b9273 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1605,7 +1605,9 @@ static int va_macro_probe(struct platform_device *pdev) va->has_npl_clk = data->has_npl_clk; /* mclk rate */ - clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); + ret = clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); + if (ret) + goto err; if (va->has_npl_clk) { va->npl = devm_clk_get(dev, "npl"); @@ -1614,7 +1616,9 @@ static int va_macro_probe(struct platform_device *pdev) goto err; } - clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); + ret = clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); + if (ret) + goto err; } ret = devm_pm_clk_create(dev); From fcf2a365da23994f47af0f1203cf245d5e467b6a Mon Sep 17 00:00:00 2001 From: wangdicheng Date: Fri, 17 Jul 2026 17:15:40 +0800 Subject: [PATCH 206/438] ASoC: mediatek: mt8189: Remove redundant else-if branch with identical body Fix a compiler warning about a condition with no effect: sound/mediatek/mt8189/mt8189-dai-adda.c:388:7-9: WARNING: possible condition with no effect (if == else) The MTKAIF_PROTOCOL_2 branch and the else branch both write the same value 0xB0 to AFE_AUD_PAD_TOP_CFG0, making the else-if condition meaningless. Remove the redundant branch. Signed-off-by: wangdicheng Link: https://patch.msgid.link/20260717091542.721877-2-wangdich9700@163.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8189/mt8189-dai-adda.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c index ad5b9546ff63..5c41a6386204 100644 --- a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c +++ b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c @@ -385,8 +385,6 @@ static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, if (event == SND_SOC_DAPM_PRE_PMU) { if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8); - else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) - regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0); else regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0); } From a46ccc71877e962783e0fffa105e41615904c511 Mon Sep 17 00:00:00 2001 From: wangdicheng Date: Fri, 17 Jul 2026 17:15:42 +0800 Subject: [PATCH 207/438] ASoC: fsl_easrc: Use div64_u64 for 64-by-64 division Fix a coccinelle warning about do_div() truncating a 64-bit divisor: sound/soc/fsl/fsl_easrc.c:2061:2-8: WARNING: do_div() does a 64-by-32 division, please consider using div64_u64 instead. In fsl_easrc_m2m_calc_out_len(), val1 is computed as: val1 = (u64)in_rate << frac_bits; // frac_bits up to 39 do_div(val1, out_rate); val1 += (s64)ctx_priv->ratio_mod << (frac_bits - 31); val1 = val1 >> 12; In the worst case (in_rate=384000, out_rate=8000, frac_bits=39): val1 = 384000 << 39 / 8000 = 26,388,279,068,672 val1 >> 12 = 6,440,497,829 (33 bits, exceeds 32-bit range) val1 is then used as the divisor in do_div(val2, val1), where do_div() silently truncates it to 32 bits, producing incorrect results. Use div64_u64() to perform a proper 64-by-64 division. Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") Cc: stable@vger.kernel.org Signed-off-by: wangdicheng Link: https://patch.msgid.link/20260717091542.721877-4-wangdich9700@163.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index edfd943197a0..15a342496760 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2050,7 +2050,7 @@ static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buff /* right shift 12 bit to make ratio in 32bit space */ val2 = (u64)in_samples << (frac_bits - 12); val1 = val1 >> 12; - do_div(val2, val1); + val2 = div64_u64(val2, val1); out_samples = val2; out_length = out_samples * out_width * channels; From c462b2e14589780c2aba13156c117d90b2381157 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 17 Jul 2026 10:26:55 +0100 Subject: [PATCH 208/438] ASoC: cs35l56: Remove unnecessary goto in cs35l56_runtime_resume_common() The 'goto out_sync' in cs35l56_runtime_resume_common() is unnecessary because it only skips a single if-statement and function call. It can be replaced by inverting the conditional and merging it with the next if-statement. This was a legacy of an early version of the function, where more code was skipped by the goto. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260717092655.1730484-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-shared.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index f20bcdfd35af..b40bd3a8d27b 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -811,14 +811,10 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou if (!cs35l56_base->init_done) return 0; - if (!cs35l56_base->can_hibernate) - goto out_sync; - - /* Must be done before releasing cache-only */ - if (!is_soundwire) + /* Hibernate wake must be done before releasing cache-only */ + if (cs35l56_base->can_hibernate && !is_soundwire) cs35l56_issue_wake_event(cs35l56_base); -out_sync: ret = cs35l56_wait_for_firmware_boot(cs35l56_base); if (ret) { dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret); From d542c74cac07fdc6416fac04cf96c7e90c6b90f7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Jul 2026 19:22:47 +0200 Subject: [PATCH 209/438] ASoC: SOF: Intel: Don't use "proxy" headers Update header inclusions to follow IWYU (Include What You Use) principle. Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260717172318.1784073-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/icl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c index c1018893750c..549bb4ca73e1 100644 --- a/sound/soc/sof/intel/icl.c +++ b/sound/soc/sof/intel/icl.c @@ -9,10 +9,14 @@ * Hardware interface for audio DSP on IceLake. */ -#include -#include -#include +#include #include +#include +#include +#include +#include +#include + #include "../ipc4-priv.h" #include "../ops.h" #include "hda.h" From 50b2e4bfb4d4b7eee61a53a1524898b3f0512956 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Jul 2026 21:28:55 -0700 Subject: [PATCH 210/438] ASoC: wcd9335: switch to using sleeping variants of gpiod API The driver does not use gpiod API calls in an atomic context. Switch to gpiod_set_value_cansleep() calls to allow using the driver with GPIO controllers that might need process context to operate. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/alsAsTcQrpnnR46d@google.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index e3ca5ca6de3d..40de279a9750 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5010,9 +5010,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) */ usleep_range(600, 650); - gpiod_set_value(wcd->reset_gpio, 1); + gpiod_set_value_cansleep(wcd->reset_gpio, 1); msleep(20); - gpiod_set_value(wcd->reset_gpio, 0); + gpiod_set_value_cansleep(wcd->reset_gpio, 0); msleep(20); return 0; From c89b22faa9ba8ffaed2c696a360528844b5ba069 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 10 Jul 2026 18:02:49 +0700 Subject: [PATCH 211/438] ASoC: uniphier: Drop redundant error messages in probe Return the error directly when the helper already reports the failure, avoiding duplicate log messages. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260710110249.31830-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-cpu.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index d3dba21b2d04..78c82bf42a8f 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -795,16 +795,12 @@ int uniphier_aio_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(dev, &uniphier_aio_component, chip->chip_spec->dais, chip->chip_spec->num_dais); - if (ret) { - dev_err(dev, "Register component failed.\n"); + if (ret) goto err_out_reset; - } ret = uniphier_aiodma_soc_register_platform(pdev); - if (ret) { - dev_err(dev, "Register platform failed.\n"); + if (ret) goto err_out_reset; - } return 0; From 2aaa41cf974f83a6fb105422bac4e2f107150774 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Fri, 17 Jul 2026 09:24:33 +0800 Subject: [PATCH 212/438] ASoC: meson: Keep link pointers valid on realloc failure meson_card_reallocate_links() grows the DAI link and private data arrays with two consecutive krealloc() calls and updates the owner pointers only after both calls have succeeded. A successful krealloc() may move the data: it frees the old block and returns a new one. When that happens for the link array and the second krealloc() then fails, card->dai_link still points to the block that krealloc() already freed, and the error path frees the new block too. The probe error path then calls meson_card_clean_references(), which dereferences card->dai_link and kfree()s it again, resulting in a use-after-free and a double free. Commit card->dai_link and card->num_links right after the first krealloc() succeeds, so the pointer always refers to a valid allocation that meson_card_clean_references() can walk and free. krealloc() with __GFP_ZERO zero-initializes the added entries, so walking them on the error path is safe. With both failure paths reduced to a plain return, drop the goto labels and the error message. Fixes: 7864a79f37b5 ("ASoC: meson: add axg sound card support") Signed-off-by: Linmao Li Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/20260717012433.1432285-1-lilinmao@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/meson/meson-card-utils.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index cdb759b466ad..8617a4661a33 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -50,25 +50,20 @@ int meson_card_reallocate_links(struct snd_soc_card *card, num_links * sizeof(*priv->card.dai_link), GFP_KERNEL | __GFP_ZERO); if (!links) - goto err_links; + return -ENOMEM; + + priv->card.dai_link = links; + priv->card.num_links = num_links; ldata = krealloc(priv->link_data, num_links * sizeof(*priv->link_data), GFP_KERNEL | __GFP_ZERO); + /* meson_card_clean_references() will free the links on this error path */ if (!ldata) - goto err_ldata; + return -ENOMEM; - priv->card.dai_link = links; priv->link_data = ldata; - priv->card.num_links = num_links; return 0; - -err_ldata: - kfree(links); -err_links: - dev_err(priv->card.dev, "failed to allocate links\n"); - return -ENOMEM; - } EXPORT_SYMBOL_GPL(meson_card_reallocate_links); From acc414eda8e9b2e33c7afcd04549616b973704c2 Mon Sep 17 00:00:00 2001 From: Ethan Tidmore Date: Sun, 19 Jul 2026 17:15:02 -0500 Subject: [PATCH 213/438] ASoC: codecs: ES8389: Remove redundant comparison The comparison (target_hz < 0) will always be false because the variable 'target_hz' is of the u32 type. Remove redundant comparison and simply code around it. Fixes: 87592da1a490a ("ASoC: codecs: ES8389: Add private members about HPF") Signed-off-by: Ethan Tidmore Link: https://patch.msgid.link/20260719221502.536804-1-ethantidmore06@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8389.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c index 0c7567e2ffc2..80efce3e0a22 100644 --- a/sound/soc/codecs/es8389.c +++ b/sound/soc/codecs/es8389.c @@ -106,7 +106,7 @@ static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out) u32 f, diff; int i, j; - if ((target_hz > 1020) | (target_hz < 0)) + if (target_hz > 1020) return false; for (i = 0; i < 10; i++) { From 0f23ed0e117cbdb735be2d77b225cb92d0c6dff1 Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Mon, 13 Jul 2026 18:17:11 +0530 Subject: [PATCH 214/438] ASoC: dt-bindings: ti,omap4-dmic: Convert to DT schema Convert the TI OMAP4+ dmic bindings from txt to DT schema. Following changes are introduced during converson: - Drop ti,hwmods property as it is not needed since the sysc conversion no existing DTS uses it. - Add dma, dma-names, reg-names properties to match the DTS. - Update example node to match existing DTS. Signed-off-by: Bhargav Joshi Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260713-ti-omap4-dmic-v1-1-3cc6e13decec@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/omap-dmic.txt | 20 ------- .../bindings/sound/ti,omap4-dmic.yaml | 58 +++++++++++++++++++ 2 files changed, 58 insertions(+), 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/omap-dmic.txt create mode 100644 Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml diff --git a/Documentation/devicetree/bindings/sound/omap-dmic.txt b/Documentation/devicetree/bindings/sound/omap-dmic.txt deleted file mode 100644 index 418e30e72e89..000000000000 --- a/Documentation/devicetree/bindings/sound/omap-dmic.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Texas Instruments OMAP4+ Digital Microphone Module - -Required properties: -- compatible: "ti,omap4-dmic" -- reg: Register location and size as an array: - , - ; -- interrupts: Interrupt number for DMIC -- ti,hwmods: Name of the hwmod associated with OMAP dmic IP - -Example: - -dmic: dmic@4012e000 { - compatible = "ti,omap4-dmic"; - reg = <0x4012e000 0x7f>, /* MPU private access */ - <0x4902e000 0x7f>; /* L3 Interconnect */ - interrupts = <0 114 0x4>; - interrupt-parent = <&gic>; - ti,hwmods = "dmic"; -}; diff --git a/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml b/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml new file mode 100644 index 000000000000..773b9bf2f1c2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,omap4-dmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments OMAP4+ Digital Microphone Module + +maintainers: + - Peter Ujfalusi + +properties: + compatible: + const: ti,omap4-dmic + + reg: + items: + - description: MPU access base address + - description: L3 interconnect address + + reg-names: + items: + - const: mpu + - const: dma + + interrupts: + maxItems: 1 + + dmas: + maxItems: 1 + + dma-names: + items: + - const: up_link + +required: + - compatible + - reg + - reg-names + - interrupts + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + #include + + dmic@0 { + compatible = "ti,omap4-dmic"; + reg = <0x0 0x7f>, /* MPU private access */ + <0x4902e000 0x7f>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = ; + dmas = <&sdma 67>; + dma-names = "up_link"; + }; From 2462bdc608e6522413d5f0f103534c806aeb424f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:48:02 +0000 Subject: [PATCH 215/438] ASoC: amd: acp-sdw-legacy-mach: use &pdev->dev instead of card->dev acp-sdw-legacy-mach.c will be updated when Card capsuling. To makes its review easy, use &pdev->dev instead of card->dev in mc_probe(). There is no diff, because static int mc_probe(...) { ... card->dev = &pdev->dev; ... } No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/87a4rli04u.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-sdw-legacy-mach.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index 9726a9d33ec6..3a2034bd382b 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -521,15 +521,15 @@ static int mc_probe(struct platform_device *pdev) dmi_check_system(soc_sdw_quirk_table); if (quirk_override != -1) { - dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", soc_sdw_quirk, quirk_override); soc_sdw_quirk = quirk_override; } - log_quirks(card->dev); + log_quirks(&pdev->dev); ctx->mc_quirk = soc_sdw_quirk; - dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); + dev_dbg(&pdev->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ for (i = 0; i < ctx->codec_info_list_count; i++) codec_info_list[i].amp_num = 0; @@ -546,12 +546,12 @@ static int mc_probe(struct platform_device *pdev) for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, + card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, " cfg-amp:%d", amp_num); if (!card->components) return -ENOMEM; if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) { - card->components = devm_kasprintf(card->dev, GFP_KERNEL, + card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s mic:acp-dmic cfg-mics:%d", card->components, 1); @@ -560,9 +560,9 @@ static int mc_probe(struct platform_device *pdev) } /* Register the card */ - ret = devm_snd_soc_register_card(card->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret); asoc_sdw_mc_dailink_exit_loop(card); return ret; } From a429f382c0b00152c165f8563ed5136bce191123 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:48:05 +0000 Subject: [PATCH 216/438] ASoC: amd: acp-sdw-sof-mach: use &pdev->dev instead of card->dev acp-sdw-sof-mach.c will be updated when Card capsuling. To makes its review easy, use &pdev->dev instead of card->dev in mc_probe(). There is no diff, because static int mc_probe(...) { ... card->dev = &pdev->dev; ... } No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/878q75i04q.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-sdw-sof-mach.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index 963ce6fd4012..a1c5e97ad0b5 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -388,12 +388,12 @@ static int mc_probe(struct platform_device *pdev) dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { - dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", sof_sdw_quirk, quirk_override); sof_sdw_quirk = quirk_override; } - log_quirks(card->dev); + log_quirks(&pdev->dev); ctx->mc_quirk = sof_sdw_quirk; /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ @@ -412,15 +412,15 @@ static int mc_probe(struct platform_device *pdev) for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, + card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, " cfg-amp:%d", amp_num); if (!card->components) return -ENOMEM; /* Register the card */ - ret = devm_snd_soc_register_card(card->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret); asoc_sdw_mc_dailink_exit_loop(card); return ret; } From a846f5f62a8b5f7e1558bfc1805c898b7e4ec5fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:39:46 +0000 Subject: [PATCH 217/438] ASoC: qcom: common: use dev qcom_snd_parse_of() already have dev. Let's use it. No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/87pl0hi0il.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index edc4611691f7..e4ff247ea47f 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -91,7 +91,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = of_property_read_string(np, "link-name", &link->name); if (ret) { - dev_err(card->dev, "error getting codec dai_link name\n"); + dev_err(dev, "error getting codec dai_link name\n"); return ret; } @@ -109,7 +109,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); if (ret) { - dev_err_probe(card->dev, ret, + dev_err_probe(dev, ret, "%s: error getting cpu dai name\n", link->name); return ret; } @@ -126,7 +126,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) "sound-dai", 0); if (!link->platforms->of_node) { - dev_err(card->dev, "%s: platform dai not found\n", link->name); + dev_err(dev, "%s: platform dai not found\n", link->name); return -EINVAL; } } else { @@ -136,7 +136,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) if (codec) { ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { - dev_err_probe(card->dev, ret, + dev_err_probe(dev, ret, "%s: codec dai not found\n", link->name); return ret; } From af6111f7aa9a2433c6ccd1c1710345e2c81f8564 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:40:01 +0000 Subject: [PATCH 218/438] ASoC: qcom: sdm845: remove unused card It is not used. Let's remove. Signed-off-by: Kuninori Morimoto Reviewed-by: Srinivas Kandagatla Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/87o6g1i0i6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/sdm845.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 0ce9dff4dc52..6843ab8ba017 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -36,7 +36,6 @@ struct sdm845_snd_data { bool jack_setup; bool slim_port_setup; bool stream_prepared[AFE_PORT_MAX]; - struct snd_soc_card *card; uint32_t pri_mi2s_clk_count; uint32_t sec_mi2s_clk_count; uint32_t quat_tdm_clk_count; @@ -564,7 +563,6 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) if (ret) return ret; - data->card = card; snd_soc_card_set_drvdata(card, data); sdm845_add_ops(card); From 3c39af873af037149cdd8c57f9cc98b802fd27ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:40:10 +0000 Subject: [PATCH 219/438] ASoC: qcom: storm: use dev instead of card on storm_parse_of() storm_parse_of() can be processed without using *card. No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/87mrvli0hx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/qcom/storm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index 1e0eda8c24c4..6b42fbfd27ca 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -64,21 +64,21 @@ static struct snd_soc_dai_link storm_dai_link = { SND_SOC_DAILINK_REG(hifi), }; -static int storm_parse_of(struct snd_soc_card *card) +static int storm_parse_of(struct device *dev) { - struct snd_soc_dai_link *dai_link = card->dai_link; - struct device_node *np = card->dev->of_node; + struct snd_soc_dai_link *dai_link = &storm_dai_link; + struct device_node *np = dev->of_node; dai_link->cpus->of_node = of_parse_phandle(np, "cpu", 0); if (!dai_link->cpus->of_node) { - dev_err(card->dev, "error getting cpu phandle\n"); + dev_err(dev, "error getting cpu phandle\n"); return -EINVAL; } dai_link->platforms->of_node = dai_link->cpus->of_node; dai_link->codecs->of_node = of_parse_phandle(np, "codec", 0); if (!dai_link->codecs->of_node) { - dev_err(card->dev, "error getting codec phandle\n"); + dev_err(dev, "error getting codec phandle\n"); return -EINVAL; } @@ -106,7 +106,7 @@ static int storm_platform_probe(struct platform_device *pdev) card->dai_link = &storm_dai_link; card->num_links = 1; - ret = storm_parse_of(card); + ret = storm_parse_of(&pdev->dev); if (ret) { dev_err(&pdev->dev, "error resolving dai links: %d\n", ret); return ret; From 7fa44519a2a3a9da715669a7f359f08e49911e2f Mon Sep 17 00:00:00 2001 From: Marco Giunta Date: Fri, 17 Jul 2026 15:25:03 +0200 Subject: [PATCH 220/438] ASoC: aw88399: extract shared device library Extract the device-level functions from aw88399.c into a new shared library module (aw88399-lib.c) with a shared header at include/sound/aw88399.h, following the pattern established by CS35L41 (cs35l41-lib.c / include/sound/cs35l41.h) for chips that need both ASoC and HDA drivers. The shared header at include/sound/aw88399.h contains the register definitions, bit-field masks, hardware constants, device enums, the struct aw88399 definition, and the library function declarations. The ASoC-private header at sound/soc/codecs/aw88399.h is reduced to ASoC-specific definitions (PCM formats/rates, ALSA kcontrol helpers, calibration constants) and includes the shared header. The library contains the chip initialization, firmware loading, playback start/stop sequences, and all their internal dependencies (PLL checks, DSP management, volume control, calibration, CRC verification, etc.). The ASoC codec driver retains the ALSA controls, DAPM widgets, codec probe/remove, calibration service, and I2C bus driver registration. A new Kconfig symbol SND_SOC_AW88399_LIB is introduced. SND_SOC_AW88399 (the existing ASoC codec) selects it, ensuring no change for current users. The HDA side codec driver (introduced later in this series) selects the library without pulling in the full ASoC codec module. This avoids a build-time dependency on the full ASoC driver and follows the established pattern used by CS35L41 (SND_SOC_CS35L41_LIB) for chips with both ASoC and HDA drivers. Some library functions (DSP control, volume setting, mute, calibration updates, profile management, and status helpers) are used internally by the library's start/stop sequences but are also called directly by the ASoC driver's remaining code. These are exported from the library so the ASoC module can access them. This is a pure code movement with no functional changes. The moved functions are identical to their originals in aw88399.c. Tested-by: Nadim Kobeissi Tested-by: Xia Yun'an Tested-by: Munzir Taha Signed-off-by: Marco Giunta Link: https://patch.msgid.link/DS7PR19MB772415C485FAF74297673FD7FCC62@DS7PR19MB7724.namprd19.prod.outlook.com Signed-off-by: Mark Brown --- include/sound/aw88399.h | 618 ++++++++++++++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/aw88399-lib.c | 1381 ++++++++++++++++++++++++++++++++ sound/soc/codecs/aw88399.c | 1349 ------------------------------- sound/soc/codecs/aw88399.h | 582 +------------- 6 files changed, 2008 insertions(+), 1929 deletions(-) create mode 100644 include/sound/aw88399.h create mode 100644 sound/soc/codecs/aw88399-lib.c diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h new file mode 100644 index 000000000000..3a2153f0ee92 --- /dev/null +++ b/include/sound/aw88399.h @@ -0,0 +1,618 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * linux/sound/aw88399.h -- Platform data for AW88399 + * + * Copyright (c) 2023 AWINIC Technology CO., LTD + * + * Author: Weidong Wang + */ + +#ifndef __SOUND_AW88399_H +#define __SOUND_AW88399_H + +#include +#include + +/* registers list */ +#define AW88399_ID_REG (0x00) +#define AW88399_SYSST_REG (0x01) +#define AW88399_SYSINT_REG (0x02) +#define AW88399_SYSINTM_REG (0x03) +#define AW88399_SYSCTRL_REG (0x04) +#define AW88399_SYSCTRL2_REG (0x05) +#define AW88399_I2SCTRL1_REG (0x06) +#define AW88399_I2SCTRL2_REG (0x07) +#define AW88399_I2SCTRL3_REG (0x08) +#define AW88399_DACCFG1_REG (0x09) +#define AW88399_DACCFG2_REG (0x0A) +#define AW88399_DACCFG3_REG (0x0B) +#define AW88399_DACCFG4_REG (0x0C) +#define AW88399_DACCFG5_REG (0x0D) +#define AW88399_DACCFG6_REG (0x0E) +#define AW88399_DACCFG7_REG (0x0F) +#define AW88399_MPDCFG1_REG (0x10) +#define AW88399_MPDCFG2_REG (0x11) +#define AW88399_MPDCFG3_REG (0x12) +#define AW88399_MPDCFG4_REG (0x13) +#define AW88399_PWMCTRL1_REG (0x14) +#define AW88399_PWMCTRL2_REG (0x15) +#define AW88399_PWMCTRL3_REG (0x16) +#define AW88399_I2SCFG1_REG (0x17) +#define AW88399_DBGCTRL_REG (0x18) +#define AW88399_HAGCST_REG (0x20) +#define AW88399_VBAT_REG (0x21) +#define AW88399_TEMP_REG (0x22) +#define AW88399_PVDD_REG (0x23) +#define AW88399_ISNDAT_REG (0x24) +#define AW88399_VSNDAT_REG (0x25) +#define AW88399_I2SINT_REG (0x26) +#define AW88399_I2SCAPCNT_REG (0x27) +#define AW88399_ANASTA1_REG (0x28) +#define AW88399_ANASTA2_REG (0x29) +#define AW88399_ANASTA3_REG (0x2A) +#define AW88399_TESTDET_REG (0x2B) +#define AW88399_DSMCFG1_REG (0x30) +#define AW88399_DSMCFG2_REG (0x31) +#define AW88399_DSMCFG3_REG (0x32) +#define AW88399_DSMCFG4_REG (0x33) +#define AW88399_DSMCFG5_REG (0x34) +#define AW88399_DSMCFG6_REG (0x35) +#define AW88399_DSMCFG7_REG (0x36) +#define AW88399_DSMCFG8_REG (0x37) +#define AW88399_TESTIN_REG (0x38) +#define AW88399_TESTOUT_REG (0x39) +#define AW88399_MEMTEST_REG (0x3A) +#define AW88399_VSNCTRL1_REG (0x3B) +#define AW88399_ISNCTRL1_REG (0x3C) +#define AW88399_ISNCTRL2_REG (0x3D) +#define AW88399_DSPMADD_REG (0x40) +#define AW88399_DSPMDAT_REG (0x41) +#define AW88399_WDT_REG (0x42) +#define AW88399_ACR1_REG (0x43) +#define AW88399_ACR2_REG (0x44) +#define AW88399_ASR1_REG (0x45) +#define AW88399_ASR2_REG (0x46) +#define AW88399_DSPCFG_REG (0x47) +#define AW88399_ASR3_REG (0x48) +#define AW88399_ASR4_REG (0x49) +#define AW88399_DSPVCALB_REG (0x4A) +#define AW88399_CRCCTRL_REG (0x4B) +#define AW88399_DSPDBG1_REG (0x4C) +#define AW88399_DSPDBG2_REG (0x4D) +#define AW88399_DSPDBG3_REG (0x4E) +#define AW88399_PLLCTRL1_REG (0x50) +#define AW88399_PLLCTRL2_REG (0x51) +#define AW88399_PLLCTRL3_REG (0x52) +#define AW88399_CDACTRL1_REG (0x53) +#define AW88399_CDACTRL2_REG (0x54) +#define AW88399_CDACTRL3_REG (0x55) +#define AW88399_SADCCTRL1_REG (0x56) +#define AW88399_SADCCTRL2_REG (0x57) +#define AW88399_BOPCTRL1_REG (0x58) +#define AW88399_BOPCTRL2_REG (0x5A) +#define AW88399_BOPCTRL3_REG (0x5B) +#define AW88399_BOPCTRL4_REG (0x5C) +#define AW88399_BOPCTRL5_REG (0x5D) +#define AW88399_BOPCTRL6_REG (0x5E) +#define AW88399_BOPCTRL7_REG (0x5F) +#define AW88399_BSTCTRL1_REG (0x60) +#define AW88399_BSTCTRL2_REG (0x61) +#define AW88399_BSTCTRL3_REG (0x62) +#define AW88399_BSTCTRL4_REG (0x63) +#define AW88399_BSTCTRL5_REG (0x64) +#define AW88399_BSTCTRL6_REG (0x65) +#define AW88399_BSTCTRL7_REG (0x66) +#define AW88399_BSTCTRL8_REG (0x67) +#define AW88399_BSTCTRL9_REG (0x68) +#define AW88399_BSTCTRL10_REG (0x69) +#define AW88399_CPCTRL_REG (0x6A) +#define AW88399_EFWH_REG (0x6C) +#define AW88399_EFWM2_REG (0x6D) +#define AW88399_EFWM1_REG (0x6E) +#define AW88399_EFWL_REG (0x6F) +#define AW88399_TESTCTRL1_REG (0x70) +#define AW88399_TESTCTRL2_REG (0x71) +#define AW88399_EFCTRL1_REG (0x72) +#define AW88399_EFCTRL2_REG (0x73) +#define AW88399_EFRH4_REG (0x74) +#define AW88399_EFRH3_REG (0x75) +#define AW88399_EFRH2_REG (0x76) +#define AW88399_EFRH1_REG (0x77) +#define AW88399_EFRL4_REG (0x78) +#define AW88399_EFRL3_REG (0x79) +#define AW88399_EFRL2_REG (0x7A) +#define AW88399_EFRL1_REG (0x7B) +#define AW88399_TM_REG (0x7C) +#define AW88399_TM2_REG (0x7D) + +#define AW88399_REG_MAX (0x7E) +#define AW88399_MUTE_VOL (1023) + +#define AW88399_DSP_CFG_ADDR (0x9B00) +#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68) +#define AW88399_DSP_FW_ADDR (0x8980) +#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40) +#define AW88399_DSP_ROM_CHECK_DATA (0x4638) + +#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000)) +#define AW88399_CALI_RE_HBITS_SHIFT (16) + +#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF)) +#define AW88399_CALI_RE_LBITS_SHIFT (0) + +#define AW88399_I2STXEN_START_BIT (9) +#define AW88399_I2STXEN_BITS_LEN (1) +#define AW88399_I2STXEN_MASK \ + (~(((1<> (shift)) +#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000)) +#define AW88399_CRC_CHECK_PASS_VAL (0x4) + +#define AW88399_CRC_CFG_BASE_ADDR (0xD80) +#define AW88399_CRC_FW_BASE_ADDR (0x4C0) +#define AW88399_ACF_FILE "aw88399_acf.bin" +#define AW88399_DEV_SYSST_CHECK_MAX (10) +#define AW88399_CHIP_ID 0x2183 + +#define AW88399_START_RETRIES (5) +#define AW88399_START_WORK_DELAY_MS (0) + +enum { + AW_EF_AND_CHECK = 0, + AW_EF_OR_CHECK, +}; + +enum { + AW88399_DEV_VDSEL_DAC = 0, + AW88399_DEV_VDSEL_VSENSE = 32, +}; + +enum { + AW88399_DSP_CRC_NA = 0, + AW88399_DSP_CRC_OK = 1, +}; + +enum { + AW88399_DSP_FW_UPDATE_OFF = 0, + AW88399_DSP_FW_UPDATE_ON = 1, +}; + +enum { + AW88399_FORCE_UPDATE_OFF = 0, + AW88399_FORCE_UPDATE_ON = 1, +}; + +enum { + AW88399_1000_US = 1000, + AW88399_2000_US = 2000, + AW88399_3000_US = 3000, + AW88399_4000_US = 4000, +}; + +enum AW88399_DEV_STATUS { + AW88399_DEV_PW_OFF = 0, + AW88399_DEV_PW_ON, +}; + +enum AW88399_DEV_FW_STATUS { + AW88399_DEV_FW_FAILED = 0, + AW88399_DEV_FW_OK, +}; + +enum AW88399_DEV_MEMCLK { + AW88399_DEV_MEMCLK_OSC = 0, + AW88399_DEV_MEMCLK_PLL = 1, +}; + +enum AW88399_DEV_DSP_CFG { + AW88399_DEV_DSP_WORK = 0, + AW88399_DEV_DSP_BYPASS = 1, +}; + +enum { + AW88399_NOT_RCV_MODE = 0, + AW88399_RCV_MODE = 1, +}; + +enum { + AW88399_SYNC_START = 0, + AW88399_ASYNC_START, +}; + +struct aw_device; +struct aw_container; +struct aw_cali_desc; +struct gpio_desc; +struct i2c_client; +struct regmap; + +struct aw88399 { + struct aw_device *aw_pa; + struct mutex lock; + struct gpio_desc *reset_gpio; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + unsigned int check_val; + unsigned int crc_init_val; + unsigned int vcalb_init_val; + unsigned int dither_st; +}; + +int aw_dev_check_syspll(struct aw_device *aw_dev); +void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable); +int aw_dev_get_dsp_status(struct aw_device *aw_dev); +int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value); +int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc); +int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name); +void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute); +void aw88399_hw_reset(struct aw88399 *aw88399); +int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap); +extern const struct regmap_config aw88399_remap_config; +int aw88399_request_firmware_file(struct aw88399 *aw88399); +void aw88399_start(struct aw88399 *aw88399, bool sync_start); +void aw88399_startup_work(struct work_struct *work); +int aw88399_stop(struct aw_device *aw_dev); + +#endif /* __SOUND_AW88399_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 252f683be3c1..18e34899566e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -726,6 +726,10 @@ config SND_SOC_AW87390 sound quality, which is a new high efficiency, low noise, constant large volume, 6th Smart K audio amplifier. +config SND_SOC_AW88399_LIB + tristate + select SND_SOC_AW88395_LIB + config SND_SOC_AW88399 tristate "Soc Audio for awinic aw88399" depends on I2C @@ -733,6 +737,7 @@ config SND_SOC_AW88399 select REGMAP_I2C select GPIOLIB select SND_SOC_AW88395_LIB + select SND_SOC_AW88399_LIB help This option enables support for aw88399 Smart PA. The awinic AW88399 is an I2S/TDM input, high efficiency diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index aa0396e5b575..d2a689006d69 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-aw88395-y := aw88395/aw88395.o snd-soc-aw88166-y := aw88166.o snd-soc-aw88261-y := aw88261.o snd-soc-aw88399-y := aw88399.o +snd-soc-aw88399-lib-y := aw88399-lib.o snd-soc-bd28623-y := bd28623.o snd-soc-bt-sco-y := bt-sco.o snd-soc-chv3-codec-y := chv3-codec.o @@ -496,6 +497,7 @@ obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o +obj-$(CONFIG_SND_SOC_AW88399_LIB) += snd-soc-aw88399-lib.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c new file mode 100644 index 000000000000..258d6efbf590 --- /dev/null +++ b/sound/soc/codecs/aw88399-lib.c @@ -0,0 +1,1381 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88399-lib.c -- AW88399 Common functions for ASoC and HDA audio drivers +// +// Copyright (c) 2023 AWINIC Technology CO., LTD +// +// Author: Weidong Wang +// + +#include +#include +#include +#include +#include +#include +#include +#include "aw88395/aw88395_device.h" + +const struct regmap_config aw88399_remap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88399_REG_MAX, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; +EXPORT_SYMBOL_GPL(aw88399_remap_config); + +static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + int ret; + + if (pwd) + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, ®_val); + if (ret) + dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); + else + *int_status = reg_val; + + dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); +} + +static void aw_dev_clear_int_status(struct aw_device *aw_dev) +{ + u16 int_status; + + /* read int status and clear */ + aw_dev_get_int_status(aw_dev, &int_status); + /* make sure int status is clear */ + aw_dev_get_int_status(aw_dev, &int_status); + if (int_status) + dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); +} + +static int aw_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88399_CCO_MUX_MASK); + if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, + ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, + ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +int aw_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(aw_dev_check_syspll); + +static int aw_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, ®_val); + if (ret) + return ret; + + if (reg_val & (~AW88399_NOISE_GATE_EN_MASK)) + check_val = AW88399_BIT_SYSST_NOSWS_CHECK; + else + check_val = AW88399_BIT_SYSST_SWS_CHECK; + + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); + if (ret) + return ret; + + if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { + dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", + i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + int ret; + + if (amppd) + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) +{ + int ret; + + if (is_enable) + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed\n", __func__); +} +EXPORT_SYMBOL_GPL(aw_dev_dsp_enable); + +static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk) +{ + uint16_t icalkh_val, icalkl_val, icalk_val; + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, ®_val); + if (ret) + return ret; + icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, ®_val); + if (ret) + return ret; + icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK); + + if (aw88399->check_val == AW_EF_AND_CHECK) + icalk_val = icalkh_val & icalkl_val; + else + icalk_val = icalkh_val | icalkl_val; + + if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK)) + icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG; + *icalk = (int16_t)icalk_val; + + return 0; +} + +static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk) +{ + uint16_t vcalkh_val, vcalkl_val, vcalk_val; + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, ®_val); + if (ret) + return ret; + + vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, ®_val); + if (ret) + return ret; + + vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK); + + if (aw88399->check_val == AW_EF_AND_CHECK) + vcalk_val = vcalkh_val & vcalkl_val; + else + vcalk_val = vcalkh_val | vcalkl_val; + + if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK) + vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG; + *vcalk = (int16_t)vcalk_val; + + return 0; +} + +static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk) +{ + uint16_t vcalkh_val, vcalkl_val, vcalk_val; + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, ®_val); + if (ret) + return ret; + vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK); + + ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, ®_val); + if (ret) + return ret; + vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK); + + if (aw88399->check_val == AW_EF_AND_CHECK) + vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) & + (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); + else + vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) | + (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); + + if (vcalk_val & (~AW88399_TEM4_SIGN_MASK)) + vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG; + + *vcalk = (int16_t)vcalk_val; + + return 0; +} + +static int aw_dev_set_vcalb(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + unsigned int vsense_select, vsense_value; + int32_t ical_k, vcal_k, vcalb; + int16_t icalk, vcalk; + uint16_t reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value); + if (ret) + return ret; + + vsense_select = vsense_value & (~AW88399_VDSEL_MASK); + + ret = aw88399_dev_get_icalk(aw88399, &icalk); + if (ret) { + dev_err(aw_dev->dev, "get icalk failed\n"); + return ret; + } + + ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE; + + switch (vsense_select) { + case AW88399_DEV_VDSEL_VSENSE: + ret = aw88399_dev_get_vcalk(aw88399, &vcalk); + vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; + vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * + ical_k / vcal_k * aw88399->vcalb_init_val; + break; + case AW88399_DEV_VDSEL_DAC: + ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); + vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; + vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / + AW88399_ISCAL_DAC_FACTOR * ical_k / + vcal_k * aw88399->vcalb_init_val; + break; + default: + dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); + ret = -EINVAL; + break; + } + if (ret) + return ret; + + vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR; + reg_val = (uint32_t)vcalb; + + regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val); + + return 0; +} + +int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + uint16_t re_lbits, re_hbits; + u32 cali_re; + int ret; + + if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) || + (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN)) + return -EINVAL; + + cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + + aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT); + + re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT; + re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT; + + ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits); + if (ret) { + dev_err(aw_dev->dev, "set cali re error"); + return ret; + } + + ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits); + if (ret) + dev_err(aw_dev->dev, "set cali re error"); + + return ret; +} +EXPORT_SYMBOL_GPL(aw_dev_update_cali_re); + +static int aw_dev_fw_crc_check(struct aw_device *aw_dev) +{ + uint16_t check_val, fw_len_val; + unsigned int reg_val; + int ret; + + /* calculate fw_end_addr */ + fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR; + + /* write fw_end_addr to crc_end_addr */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_END_ADDR_MASK, fw_len_val); + if (ret) + return ret; + /* enable fw crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE); + + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + + /* read crc check result */ + regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); + if (ret) + return ret; + + check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; + + /* disable fw crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE); + if (ret) + return ret; + + if (check_val != AW88399_CRC_CHECK_PASS_VAL) { + dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x", + __func__, check_val, AW88399_CRC_CHECK_PASS_VAL); + ret = -EINVAL; + } + + return ret; +} + +static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) +{ + uint16_t check_val, cfg_len_val; + unsigned int reg_val; + int ret; + + /* calculate cfg end addr */ + cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR; + + /* write cfg_end_addr to crc_end_addr */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_END_ADDR_MASK, cfg_len_val); + if (ret) + return ret; + + /* enable cfg crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE); + if (ret) + return ret; + + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + + /* read crc check result */ + ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); + if (ret) + return ret; + + check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; + + /* disable cfg crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, + ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE); + if (ret) + return ret; + + if (check_val != AW88399_CRC_CHECK_PASS_VAL) { + dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x", + check_val, AW88399_CRC_CHECK_PASS_VAL); + ret = -EINVAL; + } + + return ret; +} + +static int aw_dev_hw_crc_check(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + int ret; + + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE); + if (ret) + return ret; + + ret = aw_dev_fw_crc_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "fw_crc_check failed\n"); + goto crc_check_failed; + } + + ret = aw_dev_cfg_crc_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "cfg_crc_check failed\n"); + goto crc_check_failed; + } + + ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val); + if (ret) + return ret; + + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); + + return ret; + +crc_check_failed: + regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); + return ret; +} + +static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + int ret; + + if (flag) + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG, + ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, + ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +int aw_dev_get_dsp_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, ®_val); + if (ret) + return ret; + if (!(reg_val & (~AW88399_WDT_CNT_MASK))) + return -EPERM; + + return 0; +} +EXPORT_SYMBOL_GPL(aw_dev_get_dsp_status); + +static int aw_dev_dsp_check(struct aw_device *aw_dev) +{ + int ret, i; + + switch (aw_dev->dsp_cfg) { + case AW88399_DEV_DSP_BYPASS: + dev_dbg(aw_dev->dev, "dsp bypass"); + ret = 0; + break; + case AW88399_DEV_DSP_WORK: + aw_dev_dsp_enable(aw_dev, false); + aw_dev_dsp_enable(aw_dev, true); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) { + ret = aw_dev_get_dsp_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + } + } + break; + default: + dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); + ret = -EINVAL; + break; + } + + return ret; +} + +int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int reg_value; + u16 real_value; + int ret; + + real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL); + + ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, ®_value); + if (ret) + return ret; + + dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); + + real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK); + + ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value); + + return ret; +} +EXPORT_SYMBOL_GPL(aw_dev_set_volume); + +static void aw_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + u16 fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) { + aw_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88399_MUTE_VOL) { + aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } +} + +void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, + ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE); + aw_dev_fade_in(aw_dev); + } +} +EXPORT_SYMBOL_GPL(aw88399_dev_mute); + +static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + + if (dither) + regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE); +} + +static int aw88399_dev_start(struct aw88399 *aw88399) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + int ret; + + if (aw_dev->status == AW88399_DEV_PW_ON) { + dev_dbg(aw_dev->dev, "already power on"); + return 0; + } + + aw88399_dev_set_dither(aw88399, false); + + /* power on */ + aw_dev_pwd(aw_dev, false); + usleep_range(AW88399_2000_US, AW88399_2000_US + 10); + + ret = aw_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw_dev_amppd(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 50); + + /* check i2s status */ + ret = aw_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) { + ret = aw_dev_hw_crc_check(aw88399); + if (ret) { + dev_err(aw_dev->dev, "dsp crc check failed"); + goto crc_check_fail; + } + aw_dev_dsp_enable(aw_dev, false); + aw_dev_set_vcalb(aw88399); + aw_dev_update_cali_re(&aw_dev->cali_desc); + + ret = aw_dev_dsp_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp status check failed"); + goto dsp_check_fail; + } + } else { + dev_dbg(aw_dev->dev, "start pa with dsp bypass"); + } + + /* enable tx feedback */ + aw_dev_i2s_tx_enable(aw_dev, true); + + if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE) + aw88399_dev_set_dither(aw88399, true); + + /* close mute */ + aw88399_dev_mute(aw_dev, false); + /* clear inturrupt */ + aw_dev_clear_int_status(aw_dev); + aw_dev->status = AW88399_DEV_PW_ON; + + return 0; + +dsp_check_fail: +crc_check_fail: + aw_dev_dsp_enable(aw_dev, false); +sysst_check_fail: + aw_dev_clear_int_status(aw_dev); + aw_dev_amppd(aw_dev, true); +pll_check_fail: + aw_dev_pwd(aw_dev, true); + aw_dev->status = AW88399_DEV_PW_OFF; + + return ret; +} + +static int aw_dev_dsp_update_container(struct aw_device *aw_dev, + unsigned char *data, unsigned int len, unsigned short base) +{ + u32 tmp_len; + int i, ret; + + ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base); + if (ret) + return ret; + + for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) { + tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE); + ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG, + &data[i], tmp_len); + if (ret) + return ret; + } + + return 0; +} + +static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + u32 dsp_ra; + int ret; + + ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA, + &dsp_ra, AW_DSP_32_DATA); + if (ret) { + dev_err(aw_dev->dev, "read ra error"); + return ret; + } + + cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra, + AW88399_DSP_RE_SHIFT); + + return 0; +} + +static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int ret; + + dev_dbg(aw_dev->dev, "dsp config len:%d", len); + + if (!len || !data) { + dev_err(aw_dev->dev, "dsp config data is null or len is 0"); + return -EINVAL; + } + + ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR); + if (ret) + return ret; + + aw_dev->dsp_cfg_len = len; + + ret = aw_dev_get_ra(&aw_dev->cali_desc); + + return ret; +} + +static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int ret; + + dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); + + if (!len || !data) { + dev_err(aw_dev->dev, "dsp firmware data is null or len is 0"); + return -EINVAL; + } + + aw_dev->dsp_fw_len = len; + ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR); + + return ret; +} + +static int aw_dev_check_sram(struct aw_device *aw_dev) +{ + unsigned int reg_val; + + /* read dsp_rom_check_reg */ + aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, ®_val, AW_DSP_16_DATA); + if (reg_val != AW88399_DSP_ROM_CHECK_DATA) { + dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]", + reg_val, AW88399_DSP_ROM_CHECK_DATA); + return -EPERM; + } + + /* check dsp_cfg_base_addr */ + aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR, + AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA); + aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, ®_val, AW_DSP_16_DATA); + if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) { + dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", + reg_val, AW88399_DSP_ODD_NUM_BIT_TEST); + return -EPERM; + } + + return 0; +} + +static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) +{ + int ret; + + switch (flag) { + case AW88399_DEV_MEMCLK_PLL: + ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_MEM_CLKSEL_MASK, + AW88399_MEM_CLKSEL_DAPHCLK_VALUE); + if (ret) + dev_err(aw_dev->dev, "memclk select pll failed"); + break; + case AW88399_DEV_MEMCLK_OSC: + ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, + ~AW88399_MEM_CLKSEL_MASK, + AW88399_MEM_CLKSEL_OSCCLK_VALUE); + if (ret) + dev_err(aw_dev->dev, "memclk select OSC failed"); + break; + default: + dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag); + break; + } +} + +static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev) +{ + struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, ®_val); + if (ret) { + dev_dbg(aw_dev->dev, "%s failed", __func__); + return; + } + if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE) + profctrl_desc->cur_mode = AW88399_RCV_MODE; + else + profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE; +} + +static int aw_dev_update_reg_container(struct aw88399 *aw88399, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + u16 read_vol, reg_val; + int data_len, i, ret; + int16_t *reg_data; + u8 reg_addr; + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88399_DSPVCALB_REG) { + aw88399->vcalb_init_val = reg_val; + continue; + } + + if (reg_addr == AW88399_SYSCTRL_REG) { + if (reg_val & (~AW88399_DSPBY_MASK)) + aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS; + else + aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK; + + reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK | + AW88399_DSPBY_MASK); + reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE | + AW88399_DSPBY_BYPASS_VALUE); + } + + if (reg_addr == AW88399_I2SCTRL3_REG) { + reg_val &= AW88399_I2STXEN_MASK; + reg_val |= AW88399_I2STXEN_DISABLE_VALUE; + } + + if (reg_addr == AW88399_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88399_VOL_MASK)) >> + AW88399_VOL_START_BIT; + aw_dev->volume_desc.init_volume = read_vol; + } + + if (reg_addr == AW88399_DBGCTRL_REG) { + if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE) + aw88399->check_val = AW_EF_OR_CHECK; + else + aw88399->check_val = AW_EF_AND_CHECK; + + aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK); + } + + if (reg_addr == AW88399_CRCCTRL_REG) + aw88399->crc_init_val = reg_val; + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + return ret; + } + + aw_dev_pwd(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + + aw_dev_get_cur_mode_st(aw_dev); + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + else + aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); + + return 0; +} + +static int aw_dev_reg_update(struct aw88399 *aw88399, + unsigned char *data, unsigned int len) +{ + int ret; + + if (!len || !data) { + dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0"); + return -EINVAL; + } + + ret = aw_dev_update_reg_container(aw88399, data, len); + if (ret) + dev_err(aw88399->aw_pa->dev, "reg update failed"); + + return ret; +} + +int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return -EINVAL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; +} +EXPORT_SYMBOL_GPL(aw88399_dev_get_prof_name); + +static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + if ((aw_dev->prof_cur == aw_dev->prof_index) && + (force_up_en == AW88399_FORCE_UPDATE_OFF)) { + dev_dbg(aw_dev->dev, "scene no change, not update"); + return 0; + } + + if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) { + dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status); + return -EPERM; + } + + ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) + return ret; + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed"); + return ret; + } + + aw88399_dev_mute(aw_dev, true); + + if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) + aw_dev_dsp_enable(aw_dev, false); + + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); + + ret = aw_dev_check_sram(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "check sram failed"); + goto error; + } + + if (up_dsp_fw_en) { + dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); + ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, + sec_desc[AW88395_DATA_TYPE_DSP_FW].len); + if (ret) { + dev_err(aw_dev->dev, "update dsp fw failed"); + goto error; + } + } + + /* update dsp config */ + ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, + sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); + if (ret) { + dev_err(aw_dev->dev, "update dsp cfg failed"); + goto error; + } + + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; + +error: + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); + return ret; +} + +static void aw88399_start_pa(struct aw88399 *aw88399) +{ + int ret, i; + + for (i = 0; i < AW88399_START_RETRIES; i++) { + ret = aw88399_dev_start(aw88399); + if (ret) { + dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i); + ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true); + if (ret) { + dev_err(aw88399->aw_pa->dev, "fw update failed"); + continue; + } + } else { + dev_dbg(aw88399->aw_pa->dev, "start success\n"); + break; + } + } +} + +void aw88399_startup_work(struct work_struct *work) +{ + struct aw88399 *aw88399 = + container_of(work, struct aw88399, start_work.work); + + mutex_lock(&aw88399->lock); + aw88399_start_pa(aw88399); + mutex_unlock(&aw88399->lock); +} +EXPORT_SYMBOL_GPL(aw88399_startup_work); + +void aw88399_start(struct aw88399 *aw88399, bool sync_start) +{ + int ret; + + if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK) + return; + + if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) + return; + + ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true); + if (ret) { + dev_err(aw88399->aw_pa->dev, "fw update failed."); + return; + } + + if (sync_start == AW88399_SYNC_START) + aw88399_start_pa(aw88399); + else + queue_delayed_work(system_dfl_wq, + &aw88399->start_work, + AW88399_START_WORK_DELAY_MS); +} +EXPORT_SYMBOL_GPL(aw88399_start); + +static int aw_dev_check_sysint(struct aw_device *aw_dev) +{ + u16 reg_val; + + aw_dev_get_int_status(aw_dev, ®_val); + if (reg_val & AW88399_BIT_SYSINT_CHECK) { + dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +int aw88399_stop(struct aw_device *aw_dev) +{ + struct aw_sec_data_desc *dsp_cfg = + &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; + struct aw_sec_data_desc *dsp_fw = + &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; + int int_st; + + if (aw_dev->status == AW88399_DEV_PW_OFF) { + dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88399_DEV_PW_OFF; + + aw88399_dev_mute(aw_dev, true); + usleep_range(AW88399_4000_US, AW88399_4000_US + 100); + + aw_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 100); + + int_st = aw_dev_check_sysint(aw_dev); + + aw_dev_dsp_enable(aw_dev, false); + + aw_dev_amppd(aw_dev, true); + + if (int_st) { + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); + aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); + aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); + aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); + } + + aw_dev_pwd(aw_dev, true); + + return 0; +} +EXPORT_SYMBOL_GPL(aw88399_stop); + +static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88399->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed"); + return -EINVAL; + } + aw_dev->fade_in_time = AW88399_1000_US / 10; + aw_dev->fade_out_time = AW88399_1000_US >> 1; + aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; + aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; + + ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + aw88399_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88399_1000_US, AW88399_1000_US + 100); + + /* enable amppd */ + aw_dev_amppd(aw_dev, true); + + /* close dsp */ + aw_dev_dsp_enable(aw_dev, false); + /* set power down */ + aw_dev_pwd(aw_dev, true); + + return 0; +} + +int aw88399_request_firmware_file(struct aw88399 *aw88399) +{ + const struct firmware *cont = NULL; + int ret; + + aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev); + if (ret) { + dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE); + return ret; + } + + dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n", + AW88399_ACF_FILE, cont ? cont->size : 0); + + aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, + struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); + if (!aw88399->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88399->aw_cfg->len = (int)cont->size; + memcpy(aw88399->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); + if (ret) { + dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE); + return ret; + } + + mutex_lock(&aw88399->lock); + /* aw device init */ + ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); + if (ret) + dev_err(aw88399->aw_pa->dev, "dev init failed"); + mutex_unlock(&aw88399->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(aw88399_request_firmware_file); + +void aw88399_hw_reset(struct aw88399 *aw88399) +{ + if (aw88399->reset_gpio) { + gpiod_set_value_cansleep(aw88399->reset_gpio, 1); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + gpiod_set_value_cansleep(aw88399->reset_gpio, 0); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + gpiod_set_value_cansleep(aw88399->reset_gpio, 1); + usleep_range(AW88399_1000_US, AW88399_1000_US + 10); + } +} +EXPORT_SYMBOL_GPL(aw88399_hw_reset); + +static void aw88399_parse_channel_dt(struct aw_device *aw_dev) +{ + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value; + + of_property_read_u32(np, "awinic,audio-channel", &channel_value); + aw_dev->channel = channel_value; +} + +int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + ret = regmap_read(regmap, AW88399_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88399_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + aw88399->aw_pa = aw_dev; + + aw_dev->i2c = i2c; + aw_dev->dev = &i2c->dev; + aw_dev->regmap = regmap; + mutex_init(&aw_dev->dsp_lock); + + aw_dev->chip_id = chip_id; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = AW88399_DEV_DEFAULT_CH; + aw_dev->fw_status = AW88399_DEV_FW_FAILED; + + aw_dev->fade_step = AW88399_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE; + + aw88399_parse_channel_dt(aw_dev); + + return 0; +} +EXPORT_SYMBOL_GPL(aw88399_init); + +MODULE_DESCRIPTION("AW88399 common device library"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index b2ec3503f7e2..13495e71ad0e 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -10,1217 +10,12 @@ #include #include #include -#include -#include #include #include #include #include "aw88399.h" #include "aw88395/aw88395_device.h" -static const struct regmap_config aw88399_remap_config = { - .val_bits = 16, - .reg_bits = 8, - .max_register = AW88399_REG_MAX, - .reg_format_endian = REGMAP_ENDIAN_LITTLE, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) -{ - int ret; - - if (pwd) - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed", __func__); -} - -static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) -{ - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, ®_val); - if (ret) - dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); - else - *int_status = reg_val; - - dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); -} - -static void aw_dev_clear_int_status(struct aw_device *aw_dev) -{ - u16 int_status; - - /* read int status and clear */ - aw_dev_get_int_status(aw_dev, &int_status); - /* make sure int status is clear */ - aw_dev_get_int_status(aw_dev, &int_status); - if (int_status) - dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); -} - -static int aw_dev_get_iis_status(struct aw_device *aw_dev) -{ - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); - if (ret) - return ret; - if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) { - dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); - return -EINVAL; - } - - return 0; -} - -static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) -{ - int ret, i; - - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = aw_dev_get_iis_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode1 iis signal check error"); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - return 0; - } - } - - return -EPERM; -} - -static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) -{ - unsigned int reg_val; - int ret, i; - - ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, ®_val); - if (ret) - return ret; - - reg_val &= (~AW88399_CCO_MUX_MASK); - if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) { - dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); - return -EPERM; - } - - /* change mode2 */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, - ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE); - if (ret) - return ret; - - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = aw_dev_get_iis_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode2 iis signal check error"); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - break; - } - } - - /* change mode1 */ - regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, - ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE); - if (ret == 0) { - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = aw_dev_get_iis_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - break; - } - } - } - - return ret; -} - -static int aw_dev_check_syspll(struct aw_device *aw_dev) -{ - int ret; - - ret = aw_dev_check_mode1_pll(aw_dev); - if (ret) { - dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); - ret = aw_dev_check_mode2_pll(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "mode2 check iis failed"); - return ret; - } - } - - return 0; -} - -static int aw_dev_check_sysst(struct aw_device *aw_dev) -{ - unsigned int check_val; - unsigned int reg_val; - int ret, i; - - ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, ®_val); - if (ret) - return ret; - - if (reg_val & (~AW88399_NOISE_GATE_EN_MASK)) - check_val = AW88399_BIT_SYSST_NOSWS_CHECK; - else - check_val = AW88399_BIT_SYSST_SWS_CHECK; - - for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { - ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); - if (ret) - return ret; - - if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { - dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", - i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } else { - return 0; - } - } - - return -EPERM; -} - -static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) -{ - int ret; - - if (amppd) - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed", __func__); -} - -static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) -{ - int ret; - - if (is_enable) - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed\n", __func__); -} - -static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk) -{ - uint16_t icalkh_val, icalkl_val, icalk_val; - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, ®_val); - if (ret) - return ret; - icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK); - - ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, ®_val); - if (ret) - return ret; - icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK); - - if (aw88399->check_val == AW_EF_AND_CHECK) - icalk_val = icalkh_val & icalkl_val; - else - icalk_val = icalkh_val | icalkl_val; - - if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK)) - icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG; - *icalk = (int16_t)icalk_val; - - return 0; -} - -static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk) -{ - uint16_t vcalkh_val, vcalkl_val, vcalk_val; - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, ®_val); - if (ret) - return ret; - - vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK); - - ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, ®_val); - if (ret) - return ret; - - vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK); - - if (aw88399->check_val == AW_EF_AND_CHECK) - vcalk_val = vcalkh_val & vcalkl_val; - else - vcalk_val = vcalkh_val | vcalkl_val; - - if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK) - vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG; - *vcalk = (int16_t)vcalk_val; - - return 0; -} - -static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk) -{ - uint16_t vcalkh_val, vcalkl_val, vcalk_val; - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, ®_val); - if (ret) - return ret; - vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK); - - ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, ®_val); - if (ret) - return ret; - vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK); - - if (aw88399->check_val == AW_EF_AND_CHECK) - vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) & - (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); - else - vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) | - (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); - - if (vcalk_val & (~AW88399_TEM4_SIGN_MASK)) - vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG; - - *vcalk = (int16_t)vcalk_val; - - return 0; -} - -static int aw_dev_set_vcalb(struct aw88399 *aw88399) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - unsigned int vsense_select, vsense_value; - int32_t ical_k, vcal_k, vcalb; - int16_t icalk, vcalk; - uint16_t reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value); - if (ret) - return ret; - - vsense_select = vsense_value & (~AW88399_VDSEL_MASK); - - ret = aw88399_dev_get_icalk(aw88399, &icalk); - if (ret) { - dev_err(aw_dev->dev, "get icalk failed\n"); - return ret; - } - - ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE; - - switch (vsense_select) { - case AW88399_DEV_VDSEL_VSENSE: - ret = aw88399_dev_get_vcalk(aw88399, &vcalk); - vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; - vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * - ical_k / vcal_k * aw88399->vcalb_init_val; - break; - case AW88399_DEV_VDSEL_DAC: - ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); - vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; - vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / - AW88399_ISCAL_DAC_FACTOR * ical_k / - vcal_k * aw88399->vcalb_init_val; - break; - default: - dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); - ret = -EINVAL; - break; - } - if (ret) - return ret; - - vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR; - reg_val = (uint32_t)vcalb; - - regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val); - - return 0; -} - -static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) -{ - struct aw_device *aw_dev = - container_of(cali_desc, struct aw_device, cali_desc); - uint16_t re_lbits, re_hbits; - u32 cali_re; - int ret; - - if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) || - (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN)) - return -EINVAL; - - cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + - aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT); - - re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT; - re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT; - - ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits); - if (ret) { - dev_err(aw_dev->dev, "set cali re error"); - return ret; - } - - ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits); - if (ret) - dev_err(aw_dev->dev, "set cali re error"); - - return ret; -} - -static int aw_dev_fw_crc_check(struct aw_device *aw_dev) -{ - uint16_t check_val, fw_len_val; - unsigned int reg_val; - int ret; - - /* calculate fw_end_addr */ - fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR; - - /* write fw_end_addr to crc_end_addr */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_END_ADDR_MASK, fw_len_val); - if (ret) - return ret; - /* enable fw crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE); - - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - - /* read crc check result */ - regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); - if (ret) - return ret; - - check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; - - /* disable fw crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE); - if (ret) - return ret; - - if (check_val != AW88399_CRC_CHECK_PASS_VAL) { - dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x", - __func__, check_val, AW88399_CRC_CHECK_PASS_VAL); - ret = -EINVAL; - } - - return ret; -} - -static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) -{ - uint16_t check_val, cfg_len_val; - unsigned int reg_val; - int ret; - - /* calculate cfg end addr */ - cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR; - - /* write cfg_end_addr to crc_end_addr */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_END_ADDR_MASK, cfg_len_val); - if (ret) - return ret; - - /* enable cfg crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE); - if (ret) - return ret; - - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - - /* read crc check result */ - ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); - if (ret) - return ret; - - check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; - - /* disable cfg crc check */ - ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, - ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE); - if (ret) - return ret; - - if (check_val != AW88399_CRC_CHECK_PASS_VAL) { - dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x", - check_val, AW88399_CRC_CHECK_PASS_VAL); - ret = -EINVAL; - } - - return ret; -} - -static int aw_dev_hw_crc_check(struct aw88399 *aw88399) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - int ret; - - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE); - if (ret) - return ret; - - ret = aw_dev_fw_crc_check(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "fw_crc_check failed\n"); - goto crc_check_failed; - } - - ret = aw_dev_cfg_crc_check(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "cfg_crc_check failed\n"); - goto crc_check_failed; - } - - ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val); - if (ret) - return ret; - - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); - - return ret; - -crc_check_failed: - regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); - return ret; -} - -static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) -{ - int ret; - - if (flag) - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG, - ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE); - else - ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, - ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE); - - if (ret) - dev_dbg(aw_dev->dev, "%s failed", __func__); -} - -static int aw_dev_get_dsp_status(struct aw_device *aw_dev) -{ - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, ®_val); - if (ret) - return ret; - if (!(reg_val & (~AW88399_WDT_CNT_MASK))) - return -EPERM; - - return 0; -} - -static int aw_dev_dsp_check(struct aw_device *aw_dev) -{ - int ret, i; - - switch (aw_dev->dsp_cfg) { - case AW88399_DEV_DSP_BYPASS: - dev_dbg(aw_dev->dev, "dsp bypass"); - ret = 0; - break; - case AW88399_DEV_DSP_WORK: - aw_dev_dsp_enable(aw_dev, false); - aw_dev_dsp_enable(aw_dev, true); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) { - ret = aw_dev_get_dsp_status(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - } - } - break; - default: - dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); - ret = -EINVAL; - break; - } - - return ret; -} - -static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) -{ - struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; - unsigned int reg_value; - u16 real_value; - int ret; - - real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL); - - ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, ®_value); - if (ret) - return ret; - - dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); - - real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK); - - ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value); - - return ret; -} - -static void aw_dev_fade_in(struct aw_device *aw_dev) -{ - struct aw_volume_desc *desc = &aw_dev->volume_desc; - u16 fade_in_vol = desc->ctl_volume; - int fade_step = aw_dev->fade_step; - int i; - - if (fade_step == 0 || aw_dev->fade_in_time == 0) { - aw_dev_set_volume(aw_dev, fade_in_vol); - return; - } - - for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { - aw_dev_set_volume(aw_dev, i); - usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); - } - - if (i != fade_in_vol) - aw_dev_set_volume(aw_dev, fade_in_vol); -} - -static void aw_dev_fade_out(struct aw_device *aw_dev) -{ - struct aw_volume_desc *desc = &aw_dev->volume_desc; - int fade_step = aw_dev->fade_step; - int i; - - if (fade_step == 0 || aw_dev->fade_out_time == 0) { - aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); - return; - } - - for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) { - aw_dev_set_volume(aw_dev, i); - usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); - } - - if (i != AW88399_MUTE_VOL) { - aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); - usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); - } -} - -static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute) -{ - if (is_mute) { - aw_dev_fade_out(aw_dev); - regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE); - } else { - regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, - ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE); - aw_dev_fade_in(aw_dev); - } -} - -static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - - if (dither) - regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE); - else - regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE); -} - -static int aw88399_dev_start(struct aw88399 *aw88399) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - int ret; - - if (aw_dev->status == AW88399_DEV_PW_ON) { - dev_dbg(aw_dev->dev, "already power on"); - return 0; - } - - aw88399_dev_set_dither(aw88399, false); - - /* power on */ - aw_dev_pwd(aw_dev, false); - usleep_range(AW88399_2000_US, AW88399_2000_US + 10); - - ret = aw_dev_check_syspll(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "pll check failed cannot start"); - goto pll_check_fail; - } - - /* amppd on */ - aw_dev_amppd(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 50); - - /* check i2s status */ - ret = aw_dev_check_sysst(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "sysst check failed"); - goto sysst_check_fail; - } - - if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) { - ret = aw_dev_hw_crc_check(aw88399); - if (ret) { - dev_err(aw_dev->dev, "dsp crc check failed"); - goto crc_check_fail; - } - aw_dev_dsp_enable(aw_dev, false); - aw_dev_set_vcalb(aw88399); - aw_dev_update_cali_re(&aw_dev->cali_desc); - - ret = aw_dev_dsp_check(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "dsp status check failed"); - goto dsp_check_fail; - } - } else { - dev_dbg(aw_dev->dev, "start pa with dsp bypass"); - } - - /* enable tx feedback */ - aw_dev_i2s_tx_enable(aw_dev, true); - - if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE) - aw88399_dev_set_dither(aw88399, true); - - /* close mute */ - aw88399_dev_mute(aw_dev, false); - /* clear inturrupt */ - aw_dev_clear_int_status(aw_dev); - aw_dev->status = AW88399_DEV_PW_ON; - - return 0; - -dsp_check_fail: -crc_check_fail: - aw_dev_dsp_enable(aw_dev, false); -sysst_check_fail: - aw_dev_clear_int_status(aw_dev); - aw_dev_amppd(aw_dev, true); -pll_check_fail: - aw_dev_pwd(aw_dev, true); - aw_dev->status = AW88399_DEV_PW_OFF; - - return ret; -} - -static int aw_dev_dsp_update_container(struct aw_device *aw_dev, - unsigned char *data, unsigned int len, unsigned short base) -{ - u32 tmp_len; - int i, ret; - - ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base); - if (ret) - return ret; - - for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) { - tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE); - ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG, - &data[i], tmp_len); - if (ret) - return ret; - } - - return 0; -} - -static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) -{ - struct aw_device *aw_dev = - container_of(cali_desc, struct aw_device, cali_desc); - u32 dsp_ra; - int ret; - - ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA, - &dsp_ra, AW_DSP_32_DATA); - if (ret) { - dev_err(aw_dev->dev, "read ra error"); - return ret; - } - - cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra, - AW88399_DSP_RE_SHIFT); - - return 0; -} - -static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, - unsigned char *data, unsigned int len) -{ - int ret; - - dev_dbg(aw_dev->dev, "dsp config len:%d", len); - - if (!len || !data) { - dev_err(aw_dev->dev, "dsp config data is null or len is 0"); - return -EINVAL; - } - - ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR); - if (ret) - return ret; - - aw_dev->dsp_cfg_len = len; - - ret = aw_dev_get_ra(&aw_dev->cali_desc); - - return ret; -} - -static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, - unsigned char *data, unsigned int len) -{ - int ret; - - dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); - - if (!len || !data) { - dev_err(aw_dev->dev, "dsp firmware data is null or len is 0"); - return -EINVAL; - } - - aw_dev->dsp_fw_len = len; - ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR); - - return ret; -} - -static int aw_dev_check_sram(struct aw_device *aw_dev) -{ - unsigned int reg_val; - - /* read dsp_rom_check_reg */ - aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, ®_val, AW_DSP_16_DATA); - if (reg_val != AW88399_DSP_ROM_CHECK_DATA) { - dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]", - reg_val, AW88399_DSP_ROM_CHECK_DATA); - return -EPERM; - } - - /* check dsp_cfg_base_addr */ - aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR, - AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA); - aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, ®_val, AW_DSP_16_DATA); - if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) { - dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", - reg_val, AW88399_DSP_ODD_NUM_BIT_TEST); - return -EPERM; - } - - return 0; -} - -static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) -{ - int ret; - - switch (flag) { - case AW88399_DEV_MEMCLK_PLL: - ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_MEM_CLKSEL_MASK, - AW88399_MEM_CLKSEL_DAPHCLK_VALUE); - if (ret) - dev_err(aw_dev->dev, "memclk select pll failed"); - break; - case AW88399_DEV_MEMCLK_OSC: - ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, - ~AW88399_MEM_CLKSEL_MASK, - AW88399_MEM_CLKSEL_OSCCLK_VALUE); - if (ret) - dev_err(aw_dev->dev, "memclk select OSC failed"); - break; - default: - dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag); - break; - } -} - -static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev) -{ - struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; - unsigned int reg_val; - int ret; - - ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, ®_val); - if (ret) { - dev_dbg(aw_dev->dev, "%s failed", __func__); - return; - } - if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE) - profctrl_desc->cur_mode = AW88399_RCV_MODE; - else - profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE; -} - -static int aw_dev_update_reg_container(struct aw88399 *aw88399, - unsigned char *data, unsigned int len) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; - u16 read_vol, reg_val; - int data_len, i, ret; - int16_t *reg_data; - u8 reg_addr; - - reg_data = (int16_t *)data; - data_len = len >> 1; - - if (data_len & 0x1) { - dev_err(aw_dev->dev, "data len:%d unsupported", data_len); - return -EINVAL; - } - - for (i = 0; i < data_len; i += 2) { - reg_addr = reg_data[i]; - reg_val = reg_data[i + 1]; - - if (reg_addr == AW88399_DSPVCALB_REG) { - aw88399->vcalb_init_val = reg_val; - continue; - } - - if (reg_addr == AW88399_SYSCTRL_REG) { - if (reg_val & (~AW88399_DSPBY_MASK)) - aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS; - else - aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK; - - reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK | - AW88399_DSPBY_MASK); - reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE | - AW88399_DSPBY_BYPASS_VALUE); - } - - if (reg_addr == AW88399_I2SCTRL3_REG) { - reg_val &= AW88399_I2STXEN_MASK; - reg_val |= AW88399_I2STXEN_DISABLE_VALUE; - } - - if (reg_addr == AW88399_SYSCTRL2_REG) { - read_vol = (reg_val & (~AW88399_VOL_MASK)) >> - AW88399_VOL_START_BIT; - aw_dev->volume_desc.init_volume = read_vol; - } - - if (reg_addr == AW88399_DBGCTRL_REG) { - if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE) - aw88399->check_val = AW_EF_OR_CHECK; - else - aw88399->check_val = AW_EF_AND_CHECK; - - aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK); - } - - if (reg_addr == AW88399_CRCCTRL_REG) - aw88399->crc_init_val = reg_val; - - ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); - if (ret) - return ret; - } - - aw_dev_pwd(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - - aw_dev_get_cur_mode_st(aw_dev); - - if (aw_dev->prof_cur != aw_dev->prof_index) - vol_desc->ctl_volume = 0; - else - aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); - - return 0; -} - -static int aw_dev_reg_update(struct aw88399 *aw88399, - unsigned char *data, unsigned int len) -{ - int ret; - - if (!len || !data) { - dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0"); - return -EINVAL; - } - - ret = aw_dev_update_reg_container(aw88399, data, len); - if (ret) - dev_err(aw88399->aw_pa->dev, "reg update failed"); - - return ret; -} - -static int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) -{ - struct aw_prof_info *prof_info = &aw_dev->prof_info; - struct aw_prof_desc *prof_desc; - - if ((index >= aw_dev->prof_info.count) || (index < 0)) { - dev_err(aw_dev->dev, "index[%d] overflow count[%d]", - index, aw_dev->prof_info.count); - return -EINVAL; - } - - prof_desc = &aw_dev->prof_info.prof_desc[index]; - - *prof_name = prof_info->prof_name_list[prof_desc->id]; - - return 0; -} - -static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index, - struct aw_prof_desc **prof_desc) -{ - if ((index >= aw_dev->prof_info.count) || (index < 0)) { - dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", - __func__, index, aw_dev->prof_info.count); - return -EINVAL; - } - - *prof_desc = &aw_dev->prof_info.prof_desc[index]; - - return 0; -} - -static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - struct aw_prof_desc *prof_index_desc; - struct aw_sec_data_desc *sec_desc; - char *prof_name; - int ret; - - if ((aw_dev->prof_cur == aw_dev->prof_index) && - (force_up_en == AW88399_FORCE_UPDATE_OFF)) { - dev_dbg(aw_dev->dev, "scene no change, not update"); - return 0; - } - - if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) { - dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status); - return -EPERM; - } - - ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); - if (ret) - return ret; - - dev_dbg(aw_dev->dev, "start update %s", prof_name); - - ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); - if (ret) - return ret; - - /* update reg */ - sec_desc = prof_index_desc->sec_desc; - ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data, - sec_desc[AW88395_DATA_TYPE_REG].len); - if (ret) { - dev_err(aw_dev->dev, "update reg failed"); - return ret; - } - - aw88399_dev_mute(aw_dev, true); - - if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) - aw_dev_dsp_enable(aw_dev, false); - - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); - - ret = aw_dev_check_sram(aw_dev); - if (ret) { - dev_err(aw_dev->dev, "check sram failed"); - goto error; - } - - if (up_dsp_fw_en) { - dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); - ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, - sec_desc[AW88395_DATA_TYPE_DSP_FW].len); - if (ret) { - dev_err(aw_dev->dev, "update dsp fw failed"); - goto error; - } - } - - /* update dsp config */ - ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, - sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); - if (ret) { - dev_err(aw_dev->dev, "update dsp cfg failed"); - goto error; - } - - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); - - aw_dev->prof_cur = aw_dev->prof_index; - - return 0; - -error: - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); - return ret; -} - -static void aw88399_start_pa(struct aw88399 *aw88399) -{ - int ret, i; - - for (i = 0; i < AW88399_START_RETRIES; i++) { - ret = aw88399_dev_start(aw88399); - if (ret) { - dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i); - ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true); - if (ret) { - dev_err(aw88399->aw_pa->dev, "fw update failed"); - continue; - } - } else { - dev_dbg(aw88399->aw_pa->dev, "start success\n"); - break; - } - } -} - -static void aw88399_startup_work(struct work_struct *work) -{ - struct aw88399 *aw88399 = - container_of(work, struct aw88399, start_work.work); - - mutex_lock(&aw88399->lock); - aw88399_start_pa(aw88399); - mutex_unlock(&aw88399->lock); -} - -static void aw88399_start(struct aw88399 *aw88399, bool sync_start) -{ - int ret; - - if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK) - return; - - if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) - return; - - ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true); - if (ret) { - dev_err(aw88399->aw_pa->dev, "fw update failed."); - return; - } - - if (sync_start == AW88399_SYNC_START) - aw88399_start_pa(aw88399); - else - queue_delayed_work(system_dfl_wq, - &aw88399->start_work, - AW88399_START_WORK_DELAY_MS); -} - -static int aw_dev_check_sysint(struct aw_device *aw_dev) -{ - u16 reg_val; - - aw_dev_get_int_status(aw_dev, ®_val); - if (reg_val & AW88399_BIT_SYSINT_CHECK) { - dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val); - return -EINVAL; - } - - return 0; -} - -static int aw88399_stop(struct aw_device *aw_dev) -{ - struct aw_sec_data_desc *dsp_cfg = - &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; - struct aw_sec_data_desc *dsp_fw = - &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; - int int_st; - - if (aw_dev->status == AW88399_DEV_PW_OFF) { - dev_dbg(aw_dev->dev, "already power off"); - return 0; - } - - aw_dev->status = AW88399_DEV_PW_OFF; - - aw88399_dev_mute(aw_dev, true); - usleep_range(AW88399_4000_US, AW88399_4000_US + 100); - - aw_dev_i2s_tx_enable(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 100); - - int_st = aw_dev_check_sysint(aw_dev); - - aw_dev_dsp_enable(aw_dev, false); - - aw_dev_amppd(aw_dev, true); - - if (int_st) { - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); - aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); - aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); - aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); - } - - aw_dev_pwd(aw_dev, true); - - return 0; -} - static struct snd_soc_dai_driver aw88399_dai[] = { { .name = "aw88399-aif", @@ -1869,86 +664,6 @@ static int aw88399_calib_set(struct snd_kcontrol *kcontrol, return 0; } -static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) -{ - struct aw_device *aw_dev = aw88399->aw_pa; - int ret; - - ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); - if (ret) { - dev_err(aw_dev->dev, "aw_dev acf parse failed"); - return -EINVAL; - } - aw_dev->fade_in_time = AW88399_1000_US / 10; - aw_dev->fade_out_time = AW88399_1000_US >> 1; - aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; - aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; - - ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON); - if (ret) { - dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); - return ret; - } - - aw88399_dev_mute(aw_dev, true); - - /* close tx feedback */ - aw_dev_i2s_tx_enable(aw_dev, false); - usleep_range(AW88399_1000_US, AW88399_1000_US + 100); - - /* enable amppd */ - aw_dev_amppd(aw_dev, true); - - /* close dsp */ - aw_dev_dsp_enable(aw_dev, false); - /* set power down */ - aw_dev_pwd(aw_dev, true); - - return 0; -} - -static int aw88399_request_firmware_file(struct aw88399 *aw88399) -{ - const struct firmware *cont = NULL; - int ret; - - aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; - - ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev); - if (ret) { - dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE); - return ret; - } - - dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n", - AW88399_ACF_FILE, cont ? cont->size : 0); - - aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, - struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw88399->aw_cfg) { - release_firmware(cont); - return -ENOMEM; - } - aw88399->aw_cfg->len = (int)cont->size; - memcpy(aw88399->aw_cfg->data, cont->data, cont->size); - release_firmware(cont); - - ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); - if (ret) { - dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE); - return ret; - } - - mutex_lock(&aw88399->lock); - /* aw device init */ - ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); - if (ret) - dev_err(aw88399->aw_pa->dev, "dev init failed"); - mutex_unlock(&aw88399->lock); - - return ret; -} - static const struct snd_kcontrol_new aw88399_controls[] = { SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG, 6, AW88399_MUTE_VOL, 0, aw88399_volume_get, @@ -2040,70 +755,6 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88399 = { .num_controls = ARRAY_SIZE(aw88399_controls), }; -static void aw88399_hw_reset(struct aw88399 *aw88399) -{ - if (aw88399->reset_gpio) { - gpiod_set_value_cansleep(aw88399->reset_gpio, 1); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - gpiod_set_value_cansleep(aw88399->reset_gpio, 0); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - gpiod_set_value_cansleep(aw88399->reset_gpio, 1); - usleep_range(AW88399_1000_US, AW88399_1000_US + 10); - } -} - -static void aw88399_parse_channel_dt(struct aw_device *aw_dev) -{ - struct device_node *np = aw_dev->dev->of_node; - u32 channel_value; - - of_property_read_u32(np, "awinic,audio-channel", &channel_value); - aw_dev->channel = channel_value; -} - -static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap) -{ - struct aw_device *aw_dev; - unsigned int chip_id; - int ret; - - ret = regmap_read(regmap, AW88399_ID_REG, &chip_id); - if (ret) { - dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); - return ret; - } - if (chip_id != AW88399_CHIP_ID) { - dev_err(&i2c->dev, "unsupported device"); - return -ENXIO; - } - dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); - - aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); - if (!aw_dev) - return -ENOMEM; - aw88399->aw_pa = aw_dev; - - aw_dev->i2c = i2c; - aw_dev->dev = &i2c->dev; - aw_dev->regmap = regmap; - mutex_init(&aw_dev->dsp_lock); - - aw_dev->chip_id = chip_id; - aw_dev->acf = NULL; - aw_dev->prof_info.prof_desc = NULL; - aw_dev->prof_info.count = 0; - aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; - aw_dev->channel = AW88399_DEV_DEFAULT_CH; - aw_dev->fw_status = AW88399_DEV_FW_FAILED; - - aw_dev->fade_step = AW88399_VOLUME_STEP_DB; - aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE; - - aw88399_parse_channel_dt(aw_dev); - - return 0; -} - static int aw88399_i2c_probe(struct i2c_client *i2c) { struct aw88399 *aw88399; diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h index b386f4836748..04123bf0ad84 100644 --- a/sound/soc/codecs/aw88399.h +++ b/sound/soc/codecs/aw88399.h @@ -10,512 +10,10 @@ #ifndef __AW88399_H__ #define __AW88399_H__ -/* registers list */ -#define AW88399_ID_REG (0x00) -#define AW88399_SYSST_REG (0x01) -#define AW88399_SYSINT_REG (0x02) -#define AW88399_SYSINTM_REG (0x03) -#define AW88399_SYSCTRL_REG (0x04) -#define AW88399_SYSCTRL2_REG (0x05) -#define AW88399_I2SCTRL1_REG (0x06) -#define AW88399_I2SCTRL2_REG (0x07) -#define AW88399_I2SCTRL3_REG (0x08) -#define AW88399_DACCFG1_REG (0x09) -#define AW88399_DACCFG2_REG (0x0A) -#define AW88399_DACCFG3_REG (0x0B) -#define AW88399_DACCFG4_REG (0x0C) -#define AW88399_DACCFG5_REG (0x0D) -#define AW88399_DACCFG6_REG (0x0E) -#define AW88399_DACCFG7_REG (0x0F) -#define AW88399_MPDCFG1_REG (0x10) -#define AW88399_MPDCFG2_REG (0x11) -#define AW88399_MPDCFG3_REG (0x12) -#define AW88399_MPDCFG4_REG (0x13) -#define AW88399_PWMCTRL1_REG (0x14) -#define AW88399_PWMCTRL2_REG (0x15) -#define AW88399_PWMCTRL3_REG (0x16) -#define AW88399_I2SCFG1_REG (0x17) -#define AW88399_DBGCTRL_REG (0x18) -#define AW88399_HAGCST_REG (0x20) -#define AW88399_VBAT_REG (0x21) -#define AW88399_TEMP_REG (0x22) -#define AW88399_PVDD_REG (0x23) -#define AW88399_ISNDAT_REG (0x24) -#define AW88399_VSNDAT_REG (0x25) -#define AW88399_I2SINT_REG (0x26) -#define AW88399_I2SCAPCNT_REG (0x27) -#define AW88399_ANASTA1_REG (0x28) -#define AW88399_ANASTA2_REG (0x29) -#define AW88399_ANASTA3_REG (0x2A) -#define AW88399_TESTDET_REG (0x2B) -#define AW88399_DSMCFG1_REG (0x30) -#define AW88399_DSMCFG2_REG (0x31) -#define AW88399_DSMCFG3_REG (0x32) -#define AW88399_DSMCFG4_REG (0x33) -#define AW88399_DSMCFG5_REG (0x34) -#define AW88399_DSMCFG6_REG (0x35) -#define AW88399_DSMCFG7_REG (0x36) -#define AW88399_DSMCFG8_REG (0x37) -#define AW88399_TESTIN_REG (0x38) -#define AW88399_TESTOUT_REG (0x39) -#define AW88399_MEMTEST_REG (0x3A) -#define AW88399_VSNCTRL1_REG (0x3B) -#define AW88399_ISNCTRL1_REG (0x3C) -#define AW88399_ISNCTRL2_REG (0x3D) -#define AW88399_DSPMADD_REG (0x40) -#define AW88399_DSPMDAT_REG (0x41) -#define AW88399_WDT_REG (0x42) -#define AW88399_ACR1_REG (0x43) -#define AW88399_ACR2_REG (0x44) -#define AW88399_ASR1_REG (0x45) -#define AW88399_ASR2_REG (0x46) -#define AW88399_DSPCFG_REG (0x47) -#define AW88399_ASR3_REG (0x48) -#define AW88399_ASR4_REG (0x49) -#define AW88399_DSPVCALB_REG (0x4A) -#define AW88399_CRCCTRL_REG (0x4B) -#define AW88399_DSPDBG1_REG (0x4C) -#define AW88399_DSPDBG2_REG (0x4D) -#define AW88399_DSPDBG3_REG (0x4E) -#define AW88399_PLLCTRL1_REG (0x50) -#define AW88399_PLLCTRL2_REG (0x51) -#define AW88399_PLLCTRL3_REG (0x52) -#define AW88399_CDACTRL1_REG (0x53) -#define AW88399_CDACTRL2_REG (0x54) -#define AW88399_CDACTRL3_REG (0x55) -#define AW88399_SADCCTRL1_REG (0x56) -#define AW88399_SADCCTRL2_REG (0x57) -#define AW88399_BOPCTRL1_REG (0x58) -#define AW88399_BOPCTRL2_REG (0x5A) -#define AW88399_BOPCTRL3_REG (0x5B) -#define AW88399_BOPCTRL4_REG (0x5C) -#define AW88399_BOPCTRL5_REG (0x5D) -#define AW88399_BOPCTRL6_REG (0x5E) -#define AW88399_BOPCTRL7_REG (0x5F) -#define AW88399_BSTCTRL1_REG (0x60) -#define AW88399_BSTCTRL2_REG (0x61) -#define AW88399_BSTCTRL3_REG (0x62) -#define AW88399_BSTCTRL4_REG (0x63) -#define AW88399_BSTCTRL5_REG (0x64) -#define AW88399_BSTCTRL6_REG (0x65) -#define AW88399_BSTCTRL7_REG (0x66) -#define AW88399_BSTCTRL8_REG (0x67) -#define AW88399_BSTCTRL9_REG (0x68) -#define AW88399_BSTCTRL10_REG (0x69) -#define AW88399_CPCTRL_REG (0x6A) -#define AW88399_EFWH_REG (0x6C) -#define AW88399_EFWM2_REG (0x6D) -#define AW88399_EFWM1_REG (0x6E) -#define AW88399_EFWL_REG (0x6F) -#define AW88399_TESTCTRL1_REG (0x70) -#define AW88399_TESTCTRL2_REG (0x71) -#define AW88399_EFCTRL1_REG (0x72) -#define AW88399_EFCTRL2_REG (0x73) -#define AW88399_EFRH4_REG (0x74) -#define AW88399_EFRH3_REG (0x75) -#define AW88399_EFRH2_REG (0x76) -#define AW88399_EFRH1_REG (0x77) -#define AW88399_EFRL4_REG (0x78) -#define AW88399_EFRL3_REG (0x79) -#define AW88399_EFRL2_REG (0x7A) -#define AW88399_EFRL1_REG (0x7B) -#define AW88399_TM_REG (0x7C) -#define AW88399_TM2_REG (0x7D) - -#define AW88399_REG_MAX (0x7E) -#define AW88399_MUTE_VOL (1023) - -#define AW88399_DSP_CFG_ADDR (0x9B00) -#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68) -#define AW88399_DSP_FW_ADDR (0x8980) -#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40) -#define AW88399_DSP_ROM_CHECK_DATA (0x4638) - -#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000)) -#define AW88399_CALI_RE_HBITS_SHIFT (16) - -#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF)) -#define AW88399_CALI_RE_LBITS_SHIFT (0) - -#define AW88399_I2STXEN_START_BIT (9) -#define AW88399_I2STXEN_BITS_LEN (1) -#define AW88399_I2STXEN_MASK \ - (~(((1<> (shift)) -#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000)) -#define AW88399_CRC_CHECK_PASS_VAL (0x4) - -#define AW88399_CRC_CFG_BASE_ADDR (0xD80) -#define AW88399_CRC_FW_BASE_ADDR (0x4C0) -#define AW88399_ACF_FILE "aw88399_acf.bin" -#define AW88399_DEV_SYSST_CHECK_MAX (10) -#define AW88399_CHIP_ID 0x2183 +#include #define AW88399_I2C_NAME "aw88399" -#define AW88399_START_RETRIES (5) -#define AW88399_START_WORK_DELAY_MS (0) - #define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \ SNDRV_PCM_RATE_96000) #define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -550,80 +48,4 @@ .put = profile_set, \ } -enum { - AW_EF_AND_CHECK = 0, - AW_EF_OR_CHECK, -}; - -enum { - AW88399_DEV_VDSEL_DAC = 0, - AW88399_DEV_VDSEL_VSENSE = 32, -}; - -enum { - AW88399_DSP_CRC_NA = 0, - AW88399_DSP_CRC_OK = 1, -}; - -enum { - AW88399_DSP_FW_UPDATE_OFF = 0, - AW88399_DSP_FW_UPDATE_ON = 1, -}; - -enum { - AW88399_FORCE_UPDATE_OFF = 0, - AW88399_FORCE_UPDATE_ON = 1, -}; - -enum { - AW88399_1000_US = 1000, - AW88399_2000_US = 2000, - AW88399_3000_US = 3000, - AW88399_4000_US = 4000, -}; - -enum AW88399_DEV_STATUS { - AW88399_DEV_PW_OFF = 0, - AW88399_DEV_PW_ON, -}; - -enum AW88399_DEV_FW_STATUS { - AW88399_DEV_FW_FAILED = 0, - AW88399_DEV_FW_OK, -}; - -enum AW88399_DEV_MEMCLK { - AW88399_DEV_MEMCLK_OSC = 0, - AW88399_DEV_MEMCLK_PLL = 1, -}; - -enum AW88399_DEV_DSP_CFG { - AW88399_DEV_DSP_WORK = 0, - AW88399_DEV_DSP_BYPASS = 1, -}; - -enum { - AW88399_NOT_RCV_MODE = 0, - AW88399_RCV_MODE = 1, -}; - -enum { - AW88399_SYNC_START = 0, - AW88399_ASYNC_START, -}; - -struct aw88399 { - struct aw_device *aw_pa; - struct mutex lock; - struct gpio_desc *reset_gpio; - struct delayed_work start_work; - struct regmap *regmap; - struct aw_container *aw_cfg; - - unsigned int check_val; - unsigned int crc_init_val; - unsigned int vcalb_init_val; - unsigned int dither_st; -}; - -#endif +#endif /* __AW88399_H__ */ From df5654d7306197087aef090377d196573bb4ee46 Mon Sep 17 00:00:00 2001 From: Marco Giunta Date: Fri, 17 Jul 2026 15:25:04 +0200 Subject: [PATCH 221/438] ASoC: aw88399: derive channel from I2C address on ACPI systems Extend aw88399_parse_channel_dt to derive the audio channel from the I2C address when the Device Tree property "awinic,audio-channel" is absent. The original code calls of_property_read_u32 without checking the return value. On ACPI systems, the DT property is never present, and channel_value is used uninitialized in the assignment to aw_dev->channel. Add a fallback that computes the channel as (i2c_addr - 0x34), where 0x34 is the AW88399's base I2C address per the datasheet (valid range 0x34-0x37). This channel assignment may be subsequently overridden by the HDA side codec's property driver on systems that require it. No change on Device Tree systems where the property is present. Tested-by: Nadim Kobeissi Tested-by: Xia Yun'an Tested-by: Munzir Taha Co-developed-by: Yakov Till Signed-off-by: Yakov Till Signed-off-by: Marco Giunta Link: https://patch.msgid.link/DS7PR19MB772468BB9F4D6925DC4E8E3EFCC62@DS7PR19MB7724.namprd19.prod.outlook.com Signed-off-by: Mark Brown --- sound/soc/codecs/aw88399-lib.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c index 258d6efbf590..b525695c96d1 100644 --- a/sound/soc/codecs/aw88399-lib.c +++ b/sound/soc/codecs/aw88399-lib.c @@ -1328,8 +1328,20 @@ static void aw88399_parse_channel_dt(struct aw_device *aw_dev) { struct device_node *np = aw_dev->dev->of_node; u32 channel_value; + int ret; - of_property_read_u32(np, "awinic,audio-channel", &channel_value); + ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value); + if (ret) { + /* + * On ACPI systems, DT properties don't exist. Derive channel + * from I2C address: 0x34 -> channel 0 (left), 0x35 -> channel 1 (right) + */ + aw_dev->channel = aw_dev->i2c->addr - 0x34; + dev_dbg(aw_dev->dev, + "DT channel property not found, using I2C address-based channel %d (addr 0x%02x)\n", + aw_dev->channel, aw_dev->i2c->addr); + return; + } aw_dev->channel = channel_value; } From b4530a3e4895abfc308e2b45c0ea508f4dddd9f1 Mon Sep 17 00:00:00 2001 From: Marco Giunta Date: Fri, 17 Jul 2026 15:25:05 +0200 Subject: [PATCH 222/438] ASoC: aw88399: add per-instance BSTS status bypass flag Add a bsts_unreliable flag to struct aw88399 that, when set, causes the startup status check (aw_dev_check_sysst) to skip the BSTS (boost startup finished) requirement. On some hardware, the BSTS bit in the SYSST register (0x01, bit 9) does not reliably assert even during normal audio playback. Register inspection on affected Lenovo Legion hardware shows both amplifiers reporting BSTS=0 on both channels despite clean audio output. Per the AW88399 datasheet, BSTS indicates boost startup completion. If BSTS never reliably sets to 1, the chip is never allowed to start by aw_dev_check_sysst, regardless of whether the boot failure is genuine. The new flag defaults to false via kzalloc, preserving the original check behavior for all existing users. No existing code path sets this flag; it will be set by the forthcoming HDA side codec property driver for affected hardware. Tested-by: Nadim Kobeissi Tested-by: Xia Yun'an Tested-by: Munzir Taha Signed-off-by: Marco Giunta Link: https://patch.msgid.link/DS7PR19MB77242B8E5BB8BFB5E69816E9FCC62@DS7PR19MB7724.namprd19.prod.outlook.com Signed-off-by: Mark Brown --- include/sound/aw88399.h | 1 + sound/soc/codecs/aw88399-lib.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h index 3a2153f0ee92..dee91b540b81 100644 --- a/include/sound/aw88399.h +++ b/include/sound/aw88399.h @@ -598,6 +598,7 @@ struct aw88399 { unsigned int crc_init_val; unsigned int vcalb_init_val; unsigned int dither_st; + bool bsts_unreliable; }; int aw_dev_check_syspll(struct aw_device *aw_dev); diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c index b525695c96d1..2045c4171be0 100644 --- a/sound/soc/codecs/aw88399-lib.c +++ b/sound/soc/codecs/aw88399-lib.c @@ -167,8 +167,9 @@ int aw_dev_check_syspll(struct aw_device *aw_dev) } EXPORT_SYMBOL_GPL(aw_dev_check_syspll); -static int aw_dev_check_sysst(struct aw_device *aw_dev) +static int aw_dev_check_sysst(struct aw88399 *aw88399) { + struct aw_device *aw_dev = aw88399->aw_pa; unsigned int check_val; unsigned int reg_val; int ret, i; @@ -182,6 +183,14 @@ static int aw_dev_check_sysst(struct aw_device *aw_dev) else check_val = AW88399_BIT_SYSST_SWS_CHECK; + /* + * On some hardware the BSTS (boost-finished) status bit does not + * reliably assert even when audio output is working normally. + * Allow per-instance bypass when flagged by the side-codec driver. + */ + if (aw88399->bsts_unreliable) + check_val &= ~AW88399_BSTS_FINISHED_VALUE; + for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); if (ret) @@ -710,7 +719,7 @@ static int aw88399_dev_start(struct aw88399 *aw88399) usleep_range(AW88399_1000_US, AW88399_1000_US + 50); /* check i2s status */ - ret = aw_dev_check_sysst(aw_dev); + ret = aw_dev_check_sysst(aw88399); if (ret) { dev_err(aw_dev->dev, "sysst check failed"); goto sysst_check_fail; From b5e1d685fb9c9acef5942794a8dc07580c607e66 Mon Sep 17 00:00:00 2001 From: Marco Giunta Date: Fri, 17 Jul 2026 15:25:06 +0200 Subject: [PATCH 223/438] ASoC: aw88399: add firmware reload flag for resume Add a fw_needs_reload flag to struct aw88399 that, when set, causes aw88399_start to perform a full DSP firmware upload instead of assuming the firmware binary is already present in memory. After system sleep, the AW88399 loses its memory contents. The existing start sequence assumes the firmware binary persists from initialization and only uploads register configuration and DSP config (AW88399_DSP_FW_UPDATE_OFF). When memory is empty, this causes the subsequent CRC check to fail, triggering the retry mechanism in aw88399_start_pa which re-uploads the firmware on the second attempt. While the retry mechanism recovers correctly, it produces misleading error-level log messages on every resume cycle. The fw_needs_reload flag allows the HDA side codec driver to signal that a full firmware reload is needed after resume, eliminating the spurious CRC failures. The flag defaults to false via kzalloc, preserving the original behavior for existing ASoC users. No existing code path sets this flag; it will be set by the HDA side codec driver's system suspend handler. Tested-by: Nadim Kobeissi Tested-by: Xia Yun'an Tested-by: Munzir Taha Signed-off-by: Marco Giunta Link: https://patch.msgid.link/DS7PR19MB77240CB79188C0B7AE243829FCC62@DS7PR19MB7724.namprd19.prod.outlook.com Signed-off-by: Mark Brown --- include/sound/aw88399.h | 1 + sound/soc/codecs/aw88399-lib.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h index dee91b540b81..3dbc37dc13d1 100644 --- a/include/sound/aw88399.h +++ b/include/sound/aw88399.h @@ -599,6 +599,7 @@ struct aw88399 { unsigned int vcalb_init_val; unsigned int dither_st; bool bsts_unreliable; + bool fw_needs_reload; }; int aw_dev_check_syspll(struct aw_device *aw_dev); diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c index 2045c4171be0..094a37b66fb5 100644 --- a/sound/soc/codecs/aw88399-lib.c +++ b/sound/soc/codecs/aw88399-lib.c @@ -1171,12 +1171,15 @@ void aw88399_start(struct aw88399 *aw88399, bool sync_start) if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) return; - ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true); + ret = aw88399_dev_fw_update(aw88399, aw88399->fw_needs_reload ? + AW88399_DSP_FW_UPDATE_ON : AW88399_DSP_FW_UPDATE_OFF, true); if (ret) { dev_err(aw88399->aw_pa->dev, "fw update failed."); return; } + aw88399->fw_needs_reload = false; + if (sync_start == AW88399_SYNC_START) aw88399_start_pa(aw88399); else From 15c9fdb3c39d5073463ffa746cc64ad9682c875f Mon Sep 17 00:00:00 2001 From: Marco Giunta Date: Fri, 17 Jul 2026 15:25:07 +0200 Subject: [PATCH 224/438] ASoC: aw88399: add channel setter for HDA side codec Add aw88399_dev_set_channel() to the shared library so that the HDA side codec driver can set the amplifier's channel assignment without including the aw88395 device header directly. The AW88399's struct aw_device is defined in aw88395_device.h, which lives under sound/soc/codecs/aw88395/. Without this accessor, the HDA driver would need a cross-subsystem relative include path to access the channel field. Providing a setter in the library keeps the interface clean and avoids coupling the HDA driver to ASoC-internal headers. Tested-by: Nadim Kobeissi Tested-by: Xia Yun'an Tested-by: Munzir Taha Signed-off-by: Marco Giunta Link: https://patch.msgid.link/DS7PR19MB7724E8A1AD36D1E623FA2A0AFCC62@DS7PR19MB7724.namprd19.prod.outlook.com Signed-off-by: Mark Brown --- include/sound/aw88399.h | 1 + sound/soc/codecs/aw88399-lib.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h index 3dbc37dc13d1..a1e0de6be8ea 100644 --- a/include/sound/aw88399.h +++ b/include/sound/aw88399.h @@ -609,6 +609,7 @@ int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value); int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc); int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name); void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute); +void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel); void aw88399_hw_reset(struct aw88399 *aw88399); int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap); extern const struct regmap_config aw88399_remap_config; diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c index 094a37b66fb5..5c7982891def 100644 --- a/sound/soc/codecs/aw88399-lib.c +++ b/sound/soc/codecs/aw88399-lib.c @@ -1401,5 +1401,11 @@ int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap } EXPORT_SYMBOL_GPL(aw88399_init); +void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel) +{ + aw88399->aw_pa->channel = channel; +} +EXPORT_SYMBOL_GPL(aw88399_dev_set_channel); + MODULE_DESCRIPTION("AW88399 common device library"); MODULE_LICENSE("GPL"); From 315a717c716eab4e8db1ec4ddd13d4b963bf73c6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:33:38 +0000 Subject: [PATCH 225/438] ASoC: mediatek: mt8192-mt6359-rt1015-rt5682: use *dev in mt8192_mt6359_card_set_be_link() use *dev, instead of card->dev. No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/871pcxjfd9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- .../mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index 91c57765ab57..864b4d7228f5 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1019,7 +1019,7 @@ static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = { .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_routes), }; -static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card, +static int mt8192_mt6359_card_set_be_link(struct device *dev, struct snd_soc_dai_link *link, struct device_node *node, char *link_name) @@ -1027,9 +1027,9 @@ static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card, int ret; if (node && strcmp(link->name, link_name) == 0) { - ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link); + ret = snd_soc_of_get_dai_link_codecs(dev, node, link); if (ret < 0) { - dev_err_probe(card->dev, ret, "get dai link codecs fail\n"); + dev_err_probe(dev, ret, "get dai link codecs fail\n"); return ret; } } @@ -1065,21 +1065,21 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data) } for_each_card_prelinks(card, i, dai_link) { - ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3"); + ret = mt8192_mt6359_card_set_be_link(dev, dai_link, speaker_codec, "I2S3"); if (ret) { dev_err_probe(dev, ret, "%s set speaker_codec fail\n", dai_link->name); break; } - ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8"); + ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S8"); if (ret) { dev_err_probe(dev, ret, "%s set headset_codec fail\n", dai_link->name); break; } - ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9"); + ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S9"); if (ret) { dev_err_probe(dev, ret, "%s set headset_codec fail\n", dai_link->name); From 8fd27d490a87c56be8f73c0f5ed26a88a20d1b98 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:33:42 +0000 Subject: [PATCH 226/438] ASoC: mediatek: common/mtk-dsp-sof-common: use for_each_card_prelinks() We already have for_each_card_prelinks(). Let's use it. Signed-off-by: Kuninori Morimoto Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/87zezli0sp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-dsp-sof-common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c index 17b9ea6be604..adefbed5bbe7 100644 --- a/sound/soc/mediatek/common/mtk-dsp-sof-common.c +++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c @@ -232,6 +232,7 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card, const char *propname) { struct device_node *np = dev->of_node; + struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *parsed_dai_link; const char *dai_name = NULL; int i, j, ret, num_links, parsed_num_links = 0; @@ -254,9 +255,9 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card, return ret; } dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name); - for (j = 0; j < card->num_links; j++) { - if (!strcmp(dai_name, card->dai_link[j].name)) { - memcpy(&parsed_dai_link[parsed_num_links++], &card->dai_link[j], + for_each_card_prelinks(card, j, dai_link) { + if (!strcmp(dai_name, dai_link->name)) { + memcpy(&parsed_dai_link[parsed_num_links++], dai_link, sizeof(struct snd_soc_dai_link)); break; } From a5db2423440548f86b0a5608ffc9ffb6c01ac67d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:33:46 +0000 Subject: [PATCH 227/438] ASoC: mediatek: mt8196-nau8825: remove unnecessary declaration No need to declarate mt8196_nau8825_soc_card. Remove it. Signed-off-by: Kuninori Morimoto Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/87y0f5i0sl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8196/mt8196-nau8825.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c index c9424786c53d..8303ab960f80 100644 --- a/sound/soc/mediatek/mt8196/mt8196-nau8825.c +++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c @@ -104,8 +104,6 @@ static const struct snd_kcontrol_new mt8196_nau8825_controls[] = { #define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp" -static struct snd_soc_card mt8196_nau8825_soc_card; - static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] = { /* SOF Uplink */ SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0), From 7a8073fe03bbc77aa6adf71ec8c76cf6ad03c498 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:33:51 +0000 Subject: [PATCH 228/438] ASoC: mediatek: mt8365-mt6357: remove useless assignment static int mt8365_mt6357_dev_probe(...) { ... struct device *dev = card->dev; ... => card->dev = dev; ... } This is useless. Remove it. Signed-off-by: Kuninori Morimoto Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/87wlupi0sg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8365/mt8365-mt6357.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c index 4339f45ee115..dceee837c67d 100644 --- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -297,7 +297,6 @@ static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool struct mt8365_mt6357_priv *mach_priv; int ret; - card->dev = dev; ret = parse_dai_link_info(card); if (ret) goto err; From 784e04110272590a34d7faad656232b7f9aeb1df Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Wed, 22 Jul 2026 16:46:55 +0530 Subject: [PATCH 229/438] ASoC: qcom: qdsp6: Remove unused Q6AFE_MAX_CLK_ID define Q6AFE_MAX_CLK_ID is not used anywhere. Remove the unused define. Signed-off-by: Prasad Kumpatla Reviewed-by: Dmitry Baryshkov Link: https://patch.msgid.link/20260722111655.3558096-1-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index 45850f2d4342..7b553a73bc92 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -237,8 +237,6 @@ #define LPASS_HW_MACRO_VOTE 102 #define LPASS_HW_DCODEC_VOTE 103 -#define Q6AFE_MAX_CLK_ID 104 - #define LPASS_CLK_ATTRIBUTE_INVALID 0x0 #define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 #define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2 From da3048b0c6153cb03b68cbcc5db62e298806d4b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:49:17 +0000 Subject: [PATCH 230/438] ASoC: intel: sof_sdw: use &pdev->dev instead of card->dev sof_sdw.c will be updated when Card capsuling. To makes its review easy, use &pdev->dev instead of card->dev in mc_probe(). There is no diff, because static int mc_probe(...) { ... card->dev = &pdev->dev; ... } No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/877bmpi02q.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index acfa34aea242..3386beebf39d 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1481,12 +1481,12 @@ static int mc_probe(struct platform_device *pdev) dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { - dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", sof_sdw_quirk, quirk_override); sof_sdw_quirk = quirk_override; } - log_quirks(card->dev); + log_quirks(&pdev->dev); ctx->mc_quirk = sof_sdw_quirk; /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ @@ -1505,13 +1505,13 @@ static int mc_probe(struct platform_device *pdev) for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, + card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, " cfg-amp:%d", amp_num); if (!card->components) return -ENOMEM; if (mach->mach_params.dmic_num) { - card->components = devm_kasprintf(card->dev, GFP_KERNEL, + card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s mic:dmic cfg-mics:%d", card->components, mach->mach_params.dmic_num); @@ -1522,7 +1522,7 @@ static int mc_probe(struct platform_device *pdev) /* Register the card */ ret = devm_snd_soc_register_card(card->dev, card); if (ret) { - dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret); asoc_sdw_mc_dailink_exit_loop(card); return ret; } From 2700946d7bdf7a112d79db018b5f8503bd2ffa0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:30:08 +0000 Subject: [PATCH 231/438] ASoC: fsl: p1022_ds: add card_to_mdata() macro p1022_ds.c will be updated when Card capsuling. To makes its review easy, adds card_to_mdata() and useit to reduce un-related diff. No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/875x29jfj4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/p1022_ds.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index db07817a8024..98389f53246c 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -73,6 +73,8 @@ struct machine_data { char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ }; +#define card_to_mdata(_card) container_of(_card, struct machine_data, card) + /** * p1022_ds_machine_probe: initialize the board * @@ -82,8 +84,7 @@ struct machine_data { */ static int p1022_ds_machine_probe(struct snd_soc_card *card) { - struct machine_data *mdata = - container_of(card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(card); struct ccsr_guts __iomem *guts; guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); @@ -122,8 +123,7 @@ static int p1022_ds_machine_probe(struct snd_soc_card *card) static int p1022_ds_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct machine_data *mdata = - container_of(rtd->card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(rtd->card); struct device *dev = rtd->card->dev; int ret = 0; @@ -156,8 +156,7 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream) */ static int p1022_ds_machine_remove(struct snd_soc_card *card) { - struct machine_data *mdata = - container_of(card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(card); struct ccsr_guts __iomem *guts; guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); @@ -399,8 +398,7 @@ static int p1022_ds_probe(struct platform_device *pdev) static void p1022_ds_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct machine_data *mdata = - container_of(card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(card); snd_soc_unregister_card(card); kfree(mdata); From c02fe2006059c3bd2c5b7c25213a1797a0ba091e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:30:12 +0000 Subject: [PATCH 232/438] ASoC: fsl: p1022_rdk: add card_to_mdata() macro p1022_rdk.c will be updated when Card capsuling. To makes its review easy, adds card_to_mdata() and useit to reduce un-related diff. No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/874ihtjfj0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/fsl/p1022_rdk.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index f80d6d04e791..d82fe22ca5c5 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -79,6 +79,8 @@ struct machine_data { char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ }; +#define card_to_mdata(_card) container_of(_card, struct machine_data, card) + /** * p1022_rdk_machine_probe - initialize the board * @card: ASoC card instance @@ -91,8 +93,7 @@ struct machine_data { */ static int p1022_rdk_machine_probe(struct snd_soc_card *card) { - struct machine_data *mdata = - container_of(card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(card); struct ccsr_guts __iomem *guts; guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); @@ -134,8 +135,7 @@ static int p1022_rdk_machine_probe(struct snd_soc_card *card) static int p1022_rdk_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct machine_data *mdata = - container_of(rtd->card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(rtd->card); struct device *dev = rtd->card->dev; int ret = 0; @@ -169,8 +169,7 @@ static int p1022_rdk_startup(struct snd_pcm_substream *substream) */ static int p1022_rdk_machine_remove(struct snd_soc_card *card) { - struct machine_data *mdata = - container_of(card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(card); struct ccsr_guts __iomem *guts; guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); @@ -361,8 +360,7 @@ static int p1022_rdk_probe(struct platform_device *pdev) static void p1022_rdk_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - struct machine_data *mdata = - container_of(card, struct machine_data, card); + struct machine_data *mdata = card_to_mdata(card); snd_soc_unregister_card(card); kfree(mdata); From 998b8a6c8aff2f1364197abd0dc05ccb37e62801 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 22 Jul 2026 15:36:07 +0100 Subject: [PATCH 233/438] ASoC: cs35l56: Sort table of sdw_device_id Swap the entries for 3562 and 3563 to keep the table in order of increasing part number. There's nothing broken here, it's just cosmetic. Signed-off-by: Richard Fitzgerald Link: https://patch.msgid.link/20260722143607.1001473-1-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l56-sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 1e442f43b306..303d37e7d0bf 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -510,8 +510,8 @@ static const struct dev_pm_ops cs35l56_sdw_pm = { static const struct sdw_device_id cs35l56_sdw_id[] = { SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556), SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557), - SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563), SDW_SLAVE_ENTRY(0x01FA, 0x3562, 0x3562), + SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563), {}, }; MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id); From 847b7114df54b6a5448b784e74d0868bf65a69b7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:32 +0700 Subject: [PATCH 234/438] ASoC: codecs: da7213: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/da7213.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 4bf91ab2553a..923b997efbc4 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -216,13 +217,10 @@ static int da7213_volsw_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_get_volsw(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_get_volsw(kcontrol, ucontrol); } static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol, @@ -230,13 +228,10 @@ static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_put_volsw(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_put_volsw(kcontrol, ucontrol); } static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol, @@ -244,13 +239,10 @@ static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_get_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_get_enum_double(kcontrol, ucontrol); } static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol, @@ -258,13 +250,10 @@ static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7213->ctrl_lock); - ret = snd_soc_put_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); - return ret; + return snd_soc_put_enum_double(kcontrol, ucontrol); } /* ALC */ @@ -465,9 +454,8 @@ static int da7213_tonegen_freq_get(struct snd_kcontrol *kcontrol, __le16 val; int ret; - mutex_lock(&da7213->ctrl_lock); - ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7213->ctrl_lock); + scoped_guard(mutex, &da7213->ctrl_lock) + ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val)); if (ret) return ret; @@ -499,12 +487,11 @@ static int da7213_tonegen_freq_put(struct snd_kcontrol *kcontrol, */ val_new = cpu_to_le16(ucontrol->value.integer.value[0]); - mutex_lock(&da7213->ctrl_lock); + guard(mutex)(&da7213->ctrl_lock); ret = regmap_raw_read(da7213->regmap, reg, &val_old, sizeof(val_old)); if (ret == 0 && (val_old != val_new)) ret = regmap_raw_write(da7213->regmap, reg, &val_new, sizeof(val_new)); - mutex_unlock(&da7213->ctrl_lock); if (ret < 0) return ret; From 47f85aa98bb2a23e42b24bde8fd3ac244f3f7c6c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:33 +0700 Subject: [PATCH 235/438] ASoC: codecs: da7219: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 62 ++++++++++++--------------------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index f0874d891e12..f6d371e93549 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -256,13 +257,10 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_get_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_get_volsw(kcontrol, ucontrol); } static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, @@ -270,13 +268,10 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_put_volsw(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_put_volsw(kcontrol, ucontrol); } static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, @@ -284,13 +279,10 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_get_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_get_enum_double(kcontrol, ucontrol); } static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, @@ -298,13 +290,10 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->ctrl_lock); - ret = snd_soc_put_enum_double(kcontrol, ucontrol); - mutex_unlock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); - return ret; + return snd_soc_put_enum_double(kcontrol, ucontrol); } /* ALC */ @@ -422,9 +411,8 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, __le16 val; int ret; - mutex_lock(&da7219->ctrl_lock); - ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); - mutex_unlock(&da7219->ctrl_lock); + scoped_guard(mutex, &da7219->ctrl_lock) + ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); if (ret) return ret; @@ -456,12 +444,11 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, */ val_new = cpu_to_le16(ucontrol->value.integer.value[0]); - mutex_lock(&da7219->ctrl_lock); + guard(mutex)(&da7219->ctrl_lock); ret = regmap_raw_read(da7219->regmap, reg, &val_old, sizeof(val_old)); if (ret == 0 && (val_old != val_new)) ret = regmap_raw_write(da7219->regmap, reg, - &val_new, sizeof(val_new)); - mutex_unlock(&da7219->ctrl_lock); + &val_new, sizeof(val_new)); if (ret < 0) return ret; @@ -1167,15 +1154,12 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&da7219->pll_lock); + guard(mutex)(&da7219->pll_lock); - if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) { - mutex_unlock(&da7219->pll_lock); + if (da7219->clk_src == clk_id && da7219->mclk_rate == freq) return 0; - } - if ((freq < 2000000) || (freq > 54000000)) { - mutex_unlock(&da7219->pll_lock); + if (freq < 2000000 || freq > 54000000) { dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; @@ -1193,7 +1177,6 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, break; default: dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); - mutex_unlock(&da7219->pll_lock); return -EINVAL; } @@ -1203,17 +1186,13 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, freq = clk_round_rate(da7219->mclk, freq); ret = clk_set_rate(da7219->mclk, freq); if (ret) { - dev_err(codec_dai->dev, "Failed to set clock rate %d\n", - freq); - mutex_unlock(&da7219->pll_lock); + dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq); return ret; } } da7219->mclk_rate = freq; - mutex_unlock(&da7219->pll_lock); - return 0; } @@ -1296,13 +1275,10 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, { struct snd_soc_component *component = codec_dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&da7219->pll_lock); - ret = da7219_set_pll(component, source, fout); - mutex_unlock(&da7219->pll_lock); + guard(mutex)(&da7219->pll_lock); - return ret; + return da7219_set_pll(component, source, fout); } static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) From 357d20c73de668504ddf336f07d30ba7b41dbcd8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:34 +0700 Subject: [PATCH 236/438] ASoC: codecs: es8316: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 3abe77423f29..87f331868dc7 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -620,15 +621,15 @@ static irqreturn_t es8316_irq(int irq, void *data) struct snd_soc_component *comp = es8316->component; unsigned int flags; - mutex_lock(&es8316->lock); + guard(mutex)(&es8316->lock); regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); if (flags == 0x00) - goto out; /* Powered-down / reset */ + return IRQ_HANDLED; /* Powered-down / reset */ /* Catch spurious IRQ before set_jack is called */ if (!es8316->jack) - goto out; + return IRQ_HANDLED; if (es8316->jd_inverted) flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED; @@ -681,8 +682,6 @@ static irqreturn_t es8316_irq(int irq, void *data) } } -out: - mutex_unlock(&es8316->lock); return IRQ_HANDLED; } @@ -699,18 +698,16 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component, es8316->jd_inverted = device_property_read_bool(component->dev, "everest,jack-detect-inverted"); - mutex_lock(&es8316->lock); + scoped_guard(mutex, &es8316->lock) { + es8316->jack = jack; - es8316->jack = jack; + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_enable_micbias_for_mic_gnd_short_detect(component); - if (es8316->jack->status & SND_JACK_MICROPHONE) - es8316_enable_micbias_for_mic_gnd_short_detect(component); - - snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, - ES8316_GPIO_ENABLE_INTERRUPT, - ES8316_GPIO_ENABLE_INTERRUPT); - - mutex_unlock(&es8316->lock); + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, + ES8316_GPIO_ENABLE_INTERRUPT); + } /* Enable irq and sync initial jack state */ enable_irq(es8316->irq); @@ -726,7 +723,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component) disable_irq(es8316->irq); - mutex_lock(&es8316->lock); + guard(mutex)(&es8316->lock); snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, ES8316_GPIO_ENABLE_INTERRUPT, 0); @@ -737,8 +734,6 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component) } es8316->jack = NULL; - - mutex_unlock(&es8316->lock); } static int es8316_set_jack(struct snd_soc_component *component, From 61bc0010fafab96f885bb69da214674ad15d8f3d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:35 +0700 Subject: [PATCH 237/438] ASoC: codecs: es8326: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8326.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index a79b2da35099..c5460589a88b 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -6,6 +6,7 @@ // Authors: David Yang // +#include #include #include #include @@ -790,7 +791,7 @@ static void es8326_jack_button_handler(struct work_struct *work) if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */ return; - mutex_lock(&es8326->lock); + guard(mutex)(&es8326->lock); iface = snd_soc_component_read(comp, ES8326_HPDET_STA); switch (iface) { case 0x93: @@ -845,7 +846,6 @@ static void es8326_jack_button_handler(struct work_struct *work) } es8326_disable_micbias(es8326->component); } - mutex_unlock(&es8326->lock); } static void es8326_jack_detect_handler(struct work_struct *work) @@ -855,7 +855,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) struct snd_soc_component *comp = es8326->component; unsigned int iface; - mutex_lock(&es8326->lock); + guard(mutex)(&es8326->lock); iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); @@ -873,7 +873,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? ~es8326->jack_pol : es8326->jack_pol)); - goto exit; + return; } if ((iface & ES8326_HPINSERT_FLAG) == 0) { @@ -930,7 +930,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work, msecs_to_jiffies(400)); es8326->hp = 1; - goto exit; + return; } if (es8326->jack->status & SND_JACK_HEADSET) { /* detect button */ @@ -939,7 +939,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); es8326_enable_micbias(es8326->component); queue_delayed_work(system_dfl_wq, &es8326->button_press_work, 10); - goto exit; + return; } if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) { dev_dbg(comp->dev, "Headphone detected\n"); @@ -958,8 +958,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) usleep_range(10000, 15000); } } -exit: - mutex_unlock(&es8326->lock); } static irqreturn_t es8326_irq(int irq, void *dev_id) @@ -1200,13 +1198,12 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component, { struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - mutex_lock(&es8326->lock); - if (es8326->jd_inverted) - snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, - ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); - es8326->jack = jack; - - mutex_unlock(&es8326->lock); + scoped_guard(mutex, &es8326->lock) { + if (es8326->jd_inverted) + snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, + ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); + es8326->jack = jack; + } es8326_irq(es8326->irq, es8326); } @@ -1219,13 +1216,12 @@ static void es8326_disable_jack_detect(struct snd_soc_component *component) return; /* Already disabled (or never enabled) */ cancel_delayed_work_sync(&es8326->jack_detect_work); - mutex_lock(&es8326->lock); + guard(mutex)(&es8326->lock); if (es8326->jack->status & SND_JACK_MICROPHONE) { es8326_disable_micbias(component); snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); } es8326->jack = NULL; - mutex_unlock(&es8326->lock); } static int es8326_set_jack(struct snd_soc_component *component, From 17b1563aad1fb77ed9e91309a2e06307cf8f95e0 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:36 +0700 Subject: [PATCH 238/438] ASoC: codecs: es9356: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/es9356.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c index f574b3d6cb3c..a9863900bf70 100644 --- a/sound/soc/codecs/es9356.c +++ b/sound/soc/codecs/es9356.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -500,16 +501,19 @@ static int es9356_power_state(struct snd_soc_dai *dai, unsigned char ps, unsigne } /* power state changes are not independent across functions */ - mutex_lock(&es9356->pde_lock); - ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps0:ps3); - if (ret) { - regmap_write(es9356->regmap, - SDW_SDCA_CTL(func, pde_entity, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps?ps3:ps0); - es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps3:ps0); - } else - dev_dbg(component->dev, "%s PDE is already %d\n", __func__, ps?ps0:ps3); - - mutex_unlock(&es9356->pde_lock); + scoped_guard(mutex, &es9356->pde_lock) { + ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps0 : ps3); + if (ret) { + regmap_write(es9356->regmap, + SDW_SDCA_CTL(func, pde_entity, + ES9356_SDCA_CTL_REQ_POWER_STATE, 0), + ps ? ps3 : ps0); + es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps3 : ps0); + } else { + dev_dbg(component->dev, "%s PDE is already %d\n", __func__, + ps ? ps0 : ps3); + } + } if (rate) regmap_write(es9356->regmap, @@ -1091,9 +1095,8 @@ static int es9356_sdca_dev_system_suspend(struct device *dev) { struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev); - mutex_lock(&es9356->disable_irq_lock); - es9356->disable_irq = true; - mutex_unlock(&es9356->disable_irq_lock); + scoped_guard(mutex, &es9356->disable_irq_lock) + es9356->disable_irq = true; return es9356_sdca_dev_suspend(dev); } From db044108a54a12de82b344c44ae8e7fcb26caeb8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:37 +0700 Subject: [PATCH 239/438] ASoC: codecs: fs210x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-7-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/fs210x.c | 89 ++++++++++++++------------------------- 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c index 5f381fe063e8..dce525ae50dd 100644 --- a/sound/soc/codecs/fs210x.c +++ b/sound/soc/codecs/fs210x.c @@ -4,6 +4,7 @@ // // Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. +#include #include #include #include @@ -770,9 +771,8 @@ static int fs210x_dai_hw_params(struct snd_pcm_substream *substream, if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000) return -EOPNOTSUPP; - mutex_lock(&fs210x->lock); - ret = fs210x_set_hw_params(fs210x); - mutex_unlock(&fs210x->lock); + scoped_guard(mutex, &fs210x->lock) + ret = fs210x_set_hw_params(fs210x); if (ret) dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret); @@ -789,15 +789,11 @@ static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream) fs210x = snd_soc_component_get_drvdata(dai->component); - mutex_lock(&fs210x->lock); - - if (!fs210x->is_inited || fs210x->is_suspended) { - mutex_unlock(&fs210x->lock); - return 0; + scoped_guard(mutex, &fs210x->lock) { + if (!fs210x->is_inited || fs210x->is_suspended) + return 0; } - mutex_unlock(&fs210x->lock); - if (mute) { cancel_delayed_work_sync(&fs210x->fault_check_work); cancel_delayed_work_sync(&fs210x->start_work); @@ -816,15 +812,11 @@ static int fs210x_dai_trigger(struct snd_pcm_substream *substream, fs210x = snd_soc_component_get_drvdata(dai->component); - mutex_lock(&fs210x->lock); - - if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) { - mutex_unlock(&fs210x->lock); - return 0; + scoped_guard(mutex, &fs210x->lock) { + if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) + return 0; } - mutex_unlock(&fs210x->lock); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -852,13 +844,11 @@ static void fs210x_start_work(struct work_struct *work) fs210x = container_of(work, struct fs210x_priv, start_work.work); - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); ret = fs210x_dev_play(fs210x); if (ret) dev_err(fs210x->dev, "Failed to start playing: %d\n", ret); - - mutex_unlock(&fs210x->lock); } static void fs210x_fault_check_work(struct work_struct *work) @@ -869,15 +859,13 @@ static void fs210x_fault_check_work(struct work_struct *work) fs210x = container_of(work, struct fs210x_priv, fault_check_work.work); - mutex_lock(&fs210x->lock); + scoped_guard(mutex, &fs210x->lock) { + if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) + return; - if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) { - mutex_unlock(&fs210x->lock); - return; + ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); } - ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); - mutex_unlock(&fs210x->lock); if (ret) return; @@ -990,7 +978,7 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, if (fs210x->scene_id < 1) return -EINVAL; - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); /* * FS210x has scene(s) as below: * init scene: id = 0 @@ -999,7 +987,6 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, */ index = fs210x->scene_id - 1; ucontrol->value.integer.value[0] = index; - mutex_unlock(&fs210x->lock); return 0; } @@ -1018,7 +1005,7 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); /* * FS210x has scene(s) as below: @@ -1028,17 +1015,14 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, */ scene_id = ucontrol->value.integer.value[0] + 1; scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */ - if (scene_id < 1 || scene_id > scene_count) { - mutex_unlock(&fs210x->lock); + if (scene_id < 1 || scene_id > scene_count) return -ERANGE; - } if (scene_id != fs210x->scene_id) is_changed = true; if (fs210x->is_suspended) { fs210x->scene_id = scene_id; - mutex_unlock(&fs210x->lock); return is_changed; } @@ -1046,8 +1030,6 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, if (ret) dev_err(fs210x->dev, "Failed to set scene: %d\n", ret); - mutex_unlock(&fs210x->lock); - if (!ret && is_changed) return 1; @@ -1061,12 +1043,10 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w, struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt); int ret = 0; - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); - if (fs210x->is_suspended) { - mutex_unlock(&fs210x->lock); + if (fs210x->is_suspended) return 0; - } switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1087,8 +1067,6 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w, break; } - mutex_unlock(&fs210x->lock); - return ret; } @@ -1219,11 +1197,9 @@ static int fs210x_probe(struct snd_soc_component *cmpnt) if (ret) return ret; - mutex_lock(&fs210x->lock); - ret = fs210x_init_chip(fs210x); - mutex_unlock(&fs210x->lock); + guard(mutex)(&fs210x->lock); - return ret; + return fs210x_init_chip(fs210x); } static void fs210x_remove(struct snd_soc_component *cmpnt) @@ -1250,15 +1226,15 @@ static int fs210x_suspend(struct snd_soc_component *cmpnt) regcache_cache_only(fs210x->regmap, true); - mutex_lock(&fs210x->lock); - fs210x->cur_scene = NULL; - fs210x->is_inited = false; - fs210x->is_playing = false; - fs210x->is_suspended = true; + scoped_guard(mutex, &fs210x->lock) { + fs210x->cur_scene = NULL; + fs210x->is_inited = false; + fs210x->is_playing = false; + fs210x->is_suspended = true; - gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ - fsleep(30000); /* >= 30ms */ - mutex_unlock(&fs210x->lock); + gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ + fsleep(30000); /* >= 30ms */ + } cancel_delayed_work_sync(&fs210x->start_work); cancel_delayed_work_sync(&fs210x->fault_check_work); @@ -1287,14 +1263,11 @@ static int fs210x_resume(struct snd_soc_component *cmpnt) return ret; } - mutex_lock(&fs210x->lock); + guard(mutex)(&fs210x->lock); fs210x->is_suspended = false; - ret = fs210x_init_chip(fs210x); - mutex_unlock(&fs210x->lock); - - return ret; + return fs210x_init_chip(fs210x); } #else #define fs210x_suspend NULL From 51aac9ed7c0e5be51ca274a0f062e687ddb7f6ca Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:38 +0700 Subject: [PATCH 240/438] ASoC: codecs: hdac_hdmi: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-8-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 127 +++++++++++++++++------------------ 1 file changed, 62 insertions(+), 65 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 38073a70fa61..d9e6fa6d3e99 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -10,6 +10,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include #include @@ -537,10 +538,11 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( continue; list_for_each_entry(port, &pcm->port_list, head) { - mutex_lock(&pcm->lock); - ret = hdac_hdmi_query_port_connlist(hdev, - port->pin, port); - mutex_unlock(&pcm->lock); + scoped_guard(mutex, &pcm->lock) { + ret = hdac_hdmi_query_port_connlist(hdev, + port->pin, + port); + } if (ret < 0) continue; @@ -640,11 +642,11 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); if (pcm) { - mutex_lock(&pcm->lock); - pcm->chmap_set = false; - memset(pcm->chmap, 0, sizeof(pcm->chmap)); - pcm->channels = 0; - mutex_unlock(&pcm->lock); + scoped_guard(mutex, &pcm->lock) { + pcm->chmap_set = false; + memset(pcm->chmap, 0, sizeof(pcm->chmap)); + pcm->channels = 0; + } } if (dai_map->port) @@ -922,7 +924,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, if (port == NULL) return -EINVAL; - mutex_lock(&hdmi->pin_mutex); + guard(mutex)(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (list_empty(&pcm->port_list)) continue; @@ -945,12 +947,10 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, list_add_tail(&port->head, &pcm->port_list); if (port->eld.monitor_present && port->eld.eld_valid) { hdac_hdmi_jack_report_sync(pcm, port, true); - mutex_unlock(&hdmi->pin_mutex); return ret; } } } - mutex_unlock(&hdmi->pin_mutex); return ret; } @@ -1274,67 +1274,65 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * In case of non MST pin, get_eld info API expectes port * to be -1. */ - mutex_lock(&hdmi->pin_mutex); - port->eld.monitor_present = false; + scoped_guard(mutex, &hdmi->pin_mutex) { + port->eld.monitor_present = false; - if (pin->mst_capable) - port_id = port->id; + if (pin->mst_capable) + port_id = port->id; - size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id, - &port->eld.monitor_present, - port->eld.eld_buffer, - ELD_MAX_SIZE); + size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id, + &port->eld.monitor_present, + port->eld.eld_buffer, + ELD_MAX_SIZE); - if (size > 0) { - size = min(size, ELD_MAX_SIZE); - if (hdac_hdmi_parse_eld(hdev, port) < 0) - size = -EINVAL; - } - - eld_valid = port->eld.eld_valid; - - if (size > 0) { - port->eld.eld_valid = true; - port->eld.eld_size = size; - } else { - port->eld.eld_valid = false; - port->eld.eld_size = 0; - } - - eld_changed = (eld_valid != port->eld.eld_valid); - - pcm = hdac_hdmi_get_pcm(hdev, port); - - if (!port->eld.monitor_present || !port->eld.eld_valid) { - - dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", - __func__, pin->nid, port->id); - - /* - * PCMs are not registered during device probe, so don't - * report jack here. It will be done in usermode mux - * control select. - */ - if (pcm) { - hdac_hdmi_jack_report(pcm, port, false); - schedule_work(&port->dapm_work); + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(hdev, port) < 0) + size = -EINVAL; } - mutex_unlock(&hdmi->pin_mutex); - return; - } + eld_valid = port->eld.eld_valid; - if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) { - hdac_hdmi_jack_report(pcm, port, true); - schedule_work(&port->dapm_work); + if (size > 0) { + port->eld.eld_valid = true; + port->eld.eld_size = size; + } else { + port->eld.eld_valid = false; + port->eld.eld_size = 0; } - print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, - port->eld.eld_buffer, port->eld.eld_size, false); + eld_changed = (eld_valid != port->eld.eld_valid); + pcm = hdac_hdmi_get_pcm(hdev, port); + + if (!port->eld.monitor_present || !port->eld.eld_valid) { + + dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", + __func__, pin->nid, port->id); + + /* + * PCMs are not registered during device probe, so don't + * report jack here. It will be done in usermode mux + * control select. + */ + if (pcm) { + hdac_hdmi_jack_report(pcm, port, false); + schedule_work(&port->dapm_work); + } + + return; + } + + if (port->eld.monitor_present && port->eld.eld_valid) { + if (pcm) { + hdac_hdmi_jack_report(pcm, port, true); + schedule_work(&port->dapm_work); + } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + port->eld.eld_buffer, port->eld.eld_size, false); + } } - mutex_unlock(&hdmi->pin_mutex); if (eld_changed && pcm) snd_ctl_notify(hdmi->card, @@ -1795,13 +1793,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx, if (list_empty(&pcm->port_list)) return; - mutex_lock(&pcm->lock); + guard(mutex)(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); list_for_each_entry(port, &pcm->port_list, head) if (prepared) hdac_hdmi_setup_audio_infoframe(hdev, pcm, port); - mutex_unlock(&pcm->lock); } static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx) From 9c61998c9c858839664bdf0b1457639b0b6c5e4c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:39 +0700 Subject: [PATCH 241/438] ASoC: codecs: hdmi-codec: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-9-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 13ae9e83bc21..bc2c22436ba6 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -4,6 +4,7 @@ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Author: Jyri Sarha */ +#include #include #include #include @@ -452,31 +453,30 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (!((has_playback && tx) || (has_capture && !tx))) return 0; - mutex_lock(&hcp->lock); + guard(mutex)(&hcp->lock); if (hcp->busy) { dev_err(dai->dev, "Only one simultaneous stream supported!\n"); - mutex_unlock(&hcp->lock); return -EINVAL; } if (hcp->hcd.ops->audio_startup) { ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); if (ret) - goto err; + return ret; } if (tx && hcp->hcd.ops->get_eld) { ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); if (ret) - goto err; + return ret; snd_parse_eld(dai->dev, &hcp->eld_parsed, hcp->eld, sizeof(hcp->eld)); ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); if (ret) - goto err; + return ret; /* Select chmap supported */ hdmi_codec_eld_chmap(hcp); @@ -484,8 +484,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, hcp->busy = true; -err: - mutex_unlock(&hcp->lock); return ret; } @@ -503,9 +501,8 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - mutex_lock(&hcp->lock); + guard(mutex)(&hcp->lock); hcp->busy = false; - mutex_unlock(&hcp->lock); } static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, From e199ec211b5342723c68b8152b96b12846f7bbe7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:40 +0700 Subject: [PATCH 242/438] ASoC: codecs: idt821034: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-10-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/idt821034.c | 144 ++++++++++++++--------------------- 1 file changed, 57 insertions(+), 87 deletions(-) diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c index 084090ccef77..387f17b5f7b3 100644 --- a/sound/soc/codecs/idt821034.c +++ b/sound/soc/codecs/idt821034.c @@ -7,6 +7,7 @@ // Author: Herve Codina #include +#include #include #include #include @@ -413,12 +414,12 @@ static int idt821034_kctrl_gain_get(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(mc->reg); - mutex_lock(&idt821034->mutex); - if (IDT821034_ID_IS_OUT(mc->reg)) - val = idt821034->amps.ch[ch].amp_out.gain; - else - val = idt821034->amps.ch[ch].amp_in.gain; - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) { + if (IDT821034_ID_IS_OUT(mc->reg)) + val = idt821034->amps.ch[ch].amp_out.gain; + else + val = idt821034->amps.ch[ch].amp_in.gain; + } ucontrol->value.integer.value[0] = val & mask; if (invert) @@ -456,7 +457,7 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(mc->reg); - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); if (IDT821034_ID_IS_OUT(mc->reg)) { amp = &idt821034->amps.ch[ch].amp_out; @@ -466,22 +467,18 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, gain_type = IDT821034_GAIN_TX; } - if (amp->gain == val) { - ret = 0; - goto end; - } + if (amp->gain == val) + return 0; if (!amp->is_muted) { ret = idt821034_set_gain_channel(idt821034, ch, gain_type, val); if (ret) - goto end; + return ret; } amp->gain = val; - ret = 1; /* The value changed */ -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return 1; } static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, @@ -495,11 +492,11 @@ static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(id); - mutex_lock(&idt821034->mutex); - is_muted = IDT821034_ID_IS_OUT(id) ? - idt821034->amps.ch[ch].amp_out.is_muted : - idt821034->amps.ch[ch].amp_in.is_muted; - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) { + is_muted = IDT821034_ID_IS_OUT(id) ? + idt821034->amps.ch[ch].amp_out.is_muted : + idt821034->amps.ch[ch].amp_in.is_muted; + } ucontrol->value.integer.value[0] = !is_muted; @@ -521,7 +518,7 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, ch = IDT821034_ID_GET_CHAN(id); is_mute = !ucontrol->value.integer.value[0]; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); if (IDT821034_ID_IS_OUT(id)) { amp = &idt821034->amps.ch[ch].amp_out; @@ -531,21 +528,17 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, gain_type = IDT821034_GAIN_TX; } - if (amp->is_muted == is_mute) { - ret = 0; - goto end; - } + if (amp->is_muted == is_mute) + return 0; ret = idt821034_set_gain_channel(idt821034, ch, gain_type, is_mute ? 0 : amp->gain); if (ret) - goto end; + return ret; amp->is_muted = is_mute; - ret = 1; /* The value changed */ -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return 1; } static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -300, 1300); @@ -623,24 +616,20 @@ static int idt821034_power_event(struct snd_soc_dapm_widget *w, struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component); unsigned int id = w->shift; u8 power, mask; - int ret; u8 ch; ch = IDT821034_ID_GET_CHAN(id); mask = IDT821034_ID_IS_OUT(id) ? IDT821034_CONF_PWRUP_RX : IDT821034_CONF_PWRUP_TX; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); power = idt821034_get_channel_power(idt821034, ch); if (SND_SOC_DAPM_EVENT_ON(event)) power |= mask; else power &= ~mask; - ret = idt821034_set_channel_power(idt821034, ch, power); - mutex_unlock(&idt821034->mutex); - - return ret; + return idt821034_set_channel_power(idt821034, ch, power); } static const struct snd_soc_dapm_widget idt821034_dapm_widgets[] = { @@ -717,9 +706,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, ch = 0; while (mask && ch < IDT821034_NB_CHANNEL) { if (mask & 0x1) { - mutex_lock(&idt821034->mutex); - ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_RX, slot); - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) + ret = idt821034_set_channel_ts(idt821034, ch, + IDT821034_CH_RX, slot); if (ret) { dev_err(dai->dev, "ch%u set tx tdm slot failed (%d)\n", ch, ret); @@ -742,9 +731,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, ch = 0; while (mask && ch < IDT821034_NB_CHANNEL) { if (mask & 0x1) { - mutex_lock(&idt821034->mutex); - ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_TX, slot); - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) + ret = idt821034_set_channel_ts(idt821034, ch, + IDT821034_CH_TX, slot); if (ret) { dev_err(dai->dev, "ch%u set rx tdm slot failed (%d)\n", ch, ret); @@ -769,9 +758,8 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component); u8 conf; - int ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); conf = idt821034_get_codec_conf(idt821034); @@ -785,13 +773,10 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) default: dev_err(dai->dev, "Unsupported DAI format 0x%x\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); - ret = -EINVAL; - goto end; + return -EINVAL; } - ret = idt821034_set_codec_conf(idt821034, conf); -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return idt821034_set_codec_conf(idt821034, conf); } static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, @@ -800,9 +785,8 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, { struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component); u8 conf; - int ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); conf = idt821034_get_codec_conf(idt821034); @@ -816,13 +800,10 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, default: dev_err(dai->dev, "Unsupported PCM format 0x%x\n", params_format(params)); - ret = -EINVAL; - goto end; + return -EINVAL; } - ret = idt821034_set_codec_conf(idt821034, conf); -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return idt821034_set_codec_conf(idt821034, conf); } static const unsigned int idt821034_sample_bits[] = {8}; @@ -897,11 +878,11 @@ static int idt821034_reset_audio(struct idt821034 *idt821034) int ret; u8 i; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); ret = idt821034_set_codec_conf(idt821034, 0); if (ret) - goto end; + return ret; for (i = 0; i < IDT821034_NB_CHANNEL; i++) { idt821034->amps.ch[i].amp_out.gain = IDT821034_GAIN_OUT_INIT_RAW; @@ -909,24 +890,21 @@ static int idt821034_reset_audio(struct idt821034 *idt821034) ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_RX, idt821034->amps.ch[i].amp_out.gain); if (ret) - goto end; + return ret; idt821034->amps.ch[i].amp_in.gain = IDT821034_GAIN_IN_INIT_RAW; idt821034->amps.ch[i].amp_in.is_muted = false; ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_TX, idt821034->amps.ch[i].amp_in.gain); if (ret) - goto end; + return ret; ret = idt821034_set_channel_power(idt821034, i, 0); if (ret) - goto end; + return ret; } - ret = 0; -end: - mutex_unlock(&idt821034->mutex); - return ret; + return 0; } static int idt821034_component_probe(struct snd_soc_component *component) @@ -965,7 +943,7 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, u8 slic_raw; int ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_raw = idt821034_get_written_slic_raw(idt821034, ch); if (val) @@ -974,8 +952,6 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, slic_raw &= ~mask; ret = idt821034_write_slic_raw(idt821034, ch, slic_raw); - mutex_unlock(&idt821034->mutex); - if (ret) dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n", offset, ch, mask, ret); @@ -991,9 +967,8 @@ static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset) u8 slic_raw; int ret; - mutex_lock(&idt821034->mutex); - ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw); - mutex_unlock(&idt821034->mutex); + scoped_guard(mutex, &idt821034->mutex) + ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw); if (ret) { dev_err(&idt821034->spi->dev, "get gpio %d (%u, 0x%x) failed (%d)\n", offset, ch, mask, ret); @@ -1015,9 +990,8 @@ static int idt821034_chip_get_direction(struct gpio_chip *c, unsigned int offset struct idt821034 *idt821034 = gpiochip_get_data(c); u8 slic_dir; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_dir = idt821034_get_slic_conf(idt821034, ch); - mutex_unlock(&idt821034->mutex); return slic_dir & mask ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } @@ -1034,7 +1008,7 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs if (mask & ~(IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN)) return -EPERM; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_conf = idt821034_get_slic_conf(idt821034, ch) | mask; @@ -1044,7 +1018,6 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs offset, ch, mask, ret); } - mutex_unlock(&idt821034->mutex); return ret; } @@ -1060,7 +1033,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off if (ret) return ret; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); slic_conf = idt821034_get_slic_conf(idt821034, ch) & ~mask; @@ -1070,7 +1043,6 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off offset, ch, mask, ret); } - mutex_unlock(&idt821034->mutex); return ret; } @@ -1079,24 +1051,22 @@ static int idt821034_reset_gpio(struct idt821034 *idt821034) int ret; u8 i; - mutex_lock(&idt821034->mutex); + guard(mutex)(&idt821034->mutex); /* IO0 and IO1 as input for all channels and output IO set to 0 */ for (i = 0; i < IDT821034_NB_CHANNEL; i++) { ret = idt821034_set_slic_conf(idt821034, i, IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN); if (ret) - goto end; + return ret; ret = idt821034_write_slic_raw(idt821034, i, 0); if (ret) - goto end; + return ret; } - ret = 0; -end: - mutex_unlock(&idt821034->mutex); - return ret; + + return 0; } static int idt821034_gpio_init(struct idt821034 *idt821034) From 9296b430502cc1af3d48f5c90c84e33140e6c5b6 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:41 +0700 Subject: [PATCH 243/438] ASoC: codecs: lpass-macro: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-11-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-macro-common.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index 6e3b8d0897dd..7e59616ed7bc 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2022, The Linux Foundation. All rights reserved. +#include #include #include #include @@ -71,21 +72,16 @@ EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); void lpass_macro_set_codec_version(enum lpass_codec_version version) { - mutex_lock(&lpass_codec_mutex); + guard(mutex)(&lpass_codec_mutex); lpass_codec_version = version; - mutex_unlock(&lpass_codec_mutex); } EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version); enum lpass_codec_version lpass_macro_get_codec_version(void) { - enum lpass_codec_version ver; + guard(mutex)(&lpass_codec_mutex); - mutex_lock(&lpass_codec_mutex); - ver = lpass_codec_version; - mutex_unlock(&lpass_codec_mutex); - - return ver; + return lpass_codec_version; } EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version); From 5dabb2549c89234050d001ff19e9732d745855dc Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:42 +0700 Subject: [PATCH 244/438] ASoC: codecs: madera: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Charles Keepax Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-12-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/madera.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 98d72db599d8..55ea6950ca90 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -6,6 +6,7 @@ // Cirrus Logic International Semiconductor Ltd. // +#include #include #include #include @@ -513,7 +514,7 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w, * We can't rely on the DAPM mutex for locking because we need a lock * that can safely be called in hw_params */ - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -532,8 +533,6 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w, madera_debug_dump_domain_groups(priv); - mutex_unlock(&priv->rate_lock); - return 0; } EXPORT_SYMBOL_GPL(madera_domain_clk_ev); @@ -875,9 +874,8 @@ static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol, const int adsp_num = e->shift_l; int item; - mutex_lock(&priv->rate_lock); - cached_rate = priv->adsp_rate_cache[adsp_num]; - mutex_unlock(&priv->rate_lock); + scoped_guard(mutex, &priv->rate_lock) + cached_rate = priv->adsp_rate_cache[adsp_num]; item = snd_soc_enum_val_to_item(e, cached_rate); ucontrol->value.enumerated.item[0] = item; @@ -893,7 +891,6 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; const int adsp_num = e->shift_l; const unsigned int item = ucontrol->value.enumerated.item[0]; - int ret = 0; if (item >= e->items) return -EINVAL; @@ -903,22 +900,20 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, * maintain consistent behaviour that rate domains cannot be changed * while in use since this is a hardware requirement */ - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].cs_dsp.base)) { dev_warn(priv->madera->dev, "Cannot change '%s' while in use by active audio paths\n", kcontrol->id.name); - ret = -EBUSY; + return -EBUSY; } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) { /* Volatile register so defer until the codec is powered up */ priv->adsp_rate_cache[adsp_num] = e->values[item]; - ret = 1; + return 1; } - mutex_unlock(&priv->rate_lock); - - return ret; + return 0; } static const struct soc_enum madera_adsp_rate_enum[] = { @@ -1061,15 +1056,13 @@ int madera_rate_put(struct snd_kcontrol *kcontrol, * Prevent the domain powering up while we're checking whether it's * safe to change rate domain */ - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); val = snd_soc_component_read(component, e->reg); val >>= e->shift_l; val &= e->mask; - if (snd_soc_enum_item_to_val(e, item) == val) { - ret = 0; - goto out; - } + if (snd_soc_enum_item_to_val(e, item) == val) + return 0; if (!madera_can_change_grp_rate(priv, e->reg)) { dev_warn(priv->madera->dev, @@ -1082,8 +1075,6 @@ int madera_rate_put(struct snd_kcontrol *kcontrol, ret = snd_soc_put_enum_double(kcontrol, ucontrol); madera_spin_sysclk(priv); } -out: - mutex_unlock(&priv->rate_lock); return ret; } @@ -3041,12 +3032,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, if ((cur & MADERA_AIF1_RATE_MASK) == (tar & MADERA_AIF1_RATE_MASK)) return 0; - mutex_lock(&priv->rate_lock); + guard(mutex)(&priv->rate_lock); if (!madera_can_change_grp_rate(priv, base + MADERA_AIF_RATE_CTRL)) { madera_aif_warn(dai, "Cannot change rate while active\n"); - ret = -EBUSY; - goto out; + return -EBUSY; } /* Guard the rate change with SYSCLK cycles */ @@ -3055,9 +3045,6 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, MADERA_AIF1_RATE_MASK, tar); madera_spin_sysclk(priv); -out: - mutex_unlock(&priv->rate_lock); - return ret; } From 750c61b2920f993eae36da32f6ea3071e7470e26 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:43 +0700 Subject: [PATCH 245/438] ASoC: codecs: max98095: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-13-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index ced9bd4d94da..c47bfa2378b8 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -5,6 +5,7 @@ * Copyright 2011 Maxim Integrated Products */ +#include #include #include #include @@ -1532,15 +1533,17 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL); snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0); - mutex_lock(&max98095->lock); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); - m98095_eq_band(component, channel, 0, coef_set->band1); - m98095_eq_band(component, channel, 1, coef_set->band2); - m98095_eq_band(component, channel, 2, coef_set->band3); - m98095_eq_band(component, channel, 3, coef_set->band4); - m98095_eq_band(component, channel, 4, coef_set->band5); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0); - mutex_unlock(&max98095->lock); + scoped_guard(mutex, &max98095->lock) { + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, M98095_SEG); + m98095_eq_band(component, channel, 0, coef_set->band1); + m98095_eq_band(component, channel, 1, coef_set->band2); + m98095_eq_band(component, channel, 2, coef_set->band3); + m98095_eq_band(component, channel, 3, coef_set->band4); + m98095_eq_band(component, channel, 4, coef_set->band5); + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, 0); + } /* Restore the original on/off state */ snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave); @@ -1683,12 +1686,14 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL); snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0); - mutex_lock(&max98095->lock); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); - m98095_biquad_band(component, channel, 0, coef_set->band1); - m98095_biquad_band(component, channel, 1, coef_set->band2); - snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0); - mutex_unlock(&max98095->lock); + scoped_guard(mutex, &max98095->lock) { + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, M98095_SEG); + m98095_biquad_band(component, channel, 0, coef_set->band1); + m98095_biquad_band(component, channel, 1, coef_set->band2); + snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, + M98095_SEG, 0); + } /* Restore the original on/off state */ snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave); From 3ec678539a9fd98bc6100013d7900d22abd330f8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:44 +0700 Subject: [PATCH 246/438] ASoC: codecs: mt6359-accdet: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-14-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359-accdet.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index ed34cc15b80e..e1190c644021 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -6,6 +6,7 @@ // Author: Argus Lin // +#include #include #include #include @@ -398,14 +399,13 @@ static void mt6359_accdet_work(struct work_struct *work) struct mt6359_accdet *priv = container_of(work, struct mt6359_accdet, accdet_work); - mutex_lock(&priv->res_lock); + guard(mutex)(&priv->res_lock); priv->pre_accdet_status = priv->accdet_status; check_jack_btn_type(priv); if (priv->jack_plugged && priv->pre_accdet_status != priv->accdet_status) mt6359_accdet_jack_report(priv); - mutex_unlock(&priv->res_lock); } static void mt6359_accdet_jd_work(struct work_struct *work) @@ -416,7 +416,7 @@ static void mt6359_accdet_jd_work(struct work_struct *work) struct mt6359_accdet *priv = container_of(work, struct mt6359_accdet, jd_work); - mutex_lock(&priv->res_lock); + guard(mutex)(&priv->res_lock); if (priv->jd_sts == M_PLUG_IN) { priv->jack_plugged = true; @@ -450,7 +450,6 @@ static void mt6359_accdet_jd_work(struct work_struct *work) if (priv->caps & ACCDET_PMIC_EINT_IRQ) recover_eint_setting(priv); - mutex_unlock(&priv->res_lock); } static irqreturn_t mt6359_accdet_irq(int irq, void *data) @@ -459,7 +458,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) unsigned int irq_val = 0, val = 0, value = 0; int ret; - mutex_lock(&priv->res_lock); + guard(mutex)(&priv->res_lock); regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val); if (irq_val & ACCDET_IRQ_MASK_SFT) { @@ -474,7 +473,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) 1000); if (ret) { dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); - mutex_unlock(&priv->res_lock); return IRQ_NONE; } regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, @@ -498,7 +496,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) if (ret) { dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); - mutex_unlock(&priv->res_lock); return IRQ_NONE; } regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, @@ -521,7 +518,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) if (ret) { dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); - mutex_unlock(&priv->res_lock); return IRQ_NONE; } regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, @@ -540,7 +536,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) queue_work(priv->jd_workqueue, &priv->jd_work); } - mutex_unlock(&priv->res_lock); return IRQ_HANDLED; } From b812b16661e860dcc5be4d191c3b27db4c3bc481 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:45 +0700 Subject: [PATCH 247/438] ASoC: codecs: pcm512x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-15-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 10868df3c75d..bf143e3fec54 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -6,7 +6,7 @@ * Copyright 2014 Linaro Ltd */ - +#include #include #include #include @@ -399,10 +399,9 @@ static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); - mutex_lock(&pcm512x->mutex); + guard(mutex)(&pcm512x->mutex); ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); - mutex_unlock(&pcm512x->mutex); return 0; } @@ -414,7 +413,7 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); int ret, changed = 0; - mutex_lock(&pcm512x->mutex); + guard(mutex)(&pcm512x->mutex); if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { pcm512x->mute ^= 0x4; @@ -430,13 +429,10 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, if (ret != 0) { dev_err(component->dev, "Failed to update digital mute: %d\n", ret); - mutex_unlock(&pcm512x->mutex); return ret; } } - mutex_unlock(&pcm512x->mutex); - return changed; } @@ -1465,7 +1461,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) int ret; unsigned int mute_det; - mutex_lock(&pcm512x->mutex); + guard(mutex)(&pcm512x->mutex); if (mute) { pcm512x->mute |= 0x1; @@ -1475,7 +1471,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) if (ret != 0) { dev_err(component->dev, "Failed to set digital mute: %d\n", ret); - goto unlock; + return ret; } regmap_read_poll_timeout(pcm512x->regmap, @@ -1488,7 +1484,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) if (ret != 0) { dev_err(component->dev, "Failed to update digital mute: %d\n", ret); - goto unlock; + return ret; } regmap_read_poll_timeout(pcm512x->regmap, @@ -1499,9 +1495,6 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) 200, 10000); } -unlock: - mutex_unlock(&pcm512x->mutex); - return ret; } From f3da3b7f6ed247f4475855d38a55b1394e5eeb08 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:46 +0700 Subject: [PATCH 248/438] ASoC: codecs: pcm6240: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-16-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm6240.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 4ac4448ac3c8..a2b66eae6ac4 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -12,6 +12,7 @@ // Author: Shenghao Ding // +#include #include #include #include @@ -605,7 +606,7 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, unsigned int reg = mc->reg; unsigned int val; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); if (pcm_dev->chip_id == PCM1690) { ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL, @@ -613,18 +614,18 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, if (ret) { dev_err(pcm_dev->dev, "%s: read mode err=%d\n", __func__, ret); - goto out; + return ret; } val &= PCM1690_REG_MODE_CTRL_DAMS_MSK; /* Set to wide-range mode, before using vol ctrl. */ if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) { ucontrol->value.integer.value[0] = -25500; - goto out; + return ret; } /* Set to fine mode, before using fine vol ctrl. */ if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) { ucontrol->value.integer.value[0] = -12750; - goto out; + return ret; } } @@ -632,15 +633,14 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, if (ret) { dev_err(pcm_dev->dev, "%s: read err=%d\n", __func__, ret); - goto out; + return ret; } val = (val >> shift) & mask; val = (val > max) ? max : val; val = mc->invert ? max - val : val; ucontrol->value.integer.value[0] = val; -out: - mutex_unlock(&pcm_dev->codec_lock); + return ret; } @@ -678,7 +678,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; unsigned int reg = mc->reg; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); val = ucontrol->value.integer.value[0] & mask; val = (val > max) ? max : val; val = mc->invert ? max - val : val; @@ -702,7 +702,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol, __func__, rc); else rc = 1; - mutex_unlock(&pcm_dev->codec_lock); + return rc; } @@ -1645,9 +1645,8 @@ static void pcmdevice_comp_remove(struct snd_soc_component *codec) if (!pcm_dev) return; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); pcmdevice_config_info_remove(pcm_dev); - mutex_unlock(&pcm_dev->codec_lock); } static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = { @@ -1890,9 +1889,9 @@ static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream) else block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP; - mutex_lock(&pcm_dev->codec_lock); + guard(mutex)(&pcm_dev->codec_lock); pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type); - mutex_unlock(&pcm_dev->codec_lock); + return 0; } From f7a116261d6ba3b4d683539a4e9b5780f9a4ded8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:47 +0700 Subject: [PATCH 249/438] ASoC: codecs: peb2466: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Herve Codina Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-17-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/peb2466.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c index 2d71d204d8fa..5a1ed02abb84 100644 --- a/sound/soc/codecs/peb2466.c +++ b/sound/soc/codecs/peb2466.c @@ -6,6 +6,7 @@ // // Author: Herve Codina +#include #include #include #include @@ -1704,13 +1705,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x * So, a specific cache value is used. */ - mutex_lock(&peb2466->gpio.lock); + guard(mutex)(&peb2466->gpio.lock); cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); - if (!cache) { - ret = -EINVAL; - goto end; - } + if (!cache) + return -EINVAL; tmp = *cache; tmp &= ~mask; @@ -1718,14 +1717,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x ret = regmap_write(peb2466->regmap, xr_reg, tmp); if (ret) - goto end; + return ret; *cache = tmp; - ret = 0; -end: - mutex_unlock(&peb2466->gpio.lock); - return ret; + return 0; } static int peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, From ed2e18138f1849bcc573daf4f9b80ee6f0dc394c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:48 +0700 Subject: [PATCH 250/438] ASoC: codecs: rt5514-spi: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-18-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 199507d12841..91290bfe8daa 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -6,6 +6,7 @@ * Author: Oder Chiou */ +#include #include #include #include @@ -79,17 +80,17 @@ static void rt5514_spi_copy_work(struct work_struct *work) unsigned int cur_wp, remain_data; u8 buf[8]; - mutex_lock(&rt5514_dsp->dma_lock); + guard(mutex)(&rt5514_dsp->dma_lock); if (!rt5514_dsp->substream) { dev_err(rt5514_dsp->dev, "No pcm substream\n"); - goto done; + return; } runtime = rt5514_dsp->substream->runtime; period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); if (!period_bytes) { schedule_delayed_work(&rt5514_dsp->copy_work, 5); - goto done; + return; } if (rt5514_dsp->buf_size % period_bytes) @@ -111,7 +112,7 @@ static void rt5514_spi_copy_work(struct work_struct *work) if (remain_data < period_bytes) { schedule_delayed_work(&rt5514_dsp->copy_work, 5); - goto done; + return; } } @@ -146,9 +147,6 @@ static void rt5514_spi_copy_work(struct work_struct *work) snd_pcm_period_elapsed(rt5514_dsp->substream); schedule_delayed_work(&rt5514_dsp->copy_work, 5); - -done: - mutex_unlock(&rt5514_dsp->dma_lock); } static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) @@ -216,7 +214,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, snd_soc_component_get_drvdata(component); u8 buf[8]; - mutex_lock(&rt5514_dsp->dma_lock); + guard(mutex)(&rt5514_dsp->dma_lock); rt5514_dsp->substream = substream; rt5514_dsp->dma_offset = 0; @@ -225,8 +223,6 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, if (buf[0] & RT5514_IRQ_STATUS_BIT) rt5514_schedule_copy(rt5514_dsp); - mutex_unlock(&rt5514_dsp->dma_lock); - return 0; } @@ -236,9 +232,8 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component, struct rt5514_dsp *rt5514_dsp = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5514_dsp->dma_lock); - rt5514_dsp->substream = NULL; - mutex_unlock(&rt5514_dsp->dma_lock); + scoped_guard(mutex, &rt5514_dsp->dma_lock) + rt5514_dsp->substream = NULL; cancel_delayed_work_sync(&rt5514_dsp->copy_work); From 1937a1e0969e575148412f3f0af8a5a963f2944d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:49 +0700 Subject: [PATCH 251/438] ASoC: codecs: rt5645: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-19-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 164 +++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 83 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 93a4148ccccd..0d546fb34e52 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -6,6 +6,7 @@ * Author: Bard Liao */ +#include #include #include #include @@ -3323,92 +3324,89 @@ static void rt5645_jack_detect_work(struct work_struct *work) if (!rt5645->component) return; - mutex_lock(&rt5645->jd_mutex); - - switch (rt5645->pdata.jd_mode) { - case 0: /* Not using rt5645 JD */ - if (rt5645->gpiod_hp_det) { - gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); - if (rt5645->pdata.inv_hp_pol) - gpio_state ^= 1; - dev_dbg(rt5645->component->dev, "gpio_state = %d\n", - gpio_state); - report = rt5645_jack_detect(rt5645->component, gpio_state); - } - snd_soc_jack_report(rt5645->hp_jack, - report, SND_JACK_HEADPHONE); - snd_soc_jack_report(rt5645->mic_jack, - report, SND_JACK_MICROPHONE); - mutex_unlock(&rt5645->jd_mutex); - return; - case 4: - val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; - break; - default: /* read rt5645 jd1_1 status */ - val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; - break; - - } - - if (!val && (rt5645->jack_type == 0)) { /* jack in */ - report = rt5645_jack_detect(rt5645->component, 1); - } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) { - /* for push button and jack out */ - btn_type = 0; - if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) { - /* button pressed */ - report = SND_JACK_HEADSET; - btn_type = rt5645_button_detect(rt5645->component); - /* rt5650 can report three kinds of button behavior, - one click, double click and hold. However, - currently we will report button pressed/released - event. So all the three button behaviors are - treated as button pressed. */ - switch (btn_type) { - case 0x8000: - case 0x4000: - case 0x2000: - report |= SND_JACK_BTN_0; - break; - case 0x1000: - case 0x0800: - case 0x0400: - report |= SND_JACK_BTN_1; - break; - case 0x0200: - case 0x0100: - case 0x0080: - report |= SND_JACK_BTN_2; - break; - case 0x0040: - case 0x0020: - case 0x0010: - report |= SND_JACK_BTN_3; - break; - case 0x0000: /* unpressed */ - break; - default: - dev_err(rt5645->component->dev, - "Unexpected button code 0x%04x\n", - btn_type); - break; + scoped_guard(mutex, &rt5645->jd_mutex) { + switch (rt5645->pdata.jd_mode) { + case 0: /* Not using rt5645 JD */ + if (rt5645->gpiod_hp_det) { + gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); + if (rt5645->pdata.inv_hp_pol) + gpio_state ^= 1; + dev_dbg(rt5645->component->dev, "gpio_state = %d\n", + gpio_state); + report = rt5645_jack_detect(rt5645->component, gpio_state); } + snd_soc_jack_report(rt5645->hp_jack, + report, SND_JACK_HEADPHONE); + snd_soc_jack_report(rt5645->mic_jack, + report, SND_JACK_MICROPHONE); + return; + case 4: + val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; + break; + default: /* read rt5645 jd1_1 status */ + val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; + break; } - if (btn_type == 0)/* button release */ - report = rt5645->jack_type; - else { - mod_timer(&rt5645->btn_check_timer, - msecs_to_jiffies(100)); - } - } else { - /* jack out */ - report = 0; - snd_soc_component_update_bits(rt5645->component, - RT5645_INT_IRQ_ST, 0x1, 0x0); - rt5645_jack_detect(rt5645->component, 0); - } - mutex_unlock(&rt5645->jd_mutex); + if (!val && rt5645->jack_type == 0) { /* jack in */ + report = rt5645_jack_detect(rt5645->component, 1); + } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) { + /* for push button and jack out */ + btn_type = 0; + if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) { + /* button pressed */ + report = SND_JACK_HEADSET; + btn_type = rt5645_button_detect(rt5645->component); + /* + * rt5650 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + dev_err(rt5645->component->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + } + if (btn_type == 0)/* button release */ + report = rt5645->jack_type; + else + mod_timer(&rt5645->btn_check_timer, + msecs_to_jiffies(100)); + } else { + /* jack out */ + report = 0; + snd_soc_component_update_bits(rt5645->component, + RT5645_INT_IRQ_ST, 0x1, 0x0); + rt5645_jack_detect(rt5645->component, 0); + } + } snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE); snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); From f1c58069475cb2f7b14efa5a19ce0f041b60a43f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:50 +0700 Subject: [PATCH 252/438] ASoC: codecs: rt5665: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-20-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 48f57cd0920d..1d987472ba42 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -6,6 +6,7 @@ * Author: Bard Liao */ +#include #include #include #include @@ -1208,7 +1209,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work) usleep_range(10000, 15000); } - mutex_lock(&rt5665->calibrate_mutex); + guard(mutex)(&rt5665->calibrate_mutex); val = snd_soc_component_read(rt5665->component, RT5665_AJD1_CTRL) & 0x0010; if (!val) { @@ -1274,8 +1275,6 @@ static void rt5665_jack_detect_handler(struct work_struct *work) schedule_delayed_work(&rt5665->jd_check_work, 0); else cancel_delayed_work_sync(&rt5665->jd_check_work); - - mutex_unlock(&rt5665->calibrate_mutex); } static const char * const rt5665_clk_sync[] = { @@ -4564,7 +4563,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) { int value, count; - mutex_lock(&rt5665->calibrate_mutex); + guard(mutex)(&rt5665->calibrate_mutex); regcache_cache_bypass(rt5665->regmap, true); @@ -4601,7 +4600,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) pr_err("HP Calibration Failure\n"); regmap_write(rt5665->regmap, RT5665_RESET, 0); regcache_cache_bypass(rt5665->regmap, false); - goto out_unlock; + rt5665->calibration_done = true; + return; } count++; @@ -4620,7 +4620,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) pr_err("MONO Calibration Failure\n"); regmap_write(rt5665->regmap, RT5665_RESET, 0); regcache_cache_bypass(rt5665->regmap, false); - goto out_unlock; + rt5665->calibration_done = true; + return; } count++; @@ -4635,9 +4636,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); -out_unlock: rt5665->calibration_done = true; - mutex_unlock(&rt5665->calibrate_mutex); } static void rt5665_calibrate_handler(struct work_struct *work) From c745a4e595c5fd0a5c793774359e1f1831a911ab Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:51 +0700 Subject: [PATCH 253/438] ASoC: codecs: rt5668: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-21-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index fed6de40b8c8..4154bad27610 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -6,6 +6,7 @@ * Author: Bard Liao */ +#include #include #include #include @@ -986,7 +987,7 @@ static void rt5668_jack_detect_handler(struct work_struct *work) return; } - mutex_lock(&rt5668->calibrate_mutex); + guard(mutex)(&rt5668->calibrate_mutex); val = snd_soc_component_read(rt5668->component, RT5668_AJD1_CTRL) & RT5668_JDH_RS_MASK; @@ -1053,8 +1054,6 @@ static void rt5668_jack_detect_handler(struct work_struct *work) schedule_delayed_work(&rt5668->jd_check_work, 0); else cancel_delayed_work_sync(&rt5668->jd_check_work); - - mutex_unlock(&rt5668->calibrate_mutex); } static const struct snd_kcontrol_new rt5668_snd_controls[] = { @@ -2356,7 +2355,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) { int value, count; - mutex_lock(&rt5668->calibrate_mutex); + guard(mutex)(&rt5668->calibrate_mutex); rt5668_reset(rt5668->regmap); regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf); @@ -2400,9 +2399,6 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) /* restore settings */ regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4); regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000); - - mutex_unlock(&rt5668->calibrate_mutex); - } static int rt5668_i2c_probe(struct i2c_client *i2c) From be03bd5c4c3404c50a585e8bc435cddbb1f21bef Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:52 +0700 Subject: [PATCH 254/438] ASoC: codecs: rt5677: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-22-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 36 +++++++---------- sound/soc/codecs/rt5677.c | 75 ++++++++++++++++------------------- 2 files changed, 49 insertions(+), 62 deletions(-) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 1bcafd5f4468..ebc527115ea5 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -6,6 +6,7 @@ * Author: Oder Chiou */ +#include #include #include #include @@ -133,9 +134,8 @@ static int rt5677_spi_hw_params( struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5677_dsp->dma_lock); + guard(mutex)(&rt5677_dsp->dma_lock); rt5677_dsp->substream = substream; - mutex_unlock(&rt5677_dsp->dma_lock); return 0; } @@ -147,9 +147,8 @@ static int rt5677_spi_hw_free( struct rt5677_dsp *rt5677_dsp = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5677_dsp->dma_lock); + guard(mutex)(&rt5677_dsp->dma_lock); rt5677_dsp->substream = NULL; - mutex_unlock(&rt5677_dsp->dma_lock); return 0; } @@ -311,17 +310,17 @@ static void rt5677_spi_copy_work(struct work_struct *work) int ret = 0; /* Ensure runtime->dma_area buffer does not go away while copying. */ - mutex_lock(&rt5677_dsp->dma_lock); + guard(mutex)(&rt5677_dsp->dma_lock); if (!rt5677_dsp->substream) { dev_err(rt5677_dsp->dev, "No pcm substream\n"); - goto done; + return; } runtime = rt5677_dsp->substream->runtime; if (rt5677_spi_mic_write_offset(&mic_write_offset)) { dev_err(rt5677_dsp->dev, "No mic_write_offset\n"); - goto done; + return; } /* If this is the first time that we've asked for streaming data after @@ -355,7 +354,7 @@ static void rt5677_spi_copy_work(struct work_struct *work) ret = rt5677_spi_copy(rt5677_dsp, copy_bytes); if (ret) { dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret); - goto done; + return; } rt5677_dsp->avail_bytes += copy_bytes; if (rt5677_dsp->avail_bytes >= period_bytes) { @@ -367,8 +366,6 @@ static void rt5677_spi_copy_work(struct work_struct *work) delay = bytes_to_frames(runtime, period_bytes) / runtime->rate; schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay)); -done: - mutex_unlock(&rt5677_dsp->dma_lock); } static int rt5677_spi_pcm_new(struct snd_soc_component *component, @@ -507,10 +504,8 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) header[3] = ((addr + offset) & 0x0000ff00) >> 8; header[4] = ((addr + offset) & 0x000000ff) >> 0; - mutex_lock(&spi_mutex); - status |= spi_sync(g_spi, &m); - mutex_unlock(&spi_mutex); - + scoped_guard(mutex, &spi_mutex) + status |= spi_sync(g_spi, &m); /* Copy data back to caller buffer */ rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len); @@ -564,9 +559,8 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) offset += t.len; t.len += RT5677_SPI_HEADER + 1; - mutex_lock(&spi_mutex); - status |= spi_sync(g_spi, &m); - mutex_unlock(&spi_mutex); + scoped_guard(mutex, &spi_mutex) + status |= spi_sync(g_spi, &m); } return status; } @@ -591,10 +585,10 @@ void rt5677_spi_hotword_detected(void) return; } - mutex_lock(&rt5677_dsp->dma_lock); - dev_info(rt5677_dsp->dev, "Hotword detected\n"); - rt5677_dsp->new_hotword = true; - mutex_unlock(&rt5677_dsp->dma_lock); + scoped_guard(mutex, &rt5677_dsp->dma_lock) { + dev_info(rt5677_dsp->dev, "Hotword detected\n"); + rt5677_dsp->new_hotword = true; + } schedule_delayed_work(&rt5677_dsp->copy_work, 0); } diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 73fc008d558a..3e4d1dbce740 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -6,6 +6,7 @@ * Author: Oder Chiou */ +#include #include #include #include @@ -564,46 +565,43 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, struct snd_soc_component *component = rt5677->component; int ret; - mutex_lock(&rt5677->dsp_cmd_lock); + guard(mutex)(&rt5677->dsp_cmd_lock); ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); if (ret < 0) { dev_err(component->dev, "Failed to set addr msb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, addr & 0xffff); if (ret < 0) { dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, value >> 16); if (ret < 0) { dev_err(component->dev, "Failed to set data msb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, value & 0xffff); if (ret < 0) { dev_err(component->dev, "Failed to set data lsb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, opcode); if (ret < 0) { dev_err(component->dev, "Failed to set op code value: %d\n", ret); - goto err; + return ret; } -err: - mutex_unlock(&rt5677->dsp_cmd_lock); - return ret; } @@ -623,36 +621,33 @@ static int rt5677_dsp_mode_i2c_read_addr( int ret; unsigned int msb, lsb; - mutex_lock(&rt5677->dsp_cmd_lock); + guard(mutex)(&rt5677->dsp_cmd_lock); ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); if (ret < 0) { dev_err(component->dev, "Failed to set addr msb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, addr & 0xffff); if (ret < 0) { dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret); - goto err; + return ret; } ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, 0x0002); if (ret < 0) { dev_err(component->dev, "Failed to set op code value: %d\n", ret); - goto err; + return ret; } regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb); regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb); *value = (msb << 16) | lsb; -err: - mutex_unlock(&rt5677->dsp_cmd_lock); - return ret; } @@ -941,21 +936,20 @@ static void rt5677_dsp_work(struct work_struct *work) activity = false; /* Don't turn off the DSP while handling irqs */ - mutex_lock(&rt5677->irq_lock); - /* Set DSP CPU to Stop */ - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, - RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); + scoped_guard(mutex, &rt5677->irq_lock) { + /* Set DSP CPU to Stop */ + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); - rt5677_set_dsp_mode(rt5677, false); + rt5677_set_dsp_mode(rt5677, false); - /* Disable and clear VAD interrupt */ - regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); + /* Disable and clear VAD interrupt */ + regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); - /* Set GPIO1 pin back to be IRQ output for jack detect */ - regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, - RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); - - mutex_unlock(&rt5677->irq_lock); + /* Set GPIO1 pin back to be IRQ output for jack detect */ + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, + RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); + } } } @@ -4997,11 +4991,11 @@ static int rt5677_read(void *context, unsigned int reg, unsigned int *val) if (rt5677->is_dsp_mode) { if (reg > 0xff) { - mutex_lock(&rt5677->dsp_pri_lock); - rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, - reg & 0xff); - rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); - mutex_unlock(&rt5677->dsp_pri_lock); + scoped_guard(mutex, &rt5677->dsp_pri_lock) { + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, + reg & 0xff); + rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); + } } else { rt5677_dsp_mode_i2c_read(rt5677, reg, val); } @@ -5019,12 +5013,12 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val) if (rt5677->is_dsp_mode) { if (reg > 0xff) { - mutex_lock(&rt5677->dsp_pri_lock); - rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, - reg & 0xff); - rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, - val); - mutex_unlock(&rt5677->dsp_pri_lock); + scoped_guard(mutex, &rt5677->dsp_pri_lock) { + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, + reg & 0xff); + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, + val); + } } else { rt5677_dsp_mode_i2c_write(rt5677, reg, val); } @@ -5416,7 +5410,7 @@ static void rt5677_resume_irq_check(struct work_struct *work) * Without this explicit check, unplug the headset right after suspend * starts, then after resume the headset is still shown as plugged in. */ - mutex_lock(&rt5677->irq_lock); + guard(mutex)(&rt5677->irq_lock); for (i = 0; i < RT5677_IRQ_NUM; i++) { if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) { virq = irq_find_mapping(rt5677->domain, i); @@ -5424,7 +5418,6 @@ static void rt5677_resume_irq_check(struct work_struct *work) handle_nested_irq(virq); } } - mutex_unlock(&rt5677->irq_lock); } static void rt5677_irq_bus_lock(struct irq_data *data) From 97ed7ddb98d67167e422954a4378a6200d73769f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:53 +0700 Subject: [PATCH 255/438] ASoC: codecs: rt5682: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-23-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-sdw.c | 24 ++++++++++++------------ sound/soc/codecs/rt5682.c | 5 ++--- sound/soc/codecs/rt5682s.c | 17 +++++------------ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index e49ec28b6103..23c7d2a9dbee 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -6,6 +6,7 @@ // Author: Oder Chiou // +#include #include #include #include @@ -670,12 +671,11 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - mutex_lock(&rt5682->disable_irq_lock); + guard(mutex)(&rt5682->disable_irq_lock); if (status->control_port & 0x4 && !rt5682->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); } - mutex_unlock(&rt5682->disable_irq_lock); return 0; } @@ -746,11 +746,11 @@ static int rt5682_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt5682->disable_irq_lock); - rt5682->disable_irq = true; - ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, - SDW_SCP_INT1_IMPL_DEF, 0); - mutex_unlock(&rt5682->disable_irq_lock); + scoped_guard(mutex, &rt5682->disable_irq_lock) { + rt5682->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + } if (ret < 0) { /* log but don't prevent suspend from happening */ @@ -770,12 +770,12 @@ static int rt5682_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt5682->disable_irq_lock); - if (rt5682->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); - rt5682->disable_irq = false; + scoped_guard(mutex, &rt5682->disable_irq_lock) { + if (rt5682->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); + rt5682->disable_irq = false; + } } - mutex_unlock(&rt5682->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 4b82e07d3b2c..6f7e68c20d13 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -6,6 +6,7 @@ // Author: Bard Liao // +#include #include #include #include @@ -3125,7 +3126,7 @@ void rt5682_calibrate(struct rt5682_priv *rt5682) { int value, count; - mutex_lock(&rt5682->calibrate_mutex); + guard(mutex)(&rt5682->calibrate_mutex); rt5682_reset(rt5682); regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); @@ -3175,8 +3176,6 @@ void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0c0c); - - mutex_unlock(&rt5682->calibrate_mutex); } EXPORT_SYMBOL_GPL(rt5682_calibrate); diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index 3624067950c0..34997cfb465b 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -6,6 +6,7 @@ // Author: Derek Fang // +#include #include #include #include @@ -648,7 +649,7 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode { struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - mutex_lock(&rt5682s->sar_mutex); + guard(mutex)(&rt5682s->sar_mutex); switch (mode) { case SAR_PWR_SAVING: @@ -695,8 +696,6 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode); break; } - - mutex_unlock(&rt5682s->sar_mutex); } static void rt5682s_enable_push_button_irq(struct snd_soc_component *component) @@ -2534,7 +2533,7 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) if (!rt5682s_clk_check(rt5682s)) return -EINVAL; - mutex_lock(&rt5682s->wclk_mutex); + guard(mutex)(&rt5682s->wclk_mutex); snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, @@ -2556,8 +2555,6 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) rt5682s->wclk_enabled = 1; - mutex_unlock(&rt5682s->wclk_mutex); - return 0; } @@ -2570,7 +2567,7 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) if (!rt5682s_clk_check(rt5682s)) return; - mutex_lock(&rt5682s->wclk_mutex); + guard(mutex)(&rt5682s->wclk_mutex); if (!rt5682s->jack_type) snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, @@ -2585,8 +2582,6 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) rt5682s_set_pllb_power(rt5682s, 0); rt5682s->wclk_enabled = 0; - - mutex_unlock(&rt5682s->wclk_mutex); } static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, @@ -2997,7 +2992,7 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) { unsigned int count, value; - mutex_lock(&rt5682s->calibrate_mutex); + guard(mutex)(&rt5682s->calibrate_mutex); regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80); usleep_range(15000, 20000); @@ -3034,8 +3029,6 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0); regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800); regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000); - - mutex_unlock(&rt5682s->calibrate_mutex); } static const struct regmap_config rt5682s_regmap = { From 5d649ea1d05389e9aee3e38cb0349127bae7ecec Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:54 +0700 Subject: [PATCH 256/438] ASoC: codecs: rt700: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-24-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt700-sdw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index bb449f08e30c..3ba0cc37acd9 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -415,12 +416,11 @@ static int rt700_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - mutex_lock(&rt700->disable_irq_lock); + guard(mutex)(&rt700->disable_irq_lock); if (status->control_port & 0x4 && !rt700->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt700->jack_detect_work, msecs_to_jiffies(250)); } - mutex_unlock(&rt700->disable_irq_lock); return 0; } @@ -499,11 +499,11 @@ static int rt700_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt700->disable_irq_lock); - rt700->disable_irq = true; - ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, - SDW_SCP_INT1_IMPL_DEF, 0); - mutex_unlock(&rt700->disable_irq_lock); + scoped_guard(mutex, &rt700->disable_irq_lock) { + rt700->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + } if (ret < 0) { /* log but don't prevent suspend from happening */ From f8e861f73b904c063f1a189c33a270a564fbe49a Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:55 +0700 Subject: [PATCH 257/438] ASoC: codecs: rt711: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-25-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca-sdw.c | 29 ++++++++++-------- sound/soc/codecs/rt711-sdca.c | 5 ++-- sound/soc/codecs/rt711-sdw.c | 24 +++++++-------- sound/soc/codecs/rt711.c | 50 +++++++++++++++---------------- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index e028a1c3a9ac..e292b28b029e 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -415,13 +416,13 @@ static int rt711_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt711_sdca->disable_irq_lock); - rt711_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt711_sdca->disable_irq_lock); + scoped_guard(mutex, &rt711_sdca->disable_irq_lock) { + rt711_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -443,13 +444,15 @@ static int rt711_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt711->disable_irq_lock); - if (rt711->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt711->disable_irq = false; + scoped_guard(mutex, &rt711->disable_irq_lock) { + if (rt711->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt711->disable_irq = false; + } } - mutex_unlock(&rt711->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 3a26c782d800..9781f289f8ad 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -450,7 +451,7 @@ static void rt711_sdca_btn_check_handler(struct work_struct *work) static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) { - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); if (rt711->hs_jack) { /* Enable HID1 event & set button RTC mode */ @@ -515,8 +516,6 @@ static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); } - - mutex_unlock(&rt711->calibrate_mutex); } static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index a0c6a9efa840..4ad2b1da1954 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -422,12 +423,11 @@ static int rt711_interrupt_callback(struct sdw_slave *slave, dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); - mutex_lock(&rt711->disable_irq_lock); + guard(mutex)(&rt711->disable_irq_lock); if (status->control_port & 0x4 && !rt711->disable_irq) { mod_delayed_work(system_power_efficient_wq, &rt711->jack_detect_work, msecs_to_jiffies(250)); } - mutex_unlock(&rt711->disable_irq_lock); return 0; } @@ -509,11 +509,11 @@ static int rt711_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt711->disable_irq_lock); - rt711->disable_irq = true; - ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, - SDW_SCP_INT1_IMPL_DEF, 0); - mutex_unlock(&rt711->disable_irq_lock); + scoped_guard(mutex, &rt711->disable_irq_lock) { + rt711->disable_irq = true; + ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, + SDW_SCP_INT1_IMPL_DEF, 0); + } if (ret < 0) { /* log but don't prevent suspend from happening */ @@ -535,12 +535,12 @@ static int rt711_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt711->disable_irq_lock); - if (rt711->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); - rt711->disable_irq = false; + scoped_guard(mutex, &rt711->disable_irq_lock) { + if (rt711->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); + rt711->disable_irq = false; + } } - mutex_unlock(&rt711->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 5dbe9b67703e..3e49c3d0f25b 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -89,24 +90,24 @@ static int rt711_calibration(struct rt711_priv *rt711) struct regmap *regmap = rt711->regmap; int ret = 0; - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); dev = regmap_get_device(regmap); /* Calibration manual mode */ rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, - 0xf, 0x0); + 0xf, 0x0); /* trigger */ rt711_index_update_bits(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, - RT711_DAC_DC_CALI_TRIGGER); + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, + RT711_DAC_DC_CALI_TRIGGER); /* wait for calibration process */ rt711_index_read(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, &val); + RT711_DAC_DC_CALI_CTL1, &val); while (val & RT711_DAC_DC_CALI_TRIGGER) { if (loop >= 500) { @@ -119,16 +120,15 @@ static int rt711_calibration(struct rt711_priv *rt711) usleep_range(10000, 11000); rt711_index_read(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, &val); + RT711_DAC_DC_CALI_CTL1, &val); } /* depop mode */ rt711_index_update_bits(regmap, RT711_VENDOR_REG, - RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); + RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); return ret; @@ -362,24 +362,24 @@ static void rt711_jack_init(struct rt711_priv *rt711) { struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt711->component); - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); /* power on */ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY) regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); if (rt711->hs_jack) { /* unsolicited response & IRQ control */ regmap_write(rt711->regmap, - RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); + RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); regmap_write(rt711->regmap, - RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); + RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); regmap_write(rt711->regmap, - RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); + RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); rt711_index_write(rt711->regmap, RT711_VENDOR_REG, - 0x10, 0x2420); + 0x10, 0x2420); rt711_index_write(rt711->regmap, RT711_VENDOR_REG, - 0x19, 0x2e11); + 0x19, 0x2e11); switch (rt711->jd_src) { case RT711_JD1: @@ -449,8 +449,7 @@ static void rt711_jack_init(struct rt711_priv *rt711) /* power off */ if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY) regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); } static int rt711_set_jack_detect(struct snd_soc_component *component, @@ -511,7 +510,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, unsigned int read_ll, read_rl; int i; - mutex_lock(&rt711->calibrate_mutex); + guard(mutex)(&rt711->calibrate_mutex); /* Can't use update bit function, so read the original value first */ addr_h = mc->reg; @@ -599,7 +598,6 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); return 0; } @@ -908,11 +906,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: - mutex_lock(&rt711->calibrate_mutex); - regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, - AC_PWRST_D3); - mutex_unlock(&rt711->calibrate_mutex); + scoped_guard(mutex, &rt711->calibrate_mutex) { + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, + AC_PWRST_D3); + } break; default: From cd1c99ff8cf7682bb2ac92973d1da2db01975cf7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:56 +0700 Subject: [PATCH 258/438] ASoC: codecs: rt712-sdca-sdw: Simplify regcache error handling in resume Calling regcache_mark_dirty() on error is redundant as regcache_sync() retains dirty state on failure, and any write in cache_only mode marks the cache dirty anyway. Restore cache_only directly on error for active regmaps and drop the redundant regcache_mark_dirty() calls. This also removes goto labels to prepare for guard cleanup. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-26-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index ebdf7b308331..e23501ed87a7 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -473,22 +473,20 @@ static int rt712_sdca_dev_resume(struct device *dev) regcache_cache_only(rt712->regmap, false); ret = regcache_sync(rt712->regmap); - if (ret) - goto err_sync; + if (ret) { + regcache_cache_only(rt712->regmap, true); + return ret; + } regcache_cache_only(rt712->mbq_regmap, false); ret = regcache_sync(rt712->mbq_regmap); - if (ret) - goto err_sync; + if (ret) { + regcache_cache_only(rt712->mbq_regmap, true); + regcache_cache_only(rt712->regmap, true); + return ret; + } return 0; - -err_sync: - regcache_cache_only(rt712->regmap, true); - regcache_cache_only(rt712->mbq_regmap, true); - regcache_mark_dirty(rt712->regmap); - regcache_mark_dirty(rt712->mbq_regmap); - return ret; } static const struct dev_pm_ops rt712_sdca_pm = { From 32ac6377cec13e0b1727507cf6cd9ff808a81e42 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:57 +0700 Subject: [PATCH 259/438] ASoC: codecs: rt712: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-27-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt712-sdca-sdw.c | 30 ++++++++++++++++-------------- sound/soc/codecs/rt712-sdca.c | 5 ++--- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index e23501ed87a7..c50e74e20a88 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -427,13 +428,13 @@ static int rt712_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt712_sdca->disable_irq_lock); - rt712_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt712_sdca->disable_irq_lock); + scoped_guard(mutex, &rt712_sdca->disable_irq_lock) { + rt712_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -455,14 +456,15 @@ static int rt712_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt712->disable_irq_lock); - if (rt712->disable_irq == true) { - - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt712->disable_irq = false; + scoped_guard(mutex, &rt712->disable_irq_lock) { + if (rt712->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt712->disable_irq = false; + } } - mutex_unlock(&rt712->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index d6353af07380..2218f9918ae3 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -7,6 +7,7 @@ // #include +#include #include #include #include @@ -403,7 +404,7 @@ static void rt712_sdca_btn_check_handler(struct work_struct *work) static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) { - mutex_lock(&rt712->calibrate_mutex); + guard(mutex)(&rt712->calibrate_mutex); if (rt712->hs_jack) { /* Enable HID1 event & set button RTC mode */ @@ -450,8 +451,6 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) dev_dbg(&rt712->slave->dev, "in %s disable\n", __func__); } - - mutex_unlock(&rt712->calibrate_mutex); } static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, From 2df329044c614fce2d0f4f46ddba276ec3aa4ae5 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:58 +0700 Subject: [PATCH 260/438] ASoC: codecs: rt721-sdca-sdw: Simplify regcache error handling in resume Calling regcache_mark_dirty() on error is redundant as regcache_sync() retains dirty state on failure, and any write in cache_only mode marks the cache dirty anyway. Restore cache_only directly on error for active regmaps and drop the redundant regcache_mark_dirty() calls. This also removes goto labels to prepare for guard cleanup. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-28-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt721-sdca-sdw.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index 6e27e761afb6..6411df4eede7 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -511,22 +511,20 @@ static int rt721_sdca_dev_resume(struct device *dev) regcache_cache_only(rt721->regmap, false); ret = regcache_sync(rt721->regmap); - if (ret) - goto err_sync; + if (ret) { + regcache_cache_only(rt721->regmap, true); + return ret; + } regcache_cache_only(rt721->mbq_regmap, false); ret = regcache_sync(rt721->mbq_regmap); - if (ret) - goto err_sync; + if (ret) { + regcache_cache_only(rt721->mbq_regmap, true); + regcache_cache_only(rt721->regmap, true); + return ret; + } return 0; - -err_sync: - regcache_cache_only(rt721->regmap, true); - regcache_cache_only(rt721->mbq_regmap, true); - regcache_mark_dirty(rt721->regmap); - regcache_mark_dirty(rt721->mbq_regmap); - return ret; } static const struct dev_pm_ops rt721_sdca_pm = { From 219fbaa1b6d1b9ac2e8bc29fc2e904d51c6f8b17 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:25:59 +0700 Subject: [PATCH 261/438] ASoC: codecs: rt721: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-29-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt721-sdca-sdw.c | 29 ++++++++++++++++------------- sound/soc/codecs/rt721-sdca.c | 5 ++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index 6411df4eede7..eae7d662efae 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -466,13 +467,13 @@ static int rt721_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt721_sdca->disable_irq_lock); - rt721_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt721_sdca->disable_irq_lock); + scoped_guard(mutex, &rt721_sdca->disable_irq_lock) { + rt721_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -494,13 +495,15 @@ static int rt721_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt721->disable_irq_lock); - if (rt721->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt721->disable_irq = false; + scoped_guard(mutex, &rt721->disable_irq_lock) { + if (rt721->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt721->disable_irq = false; + } } - mutex_unlock(&rt721->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c index 35960c225224..159c35d19dba 100644 --- a/sound/soc/codecs/rt721-sdca.c +++ b/sound/soc/codecs/rt721-sdca.c @@ -5,7 +5,7 @@ // Copyright(c) 2024 Realtek Semiconductor Corp. // // - +#include #include #include #include @@ -289,7 +289,7 @@ static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721) static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) { - mutex_lock(&rt721->calibrate_mutex); + guard(mutex)(&rt721->calibrate_mutex); if (rt721->hs_jack) { sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); @@ -309,7 +309,6 @@ static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, RT721_GE_REL_CTRL1, 0x4000, 0x4000); } - mutex_unlock(&rt721->calibrate_mutex); } static int rt721_sdca_set_jack_detect(struct snd_soc_component *component, From cce043d552cde5ee71c9261e0ad9789209275e31 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 21 Jul 2026 17:26:00 +0700 Subject: [PATCH 262/438] ASoC: codecs: rt722: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260721102600.523199-30-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt722-sdca-sdw.c | 29 ++++++++++++++++------------- sound/soc/codecs/rt722-sdca.c | 4 ++-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index d2db33b4f684..05e8e23f1f43 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -513,13 +514,13 @@ static int rt722_sdca_dev_system_suspend(struct device *dev) * deferred work completes and before the parent disables * interrupts on the link */ - mutex_lock(&rt722_sdca->disable_irq_lock); - rt722_sdca->disable_irq = true; - ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0, 0); - ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, - SDW_SCP_SDCA_INTMASK_SDCA_8, 0); - mutex_unlock(&rt722_sdca->disable_irq_lock); + scoped_guard(mutex, &rt722_sdca->disable_irq_lock) { + rt722_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + } if (ret1 < 0 || ret2 < 0) { /* log but don't prevent suspend from happening */ @@ -541,13 +542,15 @@ static int rt722_sdca_dev_resume(struct device *dev) return 0; if (!slave->unattach_request) { - mutex_lock(&rt722->disable_irq_lock); - if (rt722->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); - rt722->disable_irq = false; + scoped_guard(mutex, &rt722->disable_irq_lock) { + if (rt722->disable_irq) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + rt722->disable_irq = false; + } } - mutex_unlock(&rt722->disable_irq_lock); } ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT); diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index 1b6729f363fc..decf9407ab6d 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -6,6 +6,7 @@ // // +#include #include #include #include @@ -294,7 +295,7 @@ static void rt722_sdca_btn_check_handler(struct work_struct *work) static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) { - mutex_lock(&rt722->calibrate_mutex); + guard(mutex)(&rt722->calibrate_mutex); if (rt722->hs_jack) { /* set SCP_SDCA_IntMask1[0]=1 */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, @@ -317,7 +318,6 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2, 0x4000, 0x4000); } - mutex_unlock(&rt722->calibrate_mutex); } static int rt722_sdca_set_jack_detect(struct snd_soc_component *component, From 13651ae6548d8957b75bff0c8d1239beff8a9394 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 23 Jul 2026 04:11:51 +0000 Subject: [PATCH 263/438] ASoC: meson: axg-card: tidyup not to use card->dev struct snd_soc_card will be capsuled soon, its member will not be able to access from non soc-card.c. To reduce the difference during conversion, replace dev. - card->dev, ... + dev, ... No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/87a4ritke0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-card.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index b4dca80e15e4..c36f727af4ba 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -107,6 +107,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, struct snd_soc_dai_link *pad; struct snd_soc_dai_link *lb; struct snd_soc_dai_link_component *dlc; + struct device *dev = card->dev; int ret; /* extend links */ @@ -117,11 +118,11 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, pad = &card->dai_link[*index]; lb = &card->dai_link[*index + 1]; - lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name); + lb->name = devm_kasprintf(dev, GFP_KERNEL, "%s-lb", pad->name); if (!lb->name) return -ENOMEM; - dlc = devm_kzalloc(card->dev, sizeof(*dlc), GFP_KERNEL); + dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL); if (!dlc) return -ENOMEM; @@ -158,13 +159,14 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, struct device_node *node, struct axg_dai_link_tdm_data *be) { + struct device *dev = card->dev; char propname[32]; u32 tx, rx; int i; - be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES, + be->tx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES, sizeof(*be->tx_mask), GFP_KERNEL); - be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES, + be->rx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES, sizeof(*be->rx_mask), GFP_KERNEL); if (!be->tx_mask || !be->rx_mask) return -ENOMEM; @@ -191,7 +193,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, /* ... but the interface should at least have one direction */ if (!tx && !rx) { - dev_err(card->dev, "tdm link has no cpu slots\n"); + dev_err(dev, "tdm link has no cpu slots\n"); return -EINVAL; } @@ -207,7 +209,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, * Error if the slots can't accommodate the largest mask or * if it is just too big */ - dev_err(card->dev, "bad slot number\n"); + dev_err(dev, "bad slot number\n"); return -EINVAL; } @@ -222,8 +224,9 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, struct axg_dai_link_tdm_data *be) { struct axg_dai_link_tdm_mask *codec_mask; + struct device *dev = card->dev; - codec_mask = devm_kcalloc(card->dev, link->num_codecs, + codec_mask = devm_kcalloc(dev, link->num_codecs, sizeof(*codec_mask), GFP_KERNEL); if (!codec_mask) return -ENOMEM; @@ -249,10 +252,11 @@ static int axg_card_parse_tdm(struct snd_soc_card *card, struct meson_card *priv = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link *link = &card->dai_link[*index]; struct axg_dai_link_tdm_data *be; + struct device *dev = card->dev; int ret; /* Allocate tdm link parameters */ - be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL); + be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL); if (!be) return -ENOMEM; priv->link_data[*index] = be; @@ -266,7 +270,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card, ret = axg_card_parse_cpu_tdm_slots(card, link, node, be); if (ret) { - dev_err(card->dev, "error parsing tdm link slots\n"); + dev_err(dev, "error parsing tdm link slots\n"); return ret; } @@ -310,9 +314,10 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, { struct snd_soc_dai_link *dai_link = &card->dai_link[*index]; struct snd_soc_dai_link_component *cpu; + struct device *dev = card->dev; int ret; - cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL); + cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL); if (!cpu) return -ENOMEM; From 138a0faeaca4384e0324865c1e41b199e5f8d406 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 23 Jul 2026 04:11:55 +0000 Subject: [PATCH 264/438] ASoC: meson: gx-card: tidyup not to use card->dev struct snd_soc_card will be capsuled soon, its member will not be able to access from non soc-card.c. To reduce the difference during conversion, replace dev. - card->dev, ... + dev, ... No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/878q72tkdw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/gx-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c index b408cc2bbc91..932be0a09306 100644 --- a/sound/soc/meson/gx-card.c +++ b/sound/soc/meson/gx-card.c @@ -48,9 +48,10 @@ static int gx_card_parse_i2s(struct snd_soc_card *card, struct meson_card *priv = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link *link = &card->dai_link[*index]; struct gx_dai_link_i2s_data *be; + struct device *dev = card->dev; /* Allocate i2s link parameters */ - be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL); + be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL); if (!be) return -ENOMEM; priv->link_data[*index] = be; @@ -81,9 +82,10 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np, { struct snd_soc_dai_link *dai_link = &card->dai_link[*index]; struct snd_soc_dai_link_component *cpu; + struct device *dev = card->dev; int ret; - cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL); + cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL); if (!cpu) return -ENOMEM; From 6c3042f65f20b3d7b8972d4882a9b5339bc4fd3e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 23 Jul 2026 04:11:59 +0000 Subject: [PATCH 265/438] ASoC: meson: meson-card-utils: tidyup not to use card->dev struct snd_soc_card will be capsuled soon, its member will not be able to access from non soc-card.c. To reduce the difference during conversion, replace dev. - card->dev, ... + dev, ... No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Reviewed-by: Jerome Brunet Link: https://patch.msgid.link/877bmmtkds.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/meson/meson-card-utils.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index cdb759b466ad..be05fba2df70 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -76,6 +76,7 @@ int meson_card_parse_dai(struct snd_soc_card *card, struct device_node *node, struct snd_soc_dai_link_component *dlc) { + struct device *dev = card->dev; int ret; if (!dlc || !node) @@ -83,7 +84,7 @@ int meson_card_parse_dai(struct snd_soc_card *card, ret = snd_soc_of_get_dlc(node, NULL, dlc, 0); if (ret) - return dev_err_probe(card->dev, ret, "can't parse dai\n"); + return dev_err_probe(dev, ret, "can't parse dai\n"); return ret; } @@ -94,7 +95,8 @@ static int meson_card_set_link_name(struct snd_soc_card *card, struct device_node *node, const char *prefix) { - char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s", + struct device *dev = card->dev; + char *name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", prefix, node->full_name); if (!name) return -ENOMEM; @@ -137,16 +139,17 @@ int meson_card_set_be_link(struct snd_soc_card *card, struct device_node *node) { struct snd_soc_dai_link_component *codec; + struct device *dev = card->dev; int ret, num_codecs; num_codecs = of_get_child_count(node); if (!num_codecs) { - dev_err(card->dev, "be link %s has no codec\n", + dev_err(dev, "be link %s has no codec\n", node->full_name); return -EINVAL; } - codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL); + codec = devm_kcalloc(dev, num_codecs, sizeof(*codec), GFP_KERNEL); if (!codec) return -ENOMEM; @@ -163,7 +166,7 @@ int meson_card_set_be_link(struct snd_soc_card *card, ret = meson_card_set_link_name(card, link, node, "be"); if (ret) - dev_err(card->dev, "error setting %pOFn link name\n", node); + dev_err(dev, "error setting %pOFn link name\n", node); return ret; } @@ -194,12 +197,13 @@ EXPORT_SYMBOL_GPL(meson_card_set_fe_link); static int meson_card_add_links(struct snd_soc_card *card) { struct meson_card *priv = snd_soc_card_get_drvdata(card); - struct device_node *node = card->dev->of_node; + struct device *dev = card->dev; + struct device_node *node = dev->of_node; int num, i, ret; num = of_get_child_count(node); if (!num) { - dev_err(card->dev, "card has no links\n"); + dev_err(dev, "card has no links\n"); return -EINVAL; } @@ -224,8 +228,10 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card, int (*func)(struct snd_soc_card *c, const char *p)) { + struct device *dev = card->dev; + /* If property is not provided, don't fail ... */ - if (!of_property_present(card->dev->of_node, propname)) + if (!of_property_present(dev->of_node, propname)) return 0; /* ... but do fail if it is provided and the parsing fails */ From 3a065257412f612d4f3fe538003c4520d6e4e4c0 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 21 Jul 2026 15:59:36 -0700 Subject: [PATCH 266/438] ASoC: fsl: mpc5200_dma: use platform helpers and devm cleanup Convert mpc5200_audio_dma_create() to the managed APIs. Replace the open-coded of_address_to_resource() + devm_ioremap() of the PSC registers with devm_platform_get_and_ioremap_resource(), and irq_of_parse_and_map() with platform_get_irq() (which returns a negative errno instead of 0). Switch the allocation to devm_kzalloc(), the three interrupt requests to devm_request_irq(), and drop the now-unneeded error-path cleanup and the manual teardown in mpc5200_audio_dma_destroy(). The PSC register window is owned solely by this driver, so the new region request from devm_platform_get_and_ioremap_resource() cannot conflict with another claimant, and it is mapped exactly once (no double mapping). The resource pointer is still used (res->start) to compute the FIFO physical address. No functional change; built for powerpc (allmodconfig + CONFIG_SND_SOC_MPC5200_DMA) with LLVM=1 and sound/soc/fsl/mpc5200_dma.o compiles cleanly. Assisted-by: opencode:hy3-free Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260721225936.838299-1-rosenp@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 58 ++++++++++---------------------- sound/soc/fsl/mpc5200_psc_ac97.c | 4 +-- sound/soc/fsl/mpc5200_psc_i2s.c | 3 +- 3 files changed, 20 insertions(+), 45 deletions(-) diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index bfedb2dea0b3..8327fff3e1b5 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -314,35 +314,29 @@ int mpc5200_audio_dma_create(struct platform_device *op) { phys_addr_t fifo; struct psc_dma *psc_dma; - struct resource res; + struct resource *res; int size, irq, rc; const __be32 *prop; void __iomem *regs; - int ret; + + regs = devm_platform_get_and_ioremap_resource(op, 0, &res); + if (IS_ERR(regs)) + return PTR_ERR(regs); /* Fetch the registers and IRQ of the PSC */ - irq = irq_of_parse_and_map(op->dev.of_node, 0); - if (of_address_to_resource(op->dev.of_node, 0, &res)) { - dev_err(&op->dev, "Missing reg property\n"); - return -ENODEV; - } - regs = devm_ioremap(&op->dev, res.start, resource_size(&res)); - if (!regs) { - dev_err(&op->dev, "Could not map registers\n"); - return -ENODEV; - } + irq = platform_get_irq(op, 0); + if (irq < 0) + return irq; /* Allocate and initialize the driver private data */ - psc_dma = kzalloc_obj(*psc_dma); + psc_dma = devm_kzalloc(&op->dev, sizeof(*psc_dma), GFP_KERNEL); if (!psc_dma) return -ENOMEM; /* Get the PSC ID */ prop = of_get_property(op->dev.of_node, "cell-index", &size); - if (!prop || size < sizeof *prop) { - ret = -ENODEV; - goto out_free; - } + if (!prop || size < sizeof *prop) + return -ENODEV; spin_lock_init(&psc_dma->lock); mutex_init(&psc_dma->mutex); @@ -357,7 +351,7 @@ int mpc5200_audio_dma_create(struct platform_device *op) /* Find the address of the fifo data registers and setup the * DMA tasks */ - fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); + fifo = res->start + offsetof(struct mpc52xx_psc, buffer.buffer_32); psc_dma->capture.bcom_task = bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); psc_dma->playback.bcom_task = @@ -365,8 +359,7 @@ int mpc5200_audio_dma_create(struct platform_device *op) if (!psc_dma->capture.bcom_task || !psc_dma->playback.bcom_task) { dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); - ret = -ENODEV; - goto out_free; + return -ENODEV; } /* Disable all interrupts and reset the PSC */ @@ -399,16 +392,14 @@ int mpc5200_audio_dma_create(struct platform_device *op) psc_dma->capture.irq = bcom_get_task_irq(psc_dma->capture.bcom_task); - rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, + rc = devm_request_irq(&op->dev, psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, "psc-dma-status", psc_dma); - rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, + rc |= devm_request_irq(&op->dev, psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, "psc-dma-capture", &psc_dma->capture); - rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, + rc |= devm_request_irq(&op->dev, psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, "psc-dma-playback", &psc_dma->playback); - if (rc) { - ret = -ENODEV; - goto out_irq; - } + if (rc) + return -ENODEV; /* Save what we've done so it can be found again later */ dev_set_drvdata(&op->dev, psc_dma); @@ -416,13 +407,6 @@ int mpc5200_audio_dma_create(struct platform_device *op) /* Tell the ASoC OF helpers about it */ return devm_snd_soc_register_component(&op->dev, &mpc5200_audio_dma_component, NULL, 0); -out_irq: - free_irq(psc_dma->irq, psc_dma); - free_irq(psc_dma->capture.irq, &psc_dma->capture); - free_irq(psc_dma->playback.irq, &psc_dma->playback); -out_free: - kfree(psc_dma); - return ret; } EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); @@ -435,12 +419,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op) bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); - /* Release irqs */ - free_irq(psc_dma->irq, psc_dma); - free_irq(psc_dma->capture.irq, &psc_dma->capture); - free_irq(psc_dma->playback.irq, &psc_dma->playback); - - kfree(psc_dma); dev_set_drvdata(&op->dev, NULL); return 0; diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 2aefd6414ace..ccd8bda05860 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -276,7 +276,7 @@ static int psc_ac97_of_probe(struct platform_device *op) return rc; } - rc = snd_soc_register_component(&op->dev, &psc_ac97_component, + rc = devm_snd_soc_register_component(&op->dev, &psc_ac97_component, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); if (rc != 0) { dev_err(&op->dev, "Failed to register DAI\n"); @@ -302,8 +302,6 @@ static int psc_ac97_of_probe(struct platform_device *op) static void psc_ac97_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); - snd_soc_unregister_component(&op->dev); - snd_soc_set_ac97_ops(NULL); } /* Match table for of_platform binding */ diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 7831136f4f12..55a12be6ad18 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -166,7 +166,7 @@ static int psc_i2s_of_probe(struct platform_device *op) if (rc != 0) return rc; - rc = snd_soc_register_component(&op->dev, &psc_i2s_component, + rc = devm_snd_soc_register_component(&op->dev, &psc_i2s_component, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); if (rc != 0) { pr_err("Failed to register DAI\n"); @@ -213,7 +213,6 @@ static int psc_i2s_of_probe(struct platform_device *op) static void psc_i2s_of_remove(struct platform_device *op) { mpc5200_audio_dma_destroy(op); - snd_soc_unregister_component(&op->dev); } /* Match table for of_platform binding */ From 4c69d04958ec87163ba826e2506babab37192e4b Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Tue, 21 Jul 2026 19:35:55 -0700 Subject: [PATCH 267/438] ASoC: spacemit: rename clock inputs to match binding The driver requests the per-controller SSPA bus and functional clocks as "sspa_bus" and "sspa", but the device tree binding (spacemit,k1-i2s) specifies them as "bus" and "func". As a result, any DT written against the published binding fails to probe. There are currently no in-tree DT users referencing these names, so rename the clock inputs in the driver to match the binding rather than changing the binding. While at it, rename the matching struct member sspa_clk to func_clk for consistency with the new clock-names. Fixes: fce217449075 ("ASoC: spacemit: add i2s support for K1 SoC") Signed-off-by: Troy Mitchell Link: https://patch.msgid.link/20260721-kx-i2s-dts-v1-1-d22cb6cfaab5@linux.spacemit.com Signed-off-by: Mark Brown --- sound/soc/spacemit/k1_i2s.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c index cd461f2aa756..2751485ac0b0 100644 --- a/sound/soc/spacemit/k1_i2s.c +++ b/sound/soc/spacemit/k1_i2s.c @@ -52,7 +52,7 @@ struct spacemit_i2s_dev { struct clk *sysclk; struct clk *bclk; - struct clk *sspa_clk; + struct clk *func_clk; struct clk *sysclk_div; struct clk *c_sysclk; struct clk *c_bclk; @@ -221,7 +221,7 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - return clk_set_rate(i2s->sspa_clk, bclk_rate); + return clk_set_rate(i2s->func_clk, bclk_rate); } static int spacemit_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, @@ -452,14 +452,14 @@ static int spacemit_i2s_probe(struct platform_device *pdev) if (IS_ERR(i2s->bclk)) return dev_err_probe(i2s->dev, PTR_ERR(i2s->bclk), "failed to enable bit clock\n"); - clk = devm_clk_get_enabled(i2s->dev, "sspa_bus"); + clk = devm_clk_get_enabled(i2s->dev, "bus"); if (IS_ERR(clk)) - return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa_bus clock\n"); + return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable bus clock\n"); - i2s->sspa_clk = devm_clk_get_enabled(i2s->dev, "sspa"); - if (IS_ERR(i2s->sspa_clk)) - return dev_err_probe(i2s->dev, PTR_ERR(i2s->sspa_clk), - "failed to enable sspa clock\n"); + i2s->func_clk = devm_clk_get_enabled(i2s->dev, "func"); + if (IS_ERR(i2s->func_clk)) + return dev_err_probe(i2s->dev, PTR_ERR(i2s->func_clk), + "failed to enable func clock\n"); i2s->sysclk_div = devm_clk_get_optional_enabled(i2s->dev, "sysclk_div"); if (IS_ERR(i2s->sysclk_div)) From ec926b3bcb49000bafb402a6864d19ae40a3d288 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Tue, 21 Jul 2026 19:35:56 -0700 Subject: [PATCH 268/438] ASoC: dt-bindings: sound: spacemit,k1-i2s: allow 6 clocks for K3 i2s1 The K3 I2S controllers normally use the published 7-clock layout: sysclk, bclk, bus, func, sysclk_div, c_sysclk, c_bclk However, K3 i2s1 has no dedicated sysclk divider and therefore uses a 6-clock layout: sysclk, bclk, bus, func, c_sysclk, c_bclk Describe the 4-clock K1 and both K3 layouts as separate tuples. Lower the K3 minimum from 7 to 6 clocks while preserving the existing 7-clock ordering. Fixes: 6bc6b28c0314 ("ASoC: dt-bindings: add SpacemiT K3 SoC compatible") Signed-off-by: Troy Mitchell Link: https://patch.msgid.link/20260721-kx-i2s-dts-v1-2-d22cb6cfaab5@linux.spacemit.com Signed-off-by: Mark Brown --- .../bindings/sound/spacemit,k1-i2s.yaml | 64 +++++++++++++------ 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml index 240d90402e4f..72723f067b2a 100644 --- a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml @@ -23,9 +23,9 @@ allOf: then: properties: clocks: - minItems: 7 + minItems: 6 clock-names: - minItems: 7 + minItems: 6 else: properties: clocks: @@ -43,26 +43,50 @@ properties: maxItems: 1 clocks: - minItems: 4 - items: - - description: clock for I2S sysclk - - description: clock for I2S bclk - - description: clock for I2S bus - - description: clock for I2S controller - - description: clock for I2S sysclk divider - - description: clock for I2S common sysclk - - description: clock for I2S common bclk + oneOf: + - items: + - description: clock for I2S sysclk + - description: clock for I2S bclk + - description: clock for I2S bus + - description: clock for I2S controller + - items: + - description: clock for I2S sysclk + - description: clock for I2S bclk + - description: clock for I2S bus + - description: clock for I2S controller + - description: clock for I2S common sysclk + - description: clock for I2S common bclk + - items: + - description: clock for I2S sysclk + - description: clock for I2S bclk + - description: clock for I2S bus + - description: clock for I2S controller + - description: clock for I2S sysclk divider + - description: clock for I2S common sysclk + - description: clock for I2S common bclk clock-names: - minItems: 4 - items: - - const: sysclk - - const: bclk - - const: bus - - const: func - - const: sysclk_div - - const: c_sysclk - - const: c_bclk + oneOf: + - items: + - const: sysclk + - const: bclk + - const: bus + - const: func + - items: + - const: sysclk + - const: bclk + - const: bus + - const: func + - const: c_sysclk + - const: c_bclk + - items: + - const: sysclk + - const: bclk + - const: bus + - const: func + - const: sysclk_div + - const: c_sysclk + - const: c_bclk dmas: minItems: 1 From 7a047311de7fc738984ed10c5fc4f6c9cc418326 Mon Sep 17 00:00:00 2001 From: "shaikh.kamal" Date: Sun, 26 Jul 2026 11:22:27 +0530 Subject: [PATCH 269/438] ASoC: dt-bindings: fix spelling errors Fix spelling errors reported by codespell: susbsytem -> subsystem (amlogic,axg-sound-card, amlogic,gx-sound-card) vlaue -> value (realtek,rt1015) spped -> speed (st,sta32x) No functional change. Signed-off-by: shaikh.kamal Link: https://patch.msgid.link/20260726055227.18123-1-shaikhkamal2012@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/amlogic,axg-sound-card.yaml | 2 +- .../devicetree/bindings/sound/amlogic,gx-sound-card.yaml | 2 +- Documentation/devicetree/bindings/sound/realtek,rt1015.yaml | 2 +- Documentation/devicetree/bindings/sound/st,sta32x.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml index 4f13e8ab50b2..177db900d4a0 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml @@ -30,7 +30,7 @@ properties: minItems: 1 maxItems: 3 description: - Base PLL clocks of audio susbsytem, used to configure base clock + Base PLL clocks of audio subsystem, used to configure base clock frequencies for different audio use-cases. patternProperties: diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index 413b47778181..6fdf605ad59c 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -31,7 +31,7 @@ properties: minItems: 1 maxItems: 3 description: - Base PLL clocks of audio susbsytem, used to configure base clock + Base PLL clocks of audio subsystem, used to configure base clock frequencies for different audio use-cases. patternProperties: diff --git a/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml index 880196081a60..3c44ebf93a44 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml @@ -19,7 +19,7 @@ properties: realtek,power-up-delay-ms: description: Set a delay time for flush work to be completed, - this vlaue is adjustable depending on platform. + this value is adjustable depending on platform. maxItems: 1 required: diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt index 52265fb757c5..266b6fc9f009 100644 --- a/Documentation/devicetree/bindings/sound/st,sta32x.txt +++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt @@ -73,7 +73,7 @@ Optional properties: - st,odd-pwm-speed-mode: If present, PWM speed mode run on odd speed mode (341.3 kHz) on all - channels. If not present, normal PWM spped mode (384 kHz) will be used. + channels. If not present, normal PWM speed mode (384 kHz) will be used. - st,invalid-input-detect-mute: If present, automatic invalid input detect mute is enabled. From c626e2e0b2798e7d06a5310316253c61988c256b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Jul 2026 15:05:16 +0800 Subject: [PATCH 270/438] ASoC: Intel: add snd_soc_acpi_intel_rt712_vb_no_function_topology machine check function This check function return snd_soc_acpi_intel_sdca_is_device_rt712_vb() && snd_soc_acpi_intel_no_function_topology() for the cases that need check is the device is rt712 vb and no function topology. Signed-off-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260723070521.870256-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c | 8 ++++++++ sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h | 1 + 2 files changed, 9 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c index 7caabc501b16..9fdeb6ad96ac 100644 --- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c @@ -53,6 +53,14 @@ bool snd_soc_acpi_intel_no_function_topology(void *arg) } EXPORT_SYMBOL_NS(snd_soc_acpi_intel_no_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); +bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg) +{ + return snd_soc_acpi_intel_sdca_is_device_rt712_vb(arg) && + snd_soc_acpi_intel_no_function_topology(arg); +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_rt712_vb_no_function_topology, + "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); + MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks"); MODULE_LICENSE("GPL"); MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h index 2ea0a1881c4b..60b665ab5924 100644 --- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h @@ -11,5 +11,6 @@ bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); bool snd_soc_acpi_intel_no_function_topology(void *arg); +bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg); #endif From 168e80166596409cbe7373ca4603f73acdf409eb Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Jul 2026 15:05:17 +0800 Subject: [PATCH 271/438] ASoC: soc-acpi-intel-ptl-match: add machine check for machines can't use function topology There are still some Google machines that need to use the monolithic topology. Add the machine check for those machines. Signed-off-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260723070521.870256-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index f7694b2a2b02..41c059d43998 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -492,7 +492,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .links = ptl_rt722_l0_rt1320_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt722-l0-rt1320-l23.tplg", - .get_function_tplg_files = sof_sdw_get_tplg_files, + .machine_check = snd_soc_acpi_intel_no_function_topology, }, { .link_mask = BIT(1) | BIT(2), @@ -527,9 +527,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .link_mask = BIT(3), .links = ptl_sdw_rt712_vb_l3_rt1320_l3, .drv_name = "sof_sdw", - .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .machine_check = snd_soc_acpi_intel_rt712_vb_no_function_topology, .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg", - .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; From 3b4cfca660b533f66e417cc3dc6b0a9a8e20ab52 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Jul 2026 15:05:18 +0800 Subject: [PATCH 272/438] ASoC: soc-acpi-intel-ptl-match: use function topology by default With commit c84179a1d36b ("ASoC: Intel: sof_sdw: append dai type to dai link name unconditionally"), function topology can apply to all SoundWire codec configurations. Set .get_function_tplg_files callback to use function topology by default. If any required function topology can not be found in the file system, it will fallback to use the monolithic topology. Signed-off-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260723070521.870256-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-ptl-match.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index 41c059d43998..756bbf82a326 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -522,6 +522,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .links = ptl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt711.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(3), From c4611d4c476d69aecfe1de33a799a3a6d48d5503 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Jul 2026 15:05:19 +0800 Subject: [PATCH 273/438] ASoC: soc-acpi-intel-lnl-match: use function topology by default With commit c84179a1d36b ("ASoC: Intel: sof_sdw: append dai type to dai link name unconditionally"), function topology can apply to all SoundWire codec configurations. Set .get_function_tplg_files callback to use function topology by default. If any required function topology can not be found in the file system, it will fallback to use the monolithic topology. Signed-off-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260723070521.870256-5-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-lnl-match.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index 937a74a5d523..3b9758f73238 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -717,24 +717,28 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .links = lnl_3_in_1_sdca, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2) | BIT(3), .links = lnl_cs42l43_l0_cs35l56_l23, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(1) | BIT(2) | BIT(3), .links = lnl_cs42l43_l2_cs35l56x6_l13, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-cs42l43-l2-cs35l56x6-l13.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(3), .links = lnl_cs42l43_l0_cs35l56_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), @@ -748,12 +752,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .links = lnl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt711.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(2) | BIT(3), .links = lnl_712_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt712-l2-rt1712-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), @@ -766,19 +772,22 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .link_mask = GENMASK(2, 0), .links = lnl_sdw_rt1318_l12_rt714_l0, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg" + .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(2, 0), .links = lnl_sdw_rt1320_l12_rt714_l0, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg" + .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(1), .links = lnl_sdw_rt713_l0_rt1318_l1, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg" + .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(1) | BIT(2), From 3f17f5a1e2b2bf7f8d02b53a8d218578b78e5f5e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Jul 2026 15:05:20 +0800 Subject: [PATCH 274/438] ASoC: soc-acpi-intel-arl-match: use function topology by default With commit c84179a1d36b ("ASoC: Intel: sof_sdw: append dai type to dai link name unconditionally"), function topology can apply to all SoundWire codec configurations. Set .get_function_tplg_files callback to use function topology by default. If any required function topology can not be found in the file system, it will fallback to use the monolithic topology. Signed-off-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260723070521.870256-6-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-arl-match.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index 59bfd5248819..1033f2d45c8a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -572,6 +572,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .links = arl_rt711_l0_rt1316_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(3), @@ -600,12 +601,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .links = arl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt711.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = 0x1, /* link0 required */ .links = arl_sdca_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt711-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(2), From da1e707bc2586c7c695b4a1f9d98516b360f0b57 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 23 Jul 2026 15:05:21 +0800 Subject: [PATCH 275/438] ASoC: soc-acpi-intel-mtl-match: use function topology by default With commit c84179a1d36b ("ASoC: Intel: sof_sdw: append dai type to dai link name unconditionally"), function topology can apply to all SoundWire codec configurations. Set .get_function_tplg_files callback to use function topology by default. If any required function topology can not be found in the file system, it will fallback to use the monolithic topology. Signed-off-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260723070521.870256-7-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-mtl-match.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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 2e4222456f27..596582053d93 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -1321,60 +1321,70 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .links = tac5572_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-tac5572.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = tac5672_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-tac5672.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = tac5682_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-tac5682.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = tas2783_link0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-tas2783.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), .links = tas2883_l0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-tas2883.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(3, 0), .links = mtl_rt713_l0_rt1316_l12_rt1713_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(3, 0), .links = mtl_rt713_l0_rt1318_l12_rt1713_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(1) | BIT(3), .links = mtl_rt713_l0_rt1318_l1_rt1713_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(2, 0), .links = mtl_rt713_l0_rt1316_l12, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(3) | BIT(0), .links = mtl_712_l0_1712_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), @@ -1395,7 +1405,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .link_mask = GENMASK(2, 0), .links = mtl_sdw_rt1318_l12_rt714_l0, .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg" + .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2) | BIT(3), @@ -1455,12 +1466,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .links = mtl_3_in_1_sdca, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = 0x9, /* 2 active links required */ .links = mtl_rt711_l0_rt1316_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), @@ -1474,18 +1487,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .links = mtl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt711.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2), .links = rt5682_link2_max98373_link0, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0) | BIT(2), .links = cs42l42_link0_max98363_link2, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-sdw-cs42l42-l0-max98363-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; From 54324f3973c84f3cc81d2c614cb846be086f37f4 Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Fri, 24 Jul 2026 23:54:44 +0530 Subject: [PATCH 276/438] ASoC: dt-bindings: qcom,q6apm-lpass-dais: Document DAI subnode Extend the qcom,q6apm-lpass-dais device tree binding to explicitly describe Digital Audio Interface (DAI) child nodes. Add #address-cells and #size-cells to allow representation of multiple DAI instances as child nodes, and define a dai@ pattern to document per-DAI properties such as the interface ID and associated clocks. On platforms such as Monaco and Lemans, third-party codecs are hardware wired to the SoC and do not always have an in-tree codec driver to manage their clocks. For these designs, clock line enablement must be driven from the platform side, and this series provides the necessary support for that. On QAIF-based platforms such as Shikra and Hawi, responsibility for voting I2S MCLK and BCLK has moved from the DSP to the kernel. This series introduces the required device tree binding support to represent and vote for these clocks from the kernel. Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Signed-off-by: Mohammad Rafi Shaik Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260724182446.1484894-2-mohammad.rafi.shaik@oss.qualcomm.com Signed-off-by: Mark Brown --- .../bindings/sound/qcom,q6apm-lpass-dais.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml index 2fb95544db8b..4878c424ef03 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml @@ -21,6 +21,43 @@ properties: '#sound-dai-cells': const: 1 + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +# Digital Audio Interfaces +patternProperties: + '^dai@[0-9a-f]+$': + type: object + description: + Q6DSP Digital Audio Interfaces. + + properties: + reg: + maxItems: 1 + description: + Digital Audio Interface ID + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + items: + - enum: [bclk, mclk] + - const: mclk + + dependencies: + clocks: [clock-names] + + required: + - reg + + additionalProperties: false + required: - compatible - '#sound-dai-cells' @@ -29,7 +66,20 @@ unevaluatedProperties: false examples: - | + #include + dais { compatible = "qcom,q6apm-lpass-dais"; #sound-dai-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dai@10 { + reg = ; + clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT + LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_CLK_ID_MCLK_1 + LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "bclk", "mclk"; + }; }; From cc8495c1d45ab113a638b5df6c2e0bfa150a7376 Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Fri, 24 Jul 2026 23:54:45 +0530 Subject: [PATCH 277/438] ASoC: qcom: q6apm-lpass-dais: Add MI2S clock control Add support for MI2S clock control within q6apm-lpass DAIs, including handling of MCLK, BCLK via the DAI .set_sysclk callback. Each MI2S port now retrieves its clock handles from the device tree, allowing per-port clock configuration and proper enable/disable during startup and shutdown. Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Tested-by: Neil Armstrong Signed-off-by: Mohammad Rafi Shaik Link: https://patch.msgid.link/20260724182446.1484894-3-mohammad.rafi.shaik@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 168 +++++++++++++++++++++++- sound/soc/qcom/qdsp6/q6prm.h | 3 + 2 files changed, 169 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 006b283484d9..e68e8b000e07 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -2,10 +2,12 @@ // Copyright (c) 2021, Linaro Limited #include +#include #include #include #include #include +#include #include #include #include @@ -15,15 +17,54 @@ #include "q6dsp-common.h" #include "audioreach.h" #include "q6apm.h" +#include "q6prm.h" #define AUDIOREACH_BE_PCM_BASE 16 +struct q6apm_dai_priv_data { + struct clk *mclk; + struct clk *bclk; + bool mclk_enabled, bclk_enabled; +}; + struct q6apm_lpass_dai_data { struct q6apm_graph *graph[APM_PORT_MAX]; bool is_port_started[APM_PORT_MAX]; struct audioreach_module_config module_config[APM_PORT_MAX]; + struct q6apm_dai_priv_data priv[APM_PORT_MAX]; }; +static void q6apm_lpass_dai_disable_clocks(struct q6apm_lpass_dai_data *dai_data, int id) +{ + if (dai_data->priv[id].mclk_enabled) { + clk_disable_unprepare(dai_data->priv[id].mclk); + dai_data->priv[id].mclk_enabled = false; + } + + if (dai_data->priv[id].bclk_enabled) { + clk_disable_unprepare(dai_data->priv[id].bclk); + dai_data->priv[id].bclk_enabled = false; + } +} + +static void q6apm_lpass_dai_put_clocks(struct q6apm_lpass_dai_data *dai_data) +{ + int i; + + for (i = 0; i < APM_PORT_MAX; i++) { + q6apm_lpass_dai_disable_clocks(dai_data, i); + + if (dai_data->priv[i].mclk) { + clk_put(dai_data->priv[i].mclk); + dai_data->priv[i].mclk = NULL; + } + if (dai_data->priv[i].bclk) { + clk_put(dai_data->priv[i].bclk); + dai_data->priv[i].bclk = NULL; + } + } +} + static int q6dma_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_num, const unsigned int *tx_ch_mask, @@ -251,6 +292,62 @@ static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct s return 0; } +static int q6i2s_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + return q6apm_lpass_dai_startup(substream, dai); +} + +static void q6i2s_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); + + q6apm_lpass_dai_shutdown(substream, dai); + q6apm_lpass_dai_disable_clocks(dai_data, dai->id); +} + +static int q6i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) +{ + struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct clk *sysclk = NULL; + bool *enabled = NULL; + int ret = 0; + + switch (clk_id) { + case LPAIF_MI2S_MCLK: + sysclk = dai_data->priv[dai->id].mclk; + enabled = &dai_data->priv[dai->id].mclk_enabled; + break; + case LPAIF_MI2S_BCLK: + sysclk = dai_data->priv[dai->id].bclk; + enabled = &dai_data->priv[dai->id].bclk_enabled; + break; + default: + return -EINVAL; + } + + if (sysclk) { + ret = clk_set_rate(sysclk, freq); + if (ret) { + dev_err(dai->dev, "Error, Unable to set rate (%d) for sysclk %d\n", + freq, clk_id); + return ret; + } + + if (*enabled) + return 0; + + ret = clk_prepare_enable(sysclk); + if (ret) { + dev_err(dai->dev, "Error, Unable to prepare (%d) sysclk\n", clk_id); + return ret; + } + + *enabled = true; + } + + return ret; +} + static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); @@ -272,11 +369,12 @@ static const struct snd_soc_dai_ops q6dma_ops = { static const struct snd_soc_dai_ops q6i2s_ops = { .prepare = q6apm_lpass_dai_prepare, - .startup = q6apm_lpass_dai_startup, - .shutdown = q6apm_lpass_dai_shutdown, + .startup = q6i2s_dai_startup, + .shutdown = q6i2s_lpass_dai_shutdown, .set_channel_map = q6dma_set_channel_map, .hw_params = q6dma_hw_params, .set_fmt = q6i2s_set_fmt, + .set_sysclk = q6i2s_set_sysclk, .trigger = q6apm_lpass_dai_trigger, }; @@ -297,6 +395,64 @@ static const struct snd_soc_component_driver q6apm_lpass_dai_component = { .remove_order = SND_SOC_COMP_ORDER_FIRST, }; +static int of_q6apm_parse_dai_data(struct device *dev, + struct q6apm_lpass_dai_data *data) +{ + int ret; + + for_each_child_of_node_scoped(dev->of_node, node) { + struct q6apm_dai_priv_data *priv; + int id; + + ret = of_property_read_u32(node, "reg", &id); + if (ret || id < 0 || id >= APM_PORT_MAX) { + dev_err(dev, "valid dai id not found:%d\n", ret); + continue; + } + + switch (id) { + /* MI2S specific properties */ + case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: + case SENARY_MI2S_RX ... SENARY_MI2S_TX: + priv = &data->priv[id]; + priv->mclk = of_clk_get_by_name(node, "mclk"); + if (IS_ERR(priv->mclk)) { + int err = PTR_ERR(priv->mclk); + + priv->mclk = NULL; + if (err == -EPROBE_DEFER) { + q6apm_lpass_dai_put_clocks(data); + return dev_err_probe(dev, err, + "unable to get mi2s mclk\n"); + } + } + + priv->bclk = of_clk_get_by_name(node, "bclk"); + if (IS_ERR(priv->bclk)) { + int err = PTR_ERR(priv->bclk); + + priv->bclk = NULL; + if (err == -EPROBE_DEFER) { + q6apm_lpass_dai_put_clocks(data); + return dev_err_probe(dev, err, + "unable to get mi2s bclk\n"); + } + } + break; + default: + break; + } + } + + return 0; +} + +static void q6apm_lpass_dai_clocks_action(void *data) +{ + q6apm_lpass_dai_put_clocks(data); +} + static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev) { struct q6dsp_audio_port_dai_driver_config cfg; @@ -304,12 +460,20 @@ static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev) struct snd_soc_dai_driver *dais; struct device *dev = &pdev->dev; int num_dais; + int ret; dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL); if (!dai_data) return -ENOMEM; dev_set_drvdata(dev, dai_data); + ret = of_q6apm_parse_dai_data(dev, dai_data); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, q6apm_lpass_dai_clocks_action, dai_data); + if (ret) + return ret; memset(&cfg, 0, sizeof(cfg)); cfg.q6i2s_ops = &q6i2s_ops; diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h index a988a32086fe..bc5b9fa13283 100644 --- a/sound/soc/qcom/qdsp6/q6prm.h +++ b/sound/soc/qcom/qdsp6/q6prm.h @@ -3,6 +3,9 @@ #ifndef __Q6PRM_H__ #define __Q6PRM_H__ +#define LPAIF_MI2S_MCLK 1 +#define LPAIF_MI2S_BCLK 2 + /* Clock ID for Primary I2S IBIT */ #define Q6PRM_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100 /* Clock ID for Primary I2S EBIT */ From 766f3f79c312c9ecd3c439ef993d55c58b790c09 Mon Sep 17 00:00:00 2001 From: Mohammad Rafi Shaik Date: Fri, 24 Jul 2026 23:54:46 +0530 Subject: [PATCH 278/438] ASoC: qcom: sc8280xp: enhance machine driver for board-specific config The sc8280xp machine driver is currently written with a largely SoC-centric view and assumes a uniform audio topology across all boards. In practice, multiple products based on the same SoC use different board designs and external audio components, which require board-specific configuration to function correctly. Several Qualcomm platforms integrate third-party audio codecs or use different external audio paths. These designs often require additional configuration such as explicit MI2S MCLK/BCLK settings for audio to work. This change enhances the sc8280xp machine driver to support board-specific configuration such as allowing each board variant to provide its own DAPM widgets and routes, reflecting the actual audio components and connectors present and enabling MI2S MCLK programming for boards that use external codecs requiring a stable master clock. Tested-by: Neil Armstrong Signed-off-by: Mohammad Rafi Shaik Link: https://patch.msgid.link/20260724182446.1484894-4-mohammad.rafi.shaik@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 251 +++++++++++++++++++++++++++++++++++--- 1 file changed, 231 insertions(+), 20 deletions(-) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 98b15a527e37..2ecba74d736e 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -12,17 +12,78 @@ #include #include #include "qdsp6/q6afe.h" +#include "qdsp6/q6apm.h" +#include "qdsp6/q6prm.h" #include "common.h" #include "sdw.h" +#define I2S_MCLKFS 256 + +#define I2S_MCLK_RATE(rate) \ + ((rate) * (I2S_MCLKFS)) +#define I2S_BIT_RATE(rate, channels, format) \ + ((rate) * (channels) * (format)) + +static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("DP0 Jack", NULL), + SND_SOC_DAPM_SPK("DP1 Jack", NULL), + SND_SOC_DAPM_SPK("DP2 Jack", NULL), + SND_SOC_DAPM_SPK("DP3 Jack", NULL), + SND_SOC_DAPM_SPK("DP4 Jack", NULL), + SND_SOC_DAPM_SPK("DP5 Jack", NULL), + SND_SOC_DAPM_SPK("DP6 Jack", NULL), + SND_SOC_DAPM_SPK("DP7 Jack", NULL), +}; + +struct snd_soc_common { + const char *driver_name; + const struct snd_soc_dapm_widget *dapm_widgets; + int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + int num_dapm_routes; + const struct snd_kcontrol_new *controls; + int num_controls; + unsigned int codec_dai_fmt; + bool codec_sysclk_set; + bool mi2s_mclk_enable; + bool mi2s_bclk_enable; + bool wcd_jack; +}; + struct sc8280xp_snd_data { bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; struct snd_soc_jack jack; struct snd_soc_jack dp_jack[8]; + const struct snd_soc_common *snd_soc_common_priv; bool jack_setup; }; +static inline int sc8280xp_get_mclk_freq(struct snd_pcm_hw_params *params) +{ + int rate = params_rate(params); + + switch (rate) { + case 11025: + case 44100: + case 88200: + return I2S_MCLK_RATE(44100); + default: + break; + } + + return I2S_MCLK_RATE(rate); +} + +static inline int sc8280xp_get_bclk_freq(struct snd_pcm_hw_params *params) +{ + return I2S_BIT_RATE(params_rate(params), + params_channels(params), + snd_pcm_format_width(params_format(params))); +} + static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); @@ -32,10 +93,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) int dp_pcm_id = 0; switch (cpu_dai->id) { - case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX: - case QUINARY_MI2S_RX...QUINARY_MI2S_TX: - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); - break; case WSA_CODEC_DMA_RX_0: case WSA_CODEC_DMA_RX_1: /* @@ -64,7 +121,10 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) if (dp_jack) return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); - return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + if (data->snd_soc_common_priv->wcd_jack) + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + + return 0; } static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -96,6 +156,63 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + int mclk_freq = sc8280xp_get_mclk_freq(params); + int bclk_freq = sc8280xp_get_bclk_freq(params); + int ret; + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: + case SENARY_MI2S_RX ... SENARY_MI2S_TX: + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + if (ret && ret != -ENOTSUPP) + return ret; + + if (data->snd_soc_common_priv->codec_dai_fmt) { + ret = snd_soc_dai_set_fmt(codec_dai, + data->snd_soc_common_priv->codec_dai_fmt); + if (ret && ret != -ENOTSUPP) + return ret; + } + + if (data->snd_soc_common_priv->mi2s_mclk_enable) { + ret = snd_soc_dai_set_sysclk(cpu_dai, + LPAIF_MI2S_MCLK, mclk_freq, + SND_SOC_CLOCK_OUT); + if (ret) + return ret; + } + + if (data->snd_soc_common_priv->mi2s_bclk_enable) { + ret = snd_soc_dai_set_sysclk(cpu_dai, + LPAIF_MI2S_BCLK, bclk_freq, + SND_SOC_CLOCK_OUT); + if (ret) + return ret; + } + + if (data->snd_soc_common_priv->codec_sysclk_set) { + ret = snd_soc_dai_set_sysclk(codec_dai, + 0, mclk_freq, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + break; + default: + break; + } + + return 0; +} + static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); @@ -117,6 +234,7 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sc8280xp_be_ops = { .startup = qcom_snd_sdw_startup, .shutdown = qcom_snd_sdw_shutdown, + .hw_params = sc8280xp_snd_hw_params, .hw_free = sc8280xp_snd_hw_free, .prepare = sc8280xp_snd_prepare, }; @@ -145,38 +263,131 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; - card->owner = THIS_MODULE; + /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + data->snd_soc_common_priv = of_device_get_match_data(dev); + if (!data->snd_soc_common_priv) + return -ENODEV; + + card->owner = THIS_MODULE; card->dev = dev; dev_set_drvdata(dev, card); snd_soc_card_set_drvdata(card, data); + card->dapm_widgets = data->snd_soc_common_priv->dapm_widgets; + card->num_dapm_widgets = data->snd_soc_common_priv->num_dapm_widgets; + card->dapm_routes = data->snd_soc_common_priv->dapm_routes; + card->num_dapm_routes = data->snd_soc_common_priv->num_dapm_routes; + card->controls = data->snd_soc_common_priv->controls; + card->num_controls = data->snd_soc_common_priv->num_controls; + ret = qcom_snd_parse_of(card); if (ret) return ret; - card->driver_name = of_device_get_match_data(dev); + card->driver_name = data->snd_soc_common_priv->driver_name; sc8280xp_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } +static const struct snd_soc_common eliza_priv_data = { + .driver_name = "eliza", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common kaanapali_priv_data = { + .driver_name = "kaanapali", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common qcs9100_priv_data = { + .driver_name = "sa8775p", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), +}; + +static const struct snd_soc_common qcs615_priv_data = { + .driver_name = "qcs615", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), +}; + +static const struct snd_soc_common qcm6490_priv_data = { + .driver_name = "qcm6490", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common qcs6490_priv_data = { + .driver_name = "qcs6490", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common qcs8275_priv_data = { + .driver_name = "qcs8300", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), +}; + +static const struct snd_soc_common sc8280xp_priv_data = { + .driver_name = "sc8280xp", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8450_priv_data = { + .driver_name = "sm8450", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8550_priv_data = { + .driver_name = "sm8550", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8650_priv_data = { + .driver_name = "sm8650", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8750_priv_data = { + .driver_name = "sm8750", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + static const struct of_device_id snd_sc8280xp_dt_match[] = { - {.compatible = "qcom,eliza-sndcard", "eliza"}, - {.compatible = "qcom,kaanapali-sndcard", "kaanapali"}, - {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"}, - {.compatible = "qcom,qcs615-sndcard", "qcs615"}, - {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"}, - {.compatible = "qcom,qcs8275-sndcard", "qcs8300"}, - {.compatible = "qcom,qcs9075-sndcard", "sa8775p"}, - {.compatible = "qcom,qcs9100-sndcard", "sa8775p"}, - {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, - {.compatible = "qcom,sm8450-sndcard", "sm8450"}, - {.compatible = "qcom,sm8550-sndcard", "sm8550"}, - {.compatible = "qcom,sm8650-sndcard", "sm8650"}, - {.compatible = "qcom,sm8750-sndcard", "sm8750"}, + { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data }, + { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data }, + { .compatible = "qcom,qcm6490-idp-sndcard", .data = &qcm6490_priv_data }, + { .compatible = "qcom,qcs615-sndcard", .data = &qcs615_priv_data }, + { .compatible = "qcom,qcs6490-rb3gen2-sndcard", .data = &qcs6490_priv_data }, + { .compatible = "qcom,qcs8275-sndcard", .data = &qcs8275_priv_data }, + { .compatible = "qcom,qcs9075-sndcard", .data = &qcs9100_priv_data }, + { .compatible = "qcom,qcs9100-sndcard", .data = &qcs9100_priv_data }, + { .compatible = "qcom,sc8280xp-sndcard", .data = &sc8280xp_priv_data }, + { .compatible = "qcom,sm8450-sndcard", .data = &sm8450_priv_data }, + { .compatible = "qcom,sm8550-sndcard", .data = &sm8550_priv_data }, + { .compatible = "qcom,sm8650-sndcard", .data = &sm8650_priv_data }, + { .compatible = "qcom,sm8750-sndcard", .data = &sm8750_priv_data }, {} }; From 7859b74c0bd600cddd86afd55a3dde285a8c2937 Mon Sep 17 00:00:00 2001 From: Linmao Li Date: Thu, 23 Jul 2026 17:36:39 +0800 Subject: [PATCH 279/438] ASoC: Intel: avs: da7219: Remove redundant DAI link name allocation avs_create_dai_link() assigns dl->name twice; the first devm_kasprintf() is immediately overwritten by the TDM-aware name. Drop the redundant first assignment. Signed-off-by: Linmao Li Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260723093639.2364360-1-lilinmao@kylinos.cn Signed-off-by: Mark Brown --- sound/soc/intel/avs/boards/da7219.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 2b17abcbd2bc..6cc8a6618fa1 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -175,7 +175,6 @@ static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, if (!dl || !platform) return -ENOMEM; - dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); From 78a9d1426416248eec2afff8a86f1a8456780b4d Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 15 May 2026 10:52:03 -0400 Subject: [PATCH 280/438] ASoC: dt-bindings: Convert eukrea-tlv320.txt to yaml Convert eukrea-tlv320.txt to yaml format. Signed-off-by: Frank Li Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260515145205.1696584-1-Frank.Li@oss.nxp.com Signed-off-by: Mark Brown --- .../bindings/sound/eukrea,asoc-tlv320.yaml | 61 +++++++++++++++++++ .../bindings/sound/eukrea-tlv320.txt | 26 -------- 2 files changed, 61 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml delete mode 100644 Documentation/devicetree/bindings/sound/eukrea-tlv320.txt diff --git a/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml b/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml new file mode 100644 index 000000000000..24b793feb02d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/eukrea,asoc-tlv320.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Audio complex for Eukrea boards with tlv320aic23 codec. + +maintainers: + - Frank Li + +properties: + compatible: + const: eukrea,asoc-tlv320 + + eukrea,model: + $ref: /schemas/types.yaml#/definitions/string + description: + The user-visible name of this sound complex. + + ssi-controller: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle of the SSI controller. + + fsl,mux-int-port: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The internal port of the i.MX audio muxer (AUDMUX). + Note: The AUDMUX port numbering should start at 1, which is consistent with + hardware manual. + minimum: 1 + maximum: 8 + + fsl,mux-ext-port: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The external port of the i.MX audio muxer. + Note: The AUDMUX port numbering should start at 1, which is consistent with + hardware manual. + minimum: 1 + maximum: 8 + +required: + - compatible + - eukrea,model + - ssi-controller + - fsl,mux-int-port + - fsl,mux-ext-port + +additionalProperties: false + +examples: + - | + sound { + compatible = "eukrea,asoc-tlv320"; + eukrea,model = "imx51-eukrea-tlv320aic23"; + ssi-controller = <&ssi2>; + fsl,mux-int-port = <2>; + fsl,mux-ext-port = <3>; + }; diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt deleted file mode 100644 index 6dfa88c4dc1e..000000000000 --- a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt +++ /dev/null @@ -1,26 +0,0 @@ -Audio complex for Eukrea boards with tlv320aic23 codec. - -Required properties: - - - compatible : "eukrea,asoc-tlv320" - - - eukrea,model : The user-visible name of this sound complex. - - - ssi-controller : The phandle of the SSI controller. - - - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). - - - fsl,mux-ext-port : The external port of the i.MX audio muxer. - -Note: The AUDMUX port numbering should start at 1, which is consistent with -hardware manual. - -Example: - - sound { - compatible = "eukrea,asoc-tlv320"; - eukrea,model = "imx51-eukrea-tlv320aic23"; - ssi-controller = <&ssi2>; - fsl,mux-int-port = <2>; - fsl,mux-ext-port = <3>; - }; From ca9b51f41c9ddd9b5aab9171b78d647ab05ccb17 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Fri, 24 Jul 2026 03:45:16 +0900 Subject: [PATCH 281/438] ASoC: remove conditional return with no effect Both branches of the check return the same value, so the check has no effect. Remove it and return the value directly. This is the result of running the Coccinelle script from scripts/coccinelle/misc/cond_return_no_effect.cocci. Signed-off-by: Sang-Heon Jeon Link: https://patch.msgid.link/20260723184538.3888637-15-ekffu200098@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 11 +++-------- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 7 +------ sound/soc/samsung/smdk_spdif.c | 8 ++------ sound/soc/sof/intel/hda-dsp.c | 6 +----- 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index ef784cca13f2..01a0aaa60246 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -938,15 +938,10 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, MAX98388_CODEC_DAI); - int ret; - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF); - if (ret < 0) - return ret; - - return ret; + return snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF); } static const struct snd_soc_ops acp_max98388_ops = { diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 9ee4d9926e06..a4c8cbfba096 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -236,12 +236,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, stream->stream_info.str_id = str_params.stream_id; - ret_val = stream->ops->open(sst->dev, &str_params); - if (ret_val <= 0) - return ret_val; - - - return ret_val; + return stream->ops->open(sst->dev, &str_params); } static void sst_period_elapsed(void *arg) diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c index 2474eb619882..515e4dfc1432 100644 --- a/sound/soc/samsung/smdk_spdif.c +++ b/sound/soc/samsung/smdk_spdif.c @@ -130,12 +130,8 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, return ret; /* Set S/PDIF uses internal source clock */ - ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK, - rclk_rate, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return ret; + return snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK, + rclk_rate, SND_SOC_CLOCK_IN); } static const struct snd_soc_ops smdk_spdif_ops = { diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e9f092f082a1..b9b2bdff4ccb 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -1114,11 +1114,7 @@ static int hda_dsp_s5_quirk(struct snd_sof_dev *sdev) usleep_range(500, 1000); /* Restore state for shutdown, back to reset */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) - return ret; - - return ret; + return hda_dsp_ctrl_link_reset(sdev, true); } int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev) From 3799a56da8f3250e5765344aa5d280678dc89124 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sun, 26 Jul 2026 01:03:40 +0900 Subject: [PATCH 282/438] ASoC: amd: acp: remove conditional return with no effect Both branches of the check return the same value, so the check has no effect. Remove it and return the value directly. This is the result of running the Coccinelle script from scripts/coccinelle/misc/cond_return_no_effect.cocci. Signed-off-by: Sang-Heon Jeon Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/20260725160344.916838-2-ekffu200098@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-mach-common.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index ef784cca13f2..01a0aaa60246 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -938,15 +938,10 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, MAX98388_CODEC_DAI); - int ret; - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF); - if (ret < 0) - return ret; - - return ret; + return snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF); } static const struct snd_soc_ops acp_max98388_ops = { From 52c09577296275d96233429d6375b50fae24cd9c Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sun, 26 Jul 2026 01:03:41 +0900 Subject: [PATCH 283/438] ASoC: Intel: atom: remove conditional return with no effect Both branches of the check return the same value, so the check has no effect. Remove it and return the value directly. This is the result of running the Coccinelle script from scripts/coccinelle/misc/cond_return_no_effect.cocci. Signed-off-by: Sang-Heon Jeon Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260725160344.916838-3-ekffu200098@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 9ee4d9926e06..a4c8cbfba096 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -236,12 +236,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, stream->stream_info.str_id = str_params.stream_id; - ret_val = stream->ops->open(sst->dev, &str_params); - if (ret_val <= 0) - return ret_val; - - - return ret_val; + return stream->ops->open(sst->dev, &str_params); } static void sst_period_elapsed(void *arg) From cdb8b41357bb8319c1f57c5694b3323846d11dd5 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sun, 26 Jul 2026 01:03:42 +0900 Subject: [PATCH 284/438] ASoC: samsung: smdk_spdif: remove conditional return with no effect Both branches of the check return the same value, so the check has no effect. Remove it and return the value directly. This is the result of running the Coccinelle script from scripts/coccinelle/misc/cond_return_no_effect.cocci. Signed-off-by: Sang-Heon Jeon Link: https://patch.msgid.link/20260725160344.916838-4-ekffu200098@gmail.com Signed-off-by: Mark Brown --- sound/soc/samsung/smdk_spdif.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c index 2474eb619882..515e4dfc1432 100644 --- a/sound/soc/samsung/smdk_spdif.c +++ b/sound/soc/samsung/smdk_spdif.c @@ -130,12 +130,8 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, return ret; /* Set S/PDIF uses internal source clock */ - ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK, - rclk_rate, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return ret; + return snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK, + rclk_rate, SND_SOC_CLOCK_IN); } static const struct snd_soc_ops smdk_spdif_ops = { From 619446b87c0eb6ca896170c30c0285e6adfa1594 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sun, 26 Jul 2026 01:03:43 +0900 Subject: [PATCH 285/438] ASoC: SOF: Intel: remove conditional return with no effect Both branches of the check return the same value, so the check has no effect. Remove it and return the value directly. This is the result of running the Coccinelle script from scripts/coccinelle/misc/cond_return_no_effect.cocci. Signed-off-by: Sang-Heon Jeon Link: https://patch.msgid.link/20260725160344.916838-5-ekffu200098@gmail.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e9f092f082a1..b9b2bdff4ccb 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -1114,11 +1114,7 @@ static int hda_dsp_s5_quirk(struct snd_sof_dev *sdev) usleep_range(500, 1000); /* Restore state for shutdown, back to reset */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) - return ret; - - return ret; + return hda_dsp_ctrl_link_reset(sdev, true); } int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev) From 6b44ad3ec83b4f06bb6959f4e75998c7d7f7f070 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 10 Jul 2026 23:09:49 +0200 Subject: [PATCH 286/438] ASoC: meson: aiu-encoder-i2s: fix bs quirk incompatibility check The bs-quirk incompatibility check has two flaws: - It only rejects one direction of the mismatch. A stream that does not require the quirk is rejected while a quirked stream is active, but the opposite is not true: a stream requiring the quirk passes the check while a non-quirked stream is active, silently reprogramming the shared mclk/bclk divider with the 50% increase and corrupting the output of the running stream. - 'bs_quirk' is only cleared in hw_free() when the last substream closes, but userspace may legally stop/reconfigure/start the stream without an intervening hw_free. Reconfiguring a single stream from the quirked configuration (8ch/16-bit) to one that does not need the quirk therefore fails with -EINVAL due to the stale flag. Drop the interface-wide flag and instead compare the quirk requirement of the incoming parameters against the committed configuration of the opposite stream at hw_params() time. The committed channels/width are cleared in hw_free() so that a released stream no longer constrains the other one. Signed-off-by: Valerio Setti Link: https://patch.msgid.link/20260710-aiu-improve-quirk-check-v1-1-2fdd1b6f8896@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-encoder-i2s.c | 66 ++++++++++++++++++++----------- sound/soc/meson/gx-interface.h | 3 -- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index 83b579e98f1c..c2a280bfdfe2 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -62,13 +62,36 @@ static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component, return 0; } +/* + * Return true if the given combination of channels and sample width requires + * the bs quirk. Return false otherwise. + */ +static bool aiu_encoder_is_bs_quirk(unsigned int channels, int width) +{ + return (channels == 8) && (width == 16); +} + +static int aiu_encoder_check_bs_quirk(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream); + + /* Nothing to do if the other stream doesn't exist or it's not configured yet. */ + if (!other_stream || !other_stream->channels) + return 0; + + if (aiu_encoder_is_bs_quirk(other_stream->channels, other_stream->width) != + aiu_encoder_is_bs_quirk(params_channels(params), params_width(params))) + return -EINVAL; + + return 0; +} + static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, struct snd_pcm_hw_params *params, unsigned int bs) { - struct aiu *aiu = snd_soc_component_get_drvdata(component); - struct gx_iface *iface = &aiu->i2s.iface; - /* * NOTE: this HW is odd. * In most configuration, the i2s divider is 'mclk / blck'. @@ -76,25 +99,13 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, * increased by 50% to get the correct output rate. * No idea why ! */ - if (params_width(params) == 16 && params_channels(params) == 8) { + if (aiu_encoder_is_bs_quirk(params_channels(params), params_width(params))) { if (bs % 2) { dev_err(component->dev, "Cannot increase i2s divider by 50%%\n"); return -EINVAL; } bs += bs / 2; - iface->bs_quirk = true; - } else { - /* - * If the bs quirk is currently applied for one stream and another - * ones tries to setup a configuration for which the quirk is - * not required, then fail. - */ - if (iface->bs_quirk) { - dev_err(component->dev, - "bclk requirements are incompatible with active stream\n"); - return -EINVAL; - } } /* Use CLK_MORE for mclk to bclk divider */ @@ -110,9 +121,11 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, return 0; } -static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, - struct snd_pcm_hw_params *params) +static int aiu_encoder_i2s_set_clocks(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { + struct snd_soc_component *component = dai->component; struct aiu *aiu = snd_soc_component_get_drvdata(component); struct gx_iface *iface = &aiu->i2s.iface; unsigned int srate = params_rate(params); @@ -133,10 +146,15 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, bs = fs / 64; - if (aiu->platform->has_clk_ctrl_more_i2s_div) + if (aiu->platform->has_clk_ctrl_more_i2s_div) { + if (aiu_encoder_check_bs_quirk(substream, params, dai)) { + dev_err(dai->dev, "bclk requirements incompatible with other stream\n"); + return -EINVAL; + } ret = aiu_encoder_i2s_set_more_div(component, params, bs); - else + } else { ret = aiu_encoder_i2s_set_legacy_div(component, params, bs); + } if (ret) return ret; @@ -155,7 +173,6 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, { struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); struct gx_iface *iface = ts->iface; - struct snd_soc_component *component = dai->component; int ret; /* @@ -170,7 +187,7 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, } } - ret = aiu_encoder_i2s_set_clocks(component, params); + ret = aiu_encoder_i2s_set_clocks(substream, params, dai); if (ret) { dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); return ret; @@ -219,7 +236,6 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, if (snd_soc_dai_active(dai) <= 1) { aiu_encoder_i2s_divider_enable(component, 0); iface->rate = 0; - iface->bs_quirk = false; } if (ts->clk_enabled) { @@ -227,6 +243,10 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, ts->clk_enabled = false; } + ts->channels = 0; + ts->width = 0; + ts->physical_width = 0; + return 0; } diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h index 65c46dcce32a..d9ab894589fa 100644 --- a/sound/soc/meson/gx-interface.h +++ b/sound/soc/meson/gx-interface.h @@ -22,9 +22,6 @@ struct gx_iface { /* For component wide symmetry */ int rate; - - /* Only for GX platform */ - int bs_quirk; }; struct gx_stream { From df3c987ab3d70146e2c657bc50efe8737aa4da28 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 10 Jul 2026 23:09:50 +0200 Subject: [PATCH 287/438] ASoC: meson: aiu-encoder-i2s: reflect bs quirk in hw constraints Currently the only check for bs-quirk is implemented in hw_params(), but this is too late: nothing in the refined hw parameters hints at the restriction, so userspace has no way to know the configuration is invalid until the setup fails, as Jerome pointed out during review [1]. Add hw rules on CHANNELS and SAMPLE_BITS at startup() so that the restriction shows up during parameter refinement instead. The rules are refined against the committed configuration of the opposite stream: - if it uses the quirk, the current stream is narrowed to the same 8ch/16-bit configuration; - otherwise, selecting a 16-bit physical width limits the stream to 2 channels, and selecting 8 channels requires a physical width larger than 16 bits. The rules key on the physical width while the quirk is defined on the significant bits. This is safe because S16_LE is the only format supported by the encoder where both are 16 bits. The check in aiu_encoder_i2s_set_clocks() is kept as the last backstop: both streams may be refined concurrently before either commits its configuration. The rules are only registered on GX platforms where the bs-quirk exists and only when the DAI has a stream in the opposite direction. [1] https://lore.kernel.org/r/1jik7pebk7.fsf@starbuckisacylon.baylibre.com/ Suggested-by: Jerome Brunet Signed-off-by: Valerio Setti Link: https://lore.kernel.org/r/1jik7pebk7.fsf@starbuckisacylon.baylibre.com/ Link: https://patch.msgid.link/20260710-aiu-improve-quirk-check-v1-2-2fdd1b6f8896@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-encoder-i2s.c | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index c2a280bfdfe2..4c62ea41d7e8 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -147,6 +147,13 @@ static int aiu_encoder_i2s_set_clocks(struct snd_pcm_substream *substream, bs = fs / 64; if (aiu->platform->has_clk_ctrl_more_i2s_div) { + /* + * The hw rules added in startup() make this unreachable in the + * sequential case, but both streams may be refined concurrently + * before either commits its config, since only ops->hw_params + * runs under the card's pcm_mutex. Re-check against the committed + * state of the other stream, which is stable under that mutex. + */ if (aiu_encoder_check_bs_quirk(substream, params, dai)) { dev_err(dai->dev, "bclk requirements incompatible with other stream\n"); return -EINVAL; @@ -333,10 +340,45 @@ static const struct snd_pcm_hw_constraint_list hw_channel_constraints = { .mask = 0, }; +static int aiu_encoder_i2s_pcm_hw_rule(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct gx_stream *other = rule->private; + struct snd_interval *ch = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + /* + * The quirk is technically based on the significant bits whereas here + * we're using the physical width for simplicity. This works because + * S16_LE is the only format supported by this encoder that has: + * significant bits = physical width = 16-bits + */ + struct snd_interval *phys_width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + struct snd_interval new_i; + + if (other->channels == 0) + return 0; + + snd_interval_any(&new_i); + + if (rule->var == SNDRV_PCM_HW_PARAM_CHANNELS) { + if (aiu_encoder_is_bs_quirk(other->channels, other->width)) + new_i.min = new_i.max = 8; + else if (snd_interval_single(phys_width) && phys_width->min == 16) + new_i.max = 2; /* Force 2ch */ + } else { /* SNDRV_PCM_HW_PARAM_SAMPLE_BITS */ + if (aiu_encoder_is_bs_quirk(other->channels, other->width)) + new_i.min = new_i.max = 16; + else if (snd_interval_single(ch) && ch->min == 8) + new_i.min = 17; /* Request physical width > 16 bits */ + } + + return snd_interval_refine(hw_param_interval(params, rule->var), &new_i); +} + static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct aiu *aiu = snd_soc_component_get_drvdata(dai->component); + struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream); int ret; /* Make sure the encoder gets either 2 or 8 channels */ @@ -348,6 +390,31 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream, return ret; } + /* + * If DAI supports both playback and capture streams ensure the bs-quirk is + * handled correctly. + * This is only valid for GX platforms (has_clk_ctrl_more_i2s_div=true). + */ + if (aiu->platform->has_clk_ctrl_more_i2s_div && other_stream) { + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + aiu_encoder_i2s_pcm_hw_rule, + other_stream, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); + if (ret) + return ret; + + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + aiu_encoder_i2s_pcm_hw_rule, + other_stream, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); + if (ret) + return ret; + } + /* * Enable only clocks which are required for the interface internal * logic. MCLK is enabled/disabled from the formatter and the I2S From e82159384a5052212e7d2f2aa1de39827f1bed3c Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Fri, 10 Jul 2026 23:09:51 +0200 Subject: [PATCH 288/438] ASoC: meson: aiu-encoder-i2s: use the core symmetric_rate handling The driver manually implement the interface-wide rate symmetry enforcement in hw_params(), which suffers from the same problem addressed in the previous patch: the restriction is not visible in the hw parameter constraints, so a stream with a mismatching rate only finds out via -EINVAL late in the stream setup. The ASoC core already provides this feature through the DAI's 'symmetric_rate' flag: when another stream of the DAI is active, soc_pcm_apply_symmetry() constrains the rate at open time so the restriction shows up during parameter refinement, and soc_pcm_params_symmetry() still rejects a mismatch at hw_params() time as a backstop. Set 'symmetric_rate' on the I2S encoder DAI and drop the open-coded check along with the now unused 'rate' member of struct gx_iface. Signed-off-by: Valerio Setti Link: https://patch.msgid.link/20260710-aiu-improve-quirk-check-v1-3-2fdd1b6f8896@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/aiu-encoder-i2s.c | 21 ++------------------- sound/soc/meson/aiu.c | 1 + sound/soc/meson/gx-interface.h | 3 --- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c index 4c62ea41d7e8..58dce9f08c9d 100644 --- a/sound/soc/meson/aiu-encoder-i2s.c +++ b/sound/soc/meson/aiu-encoder-i2s.c @@ -179,28 +179,14 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); - struct gx_iface *iface = ts->iface; int ret; - /* - * Enforce interface wide rate symmetry only if there is more than - * 1 stream active. - */ - if (snd_soc_dai_active(dai) > 1) { - if (iface->rate && iface->rate != params_rate(params)) { - dev_err(dai->dev, "can't set iface rate (%d != %d)\n", - iface->rate, params_rate(params)); - return -EINVAL; - } - } - ret = aiu_encoder_i2s_set_clocks(substream, params, dai); if (ret) { dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); return ret; } - iface->rate = params_rate(params); ts->physical_width = params_physical_width(params); ts->width = params_width(params); ts->channels = params_channels(params); @@ -233,17 +219,14 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); - struct gx_iface *iface = ts->iface; struct snd_soc_component *component = dai->component; /* * If this is the last substream being closed then disable the i2s - * clock divider and clear 'iface->rate'. + * clock divider. */ - if (snd_soc_dai_active(dai) <= 1) { + if (snd_soc_dai_active(dai) <= 1) aiu_encoder_i2s_divider_enable(component, 0); - iface->rate = 0; - } if (ts->clk_enabled) { clk_disable_unprepare(ts->iface->mclk); diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index 64ace4d25d92..2668646e3597 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -154,6 +154,7 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { .formats = AIU_FORMATS, }, .ops = &aiu_encoder_i2s_dai_ops, + .symmetric_rate = 1, }, [CPU_SPDIF_ENCODER] = { .name = "SPDIF Encoder", diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h index d9ab894589fa..2a6207e393e8 100644 --- a/sound/soc/meson/gx-interface.h +++ b/sound/soc/meson/gx-interface.h @@ -19,9 +19,6 @@ struct gx_iface { /* format is common to all the DAIs of the iface */ unsigned int fmt; - - /* For component wide symmetry */ - int rate; }; struct gx_stream { From c7a6909de856f89c9d913550d9d70e4b3ebec4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 20 Jul 2026 08:23:45 +0200 Subject: [PATCH 289/438] ASoC: codecs: mt6357: Drop unused assignment of platform_device_id driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver explicitly sets the .driver_data member of struct platform_device_id to zero without relying on that value. Drop this unused assignment. While touching this array unify spacing, use a named initializer for .name and drop a trailing comma after the list terminator. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/724af6f60ed9420d5513724d126d70f22e319c91.1784528081.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6357.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c index 674cf7df9df4..3b07087e1cab 100644 --- a/sound/soc/codecs/mt6357.c +++ b/sound/soc/codecs/mt6357.c @@ -1834,8 +1834,8 @@ static int mt6357_platform_driver_probe(struct platform_device *pdev) } static const struct platform_device_id mt6357_platform_ids[] = { - {"mt6357-sound", 0}, - { /* sentinel */ }, + { .name = "mt6357-sound" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); From 0ca8f65516a9ebc155ecca98e386ec592ed71eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 20 Jul 2026 08:23:46 +0200 Subject: [PATCH 290/438] ASoC: renesas: fsi: Drop platform probing metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 38d3273075d6 ("ASoC: renesas: fsi: remove platform data style support") probing using the traditional platform bus matching isn't supported any more. Drop the platform_device_id entries that should have been removed in the above commit. Note that keeping the empty array results in the driver not matching on "fsi-pcm-audio" (i.e. the driver name). While touching that array, use a single space and no trailing comma for the list terminator, which is the most used style for this. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/c79fa0d31abc0c80fbd7b4ec94d95b197ddb9f94.1784528081.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/renesas/fsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c index ae86014c3819..1e1a04cc7929 100644 --- a/sound/soc/renesas/fsi.c +++ b/sound/soc/renesas/fsi.c @@ -1979,8 +1979,8 @@ static const struct of_device_id fsi_of_match[] = { MODULE_DEVICE_TABLE(of, fsi_of_match); static const struct platform_device_id fsi_id_table[] = { - { "sh_fsi", (kernel_ulong_t)&fsi1_core }, - {}, + /* an array with no valid entry prevents matching on driver name */ + { } }; MODULE_DEVICE_TABLE(platform, fsi_id_table); From 2b26d06fd3d81659b482b9de17e135edba1fb27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 20 Jul 2026 08:23:47 +0200 Subject: [PATCH 291/438] ASoC: amd: acp: Use named initializers for platform_device_id arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Named initializers are better readable and more robust to changes of the struct definition. This robustness is relevant for a planned change to struct platform_device_id replacing .driver_data by an anonymous union. While touching these arrays unify spacing and usage of commas. Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/a23fa9f649eaab706c704b671527c238f211ee26.1784528081.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-sdw-legacy-mach.c | 4 ++-- sound/soc/amd/acp/acp-sdw-sof-mach.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index e8b6819cc4b4..8947d3ad8cdc 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -580,8 +580,8 @@ static void mc_remove(struct platform_device *pdev) } static const struct platform_device_id mc_id_table[] = { - { "amd_sdw", }, - {} + { .name = "amd_sdw" }, + { } }; MODULE_DEVICE_TABLE(platform, mc_id_table); diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index a423853f3a97..d200388f1393 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -438,8 +438,8 @@ static void mc_remove(struct platform_device *pdev) } static const struct platform_device_id mc_id_table[] = { - { "amd_sof_sdw", }, - {} + { .name = "amd_sof_sdw" }, + { } }; MODULE_DEVICE_TABLE(platform, mc_id_table); From 4bed1074db1e65d5250ecbb528c05f16f137ad8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 20 Jul 2026 08:23:48 +0200 Subject: [PATCH 292/438] ASoC: amd: acp: Unify code style for platform_device_id array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a trailing comma for initializers unless the closing brace is on the same line and for the list terminator; - Use a single space in the list terminator; Acked-by: Cezary Rojewski Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Vijendar Mukunda Link: https://patch.msgid.link/08137cf5b3cdd0cc2e00da32256664f3cb9b1e4e.1784528081.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-sof-mach.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index 36ecef7013b9..8874151e159a 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -128,31 +128,31 @@ static int acp_sof_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { .name = "rt5682-rt1019", - .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data + .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data, }, { .name = "rt5682-max", - .driver_data = (kernel_ulong_t)&sof_rt5682_max_data + .driver_data = (kernel_ulong_t)&sof_rt5682_max_data, }, { .name = "rt5682s-max", - .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data + .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data, }, { .name = "rt5682s-rt1019", - .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data + .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data, }, { .name = "nau8825-max", - .driver_data = (kernel_ulong_t)&sof_nau8825_data + .driver_data = (kernel_ulong_t)&sof_nau8825_data, }, { .name = "rt5682s-hs-rt1019", - .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data + .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data, }, { .name = "nau8821-max", - .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data + .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data, }, { } }; From 232725a0e3867fc9845e2bccfa94e01840db30be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 20 Jul 2026 08:23:49 +0200 Subject: [PATCH 293/438] ASoC: Use named initializers for platform_device_id arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Named initializers are better readable and more robust to changes of the struct definition. This robustness is relevant for a planned change to struct platform_device_id replacing .driver_data by an anonymous union. While touching these arrays unify spacing and usage of commas. Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Charles Keepax Link: https://patch.msgid.link/a76e26aa4edb901b4bea684919463b2243dd8d9d.1784528081.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs40l50-codec.c | 4 ++-- sound/soc/codecs/cs42l43.c | 4 ++-- sound/soc/intel/boards/sof_sdw.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c index aa629ef53db4..676367163067 100644 --- a/sound/soc/codecs/cs40l50-codec.c +++ b/sound/soc/codecs/cs40l50-codec.c @@ -288,8 +288,8 @@ static int cs40l50_codec_driver_probe(struct platform_device *pdev) } static const struct platform_device_id cs40l50_id[] = { - { "cs40l50-codec", }, - {} + { .name = "cs40l50-codec" }, + { } }; MODULE_DEVICE_TABLE(platform, cs40l50_id); diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index 1d133577702e..67283efdd268 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2941,8 +2941,8 @@ static const struct dev_pm_ops cs42l43_codec_pm_ops = { }; static const struct platform_device_id cs42l43_codec_id_table[] = { - { "cs42l43-codec", }, - {} + { .name = "cs42l43-codec" }, + { } }; MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index c527d575d1ed..b306cc19fcc7 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1542,8 +1542,8 @@ static void mc_remove(struct platform_device *pdev) } static const struct platform_device_id mc_id_table[] = { - { "sof_sdw", }, - {} + { .name = "sof_sdw" }, + { } }; MODULE_DEVICE_TABLE(platform, mc_id_table); From e4dc03df1f716981712f41a5dabe88acdb843aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 20 Jul 2026 08:23:50 +0200 Subject: [PATCH 294/438] ASOC: Unify code style for platform_device_id arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add a trailing comma for initializers unless the closing brace is on the same line and for the list terminator; - Use a single space in the list terminator; - Use compact one-line style for small entries; - s/\t=/ =/ were the tab is only one char wide anyhow; Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/093867d47c079d2aaab06bccaae734c54c342a7d.1784528081.git.u.kleine-koenig@baylibre.com Signed-off-by: Mark Brown --- sound/soc/au1x/db1200.c | 2 +- sound/soc/codecs/adau7118-hw.c | 2 +- sound/soc/codecs/bt-sco.c | 10 +++------- sound/soc/codecs/wcd934x.c | 6 ++---- sound/soc/fsl/imx-pcm-rpmsg.c | 6 +++--- sound/soc/intel/avs/boards/da7219.c | 6 ++---- sound/soc/intel/avs/boards/dmic.c | 6 ++---- sound/soc/intel/avs/boards/es8336.c | 6 ++---- sound/soc/intel/avs/boards/hdaudio.c | 6 ++---- sound/soc/intel/avs/boards/i2s_test.c | 6 ++---- sound/soc/intel/avs/boards/max98357a.c | 6 ++---- sound/soc/intel/avs/boards/max98373.c | 6 ++---- sound/soc/intel/avs/boards/max98927.c | 6 ++---- sound/soc/intel/avs/boards/nau8825.c | 6 ++---- sound/soc/intel/avs/boards/pcm3168a.c | 6 ++---- sound/soc/intel/avs/boards/probe.c | 2 +- sound/soc/intel/avs/boards/rt274.c | 2 +- sound/soc/intel/avs/boards/rt286.c | 2 +- sound/soc/intel/avs/boards/rt298.c | 2 +- sound/soc/intel/avs/boards/rt5514.c | 2 +- sound/soc/intel/avs/boards/rt5640.c | 2 +- sound/soc/intel/avs/boards/rt5663.c | 2 +- sound/soc/intel/avs/boards/rt5682.c | 2 +- sound/soc/intel/avs/boards/ssm4567.c | 2 +- sound/soc/samsung/i2s.c | 2 +- 25 files changed, 40 insertions(+), 66 deletions(-) diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index 81abe2e18402..78346cd7959c 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -42,7 +42,7 @@ static const struct platform_device_id db1200_pids[] = { .name = "db1550-i2s", .driver_data = 5, }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, db1200_pids); diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c index 92b226b8b4bb..4342eb7dd9e5 100644 --- a/sound/soc/codecs/adau7118-hw.c +++ b/sound/soc/codecs/adau7118-hw.c @@ -22,7 +22,7 @@ static const struct of_device_id adau7118_of_match[] = { MODULE_DEVICE_TABLE(of, adau7118_of_match); static const struct platform_device_id adau7118_id[] = { - { .name = "adau7118" }, + { .name = "adau7118" }, { } }; MODULE_DEVICE_TABLE(platform, adau7118_id); diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index c0bf45b76cb8..b085885e3f18 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -85,13 +85,9 @@ static int bt_sco_probe(struct platform_device *pdev) } static const struct platform_device_id bt_sco_driver_ids[] = { - { - .name = "dfbmcs320", - }, - { - .name = "bt-sco", - }, - {}, + { .name = "dfbmcs320" }, + { .name = "bt-sco" }, + { } }; MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index bc41a1466c70..a9e6f2923099 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -5899,10 +5899,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev) } static const struct platform_device_id wcd934x_driver_id[] = { - { - .name = "wcd934x-codec", - }, - {}, + { .name = "wcd934x-codec" }, + { } }; MODULE_DEVICE_TABLE(platform, wcd934x_driver_id); diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 2a4813c6cda9..792a416d552f 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -819,9 +819,9 @@ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = { }; static const struct platform_device_id imx_rpmsg_pcm_id_table[] = { - { .name = "rpmsg-audio-channel" }, - { .name = "rpmsg-micfil-channel" }, - { }, + { .name = "rpmsg-audio-channel" }, + { .name = "rpmsg-micfil-channel" }, + { } }; MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table); diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 2b17abcbd2bc..163d9982d797 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -259,10 +259,8 @@ static int avs_da7219_probe(struct platform_device *pdev) } static const struct platform_device_id avs_da7219_driver_ids[] = { - { - .name = "avs_da7219", - }, - {}, + { .name = "avs_da7219" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids); diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index bf6f580a5164..8d36bc7ddf16 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -104,10 +104,8 @@ static int avs_dmic_probe(struct platform_device *pdev) } static const struct platform_device_id avs_dmic_driver_ids[] = { - { - .name = "avs_dmic", - }, - {}, + { .name = "avs_dmic" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids); diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 301cfb3cf15b..36c13db3a272 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -309,10 +309,8 @@ static int avs_es8336_probe(struct platform_device *pdev) } static const struct platform_device_id avs_es8336_driver_ids[] = { - { - .name = "avs_es8336", - }, - {}, + { .name = "avs_es8336" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids); diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index aec769e2396c..03cfd91202d3 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -231,10 +231,8 @@ static int avs_hdaudio_probe(struct platform_device *pdev) } static const struct platform_device_id avs_hdaudio_driver_ids[] = { - { - .name = "avs_hdaudio", - }, - {}, + { .name = "avs_hdaudio" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids); diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 9a6b89ffdf14..787d781ba1d9 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -107,10 +107,8 @@ static int avs_i2s_test_probe(struct platform_device *pdev) } static const struct platform_device_id avs_i2s_test_driver_ids[] = { - { - .name = "avs_i2s_test", - }, - {}, + { .name = "avs_i2s_test" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids); diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index e9a87804f918..389a50923d3b 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -136,10 +136,8 @@ static int avs_max98357a_probe(struct platform_device *pdev) } static const struct platform_device_id avs_max98357a_driver_ids[] = { - { - .name = "avs_max98357a", - }, - {}, + { .name = "avs_max98357a" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids); diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index 8b45b643ca29..b8231f71d3d6 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -191,10 +191,8 @@ static int avs_max98373_probe(struct platform_device *pdev) } static const struct platform_device_id avs_max98373_driver_ids[] = { - { - .name = "avs_max98373", - }, - {}, + { .name = "avs_max98373" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids); diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index db073125fa4d..d657e7da1cc0 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -188,10 +188,8 @@ static int avs_max98927_probe(struct platform_device *pdev) } static const struct platform_device_id avs_max98927_driver_ids[] = { - { - .name = "avs_max98927", - }, - {}, + { .name = "avs_max98927" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids); diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index d44edacbfc9a..d7ea08bb27cd 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -293,10 +293,8 @@ static int avs_nau8825_probe(struct platform_device *pdev) } static const struct platform_device_id avs_nau8825_driver_ids[] = { - { - .name = "avs_nau8825", - }, - {}, + { .name = "avs_nau8825" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids); diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c index b5bebadbbcb2..9d415fd0499a 100644 --- a/sound/soc/intel/avs/boards/pcm3168a.c +++ b/sound/soc/intel/avs/boards/pcm3168a.c @@ -132,10 +132,8 @@ static int avs_pcm3168a_probe(struct platform_device *pdev) } static const struct platform_device_id avs_pcm3168a_driver_ids[] = { - { - .name = "avs_pcm3168a", - }, - {}, + { .name = "avs_pcm3168a" }, + { } }; MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids); diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index 73884f8a535c..4053d14289b9 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -64,7 +64,7 @@ static const struct platform_device_id avs_probe_mb_driver_ids[] = { { .name = "avs_probe_mb", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index a689f4c80867..289f1230851f 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -261,7 +261,7 @@ static const struct platform_device_id avs_rt274_driver_ids[] = { { .name = "avs_rt274", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 4c9ac545555a..9364d60cfcc7 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -231,7 +231,7 @@ static const struct platform_device_id avs_rt286_driver_ids[] = { { .name = "avs_rt286", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 2d7a7748d577..5d3b3cdc9564 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -250,7 +250,7 @@ static const struct platform_device_id avs_rt298_driver_ids[] = { { .name = "avs_rt298", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index 22139eaad83a..e448bc9fa5ad 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -178,7 +178,7 @@ static const struct platform_device_id avs_rt5514_driver_ids[] = { { .name = "avs_rt5514", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c index 2990d32f2301..c4e33d71e82f 100644 --- a/sound/soc/intel/avs/boards/rt5640.c +++ b/sound/soc/intel/avs/boards/rt5640.c @@ -252,7 +252,7 @@ static const struct platform_device_id avs_rt5640_driver_ids[] = { { .name = "avs_rt5640", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 68fea325376a..aadbd3f2a1b2 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -249,7 +249,7 @@ static const struct platform_device_id avs_rt5663_driver_ids[] = { { .name = "avs_rt5663", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids); diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 81863728da1d..d33699cca595 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -325,7 +325,7 @@ static const struct platform_device_id avs_rt5682_driver_ids[] = { { .name = "avs_rt5682", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids); diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index ae0e6e27a8b8..d7c9bff37556 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -180,7 +180,7 @@ static const struct platform_device_id avs_ssm4567_driver_ids[] = { { .name = "avs_ssm4567", }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids); diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index f80f697a5d55..1aa51062ed7f 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1682,7 +1682,7 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { .name = "samsung-i2s", .driver_data = (kernel_ulong_t)&i2sv3_dai_type, }, - {}, + { } }; MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); From 52ead5e1f1110e570a4b2dd03ec78188b8c831cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:27:14 +0000 Subject: [PATCH 295/438] ASoC: atmel: atmel_wm8904: use dev in atmel_asoc_wm8904_dt_init() atmel_asoc_wm8904_dt_init() will be updated when Card capsuling. To makes its review easy, use dev in this function and reduce un-related diff. No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/878q75jfny.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_wm8904.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index 0f4021c6c588..df3e5ef8fa61 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -82,32 +82,33 @@ static struct snd_soc_card atmel_asoc_wm8904_card = { static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct device_node *codec_np, *cpu_np; struct snd_soc_card *card = &atmel_asoc_wm8904_card; struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; int ret; if (!np) { - dev_err(&pdev->dev, "only device tree supported\n"); + dev_err(dev, "only device tree supported\n"); return -EINVAL; } ret = snd_soc_of_parse_card_name(card, "atmel,model"); if (ret) { - dev_err(&pdev->dev, "failed to parse card name\n"); + dev_err(dev, "failed to parse card name\n"); return ret; } ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing"); if (ret) { - dev_err(&pdev->dev, "failed to parse audio routing\n"); + dev_err(dev, "failed to parse audio routing\n"); return ret; } cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); if (!cpu_np) { - dev_err(&pdev->dev, "failed to get dai and pcm info\n"); + dev_err(dev, "failed to get dai and pcm info\n"); ret = -EINVAL; return ret; } @@ -117,7 +118,7 @@ static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev) codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); if (!codec_np) { - dev_err(&pdev->dev, "failed to get codec info\n"); + dev_err(dev, "failed to get codec info\n"); ret = -EINVAL; return ret; } From 327679a605129bda12df53345881a331c4449d46 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Mon, 13 Jul 2026 23:39:06 +0530 Subject: [PATCH 296/438] ASoC: dt-bindings: qcom,sm8250: Add Hawi sound card Add bindings for Hawi sound card, which is compatible with the existing SM8450. Signed-off-by: Prasad Kumpatla Link: https://patch.msgid.link/20260713180907.874954-2-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index dae440ecab59..bd5f5a6268a3 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -24,6 +24,7 @@ properties: - items: - enum: - qcom,eliza-sndcard + - qcom,hawi-sndcard - qcom,kaanapali-sndcard - qcom,sm8550-sndcard - qcom,sm8650-sndcard From 358782121d824e0650a72be664d94c207f677f79 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Mon, 13 Jul 2026 23:39:07 +0530 Subject: [PATCH 297/438] ASoC: qcom: sc8280xp: Add support for Hawi Add compatible for sound card on Qualcomm Hawi platform. Signed-off-by: Prasad Kumpatla Link: https://patch.msgid.link/20260713180907.874954-3-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 2ecba74d736e..a9304784d41e 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -300,6 +300,15 @@ static const struct snd_soc_common eliza_priv_data = { .wcd_jack = true, }; +static const struct snd_soc_common hawi_priv_data = { + .driver_name = "hawi", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .codec_sysclk_set = true, + .mi2s_bclk_enable = true, + .wcd_jack = true, +}; + static const struct snd_soc_common kaanapali_priv_data = { .driver_name = "kaanapali", .dapm_widgets = sc8280xp_dapm_widgets, @@ -376,6 +385,7 @@ static const struct snd_soc_common sm8750_priv_data = { static const struct of_device_id snd_sc8280xp_dt_match[] = { { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data }, + { .compatible = "qcom,hawi-sndcard", .data = &hawi_priv_data }, { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data }, { .compatible = "qcom,qcm6490-idp-sndcard", .data = &qcm6490_priv_data }, { .compatible = "qcom,qcs615-sndcard", .data = &qcs615_priv_data }, From 0f97c75d15c3869836cd58d8c3b89add2d9b68f5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Jul 2026 16:34:29 -0700 Subject: [PATCH 298/438] ASoC: ti: omap-twl4030: drop support for platform data There are no users of omap_tw4030_pdata in the mainline kernel so remove support for it from the driver. Signed-off-by: Dmitry Torokhov Reviewed-by: Sebastian Reichel Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260724233432.31325-1-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- include/linux/platform_data/omap-twl4030.h | 42 ------- sound/soc/ti/omap-twl4030.c | 134 +++++++-------------- 2 files changed, 44 insertions(+), 132 deletions(-) delete mode 100644 include/linux/platform_data/omap-twl4030.h diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h deleted file mode 100644 index 7fcb55fe21c9..000000000000 --- a/include/linux/platform_data/omap-twl4030.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/** - * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030 - * codec, header. - * - * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com - * All rights reserved. - * - * Author: Peter Ujfalusi - */ - -#ifndef _OMAP_TWL4030_H_ -#define _OMAP_TWL4030_H_ - -/* To select if only one channel is connected in a stereo port */ -#define OMAP_TWL4030_LEFT (1 << 0) -#define OMAP_TWL4030_RIGHT (1 << 1) - -struct omap_tw4030_pdata { - const char *card_name; - /* Voice port is connected to McBSP3 */ - bool voice_connected; - - /* The driver will parse the connection flags if this flag is set */ - bool custom_routing; - /* Flags to indicate connected audio ports. */ - u8 has_hs; - u8 has_hf; - u8 has_predriv; - u8 has_carkit; - bool has_ear; - - bool has_mainmic; - bool has_submic; - bool has_hsmic; - bool has_carkitmic; - bool has_digimic0; - bool has_digimic1; - u8 has_linein; -}; - -#endif /* _OMAP_TWL4030_H_ */ diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c index 4d80f8a7a947..950879fc7275 100644 --- a/sound/soc/ti/omap-twl4030.c +++ b/sound/soc/ti/omap-twl4030.c @@ -17,7 +17,6 @@ */ #include -#include #include #include @@ -133,20 +132,12 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = { }, }; -static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm, - int connected, char *pin) -{ - if (!connected) - snd_soc_dapm_disable_pin(dapm, pin); -} - static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; - struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); - struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); + struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); - int ret = 0; + int ret; /* * This is a bit of a hack, but the GPIO is optional so we @@ -170,29 +161,7 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) return ret; } - /* - * NULL pdata means we booted with DT. In this case the routing is - * provided and the card is fully routed, no need to mark pins. - */ - if (!pdata || !pdata->custom_routing) - return ret; - - /* Disable not connected paths if not used */ - twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk"); - twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk"); - twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); - twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk"); - twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk"); - - twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic"); - twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic"); - twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); - twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic"); - twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic"); - twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic"); - twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In"); - - return ret; + return 0; } /* Digital audio interface glue - connects codec <--> CPU */ @@ -237,11 +206,15 @@ static struct snd_soc_card omap_twl4030_card = { static int omap_twl4030_probe(struct platform_device *pdev) { - struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); - struct device_node *node = pdev->dev.of_node; struct snd_soc_card *card = &omap_twl4030_card; + struct device_node *node, *dai_node; struct omap_twl4030 *priv; - int ret = 0; + struct property *prop; + int ret; + + node = pdev->dev.of_node; + if (!node) + return -ENODEV; card->dev = &pdev->dev; @@ -249,62 +222,43 @@ static int omap_twl4030_probe(struct platform_device *pdev) if (priv == NULL) return -ENOMEM; - if (node) { - struct device_node *dai_node; - struct property *prop; - - if (snd_soc_of_parse_card_name(card, "ti,model")) { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } - - dai_node = of_parse_phandle(node, "ti,mcbsp", 0); - if (!dai_node) { - dev_err(&pdev->dev, "McBSP node is not provided\n"); - return -EINVAL; - } - omap_twl4030_dai_links[0].cpus->dai_name = NULL; - omap_twl4030_dai_links[0].cpus->of_node = dai_node; - - omap_twl4030_dai_links[0].platforms->name = NULL; - omap_twl4030_dai_links[0].platforms->of_node = dai_node; - - dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0); - if (!dai_node) { - card->num_links = 1; - } else { - omap_twl4030_dai_links[1].cpus->dai_name = NULL; - omap_twl4030_dai_links[1].cpus->of_node = dai_node; - - omap_twl4030_dai_links[1].platforms->name = NULL; - omap_twl4030_dai_links[1].platforms->of_node = dai_node; - } - - /* Optional: audio routing can be provided */ - prop = of_find_property(node, "ti,audio-routing", NULL); - if (prop) { - ret = snd_soc_of_parse_audio_routing(card, - "ti,audio-routing"); - if (ret) - return ret; - - card->fully_routed = 1; - } - } else if (pdata) { - if (pdata->card_name) { - card->name = pdata->card_name; - } else { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } - - if (!pdata->voice_connected) - card->num_links = 1; - } else { - dev_err(&pdev->dev, "Missing pdata\n"); + if (snd_soc_of_parse_card_name(card, "ti,model")) { + dev_err(&pdev->dev, "Card name is not provided\n"); return -ENODEV; } + dai_node = of_parse_phandle(node, "ti,mcbsp", 0); + if (!dai_node) { + dev_err(&pdev->dev, "McBSP node is not provided\n"); + return -EINVAL; + } + omap_twl4030_dai_links[0].cpus->dai_name = NULL; + omap_twl4030_dai_links[0].cpus->of_node = dai_node; + + omap_twl4030_dai_links[0].platforms->name = NULL; + omap_twl4030_dai_links[0].platforms->of_node = dai_node; + + dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0); + if (!dai_node) { + card->num_links = 1; + } else { + omap_twl4030_dai_links[1].cpus->dai_name = NULL; + omap_twl4030_dai_links[1].cpus->of_node = dai_node; + + omap_twl4030_dai_links[1].platforms->name = NULL; + omap_twl4030_dai_links[1].platforms->of_node = dai_node; + } + + /* Optional: audio routing can be provided */ + prop = of_find_property(node, "ti,audio-routing", NULL); + if (prop) { + ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); + if (ret) + return ret; + + card->fully_routed = 1; + } + snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { From a9b7250a2f8b84372b1d2fc039fefe2a9f7459b5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Jul 2026 16:34:30 -0700 Subject: [PATCH 299/438] ASoC: ti: omap-twl4030: use per-device instance of headset jack gpio hs_jack_gpios is being potentially shared among several instances of the same device, and is being modified. This is not the best approach to structuring the code (even if the device is in fact a singleton). Change it to allocate a per-device instance. Signed-off-by: Dmitry Torokhov Reviewed-by: Sebastian Reichel Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260724233432.31325-2-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-twl4030.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c index 950879fc7275..4abcfff04bc7 100644 --- a/sound/soc/ti/omap-twl4030.c +++ b/sound/soc/ti/omap-twl4030.c @@ -28,6 +28,7 @@ #include "omap-mcbsp.h" struct omap_twl4030 { + struct snd_soc_jack_gpio hs_jack_gpio; struct snd_soc_jack hs_jack; }; @@ -123,15 +124,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { }, }; -/* Headset jack detection gpios */ -static struct snd_soc_jack_gpio hs_jack_gpios[] = { - { - .name = "ti,jack-det", - .report = SND_JACK_HEADSET, - .debounce_time = 200, - }, -}; - static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -144,9 +136,6 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) * only want to add the jack detection if the GPIO is there. */ if (of_property_present(card->dev->of_node, "ti,jack-det-gpio")) { - hs_jack_gpios[0].gpiod_dev = card->dev; - hs_jack_gpios[0].idx = 0; - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", SND_JACK_HEADSET, &priv->hs_jack, hs_jack_pins, @@ -154,9 +143,14 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - ret = snd_soc_jack_add_gpios(&priv->hs_jack, - ARRAY_SIZE(hs_jack_gpios), - hs_jack_gpios); + priv->hs_jack_gpio.name = "ti,jack-det"; + priv->hs_jack_gpio.report = SND_JACK_HEADSET; + priv->hs_jack_gpio.debounce_time = 200; + priv->hs_jack_gpio.gpiod_dev = card->dev; + priv->hs_jack_gpio.idx = 0; + + ret = snd_soc_jack_add_gpios(&priv->hs_jack, 1, + &priv->hs_jack_gpio); if (ret) return ret; } From 34dfc478c963e035d0c2ce61bbe610c9c745b634 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 13 Jul 2026 10:55:09 -0700 Subject: [PATCH 300/438] ASoC: SOF: don't use "/**" for non-kernel-doc comments Modify these errant comments to use "/*" since they are not kernel-doc comments. Warning: ../include/sound/sof/header.h:182 This comment starts with '/**', but isn't a kernel-doc comment. * OOPS header architecture specific data. Warning: ../include/sound/sof/header.h:190 This comment starts with '/**', but isn't a kernel-doc comment. * OOPS header platform specific data. Signed-off-by: Randy Dunlap Link: https://patch.msgid.link/20260713175510.524728-1-rdunlap@infradead.org Signed-off-by: Mark Brown --- include/sound/sof/header.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 4e406dc22f31..6c2c3a5fc90d 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -179,7 +179,7 @@ struct sof_ipc_compound_hdr { uint32_t count; /**< count of 0 means end of compound sequence */ } __packed; -/** +/* * OOPS header architecture specific data. */ struct sof_ipc_dsp_oops_arch_hdr { @@ -187,7 +187,7 @@ struct sof_ipc_dsp_oops_arch_hdr { uint32_t totalsize; /* Total size of oops message */ } __packed; -/** +/* * OOPS header platform specific data. */ struct sof_ipc_dsp_oops_plat_hdr { From 14cdac7638c3367c39af206456ed2f2d37e59401 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 13 Jul 2026 10:55:10 -0700 Subject: [PATCH 301/438] ASoC: SOF: ipc4-topology: repair struct kernel-doc comments Use the correct struct names in the kernel-doc comments. Add missing struct member descriptions. This prevents all kernel-doc warnings: Warning: ../sound/soc/sof/ipc4-topology.h:176 expecting prototype for struct sof_ipc4_multi_pipeline_data. Prototype was for struct ipc4_pipeline_set_state_data instead Warning: ../sound/soc/sof/ipc4-topology.h:307 expecting prototype for struct sof_ipc4_dma_config. Prototype was for struct sof_ipc4_dma_config_tlv instead Signed-off-by: Randy Dunlap Link: https://patch.msgid.link/20260713175510.524728-2-rdunlap@infradead.org Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index a289c1d8f3ff..54bf0236a127 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -167,7 +167,7 @@ struct sof_ipc4_pipeline { }; /** - * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data + * struct ipc4_pipeline_set_state_data - multi pipeline trigger IPC data * @count: Number of pipelines to be triggered * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered */ @@ -210,7 +210,7 @@ struct sof_ipc4_available_audio_format { * @node_id: ID of Gateway Node * @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes) * @config_length: Length of gateway node configuration blob specified in #config_data - * config_data: Gateway node configuration blob + * @config_data: Gateway node configuration blob */ struct sof_copier_gateway_cfg { uint32_t node_id; @@ -285,7 +285,9 @@ struct sof_ipc4_dma_stream_ch_map { struct sof_ipc4_dma_config { uint8_t dma_method; uint8_t pre_allocated_by_host; + /* private: */ uint16_t rsvd; + /* public: */ uint32_t dma_channel_id; uint32_t stream_id; struct sof_ipc4_dma_stream_ch_map dma_stream_channel_map; @@ -296,7 +298,7 @@ struct sof_ipc4_dma_config { #define SOF_IPC4_GTW_DMA_CONFIG_ID 0x1000 /** - * struct sof_ipc4_dma_config: DMA configuration + * struct sof_ipc4_dma_config_tlv - DMA configuration * @type: set to SOF_IPC4_GTW_DMA_CONFIG_ID * @length: sizeof(struct sof_ipc4_dma_config) + dma_config.dma_priv_config_size * @dma_config: actual DMA configuration @@ -321,6 +323,7 @@ struct sof_ipc4_alh_configuration_blob { * @data: IPC copier data * @copier_config: Copier + blob * @ipc_config_size: Size of copier_config + * @ipc_config_data: Copier module config data * @available_fmt: Available audio format * @frame_fmt: frame format * @msg: message structure for copier From 9167f260477b18ee9ffffc35fcf721f7255c444f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 20 Jul 2026 13:41:31 +0700 Subject: [PATCH 302/438] ASoC: soc-generic-dmaengine: Handle DMA channel request failures correctly Currently any dma_request_chan() failure other than -EPROBE_DEFER is silently ignored, since a missing channel is expected for devices that only support one DMA direction. Improve the handling of these failures by: - reporting failures when a configured DMA channel cannot be requested; - failing probe if neither playback nor capture obtains a DMA channel, since the PCM device would be unusable. Devices that legitimately support only one DMA direction continue to work as before. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260720064131.75156-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 467426d2b5e4..98ba9a836936 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -3,6 +3,7 @@ // Copyright (C) 2013, Analog Devices Inc. // Author: Lars-Peter Clausen +#include #include #include #include @@ -395,6 +396,27 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, */ if (PTR_ERR(chan) == -EPROBE_DEFER) return -EPROBE_DEFER; + + bool has_fw_node = dev->of_node || is_acpi_device_node(dev->fwnode); + bool name_exists_in_fw = false; + + if (has_fw_node) + name_exists_in_fw = device_property_match_string(dev, + "dma-names", + name) >= 0; + + if (has_fw_node && name_exists_in_fw) + dev_warn(dev, "DTS/ACPI DMA channel '%s' request failed (%ld)\n", + name, PTR_ERR(chan)); + + if (has_fw_node && !name_exists_in_fw) + dev_warn(dev, "DTS/ACPI name '%s' not found, legacy failed (%ld)\n", + name, PTR_ERR(chan)); + + if (!has_fw_node) + dev_warn(dev, "Legacy DMA channel '%s' request failed (%ld)\n", + name, PTR_ERR(chan)); + pcm->chan[i] = NULL; } else { pcm->chan[i] = chan; @@ -406,6 +428,12 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) pcm->chan[1] = pcm->chan[0]; + if (!pcm->chan[0] && + !pcm->chan[1]) { + dev_err(dev, "no DMA channel found for either playback or capture\n"); + return -ENODEV; + } + return 0; } From 5413fb3ba54c4cffaeb7c6dd8220071afcdc6ab4 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:02 +0700 Subject: [PATCH 303/438] ASoC: ti: ams-delta: Use dev_err_probe() for error handling Use dev_err_probe() to replace dev_err() followed by returning the error code. This keeps the error handling concise and suppresses log messages for deferred probe errors. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260716103911.77652-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/ams-delta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 61252359d5cb..2759b39c4ebe 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -574,9 +574,9 @@ static int ams_delta_probe(struct platform_device *pdev) ret = snd_soc_register_card(card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); card->dev = NULL; - return ret; + return dev_err_probe(&pdev->dev, ret, + "snd_soc_register_card() failed\n"); } return 0; } From 7ae5829ab0f2f69e8a62689a147e16cd41d1b155 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:03 +0700 Subject: [PATCH 304/438] ASoC: ti: davinci-evm: Use dev_err_probe() for error handling Replace dev_err() with dev_err_probe() when reporting devm_snd_soc_register_card() failures. This suppresses unnecessary log messages for deferred probe errors. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260716103911.77652-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-evm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index ad514c2e5a25..3156d87a3a12 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -245,9 +245,8 @@ static int davinci_evm_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&evm_soc_card, drvdata); ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); goto err_put; } From 1a1145d1b249acf36ff576f303ca6cdea4add99c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:04 +0700 Subject: [PATCH 305/438] ASoC: ti: j721e-evm: Return the original error from card name parsing Return the error from snd_soc_of_parse_card_name() directly instead of converting it to -ENODEV. The helper already logs the error, so drop the redundant dev_err(). Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260716103911.77652-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/j721e-evm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c index c214ae0d7b95..b95ade8198eb 100644 --- a/sound/soc/ti/j721e-evm.c +++ b/sound/soc/ti/j721e-evm.c @@ -868,10 +868,9 @@ static int j721e_soc_probe(struct platform_device *pdev) card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes); card->fully_routed = 1; - if (snd_soc_of_parse_card_name(card, "model")) { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret) + return ret; link_cnt = 0; conf_cnt = 0; From e0b2ab952d198a514222df6109e46f5b0727203d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:05 +0700 Subject: [PATCH 306/438] ASoC: ti: omap-abe-twl6040: Preserve error code and drop redundant log Return the original errors from the OF parsing helpers and remove the redundant error messages, as the helpers already report failures. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-abe-twl6040.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c index 56aa4b22083b..dfa931071d81 100644 --- a/sound/soc/ti/omap-abe-twl6040.c +++ b/sound/soc/ti/omap-abe-twl6040.c @@ -234,16 +234,13 @@ static int omap_abe_probe(struct platform_device *pdev) card->dapm_routes = audio_map; card->num_dapm_routes = ARRAY_SIZE(audio_map); - if (snd_soc_of_parse_card_name(card, "ti,model")) { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } + ret = snd_soc_of_parse_card_name(card, "ti,model"); + if (ret) + return ret; ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); - if (ret) { - dev_err(&pdev->dev, "Error while parsing DAPM routing\n"); + if (ret) return ret; - } dai_node = of_parse_phandle(node, "ti,mcpdm", 0); if (!dai_node) { From 3e8b2361c651d95b08b8f406d3c9f24b1f2d6746 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:06 +0700 Subject: [PATCH 307/438] ASoC: ti: omap-abe-twl6040: Use dev_err_probe() for error handling Replace dev_err() with dev_err_probe() when reporting devm_snd_soc_register_card() failures. This suppresses unnecessary log messages for deferred probe errors. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-abe-twl6040.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c index dfa931071d81..05239ccc1f41 100644 --- a/sound/soc/ti/omap-abe-twl6040.c +++ b/sound/soc/ti/omap-abe-twl6040.c @@ -296,8 +296,8 @@ static int omap_abe_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) - dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", - ret); + dev_err_probe(&pdev->dev, ret, + "devm_snd_soc_register_card() failed\n"); return ret; } From fa1d248f163880a0b4486d9a587ab79450846a8e Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:07 +0700 Subject: [PATCH 308/438] ASoC: ti: omap-dmic: Use dev_err_probe() for error handling Replace dev_err() with dev_err_probe() when handling clock lookup failures. This preserves the original error code and suppresses unnecessary deferred probe error messages. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-7-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-dmic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index b795b9f66b0e..c8d791f05ae4 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -465,10 +465,9 @@ static int asoc_dmic_probe(struct platform_device *pdev) mutex_init(&dmic->mutex); dmic->fclk = devm_clk_get(dmic->dev, "fck"); - if (IS_ERR(dmic->fclk)) { - dev_err(dmic->dev, "can't get fck\n"); - return -ENODEV; - } + if (IS_ERR(dmic->fclk)) + return dev_err_probe(dmic->dev, PTR_ERR(dmic->fclk), + "can't get fck\n"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); if (!res) { From 492a53506ab27d59e9c1a1ac32adac954607b512 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:08 +0700 Subject: [PATCH 309/438] ASoC: ti: omap-hdmi: Use dev_err_probe() for error handling Replace dev_err() with dev_err_probe() when reporting devm_snd_soc_register_card() failures. This suppresses unnecessary log messages for deferred probe errors. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-8-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-hdmi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index e60f5b483fc5..1e3a9711e70c 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -375,10 +375,8 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) card->dev = dev; ret = devm_snd_soc_register_card(dev, card); - if (ret) { - dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "snd_soc_register_card() failed\n"); ad->card = card; snd_soc_card_set_drvdata(card, ad); From 23c89b7d91ccd9de3e2e6ab90202d52bfdaaff54 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:09 +0700 Subject: [PATCH 310/438] ASoC: ti: omap-twl4030: Return the original error code Return the error from snd_soc_of_parse_card_name() directly and drop the redundant error message since the helper already logs the failure. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-9-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-twl4030.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c index 4d80f8a7a947..2a80e44035d7 100644 --- a/sound/soc/ti/omap-twl4030.c +++ b/sound/soc/ti/omap-twl4030.c @@ -253,10 +253,9 @@ static int omap_twl4030_probe(struct platform_device *pdev) struct device_node *dai_node; struct property *prop; - if (snd_soc_of_parse_card_name(card, "ti,model")) { - dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } + ret = snd_soc_of_parse_card_name(card, "ti,model"); + if (ret) + return ret; dai_node = of_parse_phandle(node, "ti,mcbsp", 0); if (!dai_node) { From 31d9b5bc1abb5b0dc58e47c75f947d9706577aa9 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:10 +0700 Subject: [PATCH 311/438] ASoC: ti: omap-twl4030: Use dev_err_probe() for error handling Replace dev_err() with dev_err_probe() when reporting devm_snd_soc_register_card() failures. This suppresses unnecessary log messages for deferred probe errors. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-10-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-twl4030.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c index 2a80e44035d7..576f4d3615e8 100644 --- a/sound/soc/ti/omap-twl4030.c +++ b/sound/soc/ti/omap-twl4030.c @@ -306,11 +306,9 @@ static int omap_twl4030_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { - dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "devm_snd_soc_register_card() failed\n"); return 0; } From 924448b41b65fedac11f35b2191d9eb58ef56e08 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 16 Jul 2026 17:39:11 +0700 Subject: [PATCH 312/438] ASoC: ti: rx51: Use dev_err_probe() for error handling Replace dev_err() with dev_err_probe() when reporting probe failures. This preserves the original error code and suppresses unnecessary log messages for deferred probe errors. Signed-off-by: bui duc phuc Acked-by: Jarkko Nikula Link: https://patch.msgid.link/20260716103911.77652-11-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/rx51.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index cfc23e0838c2..b13faf162c75 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -418,31 +418,27 @@ static int rx51_soc_probe(struct platform_device *pdev) pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, "tvout-selection", GPIOD_OUT_LOW); - if (IS_ERR(pdata->tvout_selection_gpio)) { - dev_err(card->dev, "could not get tvout selection gpio\n"); - return PTR_ERR(pdata->tvout_selection_gpio); - } + if (IS_ERR(pdata->tvout_selection_gpio)) + return dev_err_probe(card->dev, PTR_ERR(pdata->tvout_selection_gpio), + "could not get tvout selection gpio\n"); pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch", GPIOD_OUT_HIGH); - if (IS_ERR(pdata->eci_sw_gpio)) { - dev_err(card->dev, "could not get eci switch gpio\n"); - return PTR_ERR(pdata->eci_sw_gpio); - } + if (IS_ERR(pdata->eci_sw_gpio)) + return dev_err_probe(card->dev, PTR_ERR(pdata->eci_sw_gpio), + "could not get eci switch gpio\n"); pdata->speaker_amp_gpio = devm_gpiod_get(card->dev, "speaker-amplifier", GPIOD_OUT_LOW); - if (IS_ERR(pdata->speaker_amp_gpio)) { - dev_err(card->dev, "could not get speaker enable gpio\n"); - return PTR_ERR(pdata->speaker_amp_gpio); - } + if (IS_ERR(pdata->speaker_amp_gpio)) + return dev_err_probe(card->dev, PTR_ERR(pdata->speaker_amp_gpio), + "could not get speaker enable gpio\n"); err = devm_snd_soc_register_card(card->dev, card); - if (err) { - dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err); - return err; - } + if (err) + return dev_err_probe(card->dev, err, + "snd_soc_register_card() failed\n"); return 0; } From a8023598f3ae3c129a53aa89c7c664265377bfcb Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 16:55:20 +0700 Subject: [PATCH 313/438] ASoC: sunxi: sun4i-codec: Use dev_err_probe() for probe error handling Use dev_err_probe() for probe error handling to simplify the error paths and handle -EPROBE_DEFER correctly. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260715095525.40668-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 70 ++++++++++++++--------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index f4e22af594fa..05308df3ae5b 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -2316,67 +2316,54 @@ static int sun4i_codec_probe(struct platform_device *pdev) scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, quirks->regmap_config); - if (IS_ERR(scodec->regmap)) { - dev_err(&pdev->dev, "Failed to create our regmap\n"); - return PTR_ERR(scodec->regmap); - } + if (IS_ERR(scodec->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->regmap), + "Failed to create our regmap\n"); /* Get the clocks from the DT */ scodec->clk_apb = devm_clk_get_enabled(&pdev->dev, "apb"); - if (IS_ERR(scodec->clk_apb)) { - dev_err(&pdev->dev, "Failed to get the APB clock\n"); - return PTR_ERR(scodec->clk_apb); - } + if (IS_ERR(scodec->clk_apb)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_apb), + "Failed to get the APB clock\n"); scodec->clk_module = devm_clk_get(&pdev->dev, "codec"); - if (IS_ERR(scodec->clk_module)) { - dev_err(&pdev->dev, "Failed to get the module clock\n"); - return PTR_ERR(scodec->clk_module); - } + if (IS_ERR(scodec->clk_module)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_module), + "Failed to get the module clock\n"); if (quirks->has_reset) { scodec->rst = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL); - if (IS_ERR(scodec->rst)) { - dev_err(&pdev->dev, "Failed to get reset control\n"); - return PTR_ERR(scodec->rst); - } + if (IS_ERR(scodec->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->rst), + "Failed to get reset control\n"); } scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", GPIOD_OUT_LOW); - if (IS_ERR(scodec->gpio_pa)) { - ret = PTR_ERR(scodec->gpio_pa); - dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n"); - return ret; - } + if (IS_ERR(scodec->gpio_pa)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_pa), + "Failed to get pa gpio\n"); + scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); - if (IS_ERR(scodec->gpio_hp)) { - ret = PTR_ERR(scodec->gpio_hp); - dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n"); - return ret; - } + if (IS_ERR(scodec->gpio_hp)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_hp), + "Failed to get hp-det gpio\n"); /* reg_field setup */ scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, scodec->regmap, quirks->reg_adc_fifoc); - if (IS_ERR(scodec->reg_adc_fifoc)) { - ret = PTR_ERR(scodec->reg_adc_fifoc); - dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", - ret); - return ret; - } + if (IS_ERR(scodec->reg_adc_fifoc)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_adc_fifoc), + "Failed to create regmap fields\n"); scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev, scodec->regmap, quirks->reg_dac_fifoc); - if (IS_ERR(scodec->reg_dac_fifoc)) { - ret = PTR_ERR(scodec->reg_dac_fifoc); - dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", - ret); - return ret; - } + if (IS_ERR(scodec->reg_dac_fifoc)) + return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_dac_fifoc), + "Failed to create regmap fields\n"); /* DMA configuration for TX FIFO */ scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; @@ -2422,10 +2409,9 @@ static int sun4i_codec_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, scodec); ret = snd_soc_register_card(card); - if (ret) { - dev_err_probe(&pdev->dev, ret, "Failed to register our card\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to register our card\n"); return 0; } From de6bda2088e4b72e01538b5b116fbbb1a49dfc71 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 16:55:21 +0700 Subject: [PATCH 314/438] ASoC: sunxi: sun4i-codec: Drop redundant error messages The called functions already log failures where appropriate. Return the original error directly and avoid duplicate error messages. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260715095525.40668-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 05308df3ae5b..71f7a1fedd88 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -2380,31 +2380,22 @@ static int sun4i_codec_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec, &sun4i_codec_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Failed to register our codec\n"); + if (ret) return ret; - } ret = devm_snd_soc_register_component(&pdev->dev, &sun4i_codec_component, &dummy_cpu_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Failed to register our DAI\n"); + if (ret) return ret; - } ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to register against DMAEngine\n"); + if (ret) return ret; - } card = quirks->create_card(&pdev->dev); - if (IS_ERR(card)) { - ret = PTR_ERR(card); - dev_err(&pdev->dev, "Failed to create our card\n"); - return ret; - } + if (IS_ERR(card)) + return PTR_ERR(card); snd_soc_card_set_drvdata(card, scodec); From 3e2262df8460742b8a0cb3796e3780691e37be1f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 16:55:22 +0700 Subject: [PATCH 315/438] ASoC: sunxi: sun4i-i2s: Use dev_err_probe() for probe error handling Use dev_err_probe() for probe error handling to simplify the error paths and handle -EPROBE_DEFER correctly. Signed-off-by: bui duc phuc Reviewed-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260715095525.40668-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 40de99a34bc3..716fa4d872ff 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1550,30 +1550,26 @@ static int sun4i_i2s_probe(struct platform_device *pdev) } i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); - if (IS_ERR(i2s->bus_clk)) { - dev_err(&pdev->dev, "Can't get our bus clock\n"); - return PTR_ERR(i2s->bus_clk); - } + if (IS_ERR(i2s->bus_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->bus_clk), + "Can't get our bus clock\n"); i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, i2s->variant->sun4i_i2s_regmap); - if (IS_ERR(i2s->regmap)) { - dev_err(&pdev->dev, "Regmap initialisation failed\n"); - return PTR_ERR(i2s->regmap); - } + if (IS_ERR(i2s->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), + "Regmap initialisation failed\n"); i2s->mod_clk = devm_clk_get(&pdev->dev, "mod"); - if (IS_ERR(i2s->mod_clk)) { - dev_err(&pdev->dev, "Can't get our mod clock\n"); - return PTR_ERR(i2s->mod_clk); - } + if (IS_ERR(i2s->mod_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->mod_clk), + "Can't get our mod clock\n"); if (i2s->variant->has_reset) { i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(i2s->rst)) { - dev_err(&pdev->dev, "Failed to get reset control\n"); - return PTR_ERR(i2s->rst); - } + if (IS_ERR(i2s->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst), + "Failed to get reset control\n"); } if (!IS_ERR(i2s->rst)) { From ac95bdb9824699fd1196d91caa691afafcc0edf4 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 16:55:23 +0700 Subject: [PATCH 316/438] ASoC: sunxi: sun4i-spdif: Use dev_err_probe() for probe error handling Use dev_err_probe() for probe error handling to simplify the error paths and handle -EPROBE_DEFER correctly. Signed-off-by: bui duc phuc Reviewed-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260715095525.40668-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-spdif.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index c2ec19437cd7..d979bb00312f 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -684,26 +684,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev) host->regmap = devm_regmap_init_mmio(&pdev->dev, base, &sun4i_spdif_regmap_config); - if (IS_ERR(host->regmap)) { - dev_err(&pdev->dev, "failed to initialise regmap.\n"); - return PTR_ERR(host->regmap); - } + if (IS_ERR(host->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->regmap), + "failed to initialise regmap.\n"); /* Clocks */ host->apb_clk = devm_clk_get(&pdev->dev, "apb"); - if (IS_ERR(host->apb_clk)) { - dev_err(&pdev->dev, "failed to get a apb clock.\n"); - return PTR_ERR(host->apb_clk); - } + if (IS_ERR(host->apb_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->apb_clk), + "failed to get a apb clock.\n"); if (quirks->tx_clk_name) tx_clk_name = quirks->tx_clk_name; host->spdif_clk = devm_clk_get(&pdev->dev, tx_clk_name); - if (IS_ERR(host->spdif_clk)) { - dev_err(&pdev->dev, "failed to get the \"%s\" clock.\n", - tx_clk_name); - return PTR_ERR(host->spdif_clk); - } + if (IS_ERR(host->spdif_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->spdif_clk), + "failed to get the \"%s\" clock.\n", + tx_clk_name); host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata; host->dma_params_tx.maxburst = 8; From 76a770c30bcdb0447247c578e0283336a20b6990 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 16:55:24 +0700 Subject: [PATCH 317/438] ASoC: sunxi: sun50i-codec-analog: Improve probe error handling Drop the redundant error message after devm_platform_ioremap_resource(), which already reports failures, and use dev_err_probe() for regmap initialization errors. Signed-off-by: bui duc phuc Reviewed-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260715095525.40668-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun50i-codec-analog.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index 9f5b067a8ccc..50c0dee8c433 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -551,16 +551,13 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev) bool enable; base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - dev_err(&pdev->dev, "Failed to map the registers\n"); + if (IS_ERR(base)) return PTR_ERR(base); - } regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); - if (IS_ERR(regmap)) { - dev_err(&pdev->dev, "Failed to create regmap\n"); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(regmap), + "Failed to create regmap\n"); enable = device_property_read_bool(&pdev->dev, "allwinner,internal-bias-resistor"); From bb0d825c8ad9d35abcb4b4f88d8ca91b0755ee4b Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 15 Jul 2026 16:55:25 +0700 Subject: [PATCH 318/438] ASoC: sunxi: sun8i-codec-analog: Improve probe error handling Drop the redundant error message after devm_platform_ioremap_resource(), which already reports failures, and use dev_err_probe() for regmap initialization errors. Signed-off-by: bui duc phuc Reviewed-by: Chen-Yu Tsai Link: https://patch.msgid.link/20260715095525.40668-7-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 2024e2b2553e..3335855c6311 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -822,16 +822,13 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev) void __iomem *base; base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) { - dev_err(&pdev->dev, "Failed to map the registers\n"); + if (IS_ERR(base)) return PTR_ERR(base); - } regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); - if (IS_ERR(regmap)) { - dev_err(&pdev->dev, "Failed to create regmap\n"); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(regmap), + "Failed to create regmap\n"); return devm_snd_soc_register_component(&pdev->dev, &sun8i_codec_analog_cmpnt_drv, From 9af2c1d4f84748fbfc0d71de78e3d477d0cfa6e0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:42:58 +0000 Subject: [PATCH 319/438] ASoC: ti: omap-hdmi: remove unused *card No one is using ad->card. Remove it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87jyqpi0d9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c index e60f5b483fc5..d6b7a97a1fd9 100644 --- a/sound/soc/ti/omap-hdmi.c +++ b/sound/soc/ti/omap-hdmi.c @@ -24,8 +24,6 @@ #define DRV_NAME "omap-hdmi-audio" struct hdmi_audio_data { - struct snd_soc_card *card; - const struct omap_hdmi_audio_ops *ops; struct device *dssdev; struct snd_dmaengine_dai_dma_data dma_data; @@ -380,7 +378,6 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) return ret; } - ad->card = card; snd_soc_card_set_drvdata(card, ad); dev_set_drvdata(dev, ad); From 4bd2afcdc837244ed362a3e96ae41806e8fee541 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:43:08 +0000 Subject: [PATCH 320/438] ASoC: ti: tidyup not to use *card on rx51_soc_probe() struct snd_soc_card will be capsuled soon, its member will not be able to access from non soc-card.c. To reduce the difference during conversion, replace dev. - card->dev, ... + dev, ... No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula Link: https://patch.msgid.link/87ik69i0d0.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/rx51.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index cfc23e0838c2..09de571c898c 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -358,21 +358,22 @@ static struct snd_soc_card rx51_sound_card = { static int rx51_soc_probe(struct platform_device *pdev) { struct rx51_audio_pdata *pdata; - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct snd_soc_card *card = &rx51_sound_card; int err; if (!of_machine_is_compatible("nokia,omap3-n900")) return -ENODEV; - card->dev = &pdev->dev; + card->dev = dev; if (np) { struct device_node *dai_node; dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0); if (!dai_node) { - dev_err(card->dev, "McBSP node is not provided\n"); + dev_err(dev, "McBSP node is not provided\n"); return -EINVAL; } rx51_dai[0].cpus->dai_name = NULL; @@ -382,7 +383,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,audio-codec", 0); if (!dai_node) { - dev_err(card->dev, "Codec node is not provided\n"); + dev_err(dev, "Codec node is not provided\n"); return -EINVAL; } rx51_dai[0].codecs->name = NULL; @@ -390,7 +391,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,audio-codec", 1); if (!dai_node) { - dev_err(card->dev, "Auxiliary Codec node is not provided\n"); + dev_err(dev, "Auxiliary Codec node is not provided\n"); return -EINVAL; } rx51_aux_dev[0].dlc.name = NULL; @@ -400,7 +401,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0); if (!dai_node) { - dev_err(card->dev, "Headphone amplifier node is not provided\n"); + dev_err(dev, "Headphone amplifier node is not provided\n"); return -EINVAL; } rx51_aux_dev[1].dlc.name = NULL; @@ -409,38 +410,38 @@ static int rx51_soc_probe(struct platform_device *pdev) rx51_codec_conf[1].dlc.of_node = dai_node; } - pdata = devm_kzalloc(card->dev, sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) return -ENOMEM; snd_soc_card_set_drvdata(card, pdata); - pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, + pdata->tvout_selection_gpio = devm_gpiod_get(dev, "tvout-selection", GPIOD_OUT_LOW); if (IS_ERR(pdata->tvout_selection_gpio)) { - dev_err(card->dev, "could not get tvout selection gpio\n"); + dev_err(dev, "could not get tvout selection gpio\n"); return PTR_ERR(pdata->tvout_selection_gpio); } - pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch", + pdata->eci_sw_gpio = devm_gpiod_get(dev, "eci-switch", GPIOD_OUT_HIGH); if (IS_ERR(pdata->eci_sw_gpio)) { - dev_err(card->dev, "could not get eci switch gpio\n"); + dev_err(dev, "could not get eci switch gpio\n"); return PTR_ERR(pdata->eci_sw_gpio); } - pdata->speaker_amp_gpio = devm_gpiod_get(card->dev, + pdata->speaker_amp_gpio = devm_gpiod_get(dev, "speaker-amplifier", GPIOD_OUT_LOW); if (IS_ERR(pdata->speaker_amp_gpio)) { - dev_err(card->dev, "could not get speaker enable gpio\n"); + dev_err(dev, "could not get speaker enable gpio\n"); return PTR_ERR(pdata->speaker_amp_gpio); } - err = devm_snd_soc_register_card(card->dev, card); + err = devm_snd_soc_register_card(dev, card); if (err) { - dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err); + dev_err(dev, "snd_soc_register_card failed (%d)\n", err); return err; } From 3596abbd7bb34d159069511663962be18c191ee5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:43:14 +0000 Subject: [PATCH 321/438] ASoC: ti: ams-delta: use &pdev->dev instead of card->dev ams_delta_probe() will be updated when Card capsuling. To makes its review easy, use &pdev->dev instead of card->dev. These are same card->dev = &pdev->dev; No functional change, but is preparation for Card capsuling. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87h5lti0cu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ti/ams-delta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 61252359d5cb..6a0a3a2073bf 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -562,12 +562,12 @@ static int ams_delta_probe(struct platform_device *pdev) card->dev = &pdev->dev; - handset_mute = devm_gpiod_get(card->dev, "handset_mute", + handset_mute = devm_gpiod_get(&pdev->dev, "handset_mute", GPIOD_OUT_HIGH); if (IS_ERR(handset_mute)) return PTR_ERR(handset_mute); - handsfree_mute = devm_gpiod_get(card->dev, "handsfree_mute", + handsfree_mute = devm_gpiod_get(&pdev->dev, "handsfree_mute", GPIOD_OUT_HIGH); if (IS_ERR(handsfree_mute)) return PTR_ERR(handsfree_mute); From 3906ea776a08d13bd5ef221b1d8112a49988c644 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:11 -0700 Subject: [PATCH 322/438] ASoC: tlv320aic32x4: remove global header with platform data Commit 69d5b62c4bde ("ASoC: codec: tlv320aic32x4: Drop aic32x4_pdata usage") removed support for platform data, but left a global header file with #defines and platform data structure. Move the contents to the driver-private header. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-1-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- include/sound/tlv320aic32x4.h | 43 -------------------------------- sound/soc/codecs/tlv320aic32x4.c | 5 +++- sound/soc/codecs/tlv320aic32x4.h | 27 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 44 deletions(-) delete mode 100644 include/sound/tlv320aic32x4.h diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h deleted file mode 100644 index b779d671a995..000000000000 --- a/include/sound/tlv320aic32x4.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tlv320aic32x4.h -- TLV320AIC32X4 Soc Audio driver platform data - * - * Copyright 2011 Vista Silicon S.L. - * - * Author: Javier Martin - */ - -#ifndef _AIC32X4_PDATA_H -#define _AIC32X4_PDATA_H - -#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001 -#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002 -#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004 -#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008 -#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010 - -#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001 -#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002 - -/* GPIO API */ -#define AIC32X4_MFPX_DEFAULT_VALUE 0xff - -#define AIC32X4_MFP1_DIN_DISABLED 0 -#define AIC32X4_MFP1_DIN_ENABLED 0x2 -#define AIC32X4_MFP1_GPIO_IN 0x4 - -#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0 -#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1 - -#define AIC32X4_MFP_GPIO_ENABLED 0x4 - -#define AIC32X4_MFP5_GPIO_DISABLED 0x0 -#define AIC32X4_MFP5_GPIO_INPUT 0x8 -#define AIC32X4_MFP5_GPIO_OUTPUT 0xc -#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0 -#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1 - -struct aic32x4_setup_data { - unsigned int gpio_func[5]; -}; -#endif diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index d85094557215..da582f2c940c 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -28,10 +28,13 @@ #include #include #include -#include #include "tlv320aic32x4.h" +struct aic32x4_setup_data { + unsigned int gpio_func[5]; +}; + struct aic32x4_priv { struct regmap *regmap; u32 power_cfg; diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index f68a846ef61d..8eb9c6a4c99e 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -234,4 +234,31 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); #define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000 #define AIC32X4_MAX_PLL_CLKIN 20000000 +#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001 +#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002 +#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004 +#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008 +#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010 + +#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001 +#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002 + +/* GPIO API */ +#define AIC32X4_MFPX_DEFAULT_VALUE 0xff + +#define AIC32X4_MFP1_DIN_DISABLED 0 +#define AIC32X4_MFP1_DIN_ENABLED 0x2 +#define AIC32X4_MFP1_GPIO_IN 0x4 + +#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0 +#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1 + +#define AIC32X4_MFP_GPIO_ENABLED 0x4 + +#define AIC32X4_MFP5_GPIO_DISABLED 0x0 +#define AIC32X4_MFP5_GPIO_INPUT 0x8 +#define AIC32X4_MFP5_GPIO_OUTPUT 0xc +#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0 +#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1 + #endif /* _TLV320AIC32X4_H */ From 5143ae134636577d45de02de925da9f640259e6b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:12 -0700 Subject: [PATCH 323/438] ASoC: tlv320aic32x4: do not allocate gpio config separately Now that the driver only works with device tree we do not need to keep GPIO config separate from the driver structure. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-2-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 47 +++++++++++++------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index da582f2c940c..87b155599e94 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -31,10 +31,6 @@ #include "tlv320aic32x4.h" -struct aic32x4_setup_data { - unsigned int gpio_func[5]; -}; - struct aic32x4_priv { struct regmap *regmap; u32 power_cfg; @@ -48,7 +44,8 @@ struct aic32x4_priv { struct regulator *supply_dv; struct regulator *supply_av; - struct aic32x4_setup_data *setup; + unsigned int gpio_func[5]; + struct device *dev; enum aic32x4_type type; @@ -959,41 +956,41 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component) /* setup GPIO functions */ /* MFP1 */ - if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { + if (aic32x4->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { snd_soc_component_write(component, AIC32X4_DINCTL, - aic32x4->setup->gpio_func[0]); + aic32x4->gpio_func[0]); snd_soc_add_component_controls(component, aic32x4_mfp1, ARRAY_SIZE(aic32x4_mfp1)); } /* MFP2 */ - if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { + if (aic32x4->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { snd_soc_component_write(component, AIC32X4_DOUTCTL, - aic32x4->setup->gpio_func[1]); + aic32x4->gpio_func[1]); snd_soc_add_component_controls(component, aic32x4_mfp2, ARRAY_SIZE(aic32x4_mfp2)); } /* MFP3 */ - if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { + if (aic32x4->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { snd_soc_component_write(component, AIC32X4_SCLKCTL, - aic32x4->setup->gpio_func[2]); + aic32x4->gpio_func[2]); snd_soc_add_component_controls(component, aic32x4_mfp3, ARRAY_SIZE(aic32x4_mfp3)); } /* MFP4 */ - if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { + if (aic32x4->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { snd_soc_component_write(component, AIC32X4_MISOCTL, - aic32x4->setup->gpio_func[3]); + aic32x4->gpio_func[3]); snd_soc_add_component_controls(component, aic32x4_mfp4, ARRAY_SIZE(aic32x4_mfp4)); } /* MFP5 */ - if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { + if (aic32x4->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { snd_soc_component_write(component, AIC32X4_GPIOCTL, - aic32x4->setup->gpio_func[4]); + aic32x4->gpio_func[4]); snd_soc_add_component_controls(component, aic32x4_mfp5, ARRAY_SIZE(aic32x4_mfp5)); } @@ -1016,8 +1013,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (aic32x4->setup) - aic32x4_setup_gpios(component); + aic32x4_setup_gpios(component); clk_set_parent(clocks[0].clk, clocks[1].clk); clk_set_parent(clocks[2].clk, clocks[3].clk); @@ -1173,8 +1169,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) if (ret) return ret; - if (aic32x4->setup) - aic32x4_setup_gpios(component); + aic32x4_setup_gpios(component); clk_set_parent(clocks[0].clk, clocks[1].clk); clk_set_parent(clocks[2].clk, clocks[3].clk); @@ -1224,14 +1219,8 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np) { - struct aic32x4_setup_data *aic32x4_setup; int ret; - aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup), - GFP_KERNEL); - if (!aic32x4_setup) - return -ENOMEM; - ret = of_property_match_string(np, "clock-names", "mclk"); if (ret < 0) return -EINVAL; @@ -1248,9 +1237,11 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn"); } - if (of_property_read_u32_array(np, "aic32x4-gpio-func", - aic32x4_setup->gpio_func, 5) >= 0) - aic32x4->setup = aic32x4_setup; + for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) + aic32x4->gpio_func[i] = AIC32X4_MFPX_DEFAULT_VALUE; + of_property_read_u32_array(np, "aic32x4-gpio-func", + aic32x4->gpio_func, ARRAY_SIZE(aic32x4->gpio_func)); + return 0; } From 4ef61518b03d32bea9b13728eebb0673aeeee52d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:13 -0700 Subject: [PATCH 324/438] ASoC: tlv320aic32x4: consolidate programming functions Consolidate setting up of GPIO functions instead of repeating almost the same code block 5 times. Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-3-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 88 ++++++++++++-------------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 87b155599e94..6b3ddb89f692 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -222,25 +222,31 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, return 0; }; -static const struct snd_kcontrol_new aic32x4_mfp1[] = { - SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), -}; - -static const struct snd_kcontrol_new aic32x4_mfp2[] = { - SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), -}; - -static const struct snd_kcontrol_new aic32x4_mfp3[] = { - SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), -}; - -static const struct snd_kcontrol_new aic32x4_mfp4[] = { - SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), -}; - -static const struct snd_kcontrol_new aic32x4_mfp5[] = { - SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, - aic32x4_set_mfp5_gpio), +static const struct { + unsigned int reg; + struct snd_kcontrol_new ctrl; +} aic32x4_mfp_cfg[] = { + { + .reg = AIC32X4_DINCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), + }, + { + .reg = AIC32X4_DOUTCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), + }, + { + .reg = AIC32X4_SCLKCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), + }, + { + .reg = AIC32X4_MISOCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), + }, + { + .reg = AIC32X4_GPIOCTL, + .ctrl = SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, + aic32x4_set_mfp5_gpio), + }, }; /* 0dB min, 0.5dB steps */ @@ -955,44 +961,14 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component) struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); /* setup GPIO functions */ - /* MFP1 */ - if (aic32x4->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_DINCTL, - aic32x4->gpio_func[0]); - snd_soc_add_component_controls(component, aic32x4_mfp1, - ARRAY_SIZE(aic32x4_mfp1)); - } + BUILD_BUG_ON(ARRAY_SIZE(aic32x4->gpio_func) != ARRAY_SIZE(aic32x4_mfp_cfg)); + for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) { + if (aic32x4->gpio_func[i] == AIC32X4_MFPX_DEFAULT_VALUE) + continue; - /* MFP2 */ - if (aic32x4->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_DOUTCTL, - aic32x4->gpio_func[1]); - snd_soc_add_component_controls(component, aic32x4_mfp2, - ARRAY_SIZE(aic32x4_mfp2)); - } - - /* MFP3 */ - if (aic32x4->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_SCLKCTL, - aic32x4->gpio_func[2]); - snd_soc_add_component_controls(component, aic32x4_mfp3, - ARRAY_SIZE(aic32x4_mfp3)); - } - - /* MFP4 */ - if (aic32x4->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_MISOCTL, - aic32x4->gpio_func[3]); - snd_soc_add_component_controls(component, aic32x4_mfp4, - ARRAY_SIZE(aic32x4_mfp4)); - } - - /* MFP5 */ - if (aic32x4->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { - snd_soc_component_write(component, AIC32X4_GPIOCTL, - aic32x4->gpio_func[4]); - snd_soc_add_component_controls(component, aic32x4_mfp5, - ARRAY_SIZE(aic32x4_mfp5)); + snd_soc_component_write(component, aic32x4_mfp_cfg[i].reg, + aic32x4->gpio_func[i]); + snd_soc_add_component_controls(component, &aic32x4_mfp_cfg[i].ctrl, 1); } } From 2ba6a4dba620bcee0f2210f532b25510a0872cf1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:14 -0700 Subject: [PATCH 325/438] ASoC: tlv320aic32x4: move regmap_config into i2c and spi drivers Move regmap_config definitions to be static const structures in tlv320aic32x4-i2c.c and tlv320aic32x4-spi.c instead of dynamically modifying a shared base regmap_config at runtime during probe. Export aic32x4_regmap_pages so both bus drivers can reference page ranges. In addition, validate regmap initialization immediately upon creation in both bus probe routines and remove the redundant error check from core aic32x4_probe. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-4-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4-i2c.c | 16 +++++++++++----- sound/soc/codecs/tlv320aic32x4-spi.c | 20 +++++++++++++------- sound/soc/codecs/tlv320aic32x4.c | 13 ++----------- sound/soc/codecs/tlv320aic32x4.h | 2 +- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index 449353d5f088..e031eaaa2f7f 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -16,17 +16,23 @@ #include "tlv320aic32x4.h" +static const struct regmap_config aic32x4_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AIC32X4_REFPOWERUP, + .ranges = aic32x4_regmap_pages, + .num_ranges = 1, +}; + static int aic32x4_i2c_probe(struct i2c_client *i2c) { struct regmap *regmap; - struct regmap_config config; enum aic32x4_type type; - config = aic32x4_regmap_config; - config.reg_bits = 8; - config.val_bits = 8; + regmap = devm_regmap_init_i2c(i2c, &aic32x4_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - regmap = devm_regmap_init_i2c(i2c, &config); type = (uintptr_t)i2c_get_match_data(i2c); return aic32x4_probe(&i2c->dev, regmap, type); diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index 92246243ff94..4f842260e325 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -16,19 +16,25 @@ #include "tlv320aic32x4.h" +static const struct regmap_config aic32x4_spi_regmap_config = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + .read_flag_mask = 0x01, + .max_register = AIC32X4_REFPOWERUP, + .ranges = aic32x4_regmap_pages, + .num_ranges = 1, +}; + static int aic32x4_spi_probe(struct spi_device *spi) { struct regmap *regmap; - struct regmap_config config; enum aic32x4_type type; - config = aic32x4_regmap_config; - config.reg_bits = 7; - config.pad_bits = 1; - config.val_bits = 8; - config.read_flag_mask = 0x01; + regmap = devm_regmap_init_spi(spi, &aic32x4_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - regmap = devm_regmap_init_spi(spi, &config); type = (uintptr_t)spi_get_device_match_data(spi); return aic32x4_probe(&spi->dev, regmap, type); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 6b3ddb89f692..72be757f559c 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -581,7 +581,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { {"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"}, }; -static const struct regmap_range_cfg aic32x4_regmap_pages[] = { +const struct regmap_range_cfg aic32x4_regmap_pages[] = { { .selector_reg = 0, .selector_mask = 0xff, @@ -591,13 +591,7 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { .range_max = AIC32X4_REFPOWERUP, }, }; - -const struct regmap_config aic32x4_regmap_config = { - .max_register = AIC32X4_REFPOWERUP, - .ranges = aic32x4_regmap_pages, - .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), -}; -EXPORT_SYMBOL(aic32x4_regmap_config); +EXPORT_SYMBOL_GPL(aic32x4_regmap_pages); static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) @@ -1326,9 +1320,6 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, struct device_node *np = dev->of_node; int ret; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), GFP_KERNEL); if (aic32x4 == NULL) diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 8eb9c6a4c99e..95d010af3d5a 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -16,7 +16,7 @@ enum aic32x4_type { AIC32X4_TYPE_TAS2505, }; -extern const struct regmap_config aic32x4_regmap_config; +extern const struct regmap_range_cfg aic32x4_regmap_pages[]; int aic32x4_probe(struct device *dev, struct regmap *regmap, enum aic32x4_type type); void aic32x4_remove(struct device *dev); From dfefa7dc25ee58a38b3a6d8777ba952cda5aeaac Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:15 -0700 Subject: [PATCH 326/438] ASoC: tlv320aic32x4: do not make clocks bulk data static Declaring local clk_bulk_data structures as static inside functions is bad practice even if the driver is currently a singleton, because it relies on mutable function-static state and interferes with multi-instance safety or clean re-probing. Remove static from the clocks bulk data arrays across the driver. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-5-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 72be757f559c..690acfc005c2 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -717,7 +717,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, unsigned long adc_clock_rate, dac_clock_rate; int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "pll" }, { .id = "nadc" }, { .id = "madc" }, @@ -886,7 +886,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component, struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "madc" }, { .id = "mdac" }, { .id = "bdiv" }, @@ -972,7 +972,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) u32 tmp_reg; int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "codec_clkin" }, { .id = "pll" }, { .id = "bdiv" }, @@ -1128,7 +1128,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) u32 tmp_reg; int ret; - static struct clk_bulk_data clocks[] = { + struct clk_bulk_data clocks[] = { { .id = "codec_clkin" }, { .id = "pll" }, { .id = "bdiv" }, From e86ba7c5f24fd0346284f96093aebc128859eb31 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:16 -0700 Subject: [PATCH 327/438] ASoC: tlv320aic32x4: factor out rate configuration helper Factor out sample-rate dependent parameter setup and processing block configuration into a separate helper function aic32x4_configure_rate. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-6-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 75 +++++++++++++++++++------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 690acfc005c2..8d3f2d5c6128 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -703,6 +703,45 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component, return 0; } +static int aic32x4_configure_rate(struct snd_soc_component *component, + unsigned int rate, u8 *aosr, u8 *adc_rc, + u8 *dac_rc, u8 *dosr_inc) +{ + struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); + u8 prb_rx, prb_tx; + + if (rate <= 48000) { + *aosr = 128; + *adc_rc = 6; + *dac_rc = 8; + *dosr_inc = 8; + prb_rx = 1; + prb_tx = 1; + } else if (rate <= 96000) { + *aosr = 64; + *adc_rc = 6; + *dac_rc = 8; + *dosr_inc = 4; + prb_rx = 1; + prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 9; + } else if (rate == 192000) { + *aosr = 32; + *adc_rc = 3; + *dac_rc = 4; + *dosr_inc = 2; + prb_rx = 13; + prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 19; + } else { + dev_err(component->dev, "Sampling rate %u not supported\n", rate); + return -EINVAL; + } + + if (aic32x4->type == AIC32X4_TYPE_TAS2505) + prb_rx = 0; + + return aic32x4_set_processing_blocks(component, prb_rx, prb_tx); +} + static int aic32x4_setup_clocks(struct snd_soc_component *component, unsigned int sample_rate, unsigned int channels, unsigned int bit_depth) @@ -729,37 +768,11 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, if (ret) return ret; - if (sample_rate <= 48000) { - aosr = 128; - adc_resource_class = 6; - dac_resource_class = 8; - dosr_increment = 8; - if (aic32x4->type == AIC32X4_TYPE_TAS2505) - aic32x4_set_processing_blocks(component, 0, 1); - else - aic32x4_set_processing_blocks(component, 1, 1); - } else if (sample_rate <= 96000) { - aosr = 64; - adc_resource_class = 6; - dac_resource_class = 8; - dosr_increment = 4; - if (aic32x4->type == AIC32X4_TYPE_TAS2505) - aic32x4_set_processing_blocks(component, 0, 1); - else - aic32x4_set_processing_blocks(component, 1, 9); - } else if (sample_rate == 192000) { - aosr = 32; - adc_resource_class = 3; - dac_resource_class = 4; - dosr_increment = 2; - if (aic32x4->type == AIC32X4_TYPE_TAS2505) - aic32x4_set_processing_blocks(component, 0, 1); - else - aic32x4_set_processing_blocks(component, 13, 19); - } else { - dev_err(component->dev, "Sampling rate not supported\n"); - return -EINVAL; - } + ret = aic32x4_configure_rate(component, sample_rate, &aosr, + &adc_resource_class, &dac_resource_class, + &dosr_increment); + if (ret) + return ret; /* PCM over I2S is always 2-channel */ if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) From c3ac0aa6c3100f973b44bb0b0882f435075ed215 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Jul 2026 18:05:17 -0700 Subject: [PATCH 328/438] ASoC: tlv320aic32x4: clean up driver code formatting and logging Clean up coding style, SPDX comments, logging calls, and macro definitions across the tlv320aic32x4 driver files: - Convert SPDX comment blocks to // style in bus and clk drivers. - Replace printk(KERN_ERR/DEBUG ...) calls with dev_err/dev_dbg. - Replace msleep(10) with usleep_range(10000, 20000) in the clock driver. - Parenthesize parameters in AIC32X4_REG macro. - Clean up double blank lines and null pointer checks. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Dmitry Torokhov Link: https://patch.msgid.link/20260726010519.117805-7-dmitry.torokhov@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4-clk.c | 68 ++++--- sound/soc/codecs/tlv320aic32x4-i2c.c | 5 +- sound/soc/codecs/tlv320aic32x4-spi.c | 5 +- sound/soc/codecs/tlv320aic32x4.c | 260 +++++++++++++-------------- sound/soc/codecs/tlv320aic32x4.h | 3 +- 5 files changed, 158 insertions(+), 183 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c index 5c0a76a4a106..deed61650e09 100644 --- a/sound/soc/codecs/tlv320aic32x4-clk.c +++ b/sound/soc/codecs/tlv320aic32x4-clk.c @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0 +/* * Clock Tree for the Texas Instruments TLV320AIC32x4 * * Copyright 2019 Annaliese McDermond @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -57,7 +58,7 @@ static void clk_aic32x4_pll_unprepare(struct clk_hw *hw) struct clk_aic32x4 *pll = to_clk_aic32x4(hw); regmap_update_bits(pll->regmap, AIC32X4_PLLPR, - AIC32X4_PLLEN, 0); + AIC32X4_PLLEN, 0); } static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw) @@ -75,7 +76,7 @@ static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw) } static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll, - struct clk_aic32x4_pll_muldiv *settings) + struct clk_aic32x4_pll_muldiv *settings) { /* Change to use regmap_bulk_read? */ unsigned int val; @@ -106,19 +107,19 @@ static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll, } static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll, - struct clk_aic32x4_pll_muldiv *settings) + struct clk_aic32x4_pll_muldiv *settings) { int ret; /* Change to use regmap_bulk_write for some if not all? */ ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR, - AIC32X4_PLL_R_MASK, settings->r); + AIC32X4_PLL_R_MASK, settings->r); if (ret < 0) return ret; ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR, - AIC32X4_PLL_P_MASK, - settings->p << AIC32X4_PLL_P_SHIFT); + AIC32X4_PLL_P_MASK, + settings->p << AIC32X4_PLL_P_SHIFT); if (ret < 0) return ret; @@ -136,23 +137,21 @@ static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll, return 0; } -static unsigned long clk_aic32x4_pll_calc_rate( - struct clk_aic32x4_pll_muldiv *settings, - unsigned long parent_rate) +static unsigned long clk_aic32x4_pll_calc_rate(struct clk_aic32x4_pll_muldiv *settings, + unsigned long parent_rate) { u64 rate; /* * We scale j by 10000 to account for the decimal part of P and divide * it back out later. */ - rate = (u64) parent_rate * settings->r * - ((settings->j * 10000) + settings->d); + rate = (u64)parent_rate * settings->r * ((settings->j * 10000) + settings->d); - return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000); + return (unsigned long)DIV_ROUND_UP_ULL(rate, settings->p * 10000); } static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, - unsigned long rate, unsigned long parent_rate) + unsigned long rate, unsigned long parent_rate) { u64 multiplier; @@ -165,14 +164,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, * of the multiplier. This is because we can't do floating point * math in the kernel. */ - multiplier = (u64) rate * settings->p * 10000; + multiplier = (u64)rate * settings->p * 10000; do_div(multiplier, parent_rate); /* * J can't be over 64, so R can scale this. * R can't be greater than 4. */ - settings->r = ((u32) multiplier / 640000) + 1; + settings->r = ((u32)multiplier / 640000) + 1; if (settings->r > 4) return -1; do_div(multiplier, settings->r); @@ -184,14 +183,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, return -1; /* Figure out the integer part, J, and the fractional part, D. */ - settings->j = (u32) multiplier / 10000; - settings->d = (u32) multiplier % 10000; + settings->j = (u32)multiplier / 10000; + settings->d = (u32)multiplier % 10000; return 0; } static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_aic32x4 *pll = to_clk_aic32x4(hw); struct clk_aic32x4_pll_muldiv settings; @@ -220,8 +219,8 @@ static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw, } static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) + unsigned long rate, + unsigned long parent_rate) { struct clk_aic32x4 *pll = to_clk_aic32x4(hw); struct clk_aic32x4_pll_muldiv settings; @@ -236,7 +235,7 @@ static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, return ret; /* 10ms is the delay to wait before the clocks are stable */ - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -261,7 +260,6 @@ static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw) return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT; } - static const struct clk_ops aic32x4_pll_ops = { .prepare = clk_aic32x4_pll_prepare, .unprepare = clk_aic32x4_pll_unprepare, @@ -311,11 +309,11 @@ static void clk_aic32x4_div_unprepare(struct clk_hw *hw) struct clk_aic32x4 *div = to_clk_aic32x4(hw); regmap_update_bits(div->regmap, div->reg, - AIC32X4_DIVEN, 0); + AIC32X4_DIVEN, 0); } static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); u8 divisor; @@ -342,7 +340,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, } static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { struct clk_aic32x4 *div = to_clk_aic32x4(hw); unsigned int val; @@ -399,7 +397,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { { .name = "pll", .parent_names = - (const char* []) { "mclk", "bclk", "gpio", "din" }, + (const char *[]) { "mclk", "bclk", "gpio", "din" }, .num_parents = 4, .ops = &aic32x4_pll_ops, .reg = 0, @@ -414,28 +412,28 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { }, { .name = "ndac", - .parent_names = (const char * []) { "codec_clkin" }, + .parent_names = (const char *[]) { "codec_clkin" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_NDAC, }, { .name = "mdac", - .parent_names = (const char * []) { "ndac" }, + .parent_names = (const char *[]) { "ndac" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_MDAC, }, { .name = "nadc", - .parent_names = (const char * []) { "codec_clkin" }, + .parent_names = (const char *[]) { "codec_clkin" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_NADC, }, { .name = "madc", - .parent_names = (const char * []) { "nadc" }, + .parent_names = (const char *[]) { "nadc" }, .num_parents = 1, .ops = &aic32x4_div_ops, .reg = AIC32X4_MADC, @@ -451,7 +449,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { }; static struct clk *aic32x4_register_clk(struct device *dev, - struct aic32x4_clkdesc *desc) + struct aic32x4_clkdesc *desc) { struct clk_init_data init; struct clk_aic32x4 *priv; @@ -464,8 +462,8 @@ static struct clk *aic32x4_register_clk(struct device *dev, init.flags = 0; priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL); - if (priv == NULL) - return (struct clk *) -ENOMEM; + if (!priv) + return ERR_PTR(-ENOMEM); priv->dev = dev; priv->hw.init = &init; diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index e031eaaa2f7f..cbbb8ff3ee38 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -1,11 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0 +/* * Copyright 2011-2019 NW Digital Radio * * Author: Annaliese McDermond * * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. - * */ #include diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index 4f842260e325..cb615b2e4f02 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -1,11 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0 +/* * Copyright 2011-2019 NW Digital Radio * * Author: Annaliese McDermond * * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. - * */ #include diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 8d3f2d5c6128..9e0e4aa2b09c 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * linux/sound/soc/codecs/tlv320aic32x4.c - * * Copyright 2011 Vista Silicon S.L. * * Author: Javier Martin @@ -75,7 +73,7 @@ static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, }; static int mic_bias_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); @@ -83,25 +81,23 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: /* Change Mic Bias Registor */ snd_soc_component_update_bits(component, AIC32X4_MICBIAS, - AIC32x4_MICBIAS_MASK, - AIC32X4_MICBIAS_LDOIN | - AIC32X4_MICBIAS_2075V); - printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__); + AIC32x4_MICBIAS_MASK, + AIC32X4_MICBIAS_LDOIN | + AIC32X4_MICBIAS_2075V); + dev_dbg(component->dev, "Mic Bias will be turned ON\n"); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_component_update_bits(component, AIC32X4_MICBIAS, - AIC32x4_MICBIAS_MASK, 0); - printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n", - __func__); + AIC32x4_MICBIAS_MASK, 0); + dev_dbg(component->dev, "Mic Bias will be turned OFF\n"); break; } return 0; } - static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -114,7 +110,7 @@ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -123,8 +119,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, val = snd_soc_component_read(component, AIC32X4_DOUTCTL); gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { - printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n", - __func__); + dev_err(component->dev, "MFP2 is not configure as a GPIO output\n"); return -EINVAL; } @@ -142,7 +137,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -155,7 +150,7 @@ static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -164,8 +159,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, val = snd_soc_component_read(component, AIC32X4_MISOCTL); gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { - printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n", - __func__); + dev_err(component->dev, "MFP4 is not configure as a GPIO output\n"); return -EINVAL; } @@ -183,7 +177,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -195,7 +189,7 @@ static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, }; static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); u8 val; @@ -204,8 +198,7 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, val = snd_soc_component_read(component, AIC32X4_GPIOCTL); gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT); if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) { - printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n", - __func__); + dev_err(component->dev, "MFP5 is not configure as a GPIO output\n"); return -EINVAL; } @@ -276,53 +269,42 @@ static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text); static const struct snd_kcontrol_new aic32x4_snd_controls[] = { SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, - AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), + AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum), SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum), SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, - AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, - tlv_driver_gain), + AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain), SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, - AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, - tlv_driver_gain), + AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain), SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, - AIC32X4_HPRGAIN, 6, 0x01, 1), + AIC32X4_HPRGAIN, 6, 0x01, 1), SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, - AIC32X4_LORGAIN, 6, 0x01, 1), + AIC32X4_LORGAIN, 6, 0x01, 1), SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum), SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL, - AIC32X4_RMICPGAVOL, 7, 0x01, 1), + AIC32X4_RMICPGAVOL, 7, 0x01, 1), SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL, - AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), + AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, - AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), + AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0), SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0), - SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, - 4, 0x07, 0), - SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, - 0, 0x03, 0), - SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, - 6, 0x03, 0), - SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, - 1, 0x1F, 0), - SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, - 0, 0x7F, 0), - SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, - 3, 0x1F, 0), - SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, - 3, 0x1F, 0), - SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, - 0, 0x1F, 0), - SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, - 0, 0x0F, 0), + SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, 4, 0x07, 0), + SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, 0, 0x03, 0), + SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, 6, 0x03, 0), + SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, 1, 0x1F, 0), + SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, 0, 0x7F, 0), + SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, 3, 0x1F, 0), + SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, 3, 0x1F, 0), + SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, 0, 0x1F, 0), + SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, 0, 0x0F, 0), }; static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { @@ -360,21 +342,27 @@ static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_te static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum), }; + static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum), }; + static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum), }; + static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum), }; + static const struct snd_kcontrol_new cml_to_lmixer_controls[] = { SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum), }; + static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum), }; + static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = { SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum), }; @@ -391,21 +379,27 @@ static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_te static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum), }; + static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum), }; + static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum), }; + static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum), }; + static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = { SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum), }; + static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum), }; + static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = { SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum), }; @@ -434,38 +428,38 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in1r_to_rmixer_controls), + in1r_to_rmixer_controls), SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in2r_to_rmixer_controls), + in2r_to_rmixer_controls), SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in3r_to_rmixer_controls), + in3r_to_rmixer_controls), SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in2l_to_rmixer_controls), + in2l_to_rmixer_controls), SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - cmr_to_rmixer_controls), + cmr_to_rmixer_controls), SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in1l_to_rmixer_controls), + in1l_to_rmixer_controls), SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in3l_to_rmixer_controls), + in3l_to_rmixer_controls), SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in1l_to_lmixer_controls), + in1l_to_lmixer_controls), SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in2l_to_lmixer_controls), + in2l_to_lmixer_controls), SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in3l_to_lmixer_controls), + in3l_to_lmixer_controls), SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, - in1r_to_lmixer_controls), + in1r_to_lmixer_controls), SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - cml_to_lmixer_controls), + cml_to_lmixer_controls), SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in2r_to_lmixer_controls), + in2r_to_lmixer_controls), SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, - in3r_to_lmixer_controls), + in3r_to_lmixer_controls), SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc), @@ -624,7 +618,7 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_CBC_CFC: break; default: - printk(KERN_ERR "aic32x4: invalid clock provider\n"); + dev_err(component->dev, "invalid clock provider\n"); return -EINVAL; } @@ -651,19 +645,20 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) AIC32X4_IFACE1_DATATYPE_SHIFT); break; default: - printk(KERN_ERR "aic32x4: invalid DAI interface format\n"); + dev_err(component->dev, "invalid DAI interface format\n"); return -EINVAL; } aic32x4->fmt = fmt; snd_soc_component_update_bits(component, AIC32X4_IFACE1, - AIC32X4_IFACE1_DATATYPE_MASK | - AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); + AIC32X4_IFACE1_DATATYPE_MASK | + AIC32X4_IFACE1_MASTER_MASK, + iface_reg_1); snd_soc_component_update_bits(component, AIC32X4_IFACE2, - AIC32X4_DATA_OFFSET_MASK, iface_reg_2); + AIC32X4_DATA_OFFSET_MASK, iface_reg_2); snd_soc_component_update_bits(component, AIC32X4_IFACE3, - AIC32X4_BCLKINV_MASK, iface_reg_3); + AIC32X4_BCLKINV_MASK, iface_reg_3); return 0; } @@ -676,14 +671,13 @@ static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr) static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr) { snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8); - snd_soc_component_write(component, AIC32X4_DOSRLSB, - (dosr & 0xff)); + snd_soc_component_write(component, AIC32X4_DOSRLSB, dosr & 0xff); return 0; } static int aic32x4_set_processing_blocks(struct snd_soc_component *component, - u8 r_block, u8 p_block) + u8 r_block, u8 p_block) { struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); @@ -794,50 +788,39 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, (min_mdac * dosr * sample_rate); for (mdac = min_mdac; mdac <= 128; ++mdac) { for (ndac = max_ndac; ndac > 0; --ndac) { - dac_clock_rate = ndac * mdac * dosr * - sample_rate; - if (dac_clock_rate == adc_clock_rate) { - if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) - continue; + dac_clock_rate = ndac * mdac * dosr * sample_rate; + if (dac_clock_rate != adc_clock_rate) + continue; - clk_set_rate(clocks[0].clk, - dac_clock_rate); + if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) + continue; - clk_set_rate(clocks[1].clk, - sample_rate * aosr * - madc); - clk_set_rate(clocks[2].clk, - sample_rate * aosr); - aic32x4_set_aosr(component, - aosr); + clk_set_rate(clocks[0].clk, dac_clock_rate); - clk_set_rate(clocks[3].clk, - sample_rate * dosr * - mdac); - clk_set_rate(clocks[4].clk, - sample_rate * dosr); - aic32x4_set_dosr(component, - dosr); + clk_set_rate(clocks[1].clk, sample_rate * aosr * madc); + clk_set_rate(clocks[2].clk, sample_rate * aosr); + aic32x4_set_aosr(component, aosr); - clk_set_rate(clocks[5].clk, - sample_rate * channels * - bit_depth); + clk_set_rate(clocks[3].clk, sample_rate * dosr * mdac); + clk_set_rate(clocks[4].clk, sample_rate * dosr); + aic32x4_set_dosr(component, dosr); - return 0; - } + clk_set_rate(clocks[5].clk, + sample_rate * channels * bit_depth); + + return 0; } } } } - dev_err(component->dev, - "Could not set clocks to support sample rate.\n"); + dev_err(component->dev, "Could not set clocks to support sample rate.\n"); return -EINVAL; } static int aic32x4_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); @@ -850,24 +833,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, switch (params_physical_width(params)) { case 16: - iface1_reg |= (AIC32X4_WORD_LEN_16BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_16BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; case 20: - iface1_reg |= (AIC32X4_WORD_LEN_20BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; case 24: - iface1_reg |= (AIC32X4_WORD_LEN_24BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; case 32: - iface1_reg |= (AIC32X4_WORD_LEN_32BITS << - AIC32X4_IFACE1_DATALEN_SHIFT); + iface1_reg |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_IFACE1_DATALEN_SHIFT); break; } snd_soc_component_update_bits(component, AIC32X4_IFACE1, - AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); + AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); if (params_channels(params) == 1) { dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; @@ -878,7 +857,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; } snd_soc_component_update_bits(component, AIC32X4_DACSETUP, - AIC32X4_DAC_CHAN_MASK, dacsetup_reg); + AIC32X4_DAC_CHAN_MASK, dacsetup_reg); return 0; } @@ -888,7 +867,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction) struct snd_soc_component *component = dai->component; snd_soc_component_update_bits(component, AIC32X4_DACMUTE, - AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); + AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); return 0; } @@ -1004,7 +983,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) /* Power platform configuration */ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) { snd_soc_component_write(component, AIC32X4_MICBIAS, - AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V); + AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V); } if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE); @@ -1023,16 +1002,16 @@ static int aic32x4_component_probe(struct snd_soc_component *component) /* Mic PGA routing */ if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) snd_soc_component_write(component, AIC32X4_LMICPGANIN, - AIC32X4_LMICPGANIN_IN2R_10K); + AIC32X4_LMICPGANIN_IN2R_10K); else snd_soc_component_write(component, AIC32X4_LMICPGANIN, - AIC32X4_LMICPGANIN_CM1L_10K); + AIC32X4_LMICPGANIN_CM1L_10K); if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) snd_soc_component_write(component, AIC32X4_RMICPGANIN, - AIC32X4_RMICPGANIN_IN1L_10K); + AIC32X4_RMICPGANIN_IN1L_10K); else snd_soc_component_write(component, AIC32X4_RMICPGANIN, - AIC32X4_RMICPGANIN_CM1R_10K); + AIC32X4_RMICPGANIN_CM1R_10K); /* * Workaround: for an unknown reason, the ADC needs to be powered up @@ -1040,8 +1019,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component) * a HW BUG or some kind of behavior not documented in the datasheet. */ tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP); - snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg | - AIC32X4_LADC_EN | AIC32X4_RADC_EN); + snd_soc_component_write(component, AIC32X4_ADCSETUP, + tmp_reg | AIC32X4_LADC_EN | AIC32X4_RADC_EN); snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg); /* @@ -1084,13 +1063,13 @@ static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = { SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum), SOC_SINGLE_TLV("HP Driver Gain Volume", - AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain), + AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain), SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1), SOC_SINGLE_TLV("Speaker Driver Playback Volume", - TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain), + TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain), SOC_SINGLE_TLV("Speaker Amplifier Playback Volume", - TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol), + TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol), SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), }; @@ -1126,11 +1105,12 @@ static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = { static struct snd_soc_dai_driver aic32x4_tas2505_dai = { .name = "tas2505-hifi", .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = AIC32X4_FORMATS,}, + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = AIC32X4_FORMATS, + }, .ops = &aic32x4_ops, .symmetric_rate = 1, }; @@ -1173,7 +1153,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg); /* - * Enable the fast charging feature and ensure the needed 40ms ellapsed + * Enable the fast charging feature and ensure the needed 40ms elapsed * before using the analog circuits. */ snd_soc_component_write(component, TAS2505_REFPOWERUP, @@ -1199,8 +1179,7 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = .endianness = 1, }; -static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, - struct device_node *np) +static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np) { int ret; @@ -1243,7 +1222,7 @@ static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4) } static int aic32x4_setup_regulators(struct device *dev, - struct aic32x4_priv *aic32x4) + struct aic32x4_priv *aic32x4) { int ret = 0; @@ -1333,9 +1312,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, struct device_node *np = dev->of_node; int ret; - aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), - GFP_KERNEL); - if (aic32x4 == NULL) + aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), GFP_KERNEL); + if (!aic32x4) return -ENOMEM; aic32x4->dev = dev; @@ -1379,11 +1357,13 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, switch (aic32x4->type) { case AIC32X4_TYPE_TAS2505: ret = devm_snd_soc_register_component(dev, - &soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1); + &soc_component_dev_aic32x4_tas2505, + &aic32x4_tas2505_dai, 1); break; default: ret = devm_snd_soc_register_component(dev, - &soc_component_dev_aic32x4, &aic32x4_dai, 1); + &soc_component_dev_aic32x4, + &aic32x4_dai, 1); } if (ret) { diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 95d010af3d5a..cfab6f8ce5ac 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -3,7 +3,6 @@ * tlv320aic32x4.h */ - #ifndef _TLV320AIC32X4_H #define _TLV320AIC32X4_H @@ -24,7 +23,7 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); /* tlv320aic32x4 register space (in decimal to match datasheet) */ -#define AIC32X4_REG(page, reg) ((page * 128) + reg) +#define AIC32X4_REG(page, reg) (((page) * 128) + (reg)) #define AIC32X4_PSEL AIC32X4_REG(0, 0) From 30df43c14050365b8e26ea428b75b0d33de77fdb Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 20 Jul 2026 14:40:40 +0700 Subject: [PATCH 329/438] ASoC: stm: stm32_adfsdm: Drop redundant error message devm_snd_soc_register_component() already logs the failure internally. Drop the redundant error message and return the original error directly. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260720074044.87528-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 66efb9a0acb9..73c6460a6327 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -360,11 +360,8 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(&pdev->dev, &stm32_adfsdm_soc_platform, NULL, 0); - if (ret < 0) { - dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", - __func__); + if (ret < 0) return ret; - } pm_runtime_enable(&pdev->dev); From a6cdfb6230944082e7be64f9166eed64656b1162 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 20 Jul 2026 14:40:41 +0700 Subject: [PATCH 330/438] ASoC: stm: stm32_i2s: Drop redundant error messages Both devm_request_irq() and snd_dmaengine_pcm_register() already log failures internally. Drop the redundant error messages and return the original errors directly. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260720074044.87528-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index ae9e25657f3f..83b51893b37c 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -1238,10 +1238,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, 0, dev_name(&pdev->dev), i2s); - if (ret) { - dev_err(&pdev->dev, "irq request returned %d\n", ret); + if (ret) return ret; - } /* Reset */ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); @@ -1295,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev) ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); if (ret) - return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); + return ret; ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component, i2s->dai_drv, 1); From e502adb1cdd6c26d7c8529bdebb776bc5902d88e Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 20 Jul 2026 14:40:42 +0700 Subject: [PATCH 331/438] ASoC: stm: stm32_sai_sub: Drop redundant error messages Both devm_request_irq() and snd_dmaengine_pcm_register() already log failures internally. Drop the redundant error messages and return the original errors directly. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260720074044.87528-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index ea9e8bddd63f..9a201bdb306f 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1696,19 +1696,15 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr, IRQF_SHARED, dev_name(&pdev->dev), sai); - if (ret) { - dev_err(&pdev->dev, "IRQ request returned %d\n", ret); + if (ret) goto err_unprepare_pclk; - } if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) conf = &stm32_sai_pcm_config_spdif; ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); - if (ret) { - ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); + if (ret) goto err_unprepare_pclk; - } ret = snd_soc_register_component(&pdev->dev, &stm32_component, &sai->cpu_dai_drv, 1); From 94495c842711b43ec82f2c1259d1a74a9b3378bb Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Mon, 20 Jul 2026 14:40:43 +0700 Subject: [PATCH 332/438] ASoC: stm: stm32_spdifrx: Drop redundant error messages Both devm_request_irq() and snd_dmaengine_pcm_register() already log failures internally. Drop the redundant error messages and return the original errors directly. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260720074044.87528-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_spdifrx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 2f83ca989e68..e0fef47a227e 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -970,10 +970,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, dev_name(&pdev->dev), spdifrx); - if (ret) { - dev_err(&pdev->dev, "IRQ request returned %d\n", ret); + if (ret) return ret; - } rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); if (IS_ERR(rst)) @@ -987,7 +985,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) pcm_config = &stm32_spdifrx_pcm_config; ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); if (ret) - return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); + return ret; ret = snd_soc_register_component(&pdev->dev, &stm32_spdifrx_component, From a14b50577898c0693a4b79f73f4c3d258056e019 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:46:01 +0000 Subject: [PATCH 333/438] ASoC: ux500: mop500: tidyup mop500_of_probe() parameter mop500.c will be updated when Card capsuling. To makes its review easy, tidyup mop500_of_probe() parameter. No functional change, but is preparation for cleanup driver. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87ecgxi087.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ux500/mop500.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index ae6d326167d1..6d196b4b8802 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -68,10 +68,11 @@ static void mop500_of_node_put(void) of_node_put(mop500_dai_links[0].codecs->of_node); } -static int mop500_of_probe(struct platform_device *pdev, - struct device_node *np) +static int mop500_of_probe(struct snd_soc_card *card) { + struct device *dev = card->dev; struct device_node *codec_np, *msp_np[2]; + struct device_node *np = dev->of_node; int i; msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0); @@ -79,7 +80,7 @@ static int mop500_of_probe(struct platform_device *pdev, codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0); if (!(msp_np[0] && msp_np[1] && codec_np)) { - dev_err(&pdev->dev, "Phandle missing or invalid\n"); + dev_err(dev, "Phandle missing or invalid\n"); for (i = 0; i < 2; i++) of_node_put(msp_np[i]); of_node_put(codec_np); @@ -95,21 +96,20 @@ static int mop500_of_probe(struct platform_device *pdev, mop500_dai_links[i].codecs->name = NULL; } - snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name"); + snd_soc_of_parse_card_name(card, "stericsson,card-name"); return 0; } static int mop500_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; int ret; dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); mop500_card.dev = &pdev->dev; - ret = mop500_of_probe(pdev, np); + ret = mop500_of_probe(&mop500_card); if (ret) return ret; From 1ed8d136f77884bb32d7fd69491795e862aa3edd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:46:04 +0000 Subject: [PATCH 334/438] ASoC: ux500: mop500_ab8500: tidyup mop500_ab8500_remove() It sets drvdata again in remove(), but it want to remove it. void mop500_ab8500_remove(...) { struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card); ... snd_soc_card_set_drvdata(card, drvdata); } ^^^^^^^ Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87cxwhi083.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/ux500/mop500_ab8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index 2a459267f0f9..feb683c55d11 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -433,5 +433,5 @@ void mop500_ab8500_remove(struct snd_soc_card *card) clk_put(drvdata->clk_ptr_ulpclk); clk_put(drvdata->clk_ptr_intclk); - snd_soc_card_set_drvdata(card, drvdata); + snd_soc_card_set_drvdata(card, NULL); } From 522d7baa39e913700782cd22514ec04ac80ca036 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 21 Jul 2026 15:54:42 -0700 Subject: [PATCH 335/438] ASoC: fsl: dma: use platform helpers and devm cleanup Convert fsl_soc_dma_probe() to managed APIs. Replace the open-coded of_address_to_resource()/of_iomap() of the DMA channel registers with devm_platform_ioremap_resource(), and irq_of_parse_and_map() with platform_get_irq() (which returns a negative errno instead of 0). Switch the allocation to devm_kzalloc() and register the component via the devm variant, dropping the now-unneeded error-path cleanup and the manual fsl_soc_dma_remove(). The SSI node's register resource is still read via of_address_to_resource() to compute the SSI FIFO physical addresses (dma->ssi_stx_phys / ssi_srx_phys); only the DMA controller window is mapped. The DMA controller register window is owned solely by this driver, so the new region request from devm_platform_ioremap_resource() cannot conflict with another claimant, and it is mapped exactly once (no double mapping). The local channel pointer is declared as void __iomem * so the devm_platform_ioremap_resource() result can be stored before assignment to dma->channel. No functional change; built for powerpc (allmodconfig + CONFIG_SND_SOC_FSL_DMA) with LLVM=1 and sound/soc/fsl/fsl_dma.o compiles cleanly. Assisted-by: opencode:hy3-free Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260721225442.817787-1-rosenp@gmail.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 68 ++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index b12474880185..b1b341132dd6 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include @@ -824,9 +822,34 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct device_node *ssi_np; struct resource res; + void __iomem *channel; const uint32_t *iprop; + int irq; int ret; + channel = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(channel)) + return PTR_ERR(channel); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + dma->dai.name = DRV_NAME; + dma->dai.open = fsl_dma_open; + dma->dai.close = fsl_dma_close; + dma->dai.hw_params = fsl_dma_hw_params; + dma->dai.hw_free = fsl_dma_hw_free; + dma->dai.pointer = fsl_dma_pointer; + dma->dai.pcm_new = fsl_dma_new; + + dma->channel = channel; + dma->irq = irq; + /* Find the SSI node that points to us. */ ssi_np = find_ssi_node(np); if (!ssi_np) { @@ -842,55 +865,19 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) return ret; } - dma = kzalloc_obj(*dma); - if (!dma) { - of_node_put(ssi_np); - return -ENOMEM; - } - - dma->dai.name = DRV_NAME; - dma->dai.open = fsl_dma_open; - dma->dai.close = fsl_dma_close; - dma->dai.hw_params = fsl_dma_hw_params; - dma->dai.hw_free = fsl_dma_hw_free; - dma->dai.pointer = fsl_dma_pointer; - dma->dai.pcm_new = fsl_dma_new; - /* Store the SSI-specific information that we need */ dma->ssi_stx_phys = res.start + REG_SSI_STX0; dma->ssi_srx_phys = res.start + REG_SSI_SRX0; iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); + of_node_put(ssi_np); if (iprop) dma->ssi_fifo_depth = be32_to_cpup(iprop); else /* Older 8610 DTs didn't have the fifo-depth property */ dma->ssi_fifo_depth = 8; - of_node_put(ssi_np); - - ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); - if (ret) { - dev_err(&pdev->dev, "could not register platform\n"); - kfree(dma); - return ret; - } - - dma->channel = of_iomap(np, 0); - dma->irq = irq_of_parse_and_map(np, 0); - - dev_set_drvdata(&pdev->dev, dma); - - return 0; -} - -static void fsl_soc_dma_remove(struct platform_device *pdev) -{ - struct dma_object *dma = dev_get_drvdata(&pdev->dev); - - iounmap(dma->channel); - irq_dispose_mapping(dma->irq); - kfree(dma); + return devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); } static const struct of_device_id fsl_soc_dma_ids[] = { @@ -905,7 +892,6 @@ static struct platform_driver fsl_soc_dma_driver = { .of_match_table = fsl_soc_dma_ids, }, .probe = fsl_soc_dma_probe, - .remove = fsl_soc_dma_remove, }; module_platform_driver(fsl_soc_dma_driver); From ef9c8eb307046afa797befd84e6c741cd8954dfc Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 16 Jul 2026 14:15:36 +0800 Subject: [PATCH 336/438] ASoC: rt1320-sdw: Add settings to support more base clock frequency Add settings to support more base clock frequency on different platform. Signed-off-by: Jack Yu Link: https://patch.msgid.link/20260716061536.1563252-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1320-sdw.c | 36 ++++++++++++++++++++++++++++++++++- sound/soc/codecs/rt1320-sdw.h | 7 +++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index a30fb575918d..3a5eebcfefdd 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -836,6 +836,7 @@ static const struct reg_default rt1320_mbq_defaults[] = { static bool rt1320_readable_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0x004d: case 0xc000 ... 0xc086: case 0xc400 ... 0xc409: case 0xc480 ... 0xc48f: @@ -946,6 +947,7 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) static bool rt1320_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0x004d: case 0xc000: case 0xc003: case 0xc081: @@ -3383,6 +3385,37 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, return 0; } +static int rt1320_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev); + unsigned int clk_base; + + regmap_read(rt1320->regmap, 0x004d, &clk_base); + dev_dbg(&rt1320->sdw_slave->dev, "%s clk_base=%x", __func__, clk_base); + + switch (clk_base) { + case RT1320_CLK_FREQ_19_2_MHZ: + case RT1320_CLK_FREQ_24MHZ: + regmap_write(rt1320->regmap, 0xc600, 0x04); + regmap_write(rt1320->regmap, 0xc601, 0x83); + regmap_write(rt1320->regmap, 0xc602, 0x1f); + regmap_write(rt1320->regmap, 0xc603, 0x40); + break; + case RT1320_CLK_FREQ_24_576MHZ: + case RT1320_CLK_FREQ_22_5792MHZ: + regmap_write(rt1320->regmap, 0xc600, 0x07); + regmap_write(rt1320->regmap, 0xc601, 0x80); + regmap_write(rt1320->regmap, 0xc602, 0x0f); + regmap_write(rt1320->regmap, 0xc603, 0x40); + break; + default: + return -EINVAL; + } + + return 0; +} + /* * slave_ops: callbacks for get_clock_stop_mode, clock_stop and * port_prep are not defined for now @@ -3390,12 +3423,13 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, static const struct sdw_slave_ops rt1320_slave_ops = { .read_prop = rt1320_read_prop, .update_status = rt1320_update_status, + .bus_config = rt1320_bus_config, }; static int rt1320_sdw_component_probe(struct snd_soc_component *component) { - int ret; struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + int ret; rt1320->component = component; diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index bc0f78e03529..df9ccdf92d36 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -175,6 +175,13 @@ enum rt1320_rw_type { RT1320_PARAM_READ = 3, }; +enum { + RT1320_CLK_FREQ_19_2_MHZ = 1, + RT1320_CLK_FREQ_24MHZ = 2, + RT1320_CLK_FREQ_24_576MHZ = 3, + RT1320_CLK_FREQ_22_5792MHZ = 4, +}; + struct rt1320_sdw_priv { struct snd_soc_component *component; struct regmap *regmap; From 596f78db19528b8007fe5515d479babdc99c8455 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 19 Jul 2026 17:10:54 -0700 Subject: [PATCH 337/438] ASoC: amd: acp: Use pcim_iomap_region() in acp-pci Convert acp-pci to the pcim-managed PCI life-cycle. Replace pci_enable_device() with pcim_enable_device() and fold the open-coded pci_request_regions() + devm_ioremap() pair into a single pcim_iomap_region() call for BAR0, which reserves and iomaps the register window. This lets the driver drop the manual pci_release_regions() and pci_disable_device() calls from the probe error path; pcim releases the device and region automatically on detach or probe failure. The error check moves from a NULL test to IS_ERR(), since pcim_iomap_region() returns an IOMEM_ERR_PTR on failure. The child platform devices only use devm_ioremap() on their sub-range of BAR0 (no request_mem_region), so reserving the full BAR0 here does not conflict with them. Assisted-by: opencode:hy3-free Signed-off-by: Rosen Penev Link: https://patch.msgid.link/20260720001054.1439409-1-rosenp@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/acp/acp-pci.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index f83708755ed1..98771323eace 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -118,17 +118,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id if (!chip) return -ENOMEM; - if (pci_enable_device(pci)) + if (pcim_enable_device(pci)) return dev_err_probe(&pci->dev, -ENODEV, "pci_enable_device failed\n"); - ret = pci_request_regions(pci, "AMD ACP3x audio"); - if (ret < 0) { - dev_err(&pci->dev, "pci_request_regions failed\n"); - ret = -ENOMEM; - goto disable_pci; - } - pci_set_master(pci); chip->acp_rev = pci->revision; @@ -161,24 +154,21 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); - ret = -EINVAL; - goto release_regions; + return -EINVAL; } chip->flag = flag; addr = pci_resource_start(pci, 0); - chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); - if (!chip->base) { - ret = -ENOMEM; - goto release_regions; - } + chip->base = pcim_iomap_region(pci, 0, "AMD ACP3x audio"); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); chip->addr = addr; chip->acp_hw_ops_init(chip); ret = acp_hw_init(chip); if (ret) - goto release_regions; + goto de_init; ret = devm_request_irq(dev, pci->irq, irq_handler, IRQF_SHARED, "ACP_I2S_IRQ", chip); @@ -214,10 +204,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id de_init: acp_hw_deinit(chip); -release_regions: - pci_release_regions(pci); -disable_pci: - pci_disable_device(pci); return ret; }; From 65ebc8347a9cfdbf6133adfb018c7243ce5d30f6 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 23 Jul 2026 18:10:11 +0700 Subject: [PATCH 338/438] ASoC: starfive: jh7110-pwmdac: Remove unnecessary goto The error path after jh7110_pwmdac_runtime_resume() failure only performs a single cleanup operation before returning. Remove the unnecessary goto and return directly after calling pm_runtime_disable(), simplifying the control flow without changing the behavior. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260723111014.54071-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_pwmdac.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/starfive/jh7110_pwmdac.c b/sound/soc/starfive/jh7110_pwmdac.c index a603dd17931c..562936981cf0 100644 --- a/sound/soc/starfive/jh7110_pwmdac.c +++ b/sound/soc/starfive/jh7110_pwmdac.c @@ -486,16 +486,13 @@ static int jh7110_pwmdac_probe(struct platform_device *pdev) pm_runtime_enable(dev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = jh7110_pwmdac_runtime_resume(&pdev->dev); - if (ret) - goto err_pm_disable; + if (ret) { + pm_runtime_disable(&pdev->dev); + return ret; + } } return 0; - -err_pm_disable: - pm_runtime_disable(&pdev->dev); - - return ret; } static void jh7110_pwmdac_remove(struct platform_device *pdev) From db233669245d967c76efb8a6e59a4f19903ca35b Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 23 Jul 2026 18:10:12 +0700 Subject: [PATCH 339/438] ASoC: starfive: jh7110-pwmdac: Drop redundant error messages The called functions already log failures where appropriate. Return the original error directly and avoid duplicate error messages. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260723111014.54071-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_pwmdac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/starfive/jh7110_pwmdac.c b/sound/soc/starfive/jh7110_pwmdac.c index 562936981cf0..5953c3a4e373 100644 --- a/sound/soc/starfive/jh7110_pwmdac.c +++ b/sound/soc/starfive/jh7110_pwmdac.c @@ -477,11 +477,11 @@ static int jh7110_pwmdac_probe(struct platform_device *pdev) &jh7110_pwmdac_component, &jh7110_pwmdac_dai, 1); if (ret) - return dev_err_probe(&pdev->dev, ret, "failed to register dai\n"); + return ret; ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) - return dev_err_probe(&pdev->dev, ret, "failed to register pcm\n"); + return ret; pm_runtime_enable(dev->dev); if (!pm_runtime_enabled(&pdev->dev)) { From de621dacea09c2417b3a6995c61ecdfba72fd485 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 23 Jul 2026 18:10:13 +0700 Subject: [PATCH 340/438] ASoC: starfive: jh7110_tdm: Remove unnecessary goto The error path after jh7110_tdm_runtime_resume() failure only performs a single cleanup operation before returning. Remove the unnecessary goto and return directly after calling pm_runtime_disable(), simplifying the control flow without changing the behavior. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260723111014.54071-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_tdm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index afdcde7df91a..5365ebe44471 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -615,16 +615,13 @@ static int jh7110_tdm_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = jh7110_tdm_runtime_resume(&pdev->dev); - if (ret) - goto err_pm_disable; + if (ret) { + pm_runtime_disable(&pdev->dev); + return ret; + } } return 0; - -err_pm_disable: - pm_runtime_disable(&pdev->dev); - - return ret; } static void jh7110_tdm_dev_remove(struct platform_device *pdev) From 523c01b12ec141926ae39b9b538c2ca12e899225 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 23 Jul 2026 18:10:14 +0700 Subject: [PATCH 341/438] ASoC: starfive: jh7110_tdm: Drop redundant error messages The called functions already log failures where appropriate. Return the original error directly and avoid duplicate error messages. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260723111014.54071-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/starfive/jh7110_tdm.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index 5365ebe44471..f7522bfbe8e6 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -559,10 +559,8 @@ static int jh7110_tdm_clk_reset_get(struct platform_device *pdev, tdm->clks[5].id = "tdm"; ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks); - if (ret) { - dev_err(&pdev->dev, "Failed to get tdm clocks\n"); + if (ret) return ret; - } tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev); if (IS_ERR(tdm->resets)) { @@ -589,28 +587,22 @@ static int jh7110_tdm_probe(struct platform_device *pdev) tdm->dev = &pdev->dev; ret = jh7110_tdm_clk_reset_get(pdev, tdm); - if (ret) { - dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n"); + if (ret) return ret; - } jh7110_tdm_init_params(tdm); dev_set_drvdata(&pdev->dev, tdm); ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component, &jh7110_tdm_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Failed to register dai\n"); + if (ret) return ret; - } ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &jh7110_dmaengine_pcm_config, SND_DMAENGINE_PCM_FLAG_COMPAT); - if (ret) { - dev_err(&pdev->dev, "Could not register pcm: %d\n", ret); + if (ret) return ret; - } pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { From 088c4404b3d780c16bc8d49d3ea072043a750f10 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 28 Jul 2026 10:53:28 +0200 Subject: [PATCH 342/438] ASoC: qcom: sc8280xp: allow setting m2is clocks for SM8[456]50 boards Extend the sc8280xp card to add settings to setup I2S clock and line properties. Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260728-topic-sm8x50-next-hdk-i2s-v1-1-2393a0fe4aa9@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index a9304784d41e..c0a5dbda1185 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -360,6 +360,12 @@ static const struct snd_soc_common sm8450_priv_data = { .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, + /* I2S Connected to HDMI */ + .mi2s_mclk_enable = true, + .mi2s_bclk_enable = true, + .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S, }; static const struct snd_soc_common sm8550_priv_data = { @@ -367,6 +373,12 @@ static const struct snd_soc_common sm8550_priv_data = { .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, + /* I2S Connected to HDMI */ + .mi2s_mclk_enable = true, + .mi2s_bclk_enable = true, + .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S, }; static const struct snd_soc_common sm8650_priv_data = { @@ -374,6 +386,12 @@ static const struct snd_soc_common sm8650_priv_data = { .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, + /* I2S Connected to HDMI */ + .mi2s_mclk_enable = true, + .mi2s_bclk_enable = true, + .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S, }; static const struct snd_soc_common sm8750_priv_data = { From df3bdb5533314be6270699ef841d13363b7b1093 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Fri, 24 Jul 2026 18:25:43 +0800 Subject: [PATCH 343/438] ASoC: tas2781: Optimize calibration to avoid full device reboot after calibration Some clients have specified a new requirement: complete device restarts should be avoided after calibration. Only a hot boot of the Smart Audio Amplifier is required. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20260724102543.2067-1-shenghao-ding@ti.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-i2c.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 9e6f0ad5f05d..8eb9ead2951e 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -617,6 +617,7 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); + int i; guard(mutex)(&priv->codec_lock); if (priv->chip_id == TAS2563) @@ -624,6 +625,14 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, else tas2781_calib_stop_put(priv); + /* + * Set reloading-firmware flag after calibration, the flag will work + * during next playback, then set to the program id after reloading + * firmware. + */ + for (i = 0; i < priv->ndev; i++) + priv->tasdevice[i].cur_prog = -1; + return 1; } From c24f4797d8e59a7697d0c1152ece30c6bc9c3fc9 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 29 Jul 2026 11:22:27 +0800 Subject: [PATCH 344/438] ASoC: SDCA: export sdca_find_entity_by_label() helper Export the sdca_find_entity_by_label() helper so that codec drivers can locate SDCA entities by their labels. Signed-off-by: Shuming Fan Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20260729032227.3750770-1-shumingf@realtek.com Signed-off-by: Mark Brown --- include/sound/sdca_function.h | 2 ++ sound/soc/sdca/sdca_functions.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index b1489178b0ef..fb931ae735a2 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -1469,5 +1469,7 @@ struct sdca_control_range *sdca_selector_find_range(struct device *dev, struct sdca_cluster *sdca_id_find_cluster(struct device *dev, struct sdca_function_data *function, const int id); +struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function, + const char *entity_label); #endif diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 77940bd6b33c..d9703927325d 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -1617,7 +1617,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, return 0; } -static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function, +struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function, const char *entity_label) { struct sdca_entity *entity = NULL; @@ -1646,6 +1646,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data * return NULL; } +EXPORT_SYMBOL_NS(sdca_find_entity_by_label, "SND_SOC_SDCA"); static struct sdca_entity *find_sdca_entity_by_id(struct sdca_function_data *function, const int id) @@ -1686,7 +1687,7 @@ static int find_sdca_entity_connection_iot(struct device *dev, return ret; } - clock_entity = find_sdca_entity_by_label(function, clock_label); + clock_entity = sdca_find_entity_by_label(function, clock_label); if (!clock_entity) { dev_err(dev, "%s: failed to find clock with label %s\n", entity->label, clock_label); @@ -1871,7 +1872,7 @@ static int find_sdca_entity_connection(struct device *dev, return ret; } - connected_entity = find_sdca_entity_by_label(function, connected_label); + connected_entity = sdca_find_entity_by_label(function, connected_label); if (!connected_entity) { dev_err(dev, "%s: failed to find entity with label %s\n", entity->label, connected_label); From 772e3409961f155d023855d02946ce6e8287593d Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 29 Jul 2026 11:22:37 +0800 Subject: [PATCH 345/438] ASoC: SDCA: export sdca_asoc_populate_rate_format() helper Export populate_rate_format() as sdca_asoc_populate_rate_format() so that it can be used by codec drivers. The codec driver could get rate and format information for the IT/OT entity. Signed-off-by: Shuming Fan Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20260729032237.3750805-1-shumingf@realtek.com Signed-off-by: Mark Brown --- include/sound/sdca_asoc.h | 7 +++++++ sound/soc/sdca/sdca_asoc.c | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h index ca35d5a44370..d3024c3b38b9 100644 --- a/include/sound/sdca_asoc.h +++ b/include/sound/sdca_asoc.h @@ -25,6 +25,8 @@ struct snd_soc_dai_driver; struct snd_soc_dai_ops; struct snd_soc_dapm_route; struct snd_soc_dapm_widget; +struct snd_soc_pcm_stream; +struct sdca_entity; /* convenient macro to handle the mono volume in 7.8 fixed format representation */ #define SDCA_SINGLE_Q78_TLV(xname, xreg, xmin, xmax, xstep, tlv_array) \ @@ -82,6 +84,11 @@ int sdca_asoc_populate_component(struct device *dev, struct snd_soc_dai_driver **dai_drv, int *num_dai_drv, const struct snd_soc_dai_ops *ops); +int sdca_asoc_populate_rate_format(struct device *dev, + struct sdca_function_data *function, + struct sdca_entity *entity, + struct snd_soc_pcm_stream *stream); + int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap, struct sdca_function_data *function, struct snd_pcm_substream *substream, diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index b4dedba719dc..9a6c0036b7be 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -1231,7 +1231,7 @@ static u64 width_find_mask(unsigned int bits) } } -static int populate_rate_format(struct device *dev, +int sdca_asoc_populate_rate_format(struct device *dev, struct sdca_function_data *function, struct sdca_entity *entity, struct snd_soc_pcm_stream *stream) @@ -1292,6 +1292,7 @@ static int populate_rate_format(struct device *dev, return 0; } +EXPORT_SYMBOL_NS(sdca_asoc_populate_rate_format, "SND_SOC_SDCA"); /** * sdca_asoc_populate_dais - fill in an array of DAI drivers for a Function @@ -1344,7 +1345,7 @@ int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *funct stream->channels_min = 1; stream->channels_max = SDCA_MAX_CHANNEL_COUNT; - ret = populate_rate_format(dev, function, entity, stream); + ret = sdca_asoc_populate_rate_format(dev, function, entity, stream); if (ret) return ret; From 4f08e2b888962d0265a3af10f1d11fbe3419280d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 29 Jul 2026 14:35:31 +0700 Subject: [PATCH 346/438] ASoC: sprd: sprd-mcdt: Drop redundant error messages The called functions already log failures where appropriate. Return the original error directly and avoid duplicate error messages. Signed-off-by: bui duc phuc Reviewed-by: Baolin Wang Link: https://patch.msgid.link/20260729073532.56468-1-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sprd/sprd-mcdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c index 5f3a2a7bce31..d9a7bbd6c0b6 100644 --- a/sound/soc/sprd/sprd-mcdt.c +++ b/sound/soc/sprd/sprd-mcdt.c @@ -931,10 +931,8 @@ static int sprd_mcdt_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler, 0, "sprd-mcdt", mcdt); - if (ret) { - dev_err(&pdev->dev, "Failed to request MCDT IRQ\n"); + if (ret) return ret; - } sprd_mcdt_init_chans(mcdt, res); From 595201d3910886e323733ea21b5517d7a751b8c1 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Wed, 29 Jul 2026 14:35:32 +0700 Subject: [PATCH 347/438] ASoC: sprd: sprd-pcm-dma: Drop redundant error messages The called functions already log failures where appropriate. Remove the error log here to avoid duplicate error messages. Signed-off-by: bui duc phuc Reviewed-by: Baolin Wang Link: https://patch.msgid.link/20260729073532.56468-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/sprd/sprd-pcm-dma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c index cbf5bf82d96e..f509a4601de2 100644 --- a/sound/soc/sprd/sprd-pcm-dma.c +++ b/sound/soc/sprd/sprd-pcm-dma.c @@ -469,8 +469,6 @@ static int sprd_soc_platform_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component, NULL, 0); - if (ret) - dev_err(&pdev->dev, "could not register platform:%d\n", ret); return ret; } From a95cfed54bf9970924a257e51d47a60810410c5d Mon Sep 17 00:00:00 2001 From: Esteban Urrutia Date: Wed, 29 Jul 2026 15:31:54 -0400 Subject: [PATCH 348/438] ASoC: dt-bindings: qcom,sm8250: Add compatible string for SM8475 Add compatible string for the sound card found in the SM8475 SoC. Signed-off-by: Esteban Urrutia Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260729-sm8475-asoc-v1-1-3edad8aa7628@proton.me Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index bd5f5a6268a3..d12ac528c33f 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -26,6 +26,7 @@ properties: - qcom,eliza-sndcard - qcom,hawi-sndcard - qcom,kaanapali-sndcard + - qcom,sm8475-sndcard - qcom,sm8550-sndcard - qcom,sm8650-sndcard - qcom,sm8750-sndcard From 1ad05292c01ba9f9c4a61921ef370b906608b6d9 Mon Sep 17 00:00:00 2001 From: Esteban Urrutia Date: Wed, 29 Jul 2026 15:31:55 -0400 Subject: [PATCH 349/438] ASoC: qcom: sc8280xp: Add support for SM8475 With this, SM8475 topologies can have their own firmware folder. Signed-off-by: Esteban Urrutia Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260729-sm8475-asoc-v1-2-3edad8aa7628@proton.me Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index a9304784d41e..f0f3cd8fca38 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -362,6 +362,13 @@ static const struct snd_soc_common sm8450_priv_data = { .wcd_jack = true, }; +static const struct snd_soc_common sm8475_priv_data = { + .driver_name = "sm8475", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + static const struct snd_soc_common sm8550_priv_data = { .driver_name = "sm8550", .dapm_widgets = sc8280xp_dapm_widgets, @@ -395,6 +402,7 @@ static const struct of_device_id snd_sc8280xp_dt_match[] = { { .compatible = "qcom,qcs9100-sndcard", .data = &qcs9100_priv_data }, { .compatible = "qcom,sc8280xp-sndcard", .data = &sc8280xp_priv_data }, { .compatible = "qcom,sm8450-sndcard", .data = &sm8450_priv_data }, + { .compatible = "qcom,sm8475-sndcard", .data = &sm8475_priv_data }, { .compatible = "qcom,sm8550-sndcard", .data = &sm8550_priv_data }, { .compatible = "qcom,sm8650-sndcard", .data = &sm8650_priv_data }, { .compatible = "qcom,sm8750-sndcard", .data = &sm8750_priv_data }, From abc7daad426ef93665ef6fbc1b3cd05a814e721e Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:50 +0200 Subject: [PATCH 350/438] ASoC: Intel: catpt: Wrap the store firmware-context procedure All store/restore firmware operations are located in the loader.c file. All except the "store firmware context" procedure which is manually called during the runtime suspend, device.c file. Adding a wrapper alters functional flow slightly - DMA channel is requested after the DXSTATE IPC rather than before it but this has no real impact on the procedure. At the same time, such approach limits number of symbols exposed in the core.h file and improves code cohesiveness: all catpt_dma_xxx() definitions in dsp.c, all their usages in loader.c. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/core.h | 4 +--- sound/soc/intel/catpt/device.c | 33 +++------------------------- sound/soc/intel/catpt/loader.c | 39 +++++++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h index 3881164422b8..f68807c454c9 100644 --- a/sound/soc/intel/catpt/core.h +++ b/sound/soc/intel/catpt/core.h @@ -139,9 +139,7 @@ int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request, int catpt_first_boot_firmware(struct catpt_dev *cdev); int catpt_boot_firmware(struct catpt_dev *cdev, bool restore); -int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan); -int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan); -int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan); +int catpt_store_firmware_context(struct catpt_dev *cdev); int catpt_coredump(struct catpt_dev *cdev); #include diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index b176aebea9d5..e36eea8b5408 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -28,44 +28,17 @@ static int catpt_do_suspend(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); - struct dma_chan *chan; int ret; - chan = catpt_dma_request_config_chan(cdev); - if (IS_ERR(chan)) - return PTR_ERR(chan); - memset(&cdev->dx_ctx, 0, sizeof(cdev->dx_ctx)); ret = catpt_ipc_enter_dxstate(cdev, CATPT_DX_STATE_D3, &cdev->dx_ctx); - if (ret) { - ret = CATPT_IPC_RET(ret); - goto release_dma_chan; - } - - ret = catpt_dsp_stall(cdev, true); if (ret) - goto release_dma_chan; + return CATPT_IPC_RET(ret); - ret = catpt_store_memdumps(cdev, chan); - if (ret) { - dev_err(cdev->dev, "store memdumps failed: %d\n", ret); - goto release_dma_chan; - } - - ret = catpt_store_module_states(cdev, chan); - if (ret) { - dev_err(cdev->dev, "store module states failed: %d\n", ret); - goto release_dma_chan; - } - - ret = catpt_store_streams_context(cdev, chan); - if (ret) - dev_err(cdev->dev, "store streams ctx failed: %d\n", ret); - -release_dma_chan: - dma_release_channel(chan); + ret = catpt_store_firmware_context(cdev); if (ret) return ret; + return catpt_dsp_power_down(cdev); } diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index c577f2e17ddf..880f62896997 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -81,7 +81,7 @@ catpt_request_region(struct resource *root, resource_size_t size) return __request_region(root, addr, size, NULL, 0); } -int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) +static int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) { struct catpt_stream_runtime *stream; @@ -108,7 +108,7 @@ int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) return 0; } -int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) +static int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) { int i; @@ -138,7 +138,7 @@ int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) return 0; } -int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) +static int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) { int i; @@ -171,6 +171,39 @@ int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) return 0; } +int catpt_store_firmware_context(struct catpt_dev *cdev) +{ + struct dma_chan *chan; + int ret; + + chan = catpt_dma_request_config_chan(cdev); + if (IS_ERR(chan)) + return PTR_ERR(chan); + + ret = catpt_dsp_stall(cdev, true); + if (ret) + goto exit; + + ret = catpt_store_memdumps(cdev, chan); + if (ret) { + dev_err(cdev->dev, "store memdumps failed: %d\n", ret); + goto exit; + } + + ret = catpt_store_module_states(cdev, chan); + if (ret) { + dev_err(cdev->dev, "store module states failed: %d\n", ret); + goto exit; + } + + ret = catpt_store_streams_context(cdev, chan); + if (ret) + dev_err(cdev->dev, "store streams ctx failed: %d\n", ret); +exit: + dma_release_channel(chan); + return ret; +} + static int catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) { From 05d3ba6258026e2c8c9feefefd63ebc82319a301 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:51 +0200 Subject: [PATCH 351/438] ASoC: Intel: catpt: Drop redundant else-if If the preceding if-statement ends with return, there is no need for else-if. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-3-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/loader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 880f62896997..79742dceef53 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -652,10 +652,10 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore) if (!ret) { dev_err(cdev->dev, "firmware ready timeout\n"); return -ETIMEDOUT; - /* Wake up does not mean FW is ready, an exception could occur. */ - } else if (!cdev->ipc.ready) { - return -EREMOTEIO; } + /* Wake up does not mean FW is ready, an exception could occur. */ + if (!cdev->ipc.ready) + return -EREMOTEIO; /* update sram pg & clock once done booting */ catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); From f6c65bf0acc99079e5a9b43d4079ee2a8fe68332 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:52 +0200 Subject: [PATCH 352/438] ASoC: Intel: catpt: Drop redundant signature argument Initial design assumed the mechanism could be reused for loading external modules with signatures differing from the Intel's constant. No users with such characteristics ever appeared rendering the 'signature' argument useless. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-4-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/loader.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 79742dceef53..775781489ded 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -569,8 +569,7 @@ static int catpt_load_firmware(struct catpt_dev *cdev, } static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, - const char *name, const char *signature, - bool restore) + const char *name, bool restore) { struct catpt_fw_hdr *fw; struct firmware *img; @@ -583,7 +582,7 @@ static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, return ret; fw = (struct catpt_fw_hdr *)img->data; - if (strncmp(fw->signature, signature, FW_SIGNATURE_SIZE)) { + if (strncmp(fw->signature, FW_SIGNATURE, FW_SIGNATURE_SIZE)) { dev_err(cdev->dev, "firmware signature mismatch\n"); ret = -EINVAL; goto release_fw; @@ -617,8 +616,7 @@ static int catpt_load_images(struct catpt_dev *cdev, bool restore) if (IS_ERR(chan)) return PTR_ERR(chan); - ret = catpt_load_image(cdev, chan, cdev->spec->fw_name, - FW_SIGNATURE, restore); + ret = catpt_load_image(cdev, chan, cdev->spec->fw_name, restore); if (ret) goto release_dma_chan; From 71d1229972e2fc298dff3b40e0b81a11544a8caf Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:53 +0200 Subject: [PATCH 353/438] ASoC: Intel: catpt: Rename module header struct Goal is to match the name of its equivalent on the firmware side. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-5-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/loader.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 775781489ded..06c8b043e292 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -26,7 +26,7 @@ struct catpt_fw_hdr { u32 reserved[4]; } __packed; -struct catpt_fw_mod_hdr { +struct catpt_fw_module_hdr { char signature[FW_SIGNATURE_SIZE]; u32 mod_size; u32 blocks; @@ -357,7 +357,7 @@ static int catpt_load_block(struct catpt_dev *cdev, static int catpt_restore_basefw(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, - struct catpt_fw_mod_hdr *basefw) + struct catpt_fw_module_hdr *basefw) { u32 offset = sizeof(*basefw); int ret, i; @@ -400,7 +400,7 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, static int catpt_restore_module(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, - struct catpt_fw_mod_hdr *mod) + struct catpt_fw_module_hdr *mod) { u32 offset = sizeof(*mod); int i; @@ -441,7 +441,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, static int catpt_load_module(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, - struct catpt_fw_mod_hdr *mod) + struct catpt_fw_module_hdr *mod) { struct catpt_module_type *type; u32 offset = sizeof(*mod); @@ -497,10 +497,10 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, fw, sizeof(*fw), false); for (i = 0; i < fw->modules; i++) { - struct catpt_fw_mod_hdr *mod; + struct catpt_fw_module_hdr *mod; int ret; - mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset); + mod = (struct catpt_fw_module_hdr *)((u8 *)fw + offset); if (strncmp(fw->signature, mod->signature, FW_SIGNATURE_SIZE)) { dev_err(cdev->dev, "module signature mismatch\n"); @@ -543,10 +543,10 @@ static int catpt_load_firmware(struct catpt_dev *cdev, fw, sizeof(*fw), false); for (i = 0; i < fw->modules; i++) { - struct catpt_fw_mod_hdr *mod; + struct catpt_fw_module_hdr *mod; int ret; - mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset); + mod = (struct catpt_fw_module_hdr *)((u8 *)fw + offset); if (strncmp(fw->signature, mod->signature, FW_SIGNATURE_SIZE)) { dev_err(cdev->dev, "module signature mismatch\n"); From e692a538a421602743df8d479631b55ea7d8cea4 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:54 +0200 Subject: [PATCH 354/438] ASoC: Intel: catpt: Rename firmware loading functions To make the firmware loading proceduce easier to understand, especially around restoring DRAM context, rename the following: catpt_load_images -> catpt_request_dma_load_firmware catpt_load_image -> catpt_request_load_firmware catpt_restore_fwimage -> catpt_restore_dram_rodata catpt_restore_memdumps -> catpt_restore_dram_data catpt_store_memdumps -> catpt_store_dram_data For the exact same reason, update a number of comments related to the subject. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-6-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/loader.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 06c8b043e292..274af8fb8828 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -138,7 +138,7 @@ static int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *ch return 0; } -static int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) +static int catpt_store_dram_data(struct catpt_dev *cdev, struct dma_chan *chan) { int i; @@ -184,7 +184,7 @@ int catpt_store_firmware_context(struct catpt_dev *cdev) if (ret) goto exit; - ret = catpt_store_memdumps(cdev, chan); + ret = catpt_store_dram_data(cdev, chan); if (ret) { dev_err(cdev->dev, "store memdumps failed: %d\n", ret); goto exit; @@ -232,7 +232,7 @@ catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) return 0; } -static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) +static int catpt_restore_dram_data(struct catpt_dev *cdev, struct dma_chan *chan) { int i; @@ -267,9 +267,9 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) return 0; } -static int catpt_restore_fwimage(struct catpt_dev *cdev, - struct dma_chan *chan, dma_addr_t paddr, - struct catpt_fw_block_hdr *blk) +static int catpt_restore_dram_rodata(struct catpt_dev *cdev, + struct dma_chan *chan, dma_addr_t paddr, + struct catpt_fw_block_hdr *blk) { struct resource r1 = {}; int i; @@ -365,7 +365,7 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, basefw, sizeof(*basefw), false); - /* restore basefw image */ + /* Restore IRAM and .rodata for DRAM based on the firmware image. */ for (i = 0; i < basefw->blocks; i++) { struct catpt_fw_block_hdr *blk; @@ -377,8 +377,8 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, blk, false); break; default: - ret = catpt_restore_fwimage(cdev, chan, paddr + offset, - blk); + ret = catpt_restore_dram_rodata(cdev, chan, paddr + offset, + blk); break; } @@ -390,8 +390,8 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, offset += sizeof(*blk) + blk->size; } - /* then proceed with memory dumps */ - ret = catpt_restore_memdumps(cdev, chan); + /* Then proceed with DRAM .data saved before D3. */ + ret = catpt_restore_dram_data(cdev, chan); if (ret) dev_err(cdev->dev, "restore memdumps failed: %d\n", ret); @@ -568,8 +568,8 @@ static int catpt_load_firmware(struct catpt_dev *cdev, return 0; } -static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, - const char *name, bool restore) +static int catpt_request_load_firmware(struct catpt_dev *cdev, struct dma_chan *chan, + const char *name, bool restore) { struct catpt_fw_hdr *fw; struct firmware *img; @@ -607,7 +607,7 @@ static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, return ret; } -static int catpt_load_images(struct catpt_dev *cdev, bool restore) +static int catpt_request_dma_load_firmware(struct catpt_dev *cdev, bool restore) { struct dma_chan *chan; int ret; @@ -616,7 +616,7 @@ static int catpt_load_images(struct catpt_dev *cdev, bool restore) if (IS_ERR(chan)) return PTR_ERR(chan); - ret = catpt_load_image(cdev, chan, cdev->spec->fw_name, restore); + ret = catpt_request_load_firmware(cdev, chan, cdev->spec->fw_name, restore); if (ret) goto release_dma_chan; @@ -636,7 +636,7 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore) catpt_dsp_stall(cdev, true); - ret = catpt_load_images(cdev, restore); + ret = catpt_request_dma_load_firmware(cdev, restore); if (ret) { dev_err(cdev->dev, "load binaries failed: %d\n", ret); return ret; From ae6540c4909a0f347c43d0b996c512360867f539 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:55 +0200 Subject: [PATCH 355/438] ASoC: Intel: catpt: Streamline wording of offset variables Two words represent is currently: 'offset' and 'off'. Be cohesive and use one instead. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-7-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/loader.c | 48 ++++++++++++++++------------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index 274af8fb8828..e7ba9e1e60ae 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -359,7 +359,7 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, struct catpt_fw_module_hdr *basefw) { - u32 offset = sizeof(*basefw); + u32 off = sizeof(*basefw); int ret, i; print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, @@ -369,16 +369,14 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, for (i = 0; i < basefw->blocks; i++) { struct catpt_fw_block_hdr *blk; - blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + offset); + blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + off); switch (blk->ram_type) { case CATPT_RAM_TYPE_IRAM: - ret = catpt_load_block(cdev, chan, paddr + offset, - blk, false); + ret = catpt_load_block(cdev, chan, paddr + off, blk, false); break; default: - ret = catpt_restore_dram_rodata(cdev, chan, paddr + offset, - blk); + ret = catpt_restore_dram_rodata(cdev, chan, paddr + off, blk); break; } @@ -387,7 +385,7 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, return ret; } - offset += sizeof(*blk) + blk->size; + off += sizeof(*blk) + blk->size; } /* Then proceed with DRAM .data saved before D3. */ @@ -402,7 +400,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, struct catpt_fw_module_hdr *mod) { - u32 offset = sizeof(*mod); + u32 off = sizeof(*mod); int i; print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, @@ -412,7 +410,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, struct catpt_fw_block_hdr *blk; int ret; - blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset); + blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off); switch (blk->ram_type) { case CATPT_RAM_TYPE_INSTANCE: @@ -423,7 +421,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, ALIGN(blk->size, 4)); break; default: - ret = catpt_load_block(cdev, chan, paddr + offset, + ret = catpt_load_block(cdev, chan, paddr + off, blk, false); break; } @@ -433,7 +431,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, return ret; } - offset += sizeof(*blk) + blk->size; + off += sizeof(*blk) + blk->size; } return 0; @@ -444,7 +442,7 @@ static int catpt_load_module(struct catpt_dev *cdev, struct catpt_fw_module_hdr *mod) { struct catpt_module_type *type; - u32 offset = sizeof(*mod); + u32 off = sizeof(*mod); int i; print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, @@ -456,9 +454,9 @@ static int catpt_load_module(struct catpt_dev *cdev, struct catpt_fw_block_hdr *blk; int ret; - blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset); + blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off); - ret = catpt_load_block(cdev, chan, paddr + offset, blk, true); + ret = catpt_load_block(cdev, chan, paddr + off, blk, true); if (ret) { dev_err(cdev->dev, "load block failed: %d\n", ret); return ret; @@ -473,7 +471,7 @@ static int catpt_load_module(struct catpt_dev *cdev, type->state_size = blk->size; } - offset += sizeof(*blk) + blk->size; + off += sizeof(*blk) + blk->size; } /* init module type static info */ @@ -490,7 +488,7 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, struct catpt_fw_hdr *fw) { - u32 offset = sizeof(*fw); + u32 off = sizeof(*fw); int i; print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, @@ -500,7 +498,7 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, struct catpt_fw_module_hdr *mod; int ret; - mod = (struct catpt_fw_module_hdr *)((u8 *)fw + offset); + mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off); if (strncmp(fw->signature, mod->signature, FW_SIGNATURE_SIZE)) { dev_err(cdev->dev, "module signature mismatch\n"); @@ -512,12 +510,10 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, switch (mod->module_id) { case CATPT_MODID_BASE_FW: - ret = catpt_restore_basefw(cdev, chan, paddr + offset, - mod); + ret = catpt_restore_basefw(cdev, chan, paddr + off, mod); break; default: - ret = catpt_restore_module(cdev, chan, paddr + offset, - mod); + ret = catpt_restore_module(cdev, chan, paddr + off, mod); break; } @@ -526,7 +522,7 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, return ret; } - offset += sizeof(*mod) + mod->mod_size; + off += sizeof(*mod) + mod->mod_size; } return 0; @@ -536,7 +532,7 @@ static int catpt_load_firmware(struct catpt_dev *cdev, struct dma_chan *chan, dma_addr_t paddr, struct catpt_fw_hdr *fw) { - u32 offset = sizeof(*fw); + u32 off = sizeof(*fw); int i; print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, @@ -546,7 +542,7 @@ static int catpt_load_firmware(struct catpt_dev *cdev, struct catpt_fw_module_hdr *mod; int ret; - mod = (struct catpt_fw_module_hdr *)((u8 *)fw + offset); + mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off); if (strncmp(fw->signature, mod->signature, FW_SIGNATURE_SIZE)) { dev_err(cdev->dev, "module signature mismatch\n"); @@ -556,13 +552,13 @@ static int catpt_load_firmware(struct catpt_dev *cdev, if (mod->module_id > CATPT_MODID_LAST) return -EINVAL; - ret = catpt_load_module(cdev, chan, paddr + offset, mod); + ret = catpt_load_module(cdev, chan, paddr + off, mod); if (ret) { dev_err(cdev->dev, "load module failed: %d\n", ret); return ret; } - offset += sizeof(*mod) + mod->mod_size; + off += sizeof(*mod) + mod->mod_size; } return 0; From a0acf55be73414db280372e2ad5aae705b9de403 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:56 +0200 Subject: [PATCH 356/438] ASoC: Intel: catpt: Streamline runtime-variables naming Mimic naming pattern commonly found in the ASoC code: - 'rtd' in case of struct snd_soc_pcm_runtime - 'runtime' in case of struct snd_pcm_runtime Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-8-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/pcm.c | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 8fb0efb67eb1..12a5226cf12c 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -75,8 +75,8 @@ static struct catpt_stream_template *catpt_topology[] = { static struct catpt_stream_template * catpt_get_stream_template(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); enum catpt_stream_type type; type = cpu_dai->driver->id; @@ -159,11 +159,11 @@ static void catpt_stream_read_position(struct catpt_dev *cdev, static void catpt_arrange_page_table(struct snd_pcm_substream *substream, struct snd_dma_buffer *pgtbl) { - struct snd_pcm_runtime *rtm = substream->runtime; + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream); int i, pages; - pages = snd_sgbuf_aligned_pages(rtm->dma_bytes); + pages = snd_sgbuf_aligned_pages(runtime->dma_bytes); for (i = 0; i < pages; i++) { u32 pfn, offset; @@ -386,7 +386,7 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_pcm_runtime *rtm = substream->runtime; + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dma_buffer *dmab; struct catpt_stream_runtime *stream; struct catpt_audio_format afmt; @@ -412,8 +412,8 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, memset(&rinfo, 0, sizeof(rinfo)); rinfo.page_table_addr = stream->pgtbl.addr; - rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE); - rinfo.size = rtm->dma_bytes; + rinfo.num_pages = DIV_ROUND_UP(runtime->dma_bytes, PAGE_SIZE); + rinfo.size = runtime->dma_bytes; rinfo.offset = 0; rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0)); @@ -544,11 +544,11 @@ void catpt_stream_update_position(struct catpt_dev *cdev, struct catpt_notify_position *pos) { struct snd_pcm_substream *substream = stream->substream; - struct snd_pcm_runtime *r = substream->runtime; + struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t dsppos, newpos; int ret; - dsppos = bytes_to_frames(r, pos->stream_position); + dsppos = bytes_to_frames(runtime, pos->stream_position); if (!stream->prepared) goto exit; @@ -556,8 +556,8 @@ void catpt_stream_update_position(struct catpt_dev *cdev, if (stream->template->type != CATPT_STRM_TYPE_RENDER) goto exit; - if (dsppos >= r->buffer_size / 2) - newpos = r->buffer_size / 2; + if (dsppos >= runtime->buffer_size / 2) + newpos = runtime->buffer_size / 2; else newpos = 0; /* @@ -565,7 +565,7 @@ void catpt_stream_update_position(struct catpt_dev *cdev, * (buffer half consumed) update wp to allow stream progression. */ ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id, - frames_to_bytes(r, newpos), + frames_to_bytes(runtime, newpos), false, false); if (ret) { dev_err(cdev->dev, "update position for stream %d failed: %d\n", @@ -600,11 +600,11 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = { }; static int catpt_component_pcm_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtm) + struct snd_soc_pcm_runtime *rtd) { struct catpt_dev *cdev = dev_get_drvdata(component->dev); - snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV_SG, cdev->dev, catpt_pcm_hardware.buffer_bytes_max, catpt_pcm_hardware.buffer_bytes_max); @@ -615,9 +615,9 @@ static int catpt_component_pcm_new(struct snd_soc_component *component, static int catpt_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - if (!rtm->dai_link->no_pcm) + if (!rtd->dai_link->no_pcm) snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware); return 0; } @@ -626,13 +626,13 @@ static snd_pcm_uframes_t catpt_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct catpt_stream_runtime *stream; struct catpt_dev *cdev = dev_get_drvdata(component->dev); u32 pos; - if (rtm->dai_link->no_pcm) + if (rtd->dai_link->no_pcm) return 0; stream = snd_soc_dai_get_dma_data(cpu_dai, substream); @@ -650,10 +650,10 @@ static const struct snd_soc_dai_ops catpt_fe_dai_ops = { .trigger = catpt_dai_trigger, }; -static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, +static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtm, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct catpt_ssp_device_format devfmt; struct catpt_dev *cdev = dev_get_drvdata(dai->dev); int ret; From 4075b9d256ef5c22688e2ae812c1b89ac791182a Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 29 Jul 2026 13:00:57 +0200 Subject: [PATCH 357/438] ASoC: Intel: catpt: Streamline control-variables naming Two naming patterns exist currently in the code: 'kcontrol' and 'kctl'. Pick one and stick with it. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260729110057.342447-9-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/catpt/pcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 12a5226cf12c..f23c580ba051 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -871,8 +871,7 @@ static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol) return CATPT_IPC_RET(ret); } -static int catpt_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int catpt_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = CATPT_CHANNELS_MAX; From c50ed4627e333934aaf0473a822169786c83dce5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 11:24:44 +0300 Subject: [PATCH 358/438] ASoC: SOF: ipc4: Add decoder for RESOURCE_EVENT notifications from firmware Decode and print out the content of currently supported RESOURCE_EVENT notifications from firmware along with the needed data structures and definitions. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730082444.4828-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 53 ++++++++++++++++++++- sound/soc/sof/ipc4.c | 84 +++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 4554e5e8cab5..e747741f35c0 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -536,12 +536,63 @@ enum sof_ipc4_notification_type { SOF_IPC4_NOTIFY_TYPE_LAST, }; +enum sof_ipc4_resource_type { + SOF_IPC4_MODULE_INSTANCE, + SOF_IPC4_PIPELINE, + SOF_IPC4_GATEWAY, + SOF_IPC4_EDF_TASK, + SOF_IPC4_INVALID_RESOURCE_TYPE, +}; + +enum sof_ipc4_event_type { + /* Underrun detected by the Mixer */ + SOF_IPC4_MIXER_UNDERRUN_DETECTED = 1, + /* Error caught during data processing */ + SOF_IPC4_PROCESS_DATA_ERROR = 3, + /* Underrun detected by gateway. */ + SOF_IPC4_GATEWAY_UNDERRUN_DETECTED = 6, + /* Overrun detected by gateway */ + SOF_IPC4_GATEWAY_OVERRUN_DETECTED, +}; + +/** + * struct sof_ipc4_process_data_error_event_data - process data error event payload + * @error_code: Error code returned by data processing function + */ +struct sof_ipc4_process_data_error_event_data { + uint32_t error_code; +}; + +/** + * struct sof_ipc4_mixer_underrun_event_data - mixer underrun event payload + * @eos_flag: Indicates EndOfStream + * @data_mixed: Data processed by module (in bytes) + * @expected_data_mixed: Expected data to be processed (in bytes) + */ +struct sof_ipc4_mixer_underrun_event_data { + uint32_t eos_flag; + uint32_t data_mixed; + uint32_t expected_data_mixed; +}; + +/** + * union sof_ipc4_resource_event_data - resource event specific payload + * @dws: Raw event data payload as six dwords + * @process_data_error: SOF_IPC4_PROCESS_DATA_ERROR payload + * @mixer_underrun: SOF_IPC4_MIXER_UNDERRUN_DETECTED payload + */ +union sof_ipc4_resource_event_data { + uint32_t dws[6]; + struct sof_ipc4_process_data_error_event_data process_data_error; + struct sof_ipc4_mixer_underrun_event_data mixer_underrun; +}; + struct sof_ipc4_notify_resource_data { uint32_t resource_type; uint32_t resource_id; uint32_t event_type; uint32_t reserved; - uint32_t data[6]; + union sof_ipc4_resource_event_data data; } __packed __aligned(4); #define SOF_IPC4_DEBUG_DESCRIPTOR_SIZE 12 /* 3 x u32 */ diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index c9c6c0c52c62..e77f73390bd8 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -289,6 +289,89 @@ static void sof_ipc4_dump_payload(struct snd_sof_dev *sdev, 16, 4, ipc_data, size, false); } +static const char *sof_ipc4_resource_type_str(u32 type) +{ + switch (type) { + case SOF_IPC4_MODULE_INSTANCE: + return "resource: MODULE_INSTANCE"; + case SOF_IPC4_PIPELINE: + return "resource: PIPELINE"; + case SOF_IPC4_GATEWAY: + return "resource: GATEWAY"; + case SOF_IPC4_EDF_TASK: + return "resource: EDF_TASK"; + case SOF_IPC4_INVALID_RESOURCE_TYPE: + return "Resource is invalid"; + default: + return "Unknown resource type"; + } +} + +static const char *sof_ipc4_resource_event_type_str(u32 event_type) +{ + switch (event_type) { + case SOF_IPC4_MIXER_UNDERRUN_DETECTED: + return "event: MIXER_UNDERRUN_DETECTED"; + case SOF_IPC4_PROCESS_DATA_ERROR: + return "event: PROCESS_DATA_ERROR"; + case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED: + return "event: GATEWAY_UNDERRUN_DETECTED"; + case SOF_IPC4_GATEWAY_OVERRUN_DETECTED: + return "event: GATEWAY_OVERRUN_DETECTED"; + default: + return "Unknown event type"; + } +} + +static void sof_ipc4_resource_event_handler(struct snd_sof_dev *sdev, + struct sof_ipc4_msg *ipc4_msg) +{ + struct sof_ipc4_notify_resource_data *data = ipc4_msg->data_ptr; + + /* Print event details */ + switch (data->event_type) { + case SOF_IPC4_MIXER_UNDERRUN_DETECTED: + dev_dbg(sdev->dev, "%s (%u): eos %u, mixed %u, expected %u\n", + sof_ipc4_resource_event_type_str(data->event_type), + data->event_type, data->data.mixer_underrun.eos_flag, + data->data.mixer_underrun.data_mixed, + data->data.mixer_underrun.expected_data_mixed); + break; + case SOF_IPC4_PROCESS_DATA_ERROR: + dev_dbg(sdev->dev, "%s (%u): error_code %#x\n", + sof_ipc4_resource_event_type_str(data->event_type), + data->event_type, data->data.process_data_error.error_code); + break; + case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED: + case SOF_IPC4_GATEWAY_OVERRUN_DETECTED: + dev_dbg(sdev->dev, "%s (%u)\n", + sof_ipc4_resource_event_type_str(data->event_type), + data->event_type); + break; + default: + dev_dbg(sdev->dev, "%s (%u): raw dws %#x %#x %#x %#x %#x %#x\n", + sof_ipc4_resource_event_type_str(data->event_type), + data->event_type, + data->data.dws[0], data->data.dws[1], data->data.dws[2], + data->data.dws[3], data->data.dws[4], data->data.dws[5]); + break; + } + + /* Print resource details */ + if (data->resource_type == SOF_IPC4_MODULE_INSTANCE) { + u32 module_id = SOF_IPC4_MOD_ID_GET(data->resource_id); + u32 instance_id = SOF_IPC4_MOD_INSTANCE_GET(data->resource_id); + + dev_dbg(sdev->dev, "%s (%u), module_id %u, instance_id %u\n", + sof_ipc4_resource_type_str(data->resource_type), + data->resource_type, module_id, instance_id); + } else if (data->resource_type != SOF_IPC4_INVALID_RESOURCE_TYPE) { + dev_dbg(sdev->dev, "%s (%u), id %u\n", + sof_ipc4_resource_type_str(data->resource_type), + data->resource_type, data->resource_id); + } +} + static int sof_ipc4_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; @@ -734,6 +817,7 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) break; case SOF_IPC4_NOTIFY_RESOURCE_EVENT: data_size = sizeof(struct sof_ipc4_notify_resource_data); + handler_func = sof_ipc4_resource_event_handler; break; case SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS: sof_ipc4_mtrace_update_pos(sdev, SOF_IPC4_LOG_CORE_GET(ipc4_msg->primary)); From c663014e452d69d5f34b8b16fecf1590b3696082 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 28 Jul 2026 10:46:43 +0200 Subject: [PATCH 359/438] ASoC: qcom: audioreach: compute active channel maps from channel_map The Qualcom SM8650 based Ayaneo Pocket S2 gaming device has a set of 2 WSA speakers connected on the WSA2 lines. But the Audioreach DSP only handles WSA2 in pair with the WSA interface by using the upper bits of the active_channels_mask for WSA2 and the lower bits for WSA: /-------------------------------------------------\ | Bits | 3 | 2 | 1 | 0 | |-------------------------------------------------| | Line | WSA2 Ch2 | WSA2 Ch1 | WSA Ch2 | WSA Ch1 | \-------------------------------------------------/ Setting only the WSA2 upper bits is perfectly valid and functional but the current Audioreach code builds the bitmask from the channels count with: active_channels_mask = (1 << num_channels) - 1; In order to enable the WSA2 bits the channel count should be 4, but the lower WSA bits are then also enabled and the DSP errors out when trying to play on the disabled WSA interface. A solution would've been to add a fake WSA2 topology element which would be translated into the top bits only, but it's not clean and add some special exceptions in the generic Audioreach code. The solution suggested by Srinivas is to use the channel mapping to set this bitmask. This works but makes all the other calls using the channel mapping fail because the DSP requires the channel_mapping table to start from index 0 and using num_channel length in order to apply the mapping on the active_channels_mask bits in order. So we need to skip the empty channel mapping entries in all other users of the channel_map to build valid channel_mapping tables. This should not break any other usecases since the default channel mapping always start from index 0, and will add flexibilty to allow some special non linear mapping for other interfaces as well. Suggested-by: Srinivas Kandagatla Tested-by: Srinivas Kandagatla Reviewed-by: Srinivas Kandagatla Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260728-topic-sm8650-ayaneo-pocket-s2-wsa2-fix-v3-1-b29f44720178@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/audioreach.c | 47 ++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index e6e9eb2e85aa..0cc840aca69d 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -703,6 +703,7 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, int pm_sz = APM_HW_EP_PMODE_CFG_PSIZE; int size = ic_sz + ep_sz + fs_sz + pm_sz; void *p; + int i; struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); if (IS_ERR(pkt)) @@ -741,7 +742,12 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, intf_cfg->cfg.lpaif_type = module->hw_interface_type; intf_cfg->cfg.intf_index = module->hw_interface_idx; - intf_cfg->cfg.active_channels_mask = (1 << cfg->num_channels) - 1; + intf_cfg->cfg.active_channels_mask = 0; + /* Convert the physical channel mapping into a bit field */ + for (i = 0; i < AR_PCM_MAX_NUM_CHANNEL; i++) + if (cfg->channel_map[i]) + intf_cfg->cfg.active_channels_mask |= BIT(i); + p += ic_sz; pm_cfg = p; @@ -840,7 +846,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, uint32_t num_channels = cfg->num_channels; int payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) + APM_MODULE_PARAM_DATA_SIZE; - int i; + int i, j; void *p; struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); @@ -860,8 +866,12 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, media_format->sample_rate = cfg->sample_rate; media_format->bit_width = cfg->bit_width; media_format->num_channels = cfg->num_channels; - for (i = 0; i < num_channels; i++) - media_format->channel_mapping[i] = cfg->channel_map[i]; + /* Convert the physical mapping to a logical mapping of the channels */ + for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) { + if (!cfg->channel_map[i]) + continue; + media_format->channel_mapping[j++] = cfg->channel_map[i]; + } return q6apm_send_cmd_sync(graph->apm, pkt, 0); } @@ -1080,6 +1090,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, struct apm_pcm_module_media_fmt_cmd *cfg; struct apm_module_param_data *param_data; int payload_size; + int i, j; if (num_channels > 4) { dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); @@ -1113,7 +1124,12 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, media_cfg->num_channels = mcfg->num_channels; media_cfg->q_factor = mcfg->bit_width - 1; media_cfg->bits_per_sample = mcfg->bit_width; - memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); + /* Convert the physical mapping to a logical mapping of the channels */ + for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < mcfg->num_channels; i++) { + if (!mcfg->channel_map[i]) + continue; + media_cfg->channel_mapping[j++] = mcfg->channel_map[i]; + } return q6apm_send_cmd_sync(graph->apm, pkt, 0); } @@ -1163,6 +1179,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, struct payload_media_fmt_pcm *cfg; struct media_format *header; int rc, payload_size; + int i, j; void *p; if (num_channels > 4) { @@ -1202,7 +1219,12 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, cfg->q_factor = mcfg->bit_width - 1; cfg->endianness = PCM_LITTLE_ENDIAN; cfg->num_channels = mcfg->num_channels; - memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); + /* Convert the physical mapping to a logical mapping of the channels */ + for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) { + if (!mcfg->channel_map[i]) + continue; + cfg->channel_mapping[j++] = mcfg->channel_map[i]; + } } else { rc = audioreach_set_compr_media_format(header, p, mcfg); if (rc) @@ -1279,7 +1301,7 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph, struct apm_module_sp_vi_ex_mode_cfg *ex_cfg; int op_sz, cm_sz, ex_sz; struct apm_module_param_data *param_data; - int rc, i, payload_size; + int rc, i, payload_size, j; struct gpr_pkt *pkt; void *p; @@ -1320,14 +1342,19 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph, param_data->param_size = cm_sz - APM_MODULE_PARAM_DATA_SIZE; cm_cfg->cfg.num_channels = num_channels * 2; - for (i = 0; i < num_channels; i++) { + /* Convert the physical mapping to a logical mapping of the channels */ + for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < num_channels; i++) { + if (!mcfg->channel_map[i]) + continue; /* * Map speakers into Vsense and then Isense of each channel. * E.g. for PCM_CHANNEL_FL and PCM_CHANNEL_FR to: * [1, 2, 3, 4] */ - cm_cfg->cfg.channel_mapping[2 * i] = (mcfg->channel_map[i] - 1) * 2 + 1; - cm_cfg->cfg.channel_mapping[2 * i + 1] = (mcfg->channel_map[i] - 1) * 2 + 2; + cm_cfg->cfg.channel_mapping[2 * j] = (mcfg->channel_map[i] - 1) * 2 + 1; + cm_cfg->cfg.channel_mapping[2 * j + 1] = (mcfg->channel_map[i] - 1) * 2 + 2; + + ++j; } p += cm_sz; From b7b0a445ace2a15beb2bceaccb0213214f42f339 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 28 Jul 2026 10:46:44 +0200 Subject: [PATCH 360/438] ASoC: dt-bindings: qcom,sm8250: Add Ayaneo Pocket S2 sound card Document the bindings for the sound card on the Ayaneo Pocket S2 which uses the special speaker connection incompatible with the default SM8650 sound card. Acked-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260728-topic-sm8650-ayaneo-pocket-s2-wsa2-fix-v3-2-b29f44720178@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index bd5f5a6268a3..0998b2abd8bb 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -31,6 +31,7 @@ properties: - qcom,sm8750-sndcard - const: qcom,sm8450-sndcard - enum: + - ayaneo,pocket-s2-sndcard - fairphone,fp4-sndcard - fairphone,fp5-sndcard - qcom,apq8096-sndcard From 968d38918ae85e67069099ea456e3e13fea70081 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 28 Jul 2026 10:46:45 +0200 Subject: [PATCH 361/438] ASoC: qcom: sc8280xp: add Ayaneo Pocket S2 card with special WSA channel mapping The WSA Speakers are connected on the WSA2 interface, but the WSA and WSA2 links are handled as a single dai and DSP interface, so we need to specify the channel mapping of the Ayaneo Pocket S2 for the WSA dai in order to have functional playback and avoid DSP errors. Let's add a special entry for the Ayaneo Pocket S2 adding a prepare callback in order to set the proper channel mapping. Reviewed-by: Srinivas Kandagatla Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260728-topic-sm8650-ayaneo-pocket-s2-wsa2-fix-v3-3-b29f44720178@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index a9304784d41e..4ccff32a413b 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -14,6 +14,7 @@ #include "qdsp6/q6afe.h" #include "qdsp6/q6apm.h" #include "qdsp6/q6prm.h" +#include "qdsp6/q6dsp-common.h" #include "common.h" #include "sdw.h" @@ -50,6 +51,7 @@ struct snd_soc_common { bool mi2s_mclk_enable; bool mi2s_bclk_enable; bool wcd_jack; + int (*snd_prepare)(struct snd_pcm_substream *substream); }; struct sc8280xp_snd_data { @@ -213,12 +215,58 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, return 0; } +/* + * WSA and WSA2 are handled as a single interface with the + * following channels mask: + * __________________________________________________ + * | Bits | 3 | 2 | 1 | 0 | + * --------------------------------------------------- + * | Line | WSA2 Ch2 | WSA2 Ch1 | WSA Ch2 | WSA Ch1 | + * --------------------------------------------------- + * + * The Ayaneo Pocket S2 speakers are connected only to + * the WSA2 interface and the WSA interface is not enabled. + * + * Set the channel mapping on the WSA2 channels only. + */ +static const unsigned int ayaneo_ps2_channels_mapping[] = { + 0, /* WSA Ch1 */ + 0, /* WSA Ch2 */ + PCM_CHANNEL_FL, /* WSA2 Ch1 */ + PCM_CHANNEL_FR /* WSA2 Ch2 */ +}; + +static int ayaneo_ps2_snd_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + unsigned int channels = substream->runtime->channels; + + if (cpu_dai->id != WSA_CODEC_DMA_RX_0) + return 0; + + if (channels != 2) + return -EINVAL; + + return snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + ARRAY_SIZE(ayaneo_ps2_channels_mapping), + ayaneo_ps2_channels_mapping); +} + static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + if (data->snd_soc_common_priv->snd_prepare) { + int ret; + + ret = data->snd_soc_common_priv->snd_prepare(substream); + if (ret) + return ret; + } + return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]); } @@ -293,6 +341,14 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) return devm_snd_soc_register_card(dev, card); } +static struct snd_soc_common ayaneo_ps2_priv_data = { + .driver_name = "ayaneo-ps2", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .snd_prepare = ayaneo_ps2_snd_prepare, + .wcd_jack = true, +}; + static const struct snd_soc_common eliza_priv_data = { .driver_name = "eliza", .dapm_widgets = sc8280xp_dapm_widgets, @@ -384,6 +440,7 @@ static const struct snd_soc_common sm8750_priv_data = { }; static const struct of_device_id snd_sc8280xp_dt_match[] = { + { .compatible = "ayaneo,pocket-s2-sndcard", .data = &ayaneo_ps2_priv_data }, { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data }, { .compatible = "qcom,hawi-sndcard", .data = &hawi_priv_data }, { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data }, From 74a66323e1489cfccecf6dfcfa1df4a914676bc2 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 31 Jul 2026 16:41:14 +0800 Subject: [PATCH 362/438] ASoC: rt722: reinitialize rt722_sdca_jack_init() after reset Check whether the .set_jack callback has already been invoked before the reset. If so, call rt722_sdca_jack_init() again to restore the jack settings. Signed-off-by: Shuming Fan Link: https://patch.msgid.link/20260731084114.4142106-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt722-sdca.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index decf9407ab6d..e8c63cc9fe7f 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -1892,6 +1892,9 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt722_sdca_amp_preset(rt722); rt722_sdca_jack_preset(rt722); + if (rt722->hs_jack && (!rt722->first_hw_init)) + rt722_sdca_jack_init(rt722); + if (rt722->first_hw_init) { regcache_cache_bypass(rt722->regmap, false); regcache_mark_dirty(rt722->regmap); From 5a25f27f51185e24fc408db17aab89ef3cd33be3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 30 Jul 2026 13:41:36 +0300 Subject: [PATCH 363/438] ASoC: SOF: ipc4-topology: Remove dp_ from all module memory attributes Remove dp-prefix from all module instance's memory attributes and related data structures. The attributes are not anymore exclusively for Data Processing module instances, but generic for all module instances. However, the module init payload is still only for DP module instances. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730104141.14817-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 14 +++++++------- sound/soc/sof/sof-audio.h | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 8ac7dde32f77..7808a679e25d 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -163,11 +163,11 @@ static const struct sof_topology_token comp_ext_tokens[] = { {SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain, offsetof(struct snd_sof_widget, comp_domain)}, {SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, dp_domain_id)}, + offsetof(struct snd_sof_widget, domain_id)}, {SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, dp_heap_bytes)}, + offsetof(struct snd_sof_widget, heap_bytes)}, {SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, dp_stack_bytes)}, + offsetof(struct snd_sof_widget, stack_bytes)}, }; static const struct sof_topology_token gain_tokens[] = { @@ -3118,7 +3118,7 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, /* Add object array objects after ext_init */ - /* Add dp_memory_data if comp_domain indicates DP */ + /* Add memory_data if comp_domain indicates DP */ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | @@ -3127,9 +3127,9 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, sizeof(u32))); ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32)); dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; - dp_mem_data->domain_id = swidget->dp_domain_id; - dp_mem_data->stack_bytes = swidget->dp_stack_bytes; - dp_mem_data->heap_bytes = swidget->dp_heap_bytes; + dp_mem_data->domain_id = swidget->domain_id; + dp_mem_data->stack_bytes = swidget->stack_bytes; + dp_mem_data->heap_bytes = swidget->heap_bytes; ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 138e5fcc2dd0..ae95efc9be1c 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -459,10 +459,10 @@ struct snd_sof_widget { /* Scheduling domain (enum sof_comp_domain), unset, Low Latency, or Data Processing */ u32 comp_domain; - /* The values below are added to mod_init pay load if comp_domain indicates DP component */ - u32 dp_domain_id; /* DP process userspace domain ID */ - u32 dp_stack_bytes; /* DP process stack size requirement in bytes */ - u32 dp_heap_bytes; /* DP process heap size requirement in bytes */ + /* Module instance's memory configuration. */ + u32 domain_id; /* Module instance's userspace domain ID */ + u32 stack_bytes; /* Module instance's stack size requirement */ + u32 heap_bytes; /* Module instance's heap size requirement */ struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ From 18d0619ced261e7960efd05125dce604d1d9ac89 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 30 Jul 2026 13:41:37 +0300 Subject: [PATCH 364/438] ASoC: SOF: ipc4-topology: Fix SOF_TKN_COMP_STACK_BYTES_REQUIREMENT id The was inconsistency with SOF_TKN_COMP_STACK_BYTES_REQUIREMENT and SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT token ids in the Linux driver code with SOF FW topology code. This commit fixes the Linux side to match tools/topology/topology2/include/common/tokens.conf Link: https://github.com/thesofproject/sof/blob/main/tools/topology/topology2/include/common/tokens.conf#L30 Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730104141.14817-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index cc694a397987..d42adbef0478 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -111,8 +111,8 @@ #define SOF_TKN_COMP_SCHED_DOMAIN 418 #define SOF_TKN_COMP_DOMAIN_ID 419 -#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 420 -#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 421 +#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 420 +#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 421 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 From 52db046c388d32f8b99caa4312ae3712c1cce3e7 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 30 Jul 2026 13:41:38 +0300 Subject: [PATCH 365/438] ASoC: SOF: ipc4: Add SOF_IPC4_GLB_CREATE_PIPELINE payload macros and structs Adds SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY macros to set extension bit in SOF_IPC4_GLB_CREATE_PIPELINE indicating presence of the payload, and all necessary macros and structs to create the payload. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730104141.14817-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 76 ++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 4554e5e8cab5..6fbf62c4075c 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -187,6 +187,10 @@ enum sof_ipc4_pipeline_state { #define SOF_IPC4_GLB_PIPE_EXT_CORE_ID_MASK GENMASK(23, 20) #define SOF_IPC4_GLB_PIPE_EXT_CORE_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_CORE_ID_SHIFT) +#define SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT 29 +#define SOF_IPC4_GLB_PIPE_PAYLOAD_MASK BIT(29) +#define SOF_IPC4_GLB_PIPE_PAYLOAD(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT) + /* pipeline set state ipc msg */ #define SOF_IPC4_GLB_PIPE_STATE_ID_SHIFT 16 #define SOF_IPC4_GLB_PIPE_STATE_ID_MASK GENMASK(23, 16) @@ -654,13 +658,83 @@ enum sof_ipc4_mod_init_ext_obj_id { SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA, }; -/* DP module memory configuration data object for ext_init object array */ +/* DP module memory configuration data object for object array */ struct sof_ipc4_mod_init_ext_dp_memory_data { u32 domain_id; /* userspace domain ID */ u32 stack_bytes; /* stack size in bytes, 0 means default size */ u32 heap_bytes; /* stack size in bytes, 0 means default size */ } __packed __aligned(4); +/* + * This set of macros are very similar to the set above, but these are + * for building payload to SOF_IPC4_GLB_CREATE_PIPELINE message. + * + * Macros for creating struct sof_ipc4_glb_pipe_payload payload with + * its associated data. struct sof_ipc4_glb_pipe_payload should be the + * first piece of payload following SOF_IPC4_GLB_CREATE_PIPELINE msg, + * and its existence is indicated with SOF_IPC4_GLB_PIPE_PAYLOAD bit. + * + * The macros below apply to sof_ipc4_glb_pipe_payload.word0 + */ +#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT 0 +#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_MASK GENMASK(23, 0) +#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT) + +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT 24 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK BIT(24) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT) + +struct sof_ipc4_glb_pipe_payload { + u32 word0; + u32 rsvd1; + u32 rsvd2; +} __packed __aligned(4); + +/* + * SOF_IPC4_GLB_CREATE_PIPELINE payload may be followed by arbitrary + * number of object array objects. SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY-bit + * indicates that an array object follows struct + * sof_ipc4_glb_pipe_payload. + * + * The object header's SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST-bit in struct + * sof_ipc4_glb_pipe_ext_object indicates if the array is continued + * with another object. The header has also fields to identify the + * object, SOF_IPC4_GLB_PIPE_EXT_OBJ_ID, and to indicate the object's + * size in 32-bit words, SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS, not + * including the header itself. + * + * The macros below apply to sof_ipc4_glb_pipe_ext_object.header + */ +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT 0 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK BIT(0) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT) + +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT 1 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_MASK GENMASK(15, 1) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT) + +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT 16 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_MASK GENMASK(31, 16) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT) + +struct sof_ipc4_glb_pipe_ext_object { + u32 header; + u32 data[]; +} __packed __aligned(4); + +enum sof_ipc4_glb_pipe_ext_obj_id { + SOF_IPC4_GLB_PIPE_DATA_ID_INVALID = 0, + SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA, + SOF_IPC4_GLB_PIPE_DATA_ID_MAX = SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA, +}; + +/* Pipeline memory configuration data object for ext_init object array */ +struct sof_ipc4_glb_pipe_ext_obj_memory_data { + u32 domain_id; /* userspace domain ID */ + u32 stack_bytes; /* stack size in bytes */ + u32 heap_bytes; /* heap size in bytes */ +} __packed __aligned(4); + /** @}*/ #endif From 0244c162d1a5e4aef501feeafbe93ac439a330e6 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 30 Jul 2026 13:41:39 +0300 Subject: [PATCH 366/438] ASoC: SOF: ipc4-topology: Add payload to pipeline create messages Start adding payloads to pipeline create messages. The payload contains information for payload specific memory configuration. All non DP module instances within the same pipeline share the same memory attributes and access the same resources. The new logic sums interim, lifetime, and shared heap memory requirements together and picks the highest stack requirement of all module instances belonging to a pipeline. These pipeline specific attributes are sent as struct sof_ipc4_glb_pipe_payload payload in pipeline's create message. The idea is to pass common memory configuration for all the Low Latency modules in the pipeline in pipeline create message payload. The Data Processing module instances will still have an individual memory configuration in struct sof_ipc4_mod_init_ext_dp_memory_data payloads as before. In their payload everything is as it was before, all attributes are copied directly from their topology attributes. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730104141.14817-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 112 +++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 7808a679e25d..02948b2a809b 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1371,6 +1371,22 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget * pipeline = pipe_widget->private; pipeline->mem_usage += total; + /* + * If this is not a Data Processing module instance, add the + * required heap sizes to the sum of all module instances belonging + * to the same pipeline, and find the maximum stack requirement + * among all module instances belonging to the same pipeline. + */ + if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { + pipe_widget->heap_bytes += swidget->heap_bytes; + if (pipe_widget->stack_bytes < swidget->stack_bytes) + pipe_widget->stack_bytes = swidget->stack_bytes; + + dev_dbg(sdev->dev, "%s mem reqs to %s heap %u stack %u", + swidget->widget->name, pipe_widget->widget->name, + pipe_widget->heap_bytes, pipe_widget->stack_bytes); + } + /* Update base_config->cpc from the module manifest */ sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); @@ -1688,6 +1704,8 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; pipeline->mem_usage = 0; + pipe_widget->heap_bytes = 0; + pipe_widget->stack_bytes = 0; if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { if (pipeline->use_chain_dma) { @@ -3085,11 +3103,11 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr return 0; } -static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget, - struct sof_ipc4_msg *msg, - void *ipc_data, u32 ipc_size, - void **new_data) +static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + struct sof_ipc4_msg *msg, + void *ipc_data, u32 ipc_size, + void **new_data) { struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; struct sof_ipc4_module_init_ext_init *ext_init; @@ -3113,13 +3131,14 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, /* Add ext_init first and set objects array flag to 1 */ ext_init = (struct sof_ipc4_module_init_ext_init *)payload; - ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; ext_pos = DIV_ROUND_UP(sizeof(*ext_init), sizeof(u32)); /* Add object array objects after ext_init */ /* Add memory_data if comp_domain indicates DP */ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { + ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; + hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | @@ -3132,7 +3151,6 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, dp_mem_data->heap_bytes = swidget->heap_bytes; ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); } - /* If another array object is added, remember clear previous OBJ_LAST bit */ /* Calculate final size and check that it fits to max payload size */ @@ -3156,6 +3174,69 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, return new_size; } +static void sof_ipc4_widget_pipe_ext_obj_memory_data(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u32 *payload, u32 *ext_pos, + struct sof_ipc4_glb_pipe_ext_object **hdr) +{ + struct sof_ipc4_glb_pipe_ext_obj_memory_data *mem_data; + + *hdr = (struct sof_ipc4_glb_pipe_ext_object *)&payload[*ext_pos]; + (*hdr)->header = + SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA) | + SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*mem_data), + sizeof(u32))); + *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32)); + mem_data = (struct sof_ipc4_glb_pipe_ext_obj_memory_data *)&payload[*ext_pos]; + mem_data->domain_id = swidget->domain_id; + mem_data->stack_bytes = swidget->stack_bytes; + mem_data->heap_bytes = swidget->heap_bytes; + *ext_pos += DIV_ROUND_UP(sizeof(*mem_data), sizeof(u32)); + + dev_dbg(sdev->dev, + "%s; domain_id %u stack %u heap %u bytes", + swidget->widget->name, mem_data->domain_id, mem_data->stack_bytes, + mem_data->heap_bytes); +} + +static int sof_ipc4_widget_pipe_create_msg_payload(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + struct sof_ipc4_msg *msg, + void **new_data) +{ + struct sof_ipc4_glb_pipe_payload *payload_hdr; + struct sof_ipc4_glb_pipe_ext_object *hdr = NULL; + u32 *payload; + u32 ext_pos; + + payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + /* Add sof_ipc4_glb_pipe_payload and set array bit to 1 */ + payload_hdr = (struct sof_ipc4_glb_pipe_payload *)payload; + payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK; + ext_pos = DIV_ROUND_UP(sizeof(*payload_hdr), sizeof(u32)); + + sof_ipc4_widget_pipe_ext_obj_memory_data(sdev, swidget, payload, &ext_pos, &hdr); + /* Add following array objects here */ + + /* Mark end of object array */ + hdr->header |= SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK; + + /* Put total payload size in words to the payload header */ + payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(ext_pos); + *new_data = payload; + + /* Update msg extension bits according to the payload changes */ + msg->extension |= SOF_IPC4_GLB_PIPE_PAYLOAD_MASK; + + dev_dbg(sdev->dev, "%s: payload word0 %#x", swidget->widget->name, + payload_hdr->word0); + + return ext_pos * sizeof(int32_t); +} + static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; @@ -3309,8 +3390,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget swidget->widget->name, swidget->pipeline_id, module_id, swidget->instance_id, swidget->core); - ret = sof_ipc4_widget_setup_msg_payload(sdev, swidget, msg, ipc_data, ipc_size, - &ext_data); + ret = sof_ipc4_widget_mod_init_msg_payload(sdev, swidget, msg, ipc_data, ipc_size, + &ext_data); if (ret < 0) goto fail; @@ -3322,6 +3403,17 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n", swidget->widget->name, swidget->pipeline_id, swidget->instance_id, swidget->core); + + msg->extension &= ~SOF_IPC4_GLB_PIPE_PAYLOAD_MASK; + ret = sof_ipc4_widget_pipe_create_msg_payload(sdev, swidget, msg, + &ext_data); + if (ret < 0) + goto fail; + + if (ret > 0) { + ipc_size = ret; + ipc_data = ext_data; + } } msg->data_size = ipc_size; @@ -3379,6 +3471,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget swidget->widget->name); pipeline->mem_usage = 0; + swidget->heap_bytes = 0; + swidget->stack_bytes = 0; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; ida_free(&pipeline_ida, swidget->instance_id); swidget->instance_id = -EINVAL; From e5b0daa6f9744967c04645945c3a5efbc43f3c92 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 30 Jul 2026 13:41:40 +0300 Subject: [PATCH 367/438] ASoC: SOF: ipc4-topology: Fix sof_ipc4_mod_init_ext_dp_memory_data comments Fix a copy-paste error in struct sof_ipc4_mod_init_ext_dp_memory_data datamember comments. And while at it, drop the overly specific notes on the datamember values. The values are coming from topology and and what to do with them is decided in SOF FW. Its a bad idea to try to document their meaning in detail here. The Linux driver is only passing the values. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730104141.14817-6-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 6fbf62c4075c..b49a74007bd7 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -660,9 +660,9 @@ enum sof_ipc4_mod_init_ext_obj_id { /* DP module memory configuration data object for object array */ struct sof_ipc4_mod_init_ext_dp_memory_data { - u32 domain_id; /* userspace domain ID */ - u32 stack_bytes; /* stack size in bytes, 0 means default size */ - u32 heap_bytes; /* stack size in bytes, 0 means default size */ + u32 domain_id; /* userspace domain ID */ + u32 stack_bytes; /* required stack size in bytes */ + u32 heap_bytes; /* required heap size in bytes */ } __packed __aligned(4); /* @@ -732,7 +732,7 @@ enum sof_ipc4_glb_pipe_ext_obj_id { struct sof_ipc4_glb_pipe_ext_obj_memory_data { u32 domain_id; /* userspace domain ID */ u32 stack_bytes; /* stack size in bytes */ - u32 heap_bytes; /* heap size in bytes */ + u32 heap_bytes; /* heap size in bytes */ } __packed __aligned(4); /** @}*/ From 221f3b29366ec9f8579a8366ba438726c596ff61 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 30 Jul 2026 13:41:41 +0300 Subject: [PATCH 368/438] ASoC: SOF: ipc4-topology: Refactor sof_ipc4_widget_mod_init_msg_payload() Refactor sof_ipc4_widget_mod_init_msg_payload() to be easier to extend. Signed-off-by: Jyri Sarha Reviewed-by: Liam Girdwood Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730104141.14817-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-topology.c | 65 ++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 02948b2a809b..45f434c86cf9 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3103,27 +3103,47 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr return 0; } +static void sof_ipc4_add_init_ext_dp_memory_data(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u32 *payload, u32 *ext_pos, + struct sof_ipc4_module_init_ext_object **hdr) +{ + /* Add memory_data if comp_domain indicates DP */ + if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { + struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; + + *hdr = (struct sof_ipc4_module_init_ext_object *)&payload[*ext_pos]; + (*hdr)->header = + SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | + SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), + sizeof(u32))); + *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32)); + dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[*ext_pos]; + dp_mem_data->domain_id = swidget->domain_id; + dp_mem_data->stack_bytes = swidget->stack_bytes; + dp_mem_data->heap_bytes = swidget->heap_bytes; + *ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); + } +} + static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg, void *ipc_data, u32 ipc_size, void **new_data) { - struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; struct sof_ipc4_module_init_ext_init *ext_init; - struct sof_ipc4_module_init_ext_object *hdr; + struct sof_ipc4_module_init_ext_object *hdr = NULL; int new_size; u32 *payload; u32 ext_pos; - /* For the moment the only reason for adding init_ext_init payload is DP - * memory data. If both stack and heap size are 0 (= use default), then - * there is no need for init_ext_init payload. + /* + * Only DP widgets currently add init-ext objects here. Avoid allocating + * a max-sized payload buffer for widgets that will immediately return 0. */ - if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { - msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK; + if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) return 0; - } payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); if (!payload) @@ -3135,23 +3155,22 @@ static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, /* Add object array objects after ext_init */ - /* Add memory_data if comp_domain indicates DP */ - if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { - ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; + sof_ipc4_add_init_ext_dp_memory_data(sdev, swidget, payload, &ext_pos, &hdr); - hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; - hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | - SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | - SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), - sizeof(u32))); - ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32)); - dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; - dp_mem_data->domain_id = swidget->domain_id; - dp_mem_data->stack_bytes = swidget->stack_bytes; - dp_mem_data->heap_bytes = swidget->heap_bytes; - ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); + /* Add following object array items here */ + + if (!hdr) { + /* + * NOTE: Remove this early bail out, when struct + * sof_ipc4_module_init_ext_init alone has some + * function. + */ + kfree(payload); + return 0; } - /* If another array object is added, remember clear previous OBJ_LAST bit */ + + ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; + hdr->header |= SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK; /* Calculate final size and check that it fits to max payload size */ new_size = ext_pos * sizeof(u32) + ipc_size; From b627da43035744ca4d691fbf56eef60268319873 Mon Sep 17 00:00:00 2001 From: Andrey Golovko Date: Mon, 27 Jul 2026 12:33:09 +0300 Subject: [PATCH 369/438] ASoC: tas2783-sdw: drop stale regcache on uninitialized re-attach When the peripheral re-attaches after the SoundWire controller was power-gated during system suspend (s2idle reaching S0i3 on AMD ACP), the amplifier has lost all of its register and DSP state. tas_update_status() handles that by re-running tas_io_init(), which writes the device's TAS2783_SW_RESET register - a vendor register write that clears the device's register file and DSP state, not a SoundWire reset, so no re-enumeration is involved - and re-downloads the firmware. Before doing any of that, it syncs back a register cache that still holds the pre-suspend values. That sync is useless, since the reset immediately wipes whatever it wrote, and it leaves the cache claiming that the amplifier is already powered up and unmuted. Subsequent read-modify-write updates - DAPM amplifier power-up, SDCA PDE transitions at stream start - then see "no change" and skip the hardware write. Playback runs without a single error while the speakers stay silent. Unbinding and rebinding the driver restores audio, since probe starts from a fresh cache. Drop the cache instead of syncing it when an uninitialized device attaches, so that later accesses see the real hardware state. Reordering the sync after tas_io_init() and marking the cache dirty is not a workable alternative here: tas_regmap has no .writeable_reg, so the cache accepts every register up to .max_register, including ones for which tas2783_sdca_mbq_size() returns 0. regmap_sdw_mbq_size() rejects those with -EINVAL, so the replay fails on the first such register and takes initialization down with it. Cached user settings fall back to hardware defaults across such a power loss, which seems clearly preferable to a silent amplifier - the device is being reset and its firmware reloaded at this point anyway. Tested on an ASUS ProArt PX13 HN7306EAC (AMD Strix Halo, ACP7.0, two TAS2783 amplifiers plus RT721 on SoundWire link 1): the speakers work after an s2idle resume with ~51 s of S0i3 residency, where previously they stayed silent despite a complete firmware re-download. Fixes: 4cc9bd8d7b32 ("ASoc: tas2783A: Add soundwire based codec driver") Reported-by: Antoine Monnet Closes: https://lore.kernel.org/all/c66ae00a-e878-4af0-a05a-272e9574eaa5@montane.tech/ Signed-off-by: Andrey Golovko Link: https://patch.msgid.link/3e2751d1fb027bed0f09c88e5e56da8f@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2783-sdw.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index db58c50e8a83..f96a53a08175 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -1216,7 +1216,6 @@ static s32 tas_update_status(struct sdw_slave *slave, { struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev); struct device *dev = &slave->dev; - int ret; dev_dbg(dev, "Peripheral status = %s", status == SDW_SLAVE_UNATTACHED ? "unattached" : @@ -1232,14 +1231,23 @@ static s32 tas_update_status(struct sdw_slave *slave, if (tas_dev->hw_init || tas_dev->status != SDW_SLAVE_ATTACHED) return 0; - /* updated the cache data to device */ regcache_cache_only(tas_dev->regmap, false); - ret = regcache_sync(tas_dev->regmap); - if (ret) { - regcache_cache_only(tas_dev->regmap, true); - regcache_mark_dirty(tas_dev->regmap); - return ret; - } + + /* + * The device is attaching uninitialized: either this is the first + * attach, or it lost power (and with it all register and DSP state) + * while the controller was power-gated during system suspend. The + * cache still holds the pre-suspend values, and tas_io_init() below + * resets the device via TAS2783_SW_RESET anyway, so syncing it back + * is both useless and harmful: later read-modify-write updates would + * compare against stale data and skip the hardware write. + * + * Drop the cache instead, so that subsequent accesses see the real + * hardware state. Syncing after the reset is not an option either: + * the cache accepts registers for which tas2783_sdca_mbq_size() + * returns 0, and writing those back fails with -EINVAL. + */ + regcache_drop_region(tas_dev->regmap, 0, UINT_MAX); /* perform I/O transfers required for Slave initialization */ return tas_io_init(&slave->dev, slave); From 4efcd9d0f88bf0cee1fcb15d5b8a6687eabcb53f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:23 +0700 Subject: [PATCH 370/438] ASoC: codecs: sigmadsp: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 2e08fde3989c..b7dbeb237447 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -5,6 +5,7 @@ * Copyright 2009-2014 Analog Devices Inc. */ +#include #include #include #include @@ -135,7 +136,7 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, uint8_t *data; int ret = 0; - mutex_lock(&sigmadsp->lock); + guard(mutex)(&sigmadsp->lock); data = ucontrol->value.bytes.data; @@ -148,8 +149,6 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, ctrl->cached = true; } - mutex_unlock(&sigmadsp->lock); - return ret; } @@ -160,7 +159,7 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); int ret = 0; - mutex_lock(&sigmadsp->lock); + guard(mutex)(&sigmadsp->lock); if (!ctrl->cached) { ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, @@ -174,8 +173,6 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, ctrl->num_bytes); } - mutex_unlock(&sigmadsp->lock); - return ret; } @@ -677,10 +674,10 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, return; changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active); if (active && changed > 0) { - mutex_lock(&sigmadsp->lock); - if (ctrl->cached) - sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); - mutex_unlock(&sigmadsp->lock); + scoped_guard(mutex, &sigmadsp->lock) { + if (ctrl->cached) + sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); + } } } From 891f008aa31d02a5860d117ac747c652f1d5b4b4 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:24 +0700 Subject: [PATCH 371/438] ASoC: codecs: sta350: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/sta350.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index 99c7f7ac807b..2ba35076732b 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -16,6 +16,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ +#include #include #include #include @@ -306,9 +307,9 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; unsigned int cfud, val; - int i, ret = 0; + int i; - mutex_lock(&sta350->coeff_lock); + guard(mutex)(&sta350->coeff_lock); /* preserve reserved bits in STA350_CFUD */ regmap_read(sta350->regmap, STA350_CFUD, &cfud); @@ -320,24 +321,19 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, regmap_write(sta350->regmap, STA350_CFUD, cfud); regmap_write(sta350->regmap, STA350_CFADDR2, index); - if (numcoef == 1) { + if (numcoef == 1) regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04); - } else if (numcoef == 5) { + else if (numcoef == 5) regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08); - } else { - ret = -EINVAL; - goto exit_unlock; - } + else + return -EINVAL; for (i = 0; i < 3 * numcoef; i++) { regmap_read(sta350->regmap, STA350_B1CF1 + i, &val); ucontrol->value.bytes.data[i] = val; } -exit_unlock: - mutex_unlock(&sta350->coeff_lock); - - return ret; + return 0; } static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, From d6c5e4accf3897a5e4565da73da0387b3d2a944a Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:25 +0700 Subject: [PATCH 372/438] ASoC: codecs: sta32x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/sta32x.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 652c6e3a9e63..d6de739212f9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -269,9 +270,9 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, int numcoef = kcontrol->private_value >> 16; int index = kcontrol->private_value & 0xffff; unsigned int cfud, val; - int i, ret = 0; + int i; - mutex_lock(&sta32x->coeff_lock); + guard(mutex)(&sta32x->coeff_lock); /* preserve reserved bits in STA32X_CFUD */ regmap_read(sta32x->regmap, STA32X_CFUD, &cfud); @@ -283,24 +284,20 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, regmap_write(sta32x->regmap, STA32X_CFUD, cfud); regmap_write(sta32x->regmap, STA32X_CFADDR2, index); - if (numcoef == 1) { + if (numcoef == 1) regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04); - } else if (numcoef == 5) { + else if (numcoef == 5) regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08); - } else { - ret = -EINVAL; - goto exit_unlock; - } + else + return -EINVAL; + for (i = 0; i < 3 * numcoef; i++) { regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val); ucontrol->value.bytes.data[i] = val; } -exit_unlock: - mutex_unlock(&sta32x->coeff_lock); - - return ret; + return 0; } static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, From a41eb6d666c2e77978fd880634ad0af2a5494659 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:26 +0700 Subject: [PATCH 373/438] ASoC: codecs: tas2781: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2781-comlib-i2c.c | 5 ++-- sound/soc/codecs/tas2781-i2c.c | 33 +++++++++++---------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c index e24d56a14cfd..79b5f5b04c74 100644 --- a/sound/soc/codecs/tas2781-comlib-i2c.c +++ b/sound/soc/codecs/tas2781-comlib-i2c.c @@ -6,6 +6,7 @@ // // Author: Shenghao Ding +#include #include #include #include @@ -342,7 +343,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, /* Codec Lock Hold to ensure that codec_probe and firmware parsing and * loading do not simultaneously execute. */ - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); if (tas_priv->name_prefix) scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", @@ -360,8 +361,6 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n", ret); - /* Codec Lock Release*/ - mutex_unlock(&tas_priv->codec_lock); return ret; } EXPORT_SYMBOL_GPL(tascodec_init); diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 8eb9ead2951e..1ea0a0f9d1ec 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -13,6 +13,7 @@ // Author: Kevin Lu // +#include #include #include #include @@ -852,12 +853,12 @@ static int tasdevice_digital_gain_get( unsigned char data[4]; int ret; - mutex_lock(&tas_dev->codec_lock); + guard(mutex)(&tas_dev->codec_lock); /* Read the primary device */ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); if (ret) { dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); - goto out; + return ret; } target = get_unaligned_be32(&data[0]); @@ -877,8 +878,7 @@ static int tasdevice_digital_gain_get( /* find out the member same as or closer to the current volume */ ucontrol->value.integer.value[0] = abs(target - ar_l) <= abs(target - ar_r) ? l : r; -out: - mutex_unlock(&tas_dev->codec_lock); + return 0; } @@ -891,29 +891,26 @@ static int tasdevice_digital_gain_put( struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); int vol = ucontrol->value.integer.value[0]; - int status = 0, max = mc->max, rc = 1; + int status = 0, max = mc->max; int i, ret; unsigned int reg = mc->reg; unsigned int volrd, volwr; unsigned char data[4]; vol = clamp(vol, 0, max); - mutex_lock(&tas_dev->codec_lock); + guard(mutex)(&tas_dev->codec_lock); /* Read the primary device */ ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); if (ret) { dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); - rc = -1; - goto out; + return -1; } volrd = get_unaligned_be32(&data[0]); volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]); - if (volrd == volwr) { - rc = 0; - goto out; - } + if (volrd == volwr) + return 0; for (i = 0; i < tas_dev->ndev; i++) { ret = tasdevice_dev_bulk_write(tas_dev, i, reg, @@ -927,10 +924,9 @@ static int tasdevice_digital_gain_put( } if (status) - rc = -1; -out: - mutex_unlock(&tas_dev->codec_lock); - return rc; + return -1; + + return 1; } static const struct snd_kcontrol_new tasdevice_cali_controls[] = { @@ -1774,13 +1770,10 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); int state = 0; - /* Codec Lock Hold */ - mutex_lock(&tas_priv->codec_lock); + guard(mutex)(&tas_priv->codec_lock); if (event == SND_SOC_DAPM_PRE_PMD) state = 1; tasdevice_tuning_switch(tas_priv, state); - /* Codec Lock Release*/ - mutex_unlock(&tas_priv->codec_lock); return 0; } From 12a6af9195502987ef29abeb05cfa9a08f332474 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:27 +0700 Subject: [PATCH 374/438] ASoC: codecs: tas2783: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-6-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2783-sdw.c | 60 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index db58c50e8a83..8ebed797acb5 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -12,6 +12,7 @@ // Author: Baojun Xu // Author: Kevin Lu +#include #include #include #include @@ -693,12 +694,12 @@ static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev) return 0; } - mutex_lock(&tas_dev->calib_lock); - ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data, - tas_dev->cali_data.read_sz); - if (!ret) - tas2783_set_calib_params_to_device(tas_dev, tmp_val); - mutex_unlock(&tas_dev->calib_lock); + scoped_guard(mutex, &tas_dev->calib_lock) { + ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data, + tas_dev->cali_data.read_sz); + if (!ret) + tas2783_set_calib_params_to_device(tas_dev, tmp_val); + } return ret; } @@ -927,22 +928,23 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, dev_err(tas_dev->dev, "clear latch failed, err=%d", ret); - mutex_lock(&tas_dev->pde_lock); - /* - * Sometimes, there is error returned during power on. - * So added retry logic to ensure power on so that - * port prepare succeeds - */ - do { - ret = regmap_write(tas_dev->regmap, - SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, - TAS2783_SDCA_CTL_REQ_POW_STATE, 0), - TAS2783_SDCA_POW_STATE_ON); - if (!ret) - break; - usleep_range(2000, 2200); - } while (retry--); - mutex_unlock(&tas_dev->pde_lock); + scoped_guard(mutex, &tas_dev->pde_lock) { + /* + * Sometimes, there is error returned during power on. + * So added retry logic to ensure power on so that + * port prepare succeeds + */ + do { + ret = regmap_write(tas_dev->regmap, + SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, + TAS2783_SDCA_CTL_REQ_POW_STATE, 0), + TAS2783_SDCA_POW_STATE_ON); + if (!ret) + break; + usleep_range(2000, 2200); + } while (retry--); + } + if (ret) return ret; @@ -966,7 +968,6 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - s32 ret; struct snd_soc_component *component = dai->component; struct tas2783_prv *tas_dev = snd_soc_component_get_drvdata(component); @@ -975,14 +976,11 @@ static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream, sdw_stream_remove_slave(tas_dev->sdw_peripheral, sdw_stream); - mutex_lock(&tas_dev->pde_lock); - ret = regmap_write(tas_dev->regmap, - SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, - TAS2783_SDCA_CTL_REQ_POW_STATE, 0), - TAS2783_SDCA_POW_STATE_OFF); - mutex_unlock(&tas_dev->pde_lock); - - return ret; + guard(mutex)(&tas_dev->pde_lock); + return regmap_write(tas_dev->regmap, + SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, + TAS2783_SDCA_CTL_REQ_POW_STATE, 0), + TAS2783_SDCA_POW_STATE_OFF); } static const struct snd_soc_dai_ops tas_dai_ops = { From 58a8bdbfe568b342646e3f101a906cfe5209295d Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:28 +0700 Subject: [PATCH 375/438] ASoC: codecs: tas5805m: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-7-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas5805m.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index bcc8cab8d667..f76e04b403b5 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -12,6 +12,7 @@ // // It has been simplified a little and reworked for the 5.x ALSA SoC API. +#include #include #include #include @@ -230,10 +231,9 @@ static int tas5805m_vol_get(struct snd_kcontrol *kcontrol, struct tas5805m_priv *tas5805m = snd_soc_component_get_drvdata(component); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); ucontrol->value.integer.value[0] = tas5805m->vol[0]; ucontrol->value.integer.value[1] = tas5805m->vol[1]; - mutex_unlock(&tas5805m->lock); return 0; } @@ -249,13 +249,12 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct tas5805m_priv *tas5805m = snd_soc_component_get_drvdata(component); - int ret = 0; if (!(volume_is_valid(ucontrol->value.integer.value[0]) && volume_is_valid(ucontrol->value.integer.value[1]))) return -EINVAL; - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); if (tas5805m->vol[0] != ucontrol->value.integer.value[0] || tas5805m->vol[1] != ucontrol->value.integer.value[1]) { tas5805m->vol[0] = ucontrol->value.integer.value[0]; @@ -265,11 +264,10 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, tas5805m->is_powered); if (tas5805m->is_powered) tas5805m_refresh(tas5805m); - ret = 1; + return 1; } - mutex_unlock(&tas5805m->lock); - return ret; + return 0; } static const struct snd_kcontrol_new tas5805m_snd_controls[] = { @@ -332,7 +330,7 @@ static void do_work(struct work_struct *work) dev_dbg(&tas5805m->i2c->dev, "DSP startup\n"); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); /* We mustn't issue any I2C transactions until the I2S * clock is stable. Furthermore, we must allow a 5ms * delay after the first set of register writes to @@ -345,7 +343,6 @@ static void do_work(struct work_struct *work) tas5805m->is_powered = true; tas5805m_refresh(tas5805m); - mutex_unlock(&tas5805m->lock); } static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, @@ -362,7 +359,7 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, dev_dbg(component->dev, "DSP shutdown\n"); cancel_work_sync(&tas5805m->work); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); if (tas5805m->is_powered) { tas5805m->is_powered = false; @@ -379,7 +376,6 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ); } - mutex_unlock(&tas5805m->lock); } return 0; @@ -414,14 +410,13 @@ static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction) struct tas5805m_priv *tas5805m = snd_soc_component_get_drvdata(component); - mutex_lock(&tas5805m->lock); + guard(mutex)(&tas5805m->lock); dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n", mute, tas5805m->is_powered); tas5805m->is_muted = mute; if (tas5805m->is_powered) tas5805m_refresh(tas5805m); - mutex_unlock(&tas5805m->lock); return 0; } From dfee22ec48a5e3f0c55914516d2269a3d172c491 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:29 +0700 Subject: [PATCH 376/438] ASoC: codecs: tlv320dac33: Use guard() for mutex & spin locks Clean up the code using guard() for mutex & spin locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-8-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 87 ++++++++++++++-------------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 223c49dfc450..9bd2ddd8dacd 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -7,6 +7,7 @@ * Copyright: (C) 2009 Nokia Corporation */ +#include #include #include #include @@ -236,13 +237,10 @@ static int dac33_write_locked(struct snd_soc_component *component, unsigned int unsigned int value) { struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); - int ret; - mutex_lock(&dac33->mutex); - ret = dac33_write(component, reg, value); - mutex_unlock(&dac33->mutex); + guard(mutex)(&dac33->mutex); - return ret; + return dac33_write(component, reg, value); } #define DAC33_I2C_ADDR_AUTOINC 0x80 @@ -365,13 +363,13 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); int ret = 0; - mutex_lock(&dac33->mutex); + guard(mutex)(&dac33->mutex); /* Safety check */ if (unlikely(power == dac33->chip_power)) { dev_dbg(component->dev, "Trying to set the same power state: %s\n", power ? "ON" : "OFF"); - goto exit; + return ret; } if (power) { @@ -380,7 +378,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret != 0) { dev_err(component->dev, "Failed to enable supplies: %d\n", ret); - goto exit; + return ret; } if (dac33->reset_gpiod) { @@ -388,7 +386,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret < 0) { dev_err(&dac33->i2c->dev, "Failed to set reset GPIO: %d\n", ret); - goto exit; + return ret; } } @@ -400,7 +398,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret < 0) { dev_err(&dac33->i2c->dev, "Failed to set reset GPIO: %d\n", ret); - goto exit; + return ret; } } @@ -409,14 +407,12 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret != 0) { dev_err(component->dev, "Failed to disable supplies: %d\n", ret); - goto exit; + return ret; } dac33->chip_power = 0; } -exit: - mutex_unlock(&dac33->mutex); return ret; } @@ -659,7 +655,6 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) { struct snd_soc_component *component = dac33->component; unsigned int delay; - unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: @@ -667,10 +662,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) DAC33_THRREG(dac33->nsample)); /* Take the timestamps */ - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp2 = ktime_to_us(ktime_get()); - dac33->t_stamp1 = dac33->t_stamp2; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + dac33->t_stamp2 = ktime_to_us(ktime_get()); + dac33->t_stamp1 = dac33->t_stamp2; + } dac33_write16(component, DAC33_PREFILL_MSB, DAC33_THRREG(dac33->alarm_threshold)); @@ -682,11 +677,11 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) break; case DAC33_FIFO_MODE7: /* Take the timestamp */ - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp1 = ktime_to_us(ktime_get()); - /* Move back the timestamp with drain time */ - dac33->t_stamp1 -= dac33->mode7_us_to_lthr; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + dac33->t_stamp1 = ktime_to_us(ktime_get()); + /* Move back the timestamp with drain time */ + dac33->t_stamp1 -= dac33->mode7_us_to_lthr; + } dac33_write16(component, DAC33_PREFILL_MSB, DAC33_THRREG(DAC33_MODE7_MARGIN)); @@ -704,14 +699,12 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) { struct snd_soc_component *component = dac33->component; - unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: /* Take the timestamp */ - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp2 = ktime_to_us(ktime_get()); - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) + dac33->t_stamp2 = ktime_to_us(ktime_get()); dac33_write16(component, DAC33_NSAMPLE_MSB, DAC33_THRREG(dac33->nsample)); @@ -735,7 +728,7 @@ static void dac33_work(struct work_struct *work) dac33 = container_of(work, struct tlv320dac33_priv, work); component = dac33->component; - mutex_lock(&dac33->mutex); + guard(mutex)(&dac33->mutex); switch (dac33->state) { case DAC33_PREFILL: dac33->state = DAC33_PLAYBACK; @@ -757,18 +750,15 @@ static void dac33_work(struct work_struct *work) dac33_write(component, DAC33_FIFO_CTRL_A, reg); break; } - mutex_unlock(&dac33->mutex); } static irqreturn_t dac33_interrupt_handler(int irq, void *dev) { struct snd_soc_component *component = dev; struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); - unsigned long flags; - spin_lock_irqsave(&dac33->lock, flags); - dac33->t_stamp1 = ktime_to_us(ktime_get()); - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) + dac33->t_stamp1 = ktime_to_us(ktime_get()); /* Do not schedule the workqueue in Mode7 */ if (dac33->fifo_mode != DAC33_FIFO_MODE7) @@ -902,14 +892,13 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream, return -EINVAL; } - mutex_lock(&dac33->mutex); + guard(mutex)(&dac33->mutex); if (!dac33->chip_power) { /* * Chip is not powered yet. * Do the init in the dac33_set_bias_level later. */ - mutex_unlock(&dac33->mutex); return 0; } @@ -1053,8 +1042,6 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream, break; } - mutex_unlock(&dac33->mutex); - return 0; } @@ -1156,21 +1143,20 @@ static snd_pcm_sframes_t dac33_dai_delay( unsigned int time_delta, uthr; int samples_out, samples_in, samples; snd_pcm_sframes_t delay = 0; - unsigned long flags; switch (dac33->fifo_mode) { case DAC33_FIFO_BYPASS: break; case DAC33_FIFO_MODE1: - spin_lock_irqsave(&dac33->lock, flags); - t0 = dac33->t_stamp1; - t1 = dac33->t_stamp2; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + t0 = dac33->t_stamp1; + t1 = dac33->t_stamp2; + } t_now = ktime_to_us(ktime_get()); /* We have not started to fill the FIFO yet, delay is 0 */ if (!t1) - goto out; + return 0; if (t0 > t1) { /* @@ -1230,23 +1216,22 @@ static snd_pcm_sframes_t dac33_dai_delay( } break; case DAC33_FIFO_MODE7: - spin_lock_irqsave(&dac33->lock, flags); - t0 = dac33->t_stamp1; - uthr = dac33->uthr; - spin_unlock_irqrestore(&dac33->lock, flags); + scoped_guard(spinlock_irqsave, &dac33->lock) { + t0 = dac33->t_stamp1; + uthr = dac33->uthr; + } t_now = ktime_to_us(ktime_get()); /* We have not started to fill the FIFO yet, delay is 0 */ if (!t0) - goto out; + return 0; if (t_now <= t0) { /* * Either the timestamps are messed or equal. Report * maximum delay */ - delay = uthr; - goto out; + return uthr; } time_delta = t_now - t0; @@ -1287,7 +1272,7 @@ static snd_pcm_sframes_t dac33_dai_delay( dac33->fifo_mode); break; } -out: + return delay; } From 315b15203f6de9784ce62b0ba4ee5550b49dd5bf Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:30 +0700 Subject: [PATCH 377/438] ASoC: codecs: tscs42xx: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-9-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tscs42xx.c | 61 ++++++++++++------------------------- 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index dba581857920..02082ef790b4 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -210,25 +211,21 @@ static int power_up_audio_plls(struct snd_soc_component *component) return ret; } - mutex_lock(&tscs42xx->pll_lock); + guard(mutex)(&tscs42xx->pll_lock); ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val); if (ret < 0) { dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret); - goto exit; + return ret; } if (!plls_locked(component)) { dev_err(component->dev, "Failed to lock plls\n"); ret = -ENOMSG; - goto exit; + return ret; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->pll_lock); - - return ret; + return 0; } static int power_down_audio_plls(struct snd_soc_component *component) @@ -236,28 +233,24 @@ static int power_down_audio_plls(struct snd_soc_component *component) struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component); int ret; - mutex_lock(&tscs42xx->pll_lock); + guard(mutex)(&tscs42xx->pll_lock); ret = snd_soc_component_update_bits(component, R_PLLCTL1C, RM_PLLCTL1C_PDB_PLL1, RV_PLLCTL1C_PDB_PLL1_DISABLE); if (ret < 0) { dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret); - goto exit; + return ret; } ret = snd_soc_component_update_bits(component, R_PLLCTL1C, RM_PLLCTL1C_PDB_PLL2, RV_PLLCTL1C_PDB_PLL2_DISABLE); if (ret < 0) { dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret); - goto exit; + return ret; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->pll_lock); - - return ret; + return 0; } static int coeff_ram_get(struct snd_kcontrol *kcontrol, @@ -269,13 +262,11 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol, (struct coeff_ram_ctl *)kcontrol->private_value; struct soc_bytes_ext *params = &ctl->bytes_ext; - mutex_lock(&tscs42xx->coeff_ram_lock); + guard(mutex)(&tscs42xx->coeff_ram_lock); memcpy(ucontrol->value.bytes.data, &tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max); - mutex_unlock(&tscs42xx->coeff_ram_lock); - return 0; } @@ -290,14 +281,14 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, unsigned int coeff_cnt = params->max / COEFF_SIZE; int ret; - mutex_lock(&tscs42xx->coeff_ram_lock); + guard(mutex)(&tscs42xx->coeff_ram_lock); tscs42xx->coeff_ram_synced = false; memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], ucontrol->value.bytes.data, params->max); - mutex_lock(&tscs42xx->pll_lock); + guard(mutex)(&tscs42xx->pll_lock); if (plls_locked(component)) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, @@ -305,18 +296,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err(component->dev, "Failed to flush coeff ram cache (%d)\n", ret); - goto exit; + return ret; } tscs42xx->coeff_ram_synced = true; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->pll_lock); - - mutex_unlock(&tscs42xx->coeff_ram_lock); - - return ret; + return 0; } /* Input L Capture Route */ @@ -385,21 +370,17 @@ static int dac_event(struct snd_soc_dapm_widget *w, struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component); int ret; - mutex_lock(&tscs42xx->coeff_ram_lock); + guard(mutex)(&tscs42xx->coeff_ram_lock); if (!tscs42xx->coeff_ram_synced) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, COEFF_RAM_COEFF_COUNT); if (ret < 0) - goto exit; + return ret; tscs42xx->coeff_ram_synced = true; } - ret = 0; -exit: - mutex_unlock(&tscs42xx->coeff_ram_lock); - - return ret; + return 0; } static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = { @@ -926,12 +907,10 @@ static int setup_sample_rate(struct snd_soc_component *component, return ret; } - mutex_lock(&tscs42xx->audio_params_lock); + guard(mutex)(&tscs42xx->audio_params_lock); tscs42xx->samplerate = rate; - mutex_unlock(&tscs42xx->audio_params_lock); - return 0; } @@ -1253,12 +1232,10 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai, return ret; } - mutex_lock(&tscs42xx->audio_params_lock); + guard(mutex)(&tscs42xx->audio_params_lock); tscs42xx->bclk_ratio = ratio; - mutex_unlock(&tscs42xx->audio_params_lock); - return 0; } From 70ab50fe639af0a7b7b16367f61f234583c09ec6 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:31 +0700 Subject: [PATCH 378/438] ASoC: codecs: tscs454: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-10-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/tscs454.c | 107 +++++++++++++++---------------------- 1 file changed, 42 insertions(+), 65 deletions(-) diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index aad394937ce6..b70c9d931e1e 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -4,6 +4,7 @@ // Author: Steven Eckhoff #include +#include #include #include #include @@ -329,12 +330,10 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(coeff_ram_lock); - - memcpy(ucontrol->value.bytes.data, - &coeff_ram[ctl->addr * COEFF_SIZE], params->max); - - mutex_unlock(coeff_ram_lock); + scoped_guard(mutex, coeff_ram_lock) { + memcpy(ucontrol->value.bytes.data, + &coeff_ram[ctl->addr * COEFF_SIZE], params->max); + } return 0; } @@ -428,15 +427,15 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(coeff_ram_lock); + guard(mutex)(coeff_ram_lock); *coeff_ram_synced = false; memcpy(&coeff_ram[ctl->addr * COEFF_SIZE], ucontrol->value.bytes.data, params->max); - mutex_lock(&tscs454->pll1.lock); - mutex_lock(&tscs454->pll2.lock); + guard(mutex)(&tscs454->pll1.lock); + guard(mutex)(&tscs454->pll2.lock); val = snd_soc_component_read(component, R_PLLSTAT); if (val) { /* PLLs locked */ @@ -446,18 +445,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err(component->dev, "Failed to flush coeff ram cache (%d)\n", ret); - goto exit; + return ret; } *coeff_ram_synced = true; } - ret = 0; -exit: - mutex_unlock(&tscs454->pll2.lock); - mutex_unlock(&tscs454->pll1.lock); - mutex_unlock(coeff_ram_lock); - - return ret; + return 0; } static inline int coeff_ram_sync(struct snd_soc_component *component, @@ -465,41 +458,35 @@ static inline int coeff_ram_sync(struct snd_soc_component *component, { int ret; - mutex_lock(&tscs454->dac_ram.lock); - if (!tscs454->dac_ram.synced) { - ret = write_coeff_ram(component, tscs454->dac_ram.cache, - R_DACCRS, R_DACCRADD, R_DACCRWDL, - 0x00, COEFF_RAM_COEFF_COUNT); - if (ret < 0) { - mutex_unlock(&tscs454->dac_ram.lock); - return ret; + scoped_guard(mutex, &tscs454->dac_ram.lock) { + if (!tscs454->dac_ram.synced) { + ret = write_coeff_ram(component, tscs454->dac_ram.cache, + R_DACCRS, R_DACCRADD, R_DACCRWDL, + 0x00, COEFF_RAM_COEFF_COUNT); + if (ret < 0) + return ret; } } - mutex_unlock(&tscs454->dac_ram.lock); - mutex_lock(&tscs454->spk_ram.lock); - if (!tscs454->spk_ram.synced) { - ret = write_coeff_ram(component, tscs454->spk_ram.cache, - R_SPKCRS, R_SPKCRADD, R_SPKCRWDL, - 0x00, COEFF_RAM_COEFF_COUNT); - if (ret < 0) { - mutex_unlock(&tscs454->spk_ram.lock); - return ret; + scoped_guard(mutex, &tscs454->spk_ram.lock) { + if (!tscs454->spk_ram.synced) { + ret = write_coeff_ram(component, tscs454->spk_ram.cache, + R_SPKCRS, R_SPKCRADD, R_SPKCRWDL, + 0x00, COEFF_RAM_COEFF_COUNT); + if (ret < 0) + return ret; } } - mutex_unlock(&tscs454->spk_ram.lock); - mutex_lock(&tscs454->sub_ram.lock); - if (!tscs454->sub_ram.synced) { - ret = write_coeff_ram(component, tscs454->sub_ram.cache, - R_SUBCRS, R_SUBCRADD, R_SUBCRWDL, - 0x00, COEFF_RAM_COEFF_COUNT); - if (ret < 0) { - mutex_unlock(&tscs454->sub_ram.lock); - return ret; + scoped_guard(mutex, &tscs454->sub_ram.lock) { + if (!tscs454->sub_ram.synced) { + ret = write_coeff_ram(component, tscs454->sub_ram.cache, + R_SUBCRS, R_SUBCRADD, R_SUBCRWDL, + 0x00, COEFF_RAM_COEFF_COUNT); + if (ret < 0) + return ret; } } - mutex_unlock(&tscs454->sub_ram.lock); return 0; } @@ -658,16 +645,14 @@ static int set_sysclk(struct snd_soc_component *component) static inline void reserve_pll(struct pll *pll) { - mutex_lock(&pll->lock); + guard(mutex)(&pll->lock); pll->users++; - mutex_unlock(&pll->lock); } static inline void free_pll(struct pll *pll) { - mutex_lock(&pll->lock); + guard(mutex)(&pll->lock); pll->users--; - mutex_unlock(&pll->lock); } static int pll_connected(struct snd_soc_dapm_widget *source, @@ -679,15 +664,13 @@ static int pll_connected(struct snd_soc_dapm_widget *source, int users; if (strstr(source->name, "PLL 1")) { - mutex_lock(&tscs454->pll1.lock); - users = tscs454->pll1.users; - mutex_unlock(&tscs454->pll1.lock); + scoped_guard(mutex, &tscs454->pll1.lock) + users = tscs454->pll1.users; dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__, users); } else { - mutex_lock(&tscs454->pll2.lock); - users = tscs454->pll2.users; - mutex_unlock(&tscs454->pll2.lock); + scoped_guard(mutex, &tscs454->pll2.lock) + users = tscs454->pll2.users; dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__, users); } @@ -806,7 +789,7 @@ static inline int aif_free(struct snd_soc_component *component, { struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component); - mutex_lock(&tscs454->aifs_status_lock); + guard(mutex)(&tscs454->aifs_status_lock); dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id); @@ -829,8 +812,6 @@ static inline int aif_free(struct snd_soc_component *component, free_pll(tscs454->internal_rate.pll); } - mutex_unlock(&tscs454->aifs_status_lock); - return 0; } @@ -3174,7 +3155,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, unsigned int val; int ret; - mutex_lock(&tscs454->aifs_status_lock); + guard(mutex)(&tscs454->aifs_status_lock); dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__, aif->id, fs); @@ -3207,14 +3188,14 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, ret = set_aif_fs(component, aif->id, fs); if (ret < 0) { dev_err(component->dev, "Failed to set aif fs (%d)\n", ret); - goto exit; + return ret; } ret = set_aif_sample_format(component, params_format(params), aif->id); if (ret < 0) { dev_err(component->dev, "Failed to set aif sample format (%d)\n", ret); - goto exit; + return ret; } set_aif_status_active(&tscs454->aifs_status, aif->id, @@ -3223,11 +3204,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n", aif->id, tscs454->aifs_status.streams); - ret = 0; -exit: - mutex_unlock(&tscs454->aifs_status_lock); - - return ret; + return 0; } static int tscs454_hw_free(struct snd_pcm_substream *substream, From ff8af50301922a46ae9c90fb1f3ad1654c1c7101 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:32 +0700 Subject: [PATCH 379/438] ASoC: codecs: twl6040: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-11-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index e10c51092a35..650836f9615f 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -273,7 +274,7 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component, struct twl6040_data *priv = snd_soc_component_get_drvdata(component); int status; - mutex_lock(&priv->mutex); + guard(mutex)(&priv->mutex); /* Sync status */ status = twl6040_read(component, TWL6040_REG_STATUS); @@ -281,8 +282,6 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component, snd_soc_jack_report(jack, report, report); else snd_soc_jack_report(jack, 0, report); - - mutex_unlock(&priv->mutex); } void twl6040_hs_jack_detect(struct snd_soc_component *component, From dabbe0eb4e40bbf0d10342dd80d303a4071caad7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:34 +0700 Subject: [PATCH 380/438] ASoC: codecs: wcd934x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-13-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 42 ++++++++++++++------------------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index a9e6f2923099..caca5cc25100 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1265,13 +1265,10 @@ static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src) static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd) { - mutex_lock(&wcd->sysclk_mutex); - - if (++wcd->sysclk_users != 1) { - mutex_unlock(&wcd->sysclk_mutex); - return 0; + scoped_guard(mutex, &wcd->sysclk_mutex) { + if (++wcd->sysclk_users != 1) + return 0; } - mutex_unlock(&wcd->sysclk_mutex); regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS, WCD934X_ANA_BIAS_EN_MASK, @@ -1328,12 +1325,10 @@ static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd) static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd) { - mutex_lock(&wcd->sysclk_mutex); - if (--wcd->sysclk_users != 0) { - mutex_unlock(&wcd->sysclk_mutex); - return 0; + scoped_guard(mutex, &wcd->sysclk_mutex) { + if (--wcd->sysclk_users != 0) + return 0; } - mutex_unlock(&wcd->sysclk_mutex); regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG, WCD934X_EXT_CLK_BUF_EN_MASK | @@ -2384,7 +2379,7 @@ static int wcd934x_micbias_control(struct snd_soc_component *component, __func__, micb_num); return -EINVAL; } - mutex_lock(&wcd934x->micb_lock); + guard(mutex)(&wcd934x->micb_lock); switch (req) { case MICB_PULLUP_ENABLE: @@ -2446,8 +2441,6 @@ static int wcd934x_micbias_control(struct snd_soc_component *component, break; } - mutex_unlock(&wcd934x->micb_lock); - return 0; } @@ -2488,7 +2481,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component); - int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; switch (micb_num) { case MIC_BIAS_1: @@ -2506,7 +2499,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd934x->micb_lock); + guard(mutex)(&wcd934x->micb_lock); /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as @@ -2521,15 +2514,11 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD934X_MICB_VAL_MASK); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = -EINVAL; - goto exit; - } + if (req_vout_ctl < 0) + return -EINVAL; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; if (micb_en == WCD934X_MICB_ENABLE) snd_soc_component_write_field(component, micb_reg, @@ -2550,9 +2539,8 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, */ usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd934x->micb_lock); - return ret; + + return 0; } static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, From 5a66f232aa5a5f168c15ff26c0edafb0fb2b20ec Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:35 +0700 Subject: [PATCH 381/438] ASoC: codecs: wcd937x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-14-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd937x.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index e0169e783ee9..0dd05604f5b8 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -2,6 +2,7 @@ // Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. #include +#include #include #include #include @@ -1056,7 +1057,7 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, return -EINVAL; } - mutex_lock(&wcd937x->micb_lock); + guard(mutex)(&wcd937x->micb_lock); switch (req) { case MICB_PULLUP_ENABLE: wcd937x->pullup_ref[micb_index]++; @@ -1136,7 +1137,6 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, } break; } - mutex_unlock(&wcd937x->micb_lock); return 0; } @@ -1460,7 +1460,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); - int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; switch (micb_num) { case MIC_BIAS_1: @@ -1475,7 +1475,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd937x->micb_lock); + guard(mutex)(&wcd937x->micb_lock); /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as @@ -1490,15 +1490,11 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD937X_MICB_VOUT_MASK); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = -EINVAL; - goto exit; - } + if (req_vout_ctl < 0) + return -EINVAL; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; if (micb_en == WCD937X_MICB_ENABLE) snd_soc_component_write_field(component, micb_reg, @@ -1519,9 +1515,8 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, */ usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd937x->micb_lock); - return ret; + + return 0; } static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, From 7f9f9045153c0d74ee98406e824b3b24878f69b7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:36 +0700 Subject: [PATCH 382/438] ASoC: codecs: wcd938x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-15-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd938x.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index c69e18667a85..9a9ea37ecab3 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. +#include #include #include #include @@ -1976,7 +1977,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, int req_volt, int micb_num) { struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); - int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; + int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; switch (micb_num) { case MIC_BIAS_1: @@ -1994,7 +1995,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd938x->micb_lock); + guard(mutex)(&wcd938x->micb_lock); /* * If requested micbias voltage is same as current micbias * voltage, then just return. Otherwise, adjust voltage as @@ -2009,15 +2010,11 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD938X_MICB_VOUT_MASK); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = -EINVAL; - goto exit; - } + if (req_vout_ctl < 0) + return -EINVAL; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; if (micb_en == WCD938X_MICB_ENABLE) snd_soc_component_write_field(component, micb_reg, @@ -2038,9 +2035,8 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, */ usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd938x->micb_lock); - return ret; + + return 0; } static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, From 5a230b65cebec2622f6a417671bb6df0b7e82128 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:37 +0700 Subject: [PATCH 383/438] ASoC: codecs: wcd939x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-16-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd939x.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 010d12466722..26fe0b6313cd 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1923,7 +1924,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); unsigned int micb_reg, cur_vout_ctl, micb_en; int req_vout_ctl; - int ret = 0; switch (micb_num) { case MIC_BIAS_1: @@ -1941,7 +1941,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, default: return -EINVAL; } - mutex_lock(&wcd939x->micb_lock); + guard(mutex)(&wcd939x->micb_lock); /* * If requested micbias voltage is same as current micbias @@ -1957,15 +1957,11 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, WCD939X_MICB_VOUT_CTL); req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); - if (req_vout_ctl < 0) { - ret = req_vout_ctl; - goto exit; - } + if (req_vout_ctl < 0) + return req_vout_ctl; - if (cur_vout_ctl == req_vout_ctl) { - ret = 0; - goto exit; - } + if (cur_vout_ctl == req_vout_ctl) + return 0; dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), @@ -1990,9 +1986,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, usleep_range(2000, 2100); } -exit: - mutex_unlock(&wcd939x->micb_lock); - return ret; + return 0; } static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, From c7e517ed25438f3cc572ca27fbcdb6d0dc0af04f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:38 +0700 Subject: [PATCH 384/438] ASoC: codecs: wm0010: Use guard() for mutex & spin locks Clean up the code using guard() for mutex & spin locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-17-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 2a8c61a72c17..58c0c601ee6c 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -9,6 +9,7 @@ * Scott Ling */ +#include #include #include #include @@ -148,13 +149,11 @@ static const char *wm0010_state_to_str(enum wm0010_state state) static void wm0010_halt(struct snd_soc_component *component) { struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component); - unsigned long flags; enum wm0010_state state; /* Fetch the wm0010 state */ - spin_lock_irqsave(&wm0010->irq_lock, flags); - state = wm0010->state; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + scoped_guard(spinlock_irqsave, &wm0010->irq_lock) + state = wm0010->state; switch (state) { case WM0010_POWER_OFF: @@ -173,9 +172,8 @@ static void wm0010_halt(struct snd_soc_component *component) break; } - spin_lock_irqsave(&wm0010->irq_lock, flags); - wm0010->state = WM0010_POWER_OFF; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + scoped_guard(spinlock_irqsave, &wm0010->irq_lock) + wm0010->state = WM0010_POWER_OFF; } struct wm0010_boot_xfer { @@ -190,11 +188,9 @@ struct wm0010_boot_xfer { static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010) { enum wm0010_state state; - unsigned long flags; - spin_lock_irqsave(&wm0010->irq_lock, flags); - state = wm0010->state; - spin_unlock_irqrestore(&wm0010->irq_lock, flags); + scoped_guard(spinlock_irqsave, &wm0010->irq_lock) + state = wm0010->state; dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n", wm0010_state_to_str(state), wm0010_state_to_str(state + 1)); @@ -734,9 +730,8 @@ static int wm0010_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_STANDBY: if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) { - mutex_lock(&wm0010->lock); - wm0010_halt(component); - mutex_unlock(&wm0010->lock); + scoped_guard(mutex, &wm0010->lock) + wm0010_halt(component); } break; case SND_SOC_BIAS_OFF: @@ -832,9 +827,8 @@ static irqreturn_t wm0010_irq(int irq, void *data) case WM0010_OUT_OF_RESET: case WM0010_BOOTROM: case WM0010_STAGE2: - spin_lock(&wm0010->irq_lock); - complete(&wm0010->boot_completion); - spin_unlock(&wm0010->irq_lock); + scoped_guard(spinlock, &wm0010->irq_lock) + complete(&wm0010->boot_completion); return IRQ_HANDLED; default: return IRQ_NONE; From b0515499ffdd5d72884eb780dc2cc58dd2a18ba8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:39 +0700 Subject: [PATCH 385/438] ASoC: codecs: wm2000: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-18-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 9b68ee69324b..897b0acac5f3 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -612,20 +613,15 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); unsigned int anc_active = ucontrol->value.integer.value[0]; - int ret; if (anc_active > 1) return -EINVAL; - mutex_lock(&wm2000->lock); + guard(mutex)(&wm2000->lock); wm2000->anc_active = anc_active; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, @@ -645,20 +641,15 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); unsigned int val = ucontrol->value.integer.value[0]; - int ret; if (val > 1) return -EINVAL; - mutex_lock(&wm2000->lock); + guard(mutex)(&wm2000->lock); wm2000->spk_ena = val; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static const struct snd_kcontrol_new wm2000_controls[] = { @@ -676,9 +667,8 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); - int ret; - mutex_lock(&wm2000->lock); + guard(mutex)(&wm2000->lock); if (SND_SOC_DAPM_EVENT_ON(event)) wm2000->anc_eng_ena = 1; @@ -686,11 +676,7 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, if (SND_SOC_DAPM_EVENT_OFF(event)) wm2000->anc_eng_ena = 0; - ret = wm2000_anc_set_mode(wm2000); - - mutex_unlock(&wm2000->lock); - - return ret; + return wm2000_anc_set_mode(wm2000); } static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { From e396bb39a7702d69ced88c6e9f014fa1febdc009 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:40 +0700 Subject: [PATCH 386/438] ASoC: codecs: wm5102: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-19-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index b4d4137c05b4..74b775b95bfd 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -7,6 +7,7 @@ * Author: Mark Brown */ +#include #include #include #include @@ -667,10 +668,9 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); put_unaligned_be16(arizona->dac_comp_coeff, ucontrol->value.bytes.data); - mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -681,16 +681,14 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); - int ret = 0; - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); if (arizona->dac_comp_coeff != dac_comp_coeff) { arizona->dac_comp_coeff = dac_comp_coeff; - ret = 1; + return 1; } - mutex_unlock(&arizona->dac_comp_lock); - return ret; + return 0; } static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, @@ -699,9 +697,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; - mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -712,19 +709,17 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct arizona *arizona = dev_get_drvdata(component->dev->parent); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int ret = 0; if (ucontrol->value.integer.value[0] > mc->max) return -EINVAL; - mutex_lock(&arizona->dac_comp_lock); + guard(mutex)(&arizona->dac_comp_lock); if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) { arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; - ret = 1; + return 1; } - mutex_unlock(&arizona->dac_comp_lock); - return ret; + return 0; } static const char * const wm5102_osr_text[] = { From a4aaef818a0875359bcb70bc45a22edee8916090 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:41 +0700 Subject: [PATCH 387/438] ASoC: codecs: wm8731: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-20-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index a2f0e2f5c407..ce87280d590d 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -10,6 +10,7 @@ * Based on wm8753.c by Liam Girdwood */ +#include #include #include #include @@ -110,22 +111,20 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component); unsigned int deemph = ucontrol->value.integer.value[0]; - int ret = 0; if (deemph > 1) return -EINVAL; - mutex_lock(&wm8731->lock); + guard(mutex)(&wm8731->lock); if (wm8731->deemph != deemph) { wm8731->deemph = deemph; wm8731_set_deemph(component); - ret = 1; + return 1; } - mutex_unlock(&wm8731->lock); - return ret; + return 0; } static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0); From 06b3eee8ac1ebc756858ab2a8df1488707a82a55 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:42 +0700 Subject: [PATCH 388/438] ASoC: codecs: wm8903: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-21-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 320d7737699d..156e1e24a388 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -458,22 +459,20 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component); unsigned int deemph = ucontrol->value.integer.value[0]; - int ret = 0; if (deemph > 1) return -EINVAL; - mutex_lock(&wm8903->lock); + guard(mutex)(&wm8903->lock); if (wm8903->deemph != deemph) { wm8903->deemph = deemph; wm8903_set_deemph(component); - ret = 1; + return 1; } - mutex_unlock(&wm8903->lock); - return ret; + return 0; } /* ALSA can only do steps of .01dB */ From b6eda65e115f999eaffad4eb028e356cec45bab7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:43 +0700 Subject: [PATCH 389/438] ASoC: codecs: wm8958: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-22-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8958-dsp2.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 8ff0882732e7..f75a6dc9d2bb 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -7,6 +7,7 @@ * Author: Mark Brown */ +#include #include #include #include @@ -864,9 +865,8 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) { - mutex_lock(&wm8994->fw_lock); + guard(mutex)(&wm8994->fw_lock); wm8994->enh_eq = fw; - mutex_unlock(&wm8994->fw_lock); } } @@ -876,9 +876,8 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) { - mutex_lock(&wm8994->fw_lock); + guard(mutex)(&wm8994->fw_lock); wm8994->mbc_vss = fw; - mutex_unlock(&wm8994->fw_lock); } } @@ -888,9 +887,8 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) { - mutex_lock(&wm8994->fw_lock); + guard(mutex)(&wm8994->fw_lock); wm8994->mbc = fw; - mutex_unlock(&wm8994->fw_lock); } } From ee7bc9aa8d39d8790bf18f5b06d71903c9c7440f Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:44 +0700 Subject: [PATCH 390/438] ASoC: codecs: wm8962: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-23-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 2db822fc1de7..8a9598161b35 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1564,11 +1565,10 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int old = wm8962->dsp2_ena; - int ret = 0; int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) & WM8962_DSP2_ENA; - mutex_lock(&wm8962->dsp2_ena_lock); + guard(mutex)(&wm8962->dsp2_ena_lock); if (ucontrol->value.integer.value[0]) wm8962->dsp2_ena |= 1 << shift; @@ -1576,9 +1576,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, wm8962->dsp2_ena &= ~(1 << shift); if (wm8962->dsp2_ena == old) - goto out; - - ret = 1; + return 0; if (dsp2_running) { if (wm8962->dsp2_ena) @@ -1587,10 +1585,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, wm8962_dsp2_stop(component); } -out: - mutex_unlock(&wm8962->dsp2_ena_lock); - - return ret; + return 1; } /* The VU bits for the headphones are in a different register to the mute From e2f1f4ad30db772f14b8e628878cac815c5b7ac8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:45 +0700 Subject: [PATCH 391/438] ASoC: codecs: wm8994: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-24-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1d64c7c42ed1..8bf58a6a8af7 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -7,6 +7,7 @@ * Author: Mark Brown */ +#include #include #include #include @@ -766,7 +767,7 @@ static void active_reference(struct snd_soc_component *component) { struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); wm8994->active_refcount++; @@ -775,8 +776,6 @@ static void active_reference(struct snd_soc_component *component) /* If we're using jack detection go into audio mode */ wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO); - - mutex_unlock(&wm8994->accdet_lock); } static void active_dereference(struct snd_soc_component *component) @@ -784,7 +783,7 @@ static void active_dereference(struct snd_soc_component *component) struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); u16 mode; - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); wm8994->active_refcount--; @@ -800,8 +799,6 @@ static void active_dereference(struct snd_soc_component *component) wm1811_jackdet_set_mode(component, mode); } - - mutex_unlock(&wm8994->accdet_lock); } static int clk_sys_event(struct snd_soc_dapm_widget *w, @@ -3704,7 +3701,7 @@ static void wm8958_open_circuit_work(struct work_struct *work) open_circuit_work.work); struct device *dev = wm8994->wm8994->dev; - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); wm1811_micd_stop(wm8994->hubs.component); @@ -3718,8 +3715,6 @@ static void wm8958_open_circuit_work(struct work_struct *work) snd_soc_jack_report(wm8994->micdet[0].jack, 0, wm8994->btn_mask | SND_JACK_HEADSET); - - mutex_unlock(&wm8994->accdet_lock); } static void wm8958_mic_id(void *data, u16 status) @@ -3777,7 +3772,7 @@ static void wm1811_mic_work(struct work_struct *work) struct snd_soc_component *component = wm8994->hubs.component; struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - pm_runtime_get_sync(component->dev); + guard(pm_runtime_active)(component->dev); /* If required for an external cap force MICBIAS on */ if (control->pdata.jd_ext_cap) { @@ -3785,7 +3780,7 @@ static void wm1811_mic_work(struct work_struct *work) snd_soc_dapm_sync(dapm); } - mutex_lock(&wm8994->accdet_lock); + guard(mutex)(&wm8994->accdet_lock); dev_dbg(component->dev, "Starting mic detection\n"); @@ -3803,10 +3798,6 @@ static void wm1811_mic_work(struct work_struct *work) snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1, WM8958_MICD_ENA, WM8958_MICD_ENA); } - - mutex_unlock(&wm8994->accdet_lock); - - pm_runtime_put(component->dev); } static irqreturn_t wm1811_jackdet_irq(int irq, void *data) @@ -4026,15 +4017,10 @@ static void wm8958_mic_work(struct work_struct *work) mic_complete_work.work); struct snd_soc_component *component = wm8994->hubs.component; - pm_runtime_get_sync(component->dev); - - mutex_lock(&wm8994->accdet_lock); + guard(pm_runtime_active)(component->dev); + guard(mutex)(&wm8994->accdet_lock); wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status); - - mutex_unlock(&wm8994->accdet_lock); - - pm_runtime_put(component->dev); } static irqreturn_t wm8958_mic_irq(int irq, void *data) From a65ce15323994240d0c1f66be107db0991a8acf7 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:46 +0700 Subject: [PATCH 392/438] ASoC: codecs: wm971x: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-25-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 5 ++--- sound/soc/codecs/wm9713.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 83cd42fa0c28..3105b2e0556f 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -6,6 +6,7 @@ * Author: Liam Girdwood */ +#include #include #include #include @@ -229,7 +230,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, shift = mc->shift & 0xff; mask = 1 << shift; - mutex_lock(&wm9712->lock); + guard(mutex)(&wm9712->lock); old = wm9712->hp_mixer[mixer]; if (ucontrol->value.integer.value[0]) wm9712->hp_mixer[mixer] |= mask; @@ -251,8 +252,6 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, &update); } - mutex_unlock(&wm9712->lock); - return change; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index b3bbecf074ee..3ba7ca3c1770 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -11,6 +11,7 @@ * o Support for DAPM */ +#include #include #include #include @@ -238,7 +239,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, shift = mc->shift & 0xff; mask = (1 << shift); - mutex_lock(&wm9713->lock); + guard(mutex)(&wm9713->lock); old = wm9713->hp_mixer[mixer]; if (ucontrol->value.integer.value[0]) wm9713->hp_mixer[mixer] |= mask; @@ -260,8 +261,6 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, &update); } - mutex_unlock(&wm9713->lock); - return change; } From 46f350091576e8869e6345abb15135084df5e7fe Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:47 +0700 Subject: [PATCH 393/438] ASoC: codecs: wm_adsp: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Reviewed-by: Richard Fitzgerald Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-26-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 77 ++++++++++++-------------------------- 1 file changed, 23 insertions(+), 54 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index baa75e7ff53b..90c24c4b318e 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -348,7 +348,6 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *dsp = snd_soc_component_get_drvdata(component); - int ret = 1; if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) return 0; @@ -356,16 +355,14 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW) return -EINVAL; - mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock); + guard(mutex)(&dsp[e->shift_l].cs_dsp.pwr_lock); if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list)) - ret = -EBUSY; + return -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; - mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock); - - return ret; + return 1; } EXPORT_SYMBOL_GPL(wm_adsp_fw_put); @@ -450,15 +447,13 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, if (val == 0) return 0; /* 0 means no event */ - mutex_lock(&cs_ctl->dsp->pwr_lock); + guard(mutex)(&cs_ctl->dsp->pwr_lock); if (cs_ctl->enabled) ret = cs_dsp_coeff_write_acked_control(cs_ctl, val); else ret = -EPERM; - mutex_unlock(&cs_ctl->dsp->pwr_lock); - if (ret < 0) return ret; @@ -486,15 +481,13 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; int ret = 0; - mutex_lock(&cs_ctl->dsp->pwr_lock); + guard(mutex)(&cs_ctl->dsp->pwr_lock); ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size); if (!ret && copy_to_user(bytes, cs_ctl->cache, size)) ret = -EFAULT; - mutex_unlock(&cs_ctl->dsp->pwr_lock); - return ret; } @@ -694,10 +687,9 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, struct cs_dsp_coeff_ctl *cs_ctl; int ret; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); - mutex_unlock(&dsp->cs_dsp.pwr_lock); if (ret < 0) return ret; @@ -709,14 +701,10 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) { - int ret; + guard(mutex)(&dsp->cs_dsp.pwr_lock); - mutex_lock(&dsp->cs_dsp.pwr_lock); - ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), + return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), 0, buf, len); - mutex_unlock(&dsp->cs_dsp.pwr_lock); - - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); @@ -1270,38 +1258,32 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) { struct wm_adsp_compr *compr, *tmp; struct snd_soc_pcm_runtime *rtd = stream->private_data; - int ret = 0; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); if (wm_adsp_fw[dsp->fw].num_caps == 0) { adsp_err(dsp, "%s: Firmware does not support compressed API\n", snd_soc_rtd_to_codec(rtd, 0)->name); - ret = -ENXIO; - goto out; + return -ENXIO; } if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { adsp_err(dsp, "%s: Firmware does not support stream direction\n", snd_soc_rtd_to_codec(rtd, 0)->name); - ret = -EINVAL; - goto out; + return -EINVAL; } list_for_each_entry(tmp, &dsp->compr_list, list) { if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) { adsp_err(dsp, "%s: Only a single stream supported per dai\n", snd_soc_rtd_to_codec(rtd, 0)->name); - ret = -EBUSY; - goto out; + return -EBUSY; } } compr = kzalloc_obj(*compr); - if (!compr) { - ret = -ENOMEM; - goto out; - } + if (!compr) + return -ENOMEM; compr->dsp = dsp; compr->stream = stream; @@ -1311,10 +1293,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) stream->runtime->private_data = compr; -out: - mutex_unlock(&dsp->cs_dsp.pwr_lock); - - return ret; + return 0; } EXPORT_SYMBOL_GPL(wm_adsp_compr_open); @@ -1324,7 +1303,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component, struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp *dsp = compr->dsp; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); wm_adsp_compr_detach(compr); list_del(&compr->list); @@ -1332,8 +1311,6 @@ int wm_adsp_compr_free(struct snd_soc_component *component, kfree(compr->raw_buf); kfree(compr); - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return 0; } EXPORT_SYMBOL_GPL(wm_adsp_compr_free); @@ -1741,7 +1718,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, compr_dbg(compr, "Trigger: %d\n", cmd); - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1777,8 +1754,6 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, break; } - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); @@ -1907,21 +1882,20 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, compr_dbg(compr, "Pointer request\n"); - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); buf = compr->buf; if (dsp->fatal_error || !buf || buf->error) { snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); - ret = -EIO; - goto out; + return -EIO; } if (buf->avail < wm_adsp_compr_frag_words(compr)) { ret = wm_adsp_buffer_update_avail(buf); if (ret < 0) { compr_err(compr, "Error reading avail: %d\n", ret); - goto out; + return ret; } /* @@ -1934,14 +1908,14 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, if (buf->error) snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); - goto out; + return ret; } ret = wm_adsp_buffer_reenable_irq(buf); if (ret < 0) { compr_err(compr, "Failed to re-enable buffer IRQ: %d\n", ret); - goto out; + return ret; } } } @@ -1950,9 +1924,6 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE; tstamp->sampling_rate = compr->sample_rate; -out: - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); @@ -2063,15 +2034,13 @@ int wm_adsp_compr_copy(struct snd_soc_component *component, struct wm_adsp *dsp = compr->dsp; int ret; - mutex_lock(&dsp->cs_dsp.pwr_lock); + guard(mutex)(&dsp->cs_dsp.pwr_lock); if (stream->direction == SND_COMPRESS_CAPTURE) ret = wm_adsp_compr_read(compr, buf, count); else ret = -ENOTSUPP; - mutex_unlock(&dsp->cs_dsp.pwr_lock); - return ret; } EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); From 3ca9593964f7e4bb8e21efc536e76722ff56e5bd Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 31 Jul 2026 10:06:48 +0700 Subject: [PATCH 394/438] ASoC: codecs: wsa88xx: Use guard() for mutex locks Clean up the code using guard() for mutex locks. Merely code refactoring, and no behavior change. Signed-off-by: bui duc phuc Reviewed-by: Cezary Rojewski Link: https://patch.msgid.link/20260731030648.8706-27-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 11 +++++------ sound/soc/codecs/wsa884x.c | 10 ++++------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 24a5904d8e6c..442cf9f3eaac 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -1237,9 +1238,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - mutex_lock(&wsa883x->sp_lock); - wsa883x->pa_on = true; - mutex_unlock(&wsa883x->sp_lock); + scoped_guard(mutex, &wsa883x->sp_lock) + wsa883x->pa_on = true; switch (wsa883x->dev_mode) { case RECEIVER: @@ -1290,9 +1290,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, WSA883X_GLOBAL_PA_EN_MASK, 0); snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, WSA883X_PDM_EN_MASK, 0); - mutex_lock(&wsa883x->sp_lock); - wsa883x->pa_on = false; - mutex_unlock(&wsa883x->sp_lock); + scoped_guard(mutex, &wsa883x->sp_lock) + wsa883x->pa_on = false; break; } return 0; diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 567861dd42ad..a367c94bfb4d 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1701,9 +1701,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - mutex_lock(&wsa884x->sp_lock); - wsa884x->pa_on = true; - mutex_unlock(&wsa884x->sp_lock); + scoped_guard(mutex, &wsa884x->sp_lock) + wsa884x->pa_on = true; wsa884x_spkr_post_pmu(component, wsa884x); @@ -1717,9 +1716,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, 0x0); - mutex_lock(&wsa884x->sp_lock); - wsa884x->pa_on = false; - mutex_unlock(&wsa884x->sp_lock); + scoped_guard(mutex, &wsa884x->sp_lock) + wsa884x->pa_on = false; break; } From dc15652b92a8772a6d6a07b1d18ea88cf0b826d3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:22:41 +0300 Subject: [PATCH 395/438] ASoC: SOF: Intel: hda-stream: clear hstream->running flag in hw_params During hw_params call we make sure that the host DMA is stopped but the hstream->running flag is not explicitly cleared at the same time. If the host DMA fails to stop during previous use then the flag is left set and on next start the host DMA will be left disabled since the trigger:STOP will skip the DMA enable. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Link: https://patch.msgid.link/20260730122241.30541-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-stream.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 0778002e2bd6..c95230487a1b 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -613,6 +613,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return ret; } + /* Host DMA is not running */ + hstream->running = false; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, From f6970d8535a95c137f05e9ca825072de3b217b88 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 30 Jul 2026 14:06:02 +0100 Subject: [PATCH 396/438] ASoC: SDCA: Add missing stub for sdca_fdl_free_state() There should be a stub for sdca_fdl_free_state() for the case FDL support isn't built into the kernel. Add the missing stub. Fixes: 0880082c27b6 ("ASoC: SDCA: Remove devm from primary IRQ cleanup") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202607291304.FE3mOcJF-lkp@intel.com/ Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20260730130602.3747053-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/sdca_fdl.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/sound/sdca_fdl.h b/include/sound/sdca_fdl.h index fbaf4b384c8a..979559e9ee63 100644 --- a/include/sound/sdca_fdl.h +++ b/include/sound/sdca_fdl.h @@ -81,6 +81,10 @@ static inline int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt) return 0; } +static inline void sdca_fdl_free_state(struct sdca_interrupt *interrupt) +{ +} + static inline int sdca_fdl_process(struct sdca_interrupt *interrupt) { return 0; From 8338deeb8fc28925257a9a3bfad1dc78c8d74cef Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 31 Jul 2026 16:18:26 +0100 Subject: [PATCH 397/438] ASoC: es9356: Remove unused headers es9356 doesn't use any SDCA function/regmap features, remove the redundant included headers. Signed-off-by: Charles Keepax Link: https://patch.msgid.link/20260731151826.961912-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/es9356.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c index a9863900bf70..80db0f2f4aef 100644 --- a/sound/soc/codecs/es9356.c +++ b/sound/soc/codecs/es9356.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include #include From 7b51d4c4256cd5f8922f7ad45e79b5fff89c0995 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:28:56 +0300 Subject: [PATCH 398/438] ASoC: SOF: Intel: hda: Power down DSP if it is left enabled in pre_fw_run() It is expected that the DSP is in power down state when the firmware boot is attempted. If the DSP for any reason was left powered up then the DSP boot will fail since the ROM boot sequence might not be able to run. Make sure that the DSP is off before proceeding to boot it up. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730122857.5294-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index dc85903b8d46..007a8e4a2f3d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -421,6 +421,20 @@ static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { } /* pre fw run operations */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + int ret; + + /* Power down DSP if left enabled to ensure a clean boot state. */ + if (hda_dsp_core_is_enabled(sdev, chip->host_managed_cores_mask)) { + dev_dbg(sdev->dev, "DSP core enabled, power down DSP first\n"); + + ret = chip->power_down_dsp(sdev); + if (ret < 0) + dev_warn(sdev->dev, + "%s: failed to power down already-enabled DSP\n", __func__); + } + /* disable clock gating and power gating */ return hda_dsp_ctrl_clock_power_gating(sdev, false); } From 31fd7a0bbfa4b7e8aff11f278e817664c6a5f68b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:28:57 +0300 Subject: [PATCH 399/438] ASoC: SOF: Intel: mtl: Power down DSP if it is left enabled in pre_fw_run() It is expected that the DSP is in power down state when the firmware boot is attempted. If the DSP for any reason was left powered up then the DSP boot will fail since the ROM boot sequence might not be able to run. Make sure that the DSP is off before proceeding to boot it up. Signed-off-by: Peter Ujfalusi Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730122857.5294-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/mtl.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 9503d00e6002..3d67d6777f1b 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -236,6 +236,17 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) } EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL"); +static bool mtl_dsp_is_enabled(struct snd_sof_dev *sdev) +{ + int val; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + if (val & MTL_HFDSSCS_CPA_MASK) + return true; + + return false; +} + /* pre fw run operations */ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) { @@ -249,6 +260,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) u32 dsppwrsts; const struct sof_intel_dsp_desc *chip; + /* Power down the DSP if it is left enabled to ensure clean boot state */ + if (mtl_dsp_is_enabled(sdev)) { + dev_dbg(sdev->dev, "powering down DSP first\n"); + + ret = mtl_power_down_dsp(sdev); + if (ret < 0) { + dev_warn(sdev->dev, + "%s: failed to power down already-enabled DSP\n", __func__); + /* Continue anyway to attempt recovery */ + } + } + chip = get_chip_info(sdev->pdata); if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) { dsppwrctl = PTL_HFPWRCTL2; From c1c90903a25d2f0d5d8fe689fc6371e13c8f796e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:51:27 +0300 Subject: [PATCH 400/438] ASoC: SOF: Intel: hda: Fold mlink enumeration into hda_dsp_ctrl_init_chip() Move the hda_bus_ml_init() call from hda_init_caps() into hda_dsp_ctrl_init_chip(), right after the HDA controller reset has been de-asserted and unsolicited responses have been accepted. hda_dsp_ctrl_init_chip() already calls hda_bus_ml_reset_losidv() at the end of its sequence to clear the stream-to-link mapping. On first boot this call was a no-op because the multi-link list had not yet been populated: hda_bus_ml_init() only runs later in hda_init_caps(). Enumerating the links inside init_chip() makes the LOSIDV reset effective on first boot as well, without adding a second reset call from the probe path. hda_bus_ml_init() now returns early when the hlink_list is already populated, so the subsequent invocations from the D3 resume path (hda_resume() -> hda_dsp_ctrl_init_chip(false)) are no-ops. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730125130.29887-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-ctrl.c | 8 ++++++++ sound/soc/sof/intel/hda-mlink.c | 4 ++++ sound/soc/sof/intel/hda.c | 2 -- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 8332d4bda558..a9ead78d3fcb 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -223,6 +223,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) /* Accept unsolicited responses */ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); + /* Perform a one-time enumeration of the Multi-Link capability */ + ret = hda_bus_ml_init(bus); + if (ret < 0) { + dev_err(sdev->dev, "%s: failed to enumerate multi-links\n", + __func__); + goto err; + } + if (detect_codec) hda_codec_detect_mask(sdev); diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index 92314e3b568a..ca8551befdb5 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -432,6 +432,10 @@ int hda_bus_ml_init(struct hdac_bus *bus) if (!bus->mlcap) return 0; + /* Enumeration is a one time operation, skip if already done */ + if (!list_empty(&bus->hlink_list)) + return 0; + link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 007a8e4a2f3d..8602ae3892a2 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -639,8 +639,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) return ret; } - hda_bus_ml_init(bus); - /* Skip SoundWire if it is not supported */ if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) goto skip_soundwire; From 9e6966f7040451603d4c93341d0205421046d902 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:51:28 +0300 Subject: [PATCH 401/438] ASoC: SOF: Intel: hda: Keep non-alt mlinks powered at probe on ACE2+ Drop the hda_bus_ml_put_all() call at the end of hda_init_caps(). On multi-link (mlink) capable platforms the non-alternate links (HDaudio and iDisp) are powered on by hardware when CRST# is de-asserted (LCTL.SPA = 1) and their ref_count is pre-charged to 1 in hda_ml_alloc_h2link() to match this state. The put_all call immediately dropped that reference and toggled LCTL.SPA back to 0, relying on the first stream open to power the link up again. On ACE2+ platforms this redundant SPA 1->0->1 toggle at probe leaves the Processing Pipe Capability (PPLC) Linear Link Position counters in a state where they do not advance on the first stream after boot. The counters only start working after the first full runtime suspend/resume cycle, which includes a CRST# assert/deassert that fully resets the PPC AON block. Keep the non-alt links powered from CRST# de-assert through first use. System suspend still powers them down via hda_bus_ml_suspend(), and resume relies on CRST# de-assert to bring them back up, so no other path is affected. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730125130.29887-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 8602ae3892a2..4dbba9186b29 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -682,8 +682,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (!HDA_IDISP_CODEC(bus->codec_mask)) hda_codec_i915_display_power(sdev, false); - hda_bus_ml_put_all(bus); - return 0; } From 15488685319379212084c0513661c7dfbc239636 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:51:29 +0300 Subject: [PATCH 402/438] ASoC: SOF: Intel: hda: Remove unused hda_bus_ml_put_all() The helper became unused after probe no longer drops all non-alt links, so remove the dead API and implementation. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730125130.29887-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/hda-mlink.h | 2 -- sound/soc/sof/intel/hda-mlink.c | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index fed69998c93f..d9789b048c61 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -49,7 +49,6 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num); int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, int channel_mask, int stream_id, int dir); -void hda_bus_ml_put_all(struct hdac_bus *bus); void hda_bus_ml_reset_losidv(struct hdac_bus *bus); int hda_bus_ml_resume(struct hdac_bus *bus); int hda_bus_ml_suspend(struct hdac_bus *bus); @@ -169,7 +168,6 @@ hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, return 0; } -static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { } static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { } static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; } static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; } diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index ca8551befdb5..e0107cbd06e6 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -884,19 +884,6 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, return 0; } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK"); -void hda_bus_ml_put_all(struct hdac_bus *bus) -{ - struct hdac_ext_link *hlink; - - list_for_each_entry(hlink, &bus->hlink_list, list) { - struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink); - - if (!h2link->alt) - snd_hdac_ext_bus_link_put(bus, hlink); - } -} -EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK"); - void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { struct hdac_ext_link *hlink; From 34d466aaa0d533f082b35629f8fd91cb8c260296 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 30 Jul 2026 15:51:30 +0300 Subject: [PATCH 403/438] ASoC: SOF: Intel: hda: Avoid ACE2+ link DMA stream allocation hazards On ACE2+ platforms the link DMA stream allocator must avoid two hardware errata in mlink-capable systems: - Concurrent (cross-direction) hazard: when SoundWire shares a physical link DMA stream index with HDaudio, iDisp or UAOL across the two directions, the LLP and timestamp values for the affected stream are wrong. SSP and DMIC are not affected because every DMA request from those links carries one sample block. - Sequential (playback only) hazard: once a HDaudio or iDisp link has used a playback stream index, that index cannot drive any non HDA/iDisp link in the same direction until the next controller reset (CRST#). Track the active link type per direction in two masks (one for SoundWire, one for HDA/iDisp/UAOL) and the persistent set of playback stream indices touched by HDA/iDisp in a third mask. The link DMA allocator skips streams that would violate either rule. Streams are released from the active masks when the stream is released; all masks are cleared in hda_dsp_ctrl_init_chip() because the CRST# performed there clears the hardware state as well. A new helper hda_bus_ml_link_get_type() returns the link type from the existing extended link descriptor so the SOF allocator can tell SoundWire, HDA/iDisp and UAOL apart without duplicating the parsing. The implementation is generic. On platforms older than ACE2 every link is reported as HDA, only the sequential mask is ever set and it has no effect because no other link types are present, so behavior is unchanged. Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Liam Girdwood Link: https://patch.msgid.link/20260730125130.29887-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/hda-mlink.h | 21 +++++++++ sound/soc/sof/intel/hda-ctrl.c | 11 +++++ sound/soc/sof/intel/hda-dai-ops.c | 76 ++++++++++++++++++++++++++++--- sound/soc/sof/intel/hda-dai.c | 2 +- sound/soc/sof/intel/hda-mlink.c | 18 ++++++++ sound/soc/sof/intel/hda.h | 26 ++++++++++- 6 files changed, 146 insertions(+), 8 deletions(-) diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h index d9789b048c61..ba35f03576b9 100644 --- a/include/sound/hda-mlink.h +++ b/include/sound/hda-mlink.h @@ -9,6 +9,22 @@ struct hdac_bus; struct hdac_ext_link; +/** + * enum hda_bus_ml_link_type - mlink link type, used by SOF link DMA + * allocator constraints (see struct sof_intel_hda_dev). + * + * @HDA_BUS_ML_LINK_HDA: non-alt link, i.e. HDA codec or iDisp + * @HDA_BUS_ML_LINK_SDW: alt link, SoundWire + * @HDA_BUS_ML_LINK_UAOL: alt link, USB Audio Offload + * @HDA_BUS_ML_LINK_OTHER: alt link, SSP or DMIC + */ +enum hda_bus_ml_link_type { + HDA_BUS_ML_LINK_HDA, + HDA_BUS_ML_LINK_SDW, + HDA_BUS_ML_LINK_UAOL, + HDA_BUS_ML_LINK_OTHER, +}; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK) int hda_bus_ml_init(struct hdac_bus *bus); @@ -53,6 +69,8 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus); int hda_bus_ml_resume(struct hdac_bus *bus); int hda_bus_ml_suspend(struct hdac_bus *bus); +enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink); + struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus); struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus); struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus); @@ -172,6 +190,9 @@ static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { } static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; } static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; } +static inline enum hda_bus_ml_link_type +hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) { return HDA_BUS_ML_LINK_HDA; } + static inline struct hdac_ext_link * hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { return NULL; } diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index a9ead78d3fcb..aeb34310eebd 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -186,6 +186,7 @@ EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON" int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) { struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); struct hdac_stream *stream; int sd_offset, ret = 0; u32 gctl; @@ -193,6 +194,16 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) if (bus->chip_init) return 0; + /* + * The controller reset clears the ACE2+ link DMA stream allocation + * constraints; reset the masks to reflect this. + */ + memset(sof_hda->link_dma_active_sdw_mask, 0, + sizeof(sof_hda->link_dma_active_sdw_mask)); + memset(sof_hda->link_dma_active_multi_mask, 0, + sizeof(sof_hda->link_dma_active_multi_mask)); + sof_hda->link_dma_out_hda_used_mask = 0; + hda_codec_set_codec_wakeup(sdev, true); hda_dsp_ctrl_misc_clock_gating(sdev, false); diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c index b2c559559962..f0be42048db3 100644 --- a/sound/soc/sof/intel/hda-dai-ops.c +++ b/sound/soc/sof/intel/hda-dai-ops.c @@ -20,7 +20,7 @@ /* These ops are only applicable for the HDA DAI's in their current form */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) /* - * This function checks if the host dma channel corresponding + * This function checks if the host DMA stream corresponding * to the link DMA stream_tag argument is assigned to one * of the FEs connected to the BE DAI. */ @@ -42,23 +42,53 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, } static struct hdac_ext_stream * -hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) +hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream, + enum hda_bus_ml_link_type link_type) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); struct sof_intel_hda_stream *hda_stream; const struct sof_intel_dsp_desc *chip; struct snd_sof_dev *sdev; struct hdac_ext_stream *res = NULL; struct hdac_stream *hstream = NULL; - int stream_dir = substream->stream; + bool is_multi = link_type == HDA_BUS_ML_LINK_HDA || link_type == HDA_BUS_ML_LINK_UAOL; + bool is_play = stream_dir == SNDRV_PCM_STREAM_PLAYBACK; + bool is_sdw = link_type == HDA_BUS_ML_LINK_SDW; + bool is_hda = link_type == HDA_BUS_ML_LINK_HDA; + u32 concur_block_mask = 0; + u32 seq_block_mask = 0; + unsigned int stream_idx; if (!bus->ppcap) { dev_err(bus->dev, "stream type not supported\n"); return NULL; } + /* + * On ACE2+ the link DMA stream allocator must avoid two HW errata, + * see the comment on struct sof_intel_hda_dev. + * + * - Concurrent cross-direction: SoundWire conflicts with HDA, iDisp + * and UAOL on the same physical stream index; SSP and DMIC are safe. + * - Sequential playback: a stream index previously used by an HDA/iDisp + * link cannot drive any non-HDA/iDisp link in the same direction + * until the next controller reset. + * + * The masks are protected by bus->reg_lock; sample them inside the + * lock together with the stream walk to keep the decision atomic + * with concurrent allocations and releases. + */ guard(spinlock_irq)(&bus->reg_lock); + + if (is_sdw) + concur_block_mask = sof_hda->link_dma_active_multi_mask[!stream_dir]; + else if (is_multi) + concur_block_mask = sof_hda->link_dma_active_sdw_mask[!stream_dir]; + if (is_play && !is_hda) + seq_block_mask = sof_hda->link_dma_out_hda_used_mask; + list_for_each_entry(hstream, &bus->stream_list, list) { struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); @@ -69,6 +99,12 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream sdev = hda_stream->sdev; chip = get_chip_info(sdev->pdata); + stream_idx = hstream->stream_tag - 1; + + /* skip streams blocked by the ACE2+ allocator constraints */ + if ((concur_block_mask | seq_block_mask) & BIT(stream_idx)) + continue; + /* check if link is available */ if (!hext_stream->link_locked) { /* @@ -95,7 +131,7 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream /* * This must be a hostless stream. - * So reserve the host DMA channel. + * So reserve the host DMA stream. */ hda_stream->host_reserved = 1; break; @@ -109,6 +145,16 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream res->link_locked = 1; res->link_substream = substream; + + stream_idx = res->hstream.stream_tag - 1; + if (is_sdw) + sof_hda->link_dma_active_sdw_mask[stream_dir] |= BIT(stream_idx); + else if (is_multi) + sof_hda->link_dma_active_multi_mask[stream_dir] |= BIT(stream_idx); + + /* persistent OUT HDA/iDisp shadow, cleared only on CRST# */ + if (is_hda && is_play) + sof_hda->link_dma_out_hda_used_mask |= BIT(stream_idx); } return res; @@ -143,11 +189,13 @@ static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + struct hdac_ext_link *hlink) { struct hdac_ext_stream *hext_stream; + enum hda_bus_ml_link_type link_type = hda_bus_ml_link_get_type(hlink); - hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); + hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream, link_type); if (!hext_stream) return NULL; @@ -160,6 +208,22 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai struct snd_pcm_substream *substream) { struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); + struct sof_intel_hda_dev *sof_hda = sdev->pdata->hw_pdata; + struct hdac_bus *bus = sof_to_bus(sdev); + int dir = substream->stream; + unsigned int stream_idx = hext_stream->hstream.stream_tag - 1; + + /* + * Drop the stream index from the per-direction active concurrency masks. + * The two masks are mutually exclusive for a given stream/direction + * (and a stream of the SSP/DMIC kind appears in neither), so a blind + * clear of both is safe and lets us avoid having to remember the + * link type at allocation time. + */ + scoped_guard(spinlock_irq, &bus->reg_lock) { + sof_hda->link_dma_active_sdw_mask[dir] &= ~BIT(stream_idx); + sof_hda->link_dma_active_multi_mask[dir] &= ~BIT(stream_idx); + } snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 15faedeec16d..bb44d4f8a4da 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -188,7 +188,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, if (!hext_stream) { if (ops->assign_hext_stream) - hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); + hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream, hlink); } if (!hext_stream) diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index e0107cbd06e6..6f02fb5b70ce 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -894,6 +894,24 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus) } EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK"); +enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) +{ + struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink); + + if (!h2link->alt) + return HDA_BUS_ML_LINK_HDA; + + switch (h2link->elid) { + case AZX_REG_ML_LEPTR_ID_SDW: + return HDA_BUS_ML_LINK_SDW; + case AZX_REG_ML_LEPTR_ID_INTEL_UAOL: + return HDA_BUS_ML_LINK_UAOL; + default: + return HDA_BUS_ML_LINK_OTHER; + } +} +EXPORT_SYMBOL_NS(hda_bus_ml_link_get_type, "SND_SOC_SOF_HDA_MLINK"); + int hda_bus_ml_resume(struct hdac_bus *bus) { struct hdac_ext_link *hlink; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 799e49539b4a..1609589929a1 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -523,6 +523,29 @@ struct sof_intel_hda_dev { /* the maximum number of streams (playback + capture) supported */ u32 stream_max; + /* + * ACE2+ link DMA stream allocation constraints (stream index = + * stream_tag - 1, shared between input and output directions). All + * masks are cleared by hda_dsp_ctrl_init_chip() on controller reset + * (CRST#). + * + * - Concurrent (cross-direction) constraint: a SoundWire stream and + * a HDA/iDisp/UAOL stream cannot share a physical stream index + * across directions, the resulting LLP/timestamp values are wrong. + * link_dma_active_sdw_mask and link_dma_active_multi_mask + * (indexed by SNDRV_PCM_STREAM_*) track currently allocated + * streams per direction in each of the conflicting groups; SSP + * and DMIC do not participate. Bits are cleared on stream release. + * + * - Sequential (playback only) constraint: once a HDA/iDisp link + * has used a playback stream index, that index cannot drive a + * non-HDA/iDisp link in the same direction until the next CRST#. + * link_dma_out_hda_used_mask records this. + */ + u32 link_dma_active_sdw_mask[SNDRV_PCM_STREAM_LAST + 1]; + u32 link_dma_active_multi_mask[SNDRV_PCM_STREAM_LAST + 1]; + u32 link_dma_out_hda_used_mask; + /* PM related */ bool l1_disabled;/* is DMI link L1 disabled? */ @@ -1031,7 +1054,8 @@ struct hda_dai_widget_dma_ops { struct snd_pcm_substream *substream); struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream); + struct snd_pcm_substream *substream, + struct hdac_ext_link *hlink); void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, struct snd_pcm_substream *substream); void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, From cde33309169224df5a8a5200cb9dec8399b366e1 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Thu, 30 Jul 2026 15:56:00 +0300 Subject: [PATCH 404/438] ASoC: dapm: Add encoder and decoder widget types to kcontrol handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the issue where encoder or decoder widget types are assigned kcontrols in a topology but get ignored. The controls were parsed successfully but were not registered as ALSA kcontrols. In dapm_create_or_share_kcontrol() the snd_soc_dapm_encoder and the snd_soc_dapm_decoder are added to the switch statement to be handled similarly as e.g. the snd_soc_dapm_effect for assigning a proper long control name. In dapm_widget_show_component() the snd_soc_dapm_encoder and the snd_soc_dapm_decoder are added to switch statement to let them to be shown in the debugfs power state output. In snd_soc_dapm_new_widgets() the snd_soc_dapm_encoder and the snd_soc_dapm_decoder are added to same switch case handling as e.g. snd_soc_dapm_effect to be registered with dapm_new_pga(). The previous operation with default in the switch statement silently ignored them. Note: Despite the function name, the dapm_new_pga() is generic utility that calls dapm_create_or_share_kcontrol() for each kcontrol of the widget. Signed-off-by: Seppo Ingalsuo Reviewed-by: Bard Liao Reviewed-by: Péter Ujfalusi Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730125600.6491-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4ad126bd4f70..c98e917cc911 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1203,6 +1203,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, case snd_soc_dapm_pga: case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: + case snd_soc_dapm_encoder: + case snd_soc_dapm_decoder: wname_in_long_name = true; kcname_in_long_name = true; break; @@ -2785,6 +2787,8 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *component, case snd_soc_dapm_pga: case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: + case snd_soc_dapm_encoder: + case snd_soc_dapm_decoder: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: case snd_soc_dapm_supply: @@ -3367,6 +3371,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) case snd_soc_dapm_pga: case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: + case snd_soc_dapm_encoder: + case snd_soc_dapm_decoder: dapm_new_pga(w); break; case snd_soc_dapm_dai_link: From ea1224da5d61ea9a6c18d6b79562a1354dccf395 Mon Sep 17 00:00:00 2001 From: Yu-Hsuan Hsu Date: Thu, 30 Jul 2026 16:04:45 +0300 Subject: [PATCH 405/438] ASoC: SOF: Use high-priority workqueue for PCM period elapsed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The snd_sof_pcm_period_elapsed function currently schedules work on the system-wide workqueue. This can lead to potential delays or jitter in audio processing if the system workqueue is busy with other tasks. To improve real-time performance and ensure timely processing of PCM periods, we can use the system_highpri_wq instead of the default work queue. In performance testing, this change significantly reduced the observed scheduling delays. For instance, under load(stressapptest -M 15000 -m 60), the maximum delay dropped from 9ms on the system workqueue to 5ms on the dedicated high-priority workqueue. Suggested-by: Kai Vehmanen Signed-off-by: Yu-Hsuan Hsu Reviewed-by: Péter Ujfalusi Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Signed-off-by: Peter Ujfalusi Link: https://patch.msgid.link/20260730130445.8277-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index b2071edeaea6..f748d072109a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -62,7 +62,7 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) * To avoid sending IPC before the previous IPC is handled, we * schedule delayed work here to call the snd_pcm_period_elapsed(). */ - schedule_work(&spcm->stream[substream->stream].period_elapsed_work); + queue_work(system_highpri_wq, &spcm->stream[substream->stream].period_elapsed_work); } EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); From cdba62ff7413330451f0f65345166431a5d6e187 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 Jul 2026 19:47:04 +0530 Subject: [PATCH 406/438] ASoC: dt-bindings: qcom: add LPASS LPR vote clock ID Add a new clock ID, LPASS_HW_LPR_VOTE, to represent the LPASS low-power resource (LPR) vote through the PRM interface. The LPASS PRM supports a resource voting mechanism to control low-power states via PARAM_ID_RSC_CPU_LPR. Exposing this as a q6prm clock ID allows clients to request the LPR vote using the existing qcom,q6prm clock provider interface. This functionality is required on newer platforms (e.g. Hawi) where LPASS clients need to explicitly manage LPR resource voting via PRM. Acked-by: Krzysztof Kozlowski Signed-off-by: Prasad Kumpatla Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/20260724141708.2212057-2-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index 7b553a73bc92..8e04106d48be 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -236,6 +236,7 @@ #define LPASS_HW_AVTIMER_VOTE 101 #define LPASS_HW_MACRO_VOTE 102 #define LPASS_HW_DCODEC_VOTE 103 +#define LPASS_HW_LPR_VOTE 104 #define LPASS_CLK_ATTRIBUTE_INVALID 0x0 #define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 From 037826ea448d1ae76113288a7b80bf826a188fef Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 Jul 2026 19:47:05 +0530 Subject: [PATCH 407/438] ASoC: qcom: qdsp6: Increase Q6DSP_MAX_CLK_ID for LPASS LPR vote clock Q6DSP_MAX_CLK_ID defines the upper bound of supported clock identifiers in the qdsp6 LPASS clock driver. Increase the maximum clock ID value to accommodate the LPASS LPR vote clock identifier. Signed-off-by: Prasad Kumpatla Acked-by: Bartosz Golaszewski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260724141708.2212057-3-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c index 03838582aead..ab7d20580638 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c @@ -12,7 +12,7 @@ #include #include "q6dsp-lpass-clocks.h" -#define Q6DSP_MAX_CLK_ID 104 +#define Q6DSP_MAX_CLK_ID 105 #define Q6DSP_LPASS_CLK_ROOT_DEFAULT 0 From 42cc644e071c376410ba0c6147e94aa1ad415ad9 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 24 Jul 2026 19:47:06 +0530 Subject: [PATCH 408/438] ASoC: qcom: q6prm: add support for LPASS LPR resource voting Add support for issuing LPASS low-power resource (LPR) votes through the PRM interface. Some platforms (e.g. Hawi) require the LPASS to be kept active via LPR resource voting instead of the existing hardware core vote mechanism. Handle this by introducing support for PARAM_ID_RSC_CPU_LPR when the LPR vote clock ID is requested. For LPR requests, use the appropriate parameter ID and payload format to disable CPU subsystem sleep, ensuring that the LPASS register space remains accessible. Also add the corresponding clock mapping for LPASS_HW_LPR_VOTE. Reviewed-by: Srinivas Kandagatla Signed-off-by: Prasad Kumpatla Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/20260724141708.2212057-4-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6prm-clocks.c | 2 ++ sound/soc/qcom/qdsp6/q6prm.c | 16 +++++++++++++--- sound/soc/qcom/qdsp6/q6prm.h | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c index 4c574b48ab00..2b2b3872ed1c 100644 --- a/sound/soc/qcom/qdsp6/q6prm-clocks.c +++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c @@ -63,6 +63,8 @@ static const struct q6dsp_clk_init q6prm_clks[] = { "LPASS_HW_MACRO"), Q6DSP_VOTE_CLK(LPASS_HW_DCODEC_VOTE, Q6PRM_HW_CORE_ID_DCODEC, "LPASS_HW_DCODEC"), + Q6DSP_VOTE_CLK(LPASS_HW_LPR_VOTE, Q6PRM_HW_LPR_VOTE, + "LPASS_HW_LPR_VOTE"), }; static const struct q6dsp_clk_desc q6dsp_clk_q6prm __maybe_unused = { diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c index 04892fb4423f..1f3ce4cc0837 100644 --- a/sound/soc/qcom/qdsp6/q6prm.c +++ b/sound/soc/qcom/qdsp6/q6prm.c @@ -31,10 +31,16 @@ struct q6prm { #define PARAM_ID_RSC_HW_CORE 0x08001032 #define PARAM_ID_RSC_LPASS_CORE 0x0800102B #define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C +#define PARAM_ID_RSC_CPU_LPR 0x08001A6E + +#define LPR_CPU_SS_SLEEP_DISABLE 0x1 struct prm_cmd_request_hw_core { struct apm_module_param_data param_data; - uint32_t hw_clk_id; + union { + u32 hw_clk_id; + u32 lpr_state; + }; } __packed; struct prm_cmd_request_rsc { @@ -62,6 +68,7 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool struct prm_cmd_request_hw_core *req; gpr_device_t *gdev = prm->gdev; uint32_t opcode, rsp_opcode; + bool lpr_req = (hw_block_id == Q6PRM_HW_LPR_VOTE); if (enable) { opcode = PRM_CMD_REQUEST_HW_RSC; @@ -82,10 +89,13 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool param_data->module_instance_id = GPR_PRM_MODULE_IID; param_data->error_code = 0; - param_data->param_id = PARAM_ID_RSC_HW_CORE; + param_data->param_id = lpr_req ? PARAM_ID_RSC_CPU_LPR : PARAM_ID_RSC_HW_CORE; param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE; - req->hw_clk_id = hw_block_id; + if (lpr_req) + req->lpr_state = LPR_CPU_SS_SLEEP_DISABLE; + else + req->hw_clk_id = hw_block_id; return q6prm_send_cmd_sync(prm, pkt, rsp_opcode); } diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h index bc5b9fa13283..30dfcb8879ff 100644 --- a/sound/soc/qcom/qdsp6/q6prm.h +++ b/sound/soc/qcom/qdsp6/q6prm.h @@ -90,6 +90,7 @@ #define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0 #define Q6PRM_HW_CORE_ID_LPASS 1 #define Q6PRM_HW_CORE_ID_DCODEC 2 +#define Q6PRM_HW_LPR_VOTE 3 int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root, unsigned int freq); From 9151afc31402d092c5d24a67ccea36489eaf0185 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Wed, 15 Jul 2026 17:22:19 +0530 Subject: [PATCH 409/438] ASoC: dt-bindings: qcom,wsa8855: add Qualcomm WSA8855 speaker amplifier Add bindings for the Qualcomm WSA8855 stereo smart speaker amplifier. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Prasad Kumpatla Link: https://patch.msgid.link/20260715115220.3093799-2-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- .../bindings/sound/qcom,wsa8855.yaml | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml new file mode 100644 index 000000000000..00a6a05e9443 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,wsa8855.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WSA8855 stereo smart speaker amplifier + +maintainers: + - Srinivas Kandagatla + - Prasad Kumpatla + +description: + WSA885X is a Qualcomm Aqstic stereo smart speaker amplifier. It uses a PCM + audio interface, an I2C control interface, and a Class-H amplifier path for + high efficiency, low output noise, and low idle power consumption. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: qcom,wsa8855 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + powerdown-gpios: + description: GPIO controlling the SD_N powerdown pin. + maxItems: 1 + + reset-gpios: + description: GPIO controlling the SD_N powerdown pin. + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-1p8-supply: true + + vdd-io-supply: true + + qcom,battery-config: + description: + Battery topology connected to the speaker amplifier. 1S indicates one + battery cell in series, while 2S indicates two battery cells in series. + $ref: /schemas/types.yaml#/definitions/string + default: 1s + enum: + - 1s + - 2s + +required: + - compatible + - reg + - '#sound-dai-cells' + - interrupts + - vdd-1p8-supply + - vdd-io-supply + +oneOf: + - required: + - powerdown-gpios + - required: + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + speaker@c { + compatible = "qcom,wsa8855"; + reg = <0x0c>; + #sound-dai-cells = <0>; + powerdown-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>; + interrupt-parent = <&tlmm>; + interrupts = <77 IRQ_TYPE_EDGE_FALLING>; + vdd-1p8-supply = <&vreg_l2g_1p8>; + vdd-io-supply = <&vreg_l1g_1p2>; + qcom,battery-config = "1s"; + }; + }; +... From 1d0368c9873cddf08966bdf9642a72c7af89a7d3 Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Wed, 15 Jul 2026 17:22:20 +0530 Subject: [PATCH 410/438] ASoC: codecs: add Qualcomm WSA885X codec driver Add an ASoC codec driver for the Qualcomm WSA885X stereo smart speaker amplifier. The driver programs the register map, handles reset and interrupt support, exposes DAI operations for PCM/TDM playback, and provides mixer controls for usage mode, speaker volume and RX slot mask. Keep stream-time power-state sequencing in the DAI callbacks and use regmap for the control path. Signed-off-by: Prasad Kumpatla Link: https://patch.msgid.link/20260715115220.3093799-3-prasad.kumpatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 11 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wsa885x.c | 1533 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1546 insertions(+) create mode 100644 sound/soc/codecs/wsa885x.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 76e90144ea91..06d5048fd3d0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -367,6 +367,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WSA881X imply SND_SOC_WSA883X imply SND_SOC_WSA884X + imply SND_SOC_WSA885X imply SND_SOC_ZL38060 help Normally ASoC codec drivers are only built if a machine driver which @@ -2770,6 +2771,16 @@ config SND_SOC_WSA884X This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D Smart Speaker Amplifier. +config SND_SOC_WSA885X + tristate "WSA885X Codec" + depends on I2C + select REGMAP_I2C + help + This enables support for Qualcomm WSA885X Stereo Smart Speaker + Amplifier. The codec driver programs the amplifier register + map and exposes the DAI and mixer controls used by Qualcomm + audio machine drivers. + config SND_SOC_ZL38060 tristate "Microsemi ZL38060 Connected Home Audio Processor" depends on SPI_MASTER diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index aa0396e5b575..7a37f44724a6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -426,6 +426,7 @@ snd-soc-wm-hubs-y := wm_hubs.o snd-soc-wsa881x-y := wsa881x.o snd-soc-wsa883x-y := wsa883x.o snd-soc-wsa884x-y := wsa884x.o +snd-soc-wsa885x-y := wsa885x.o snd-soc-zl38060-y := zl38060.o # Amp snd-soc-max9877-y := max9877.o @@ -876,6 +877,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o +obj-$(CONFIG_SND_SOC_WSA885X) += snd-soc-wsa885x.o obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o # Amp diff --git a/sound/soc/codecs/wsa885x.c b/sound/soc/codecs/wsa885x.c new file mode 100644 index 000000000000..1faa8541a872 --- /dev/null +++ b/sound/soc/codecs/wsa885x.c @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* WSA885X codec driver */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Control Registers - Audio Processing */ +#define WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S 0x0000 +#define WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK 0x0004 +#define WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX 0x0140 +#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID 0x0208 +#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX 0x0240 +#define WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER 0x0340 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0 0x4405 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1 0x4406 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB 0x4409 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB 0x6409 +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB 0x440a +#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB 0x640a +#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS 0x0a04 +#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS 0x0a40 +#define WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE 0x0b10 +#define WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX 0x0e40 + +/* Analog Top Registers - Power and Clock Control */ +#define WSA885X_ANA_TOP_PON_CKSK_CTL_0 0x800d +#define WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG 0x8024 +#define WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG 0x8025 +#define WSA885X_ANA_TOP_BG_TVP_OVRD_CTL 0x8034 + +/* Analog PLL Registers */ +#define WSA885X_ANA_PLL_DIV_CTL_0 0x8090 +#define WSA885X_ANA_PLL_DIV_CTL_1 0x8091 +#define WSA885X_ANA_TOP_PLL_VCO_CTL 0x8092 +#define WSA885X_ANA_TOP_PLL_LOOPFILT_0 0x8093 +#define WSA885X_ANA_TOP_PLL_OVRD_CTL 0x8098 +#define WSA885X_ANA_TOP_PLL_STATUS_0 0x809a +#define WSA885X_ANA_TOP_PLL_STATUS_1 0x809b + +/* Analog Boost Control Registers */ +#define WSA885X_ANA_TOP_BOOST_STB_CTRL2 0x805b +#define WSA885X_ANA_TOP_BOOST_STB_CTRL3 0x805c +#define WSA885X_ANA_TOP_BOOST_BYP_CTRL2 0x805e +#define WSA885X_ANA_TOP_BOOST_BYP_CTRL3 0x805f +#define WSA885X_ANA_TOP_BOOST_MISC 0x8063 +#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2 0x8065 +#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4 0x8067 + +/* Analog IV Sense ADC Registers */ +#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2 0x80ca +#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3 0x80cb +#define WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL 0x80cc +#define WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2 0x80d0 + +/* Analog Speaker Power Stage Registers */ +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3 0x8108 +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3 0x810b +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3 0x810e +#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3 0x8111 +#define WSA885X_ANA_TOP_SPK_TOP_SPARE3 0x813c +#define WSA885X_SPK_TOP_LF_CH1_CTRL11 0x811c +#define WSA885X_SPK_TOP_LF_CH1_TUNE1 0x811d +#define WSA885X_SPK_TOP_LF_CH2_TUNE1 0x8129 +#define WSA885X_SPK_TOP_LF_CH1_CTRL9 0x811a +#define WSA885X_SPK_TOP_LF_CH2_CTRL9 0x8126 +#define WSA885X_SPK_TOP_LF_CH2_CTRL11 0x8128 +#define WSA885X_SPK_TOP_COMMON_CTRL2 0x8102 +#define WSA885X_SPK_TOP_COMMON_TUNE1 0x8103 +#define WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1 0x80ba +#define WSA885X_DIG_CTRL0_TOP_CLK_CFG 0x8418 +#define WSA885X_DIG_CTRL0_SDCA_COMMIT 0x8419 +#define WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE 0x841a +#define WSA885X_DIG_CTRL0_SYS_CLK_SEL 0x841b +#define WSA885X_DIG_CTRL0_CDC_CLK_CTL 0x841c +#define WSA885X_DIG_CTRL0_PA_FSM_CTL 0x8420 +#define WSA885X_DIG_CTRL0_POWER_FSM_CTL0 0x8423 +#define WSA885X_DIG_CTRL0_POWER_FSM_CTL1 0x8424 +#define WSA885X_DIG_CTRL0_PA0_FSM_CTL1 0x842b +#define WSA885X_DIG_CTRL0_PA1_FSM_CTL1 0x8435 +#define WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL 0x8458 +#define WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL 0x8470 +#define WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1 0x84b4 +#define WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1 0x84b7 +#define WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1 0x84A0 +#define WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1 0x84A4 + +/* Digital Control 1 Registers - I2S/TDM Interface */ +#define WSA885X_DIG_CTRL1_I2S_CTL0 0x85A0 +#define WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX 0x85A2 +#define WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX 0x85A3 +#define WSA885X_DIG_CTRL1_I2S_TDM_CTL0 0x85A7 +#define WSA885X_DIG_CTRL1_I2S_TDM_CTL1 0x85A9 +#define WSA885X_DIG_CTRL1_I2S_TDM_CH_RX 0x85AA +#define WSA885X_DIG_CTRL1_I2S_TDM_CH_TX 0x85AB +#define WSA885X_DIG_CTRL1_I2S_RESET_CTL 0x85AE + +/* CDC RX Path Registers - Audio Data Path */ +#define WSA885X_CDC_RX0_RX_PATH_CFG0 0x8601 +#define WSA885X_CDC_RX0_RX_PATH_CFG1 0x8602 +#define WSA885X_CDC_RX0_RX_PATH_CTL 0x8606 +#define WSA885X_RX0_RX_PATH_DSMDEM_CTL 0x8613 +#define WSA885X_CDC_RX1_RX_PATH_CFG0 0x8621 +#define WSA885X_CDC_RX1_RX_PATH_CFG1 0x8622 +#define WSA885X_CDC_RX1_RX_PATH_CTL 0x8626 +#define WSA885X_RX1_RX_PATH_DSMDEM_CTL 0x8633 + +/* CDC Compander Registers - Dynamic Range Control */ +#define WSA885X_CDC_COMPANDER0_CTL0 0x8640 +#define WSA885X_CDC_COMPANDER0_CTL7 0x8647 +#define WSA885X_CDC_COMPANDER1_CTL0 0x8660 +#define WSA885X_CDC_COMPANDER1_CTL7 0x8667 + +/* CDC Speaker Protection Registers - IV Sense */ +#define WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL 0x86A1 +#define WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL 0x86B1 +#define WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL 0x86A9 +#define WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL 0x86B9 + +/* CDC Class-H Registers - Headroom Control */ +#define WSA885X_CDC_CLSH_V1P8_BP_CTL1 0x86CD +#define WSA885X_CDC_CLSH_V1P8_BP_CTL0 0x86CC +#define WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0 0x86C7 +#define WSA885X_CDC_CLSH_CLSH_V_HD_PA 0x86C3 +#define WSA885X_CDC_CLSH_V1P8_BP_CTL2 0x86CE + +/* Driver Constants */ +#define WSA885X_CLK_RATE_FIXED 73728000 +#define WSA885X_NUM_REGS 0x03 + +/* Interrupt Registers */ +#define WSA885X_INTR_STATUS0 0x8584 +#define WSA885X_INTR_MASK0 0x8581 +#define WSA885X_INTR_CLEAR0 0x8587 + +/* Power and PA FSM Control Registers */ +#define WSA885X_PA0_FSM_CTL0 0x842A +#define WSA885X_PA1_FSM_CTL0 0x8434 + +/* Digital Control GPIO and Interrupt Registers */ +#define WSA885X_DIG_CTRL1_PIN_CT 0x8510 +#define WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL 0x8518 +#define WSA885X_DIG_CTRL1_INTR_MODE 0x8580 + +#define WSA885X_I2S_CTL0_PCM_RATE_MASK GENMASK(4, 1) +#define WSA885X_I2S_CTL0_ENABLE_MASK BIT(0) +#define WSA885X_I2S_CTL0_PCM_RATE(v) \ + FIELD_PREP(WSA885X_I2S_CTL0_PCM_RATE_MASK, (v)) +#define WSA885X_I2S_CTL0_PCM_RATE_8KHZ 0x0 +#define WSA885X_I2S_CTL0_PCM_RATE_16KHZ 0x1 +#define WSA885X_I2S_CTL0_PCM_RATE_32KHZ 0x2 +#define WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ 0x3 +#define WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ 0x4 +#define WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ 0x5 +#define WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ 0x6 +#define WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK GENMASK(2, 0) +#define WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK GENMASK(6, 4) +#define WSA885X_I2S_CFG0_TDM_TX_SLOT0(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, (v)) +#define WSA885X_I2S_CFG0_TDM_TX_SLOT1(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, (v)) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK GENMASK(2, 0) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK GENMASK(6, 4) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT2(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, (v)) +#define WSA885X_I2S_CFG1_TDM_TX_SLOT3(v) \ + FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, (v)) +#define WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK BIT(0) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK GENMASK(3, 2) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2 \ + FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 0) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4 \ + FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 1) +#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8 \ + FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 3) +#define WSA885X_I2S_TDM_CH_TX_CH0_EN BIT(0) +#define WSA885X_I2S_TDM_CH_TX_CH1_EN BIT(1) +#define WSA885X_I2S_TDM_CH_TX_CH2_EN BIT(2) +#define WSA885X_I2S_TDM_CH_TX_CH3_EN BIT(3) +#define WSA885X_I2S_TDM_CH_RX_CH0_EN BIT(0) +#define WSA885X_I2S_TDM_CH_RX_CH3_EN BIT(3) +#define WSA885X_I2S_RESET_CTL_RESET_MASK BIT(0) +#define WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK BIT(2) +#define WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK BIT(3) +#define WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK BIT(2) + +#define WSA885X_I2S_TX_SLOT_ISENSE0 0x1 +#define WSA885X_I2S_TX_SLOT_ISENSE1 0x2 +#define WSA885X_I2S_TX_SLOT_CUR_SENSE0 0x5 +#define WSA885X_I2S_TX_SLOT_CUR_SENSE1 0x6 + +/* RX Sample Rate Index Values - Audio Playback Path */ +#define WSA885X_RX_RATE_8000HZ 0x00 +#define WSA885X_RX_RATE_16000HZ 0x01 +#define WSA885X_RX_RATE_32000HZ 0x02 +#define WSA885X_RX_RATE_44100HZ 0x03 +#define WSA885X_RX_RATE_48000HZ 0x04 +#define WSA885X_RX_RATE_96000HZ 0x05 +#define WSA885X_RX_RATE_192000HZ 0x06 +#define WSA885X_RX_RATE_384000HZ 0x07 + +/* VI Sample Rate Index Values - Voltage/Current Sensing Path */ +#define WSA885X_VI_RATE_8000HZ 0x00 +#define WSA885X_VI_RATE_16000HZ 0x01 +#define WSA885X_VI_RATE_44100HZ 0x02 +#define WSA885X_VI_RATE_48000HZ 0x03 +#define WSA885X_VI_RATE_96000HZ 0x04 +#define WSA885X_VI_RATE_22050HZ 0x05 +#define WSA885X_VI_RATE_24000HZ 0x06 +#define WSA885X_VI_RATE_192000HZ 0x07 +#define WSA885X_VI_RATE_384000HZ 0x08 + +/* Channel Configuration Masks */ +#define WSA885X_CHANNEL_STEREO 0x03 +#define WSA885X_CHANNEL_MONO_LEFT 0x01 +#define WSA885X_CHANNEL_MONO_RIGHT 0x02 + +#define WSA885X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) + +#define WSA885X_PLL_LOCK_BIT BIT(0) + +#define WSA885X_FU21_VOL_STEPS 124 +#define WSA885X_USAGE_MODE_MAX 8 +static const DECLARE_TLV_DB_SCALE(wsa885x_fu21_digital_gain, -8400, 100, 0); + +static bool wsa885x_is_valid_rx_slot_mask(u32 mask) +{ + return mask == WSA885X_CHANNEL_MONO_LEFT || + mask == WSA885X_CHANNEL_MONO_RIGHT || + mask == WSA885X_CHANNEL_STEREO; +} + +static const char *const wsa885x_supply_name[] = { + "vdd-1p8", + "vdd-io", +}; + +enum { + WSA885X_BATT_1S = 1, + WSA885X_BATT_2S, +}; + +enum { + WSA885X_IRQ_INT_SAF2WAR = 0, + WSA885X_IRQ_INT_WAR2SAF, + WSA885X_IRQ_INT_DISABLE, + WSA885X_IRQ_INT_PA0_OCP, + WSA885X_IRQ_INT_PA1_OCP, + WSA885X_IRQ_INT_CLIP0, + WSA885X_IRQ_INT_CLIP1, + WSA885X_IRQ_INT_CLK_WD, + WSA885X_IRQ_INT_INTR_GPIO1_PIN, + WSA885X_IRQ_INT_INTR_GPIO2_PIN, + WSA885X_IRQ_INT_UVLO, + WSA885X_IRQ_INT_BOP, + WSA885X_IRQ_INT_PA0_FSM_ERR, + WSA885X_IRQ_INT_PA1_FSM_ERR, + WSA885X_IRQ_INT_MAIN_FSM_ERR, + WSA885X_IRQ_INT_PCM_DATA0_WD, + WSA885X_IRQ_INT_PCM_DATA1_WD, + WSA885X_IRQ_INT_PCM_DATA0_DC, + WSA885X_IRQ_INT_PCM_DATA1_DC, + WSA885X_IRQ_INT_PLL_UNLOCKED, + WSA885X_IRQ_INT_PROT_MODE_CHANGE, + WSA885X_IRQ_INT_PB_CLOCK_VALID, + WSA885X_IRQ_INT_SENSE_CLOCK_VALID, + WSA885X_IRQ_MAX, +}; + +struct wsa885x_priv { + struct i2c_client *client; + struct regmap *regmap; + struct device *dev; + struct snd_soc_component *component; + struct gpio_desc *sd_n; + struct reset_control *sd_reset; + u32 usage_mode; + u32 rx_slot_mask; + u32 batt_conf; + int stereo_vol_db; + struct mutex state_lock; /* protects mutable control state */ +}; + +struct wsa885x_reg_update { + unsigned int reg; + unsigned int mask; + unsigned int val; +}; + +static const struct regmap_range_cfg wsa885x_regmap_ranges[] = { + { + .range_min = 0, + .range_max = 0x88ff, + .selector_reg = 0x0, + .selector_mask = 0xFF, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + }, +}; + +static const struct reg_default wsa885x_codec_reg_defaults[] = { + {WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, 0x04}, + {WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, 0xac}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, 0xac}, + {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00}, + {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03}, + {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, 0x03}, + {WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, 0x03}, + {WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x00}, + {WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x19}, + {WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x22}, + {WSA885X_ANA_PLL_DIV_CTL_0, 0x0c}, + {WSA885X_ANA_PLL_DIV_CTL_1, 0x50}, + {WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00}, + {WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xb4}, + {WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00}, + {WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00}, + {WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x03}, + {WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x3c}, + {WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc5}, + {WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x13}, + {WSA885X_ANA_TOP_BOOST_MISC, 0x79}, + {WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x00}, + {WSA885X_SPK_TOP_COMMON_CTRL2, 0x08}, + {WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x09}, + {WSA885X_SPK_TOP_LF_CH1_TUNE1, 0x00}, + {WSA885X_SPK_TOP_LF_CH2_TUNE1, 0x00}, + {WSA885X_SPK_TOP_LF_CH1_CTRL9, 0x00}, + {WSA885X_SPK_TOP_LF_CH2_CTRL9, 0x00}, + {WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x09}, + {WSA885X_SPK_TOP_COMMON_TUNE1, 0x03}, + {WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1, 0x00}, + {WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0e}, + {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x40}, + {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0xff}, + {WSA885X_ANA_TOP_PLL_STATUS_0, 0x00}, + {WSA885X_ANA_TOP_PLL_STATUS_1, 0x00}, + {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x84}, + {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x02}, + {WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x00}, + {WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0xe0}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa4}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0xc9}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa4}, + {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0xc9}, + {WSA885X_DIG_CTRL0_TOP_CLK_CFG, 0x00}, + {WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x00}, + {WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00}, + {WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00}, + {WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00}, + {WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05}, + {WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00}, + {WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x45}, + {WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x45}, + {WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x7f}, + {WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00}, + {WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01}, + {WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01}, + {WSA885X_DIG_CTRL1_I2S_CTL0, 0x06}, + {WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00}, + {WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00}, + {WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00}, + {WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05}, + {WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00}, + {WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00}, + {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, WSA885X_I2S_TDM_CH_RX_CH3_EN}, + {WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89}, + {WSA885X_CDC_RX0_RX_PATH_CFG1, 0x64}, + {WSA885X_CDC_RX0_RX_PATH_CTL, 0x24}, + {WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01}, + {WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89}, + {WSA885X_CDC_RX1_RX_PATH_CFG1, 0x64}, + {WSA885X_CDC_RX1_RX_PATH_CTL, 0x04}, + {WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01}, + {WSA885X_CDC_COMPANDER0_CTL0, 0x01}, + {WSA885X_CDC_COMPANDER0_CTL7, 0x2a}, + {WSA885X_CDC_COMPANDER1_CTL0, 0x01}, + {WSA885X_CDC_COMPANDER1_CTL7, 0x2a}, + {WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14}, + {WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50}, + {WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c}, + {WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d}, + {WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03}, + {WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05}, +}; + +static void wsa885x_multi_update_bits(struct regmap *regmap, + const struct wsa885x_reg_update *updates, + size_t num_updates) +{ + size_t i; + + for (i = 0; i < num_updates; i++) + regmap_update_bits(regmap, updates[i].reg, + updates[i].mask, updates[i].val); +} + +static void wsa885x_toggle_irq_bit(struct wsa885x_priv *wsa885x, + unsigned int reg, unsigned int mask) +{ + regmap_update_bits(wsa885x->regmap, reg, mask, 0); + regmap_update_bits(wsa885x->regmap, reg, mask, mask); +} + +static void wsa885x_pulse_irq_bit(struct wsa885x_priv *wsa885x, + unsigned int reg, unsigned int mask) +{ + regmap_update_bits(wsa885x->regmap, reg, mask, 0); + regmap_update_bits(wsa885x->regmap, reg, mask, mask); + regmap_update_bits(wsa885x->regmap, reg, mask, 0); +} + +static int wsa885x_tdm_ctl0_slot_num_val(int slots, unsigned int *slot_num_val) +{ + if (!slot_num_val) + return -EINVAL; + + switch (slots) { + case 2: + *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2; + return 0; + case 4: + *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4; + return 0; + case 8: + *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8; + return 0; + default: + return -EINVAL; + } +} + +static int wsa885x_reg_update_sequence(struct regmap *regmap, int slots) +{ + static const struct reg_sequence regs[] = { + { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x15 }, + { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x11 }, + }; + unsigned int slot_num_val; + int ret; + + if (!regmap) + return -EINVAL; + + ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); + if (ret) + return ret; + + regmap_multi_reg_write(regmap, regs, ARRAY_SIZE(regs)); + + regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0, + WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, + slot_num_val); + regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0, + WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK, + WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK); + regmap_write(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH0_EN); + regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH1_EN, + WSA885X_I2S_TDM_CH_TX_CH1_EN); + + return 0; +} + +static int wsa885x_wait_for_pll_lock(struct wsa885x_priv *wsa885x) +{ + unsigned int status = 0; + int cnt = 0, ret = 0; + + do { + usleep_range(1000, 1100); + ret = regmap_read(wsa885x->regmap, WSA885X_ANA_TOP_PLL_STATUS_0, &status); + if (ret) { + dev_err(wsa885x->dev, "PLL status read failed: %d\n", ret); + return ret; + } + + if (status & WSA885X_PLL_LOCK_BIT) + return 0; + } while (++cnt < 20); + + dev_warn(wsa885x->dev, "PLL lock timeout after 20ms, status=0x%x\n", status); + return -ETIMEDOUT; +} + +static int wsa885x_2s_conf(struct wsa885x_priv *wsa885x) +{ + static const struct reg_sequence regs[] = { + { WSA885X_SPK_TOP_COMMON_TUNE1, 0x26 }, + { WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x0d }, + { WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x0d }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x71 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0xAA }, + }; + + return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); +} + +static const struct reg_sequence wsa885x_reg_init[] = { + { WSA885X_CDC_RX0_RX_PATH_CTL, 0x24 }, + { WSA885X_CDC_RX1_RX_PATH_CTL, 0x24 }, + { WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01 }, + { WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01 }, + { WSA885X_CDC_COMPANDER0_CTL0, 0x01 }, + { WSA885X_CDC_COMPANDER1_CTL0, 0x01 }, + { WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14 }, + { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0f }, + { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x4f }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x02 }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00 }, + { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x01 }, + { WSA885X_CDC_RX0_RX_PATH_CFG1, 0x60 }, + { WSA885X_CDC_RX1_RX_PATH_CFG1, 0x60 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa5 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa5 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x85 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0c }, + { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0e }, + { WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x0c }, + { WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01 }, + { WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01 }, + { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x88 }, + { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89 }, + { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x88 }, + { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89 }, + { WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x82 }, + { WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x34 }, + { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x41 }, + { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0x7f }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c }, + { WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d }, + { WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03 }, + { WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05 }, + { WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x20 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0x45 }, + { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0x45 }, + { WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05 }, + { WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x35 }, + { WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x21 }, + { WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc7 }, + { WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x11 }, + { WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0x80 }, + { WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x08 }, + { WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x47 }, + { WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x47 }, + { WSA885X_CDC_COMPANDER0_CTL7, 0x34 }, + { WSA885X_CDC_COMPANDER1_CTL7, 0x34 }, + { WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x79 }, +}; + +static int wsa885x_hw_init(struct wsa885x_priv *wsa885x) +{ + static const struct reg_sequence regs[] = { + { WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL, 0x2e }, + { WSA885X_DIG_CTRL1_INTR_MODE, 0x01 }, + { WSA885X_DIG_CTRL1_PIN_CT, 0x04 }, + }; + int ret; + + ret = regmap_multi_reg_write(wsa885x->regmap, wsa885x_reg_init, + ARRAY_SIZE(wsa885x_reg_init)); + if (ret) + return ret; + + if (wsa885x->batt_conf == WSA885X_BATT_2S) { + ret = wsa885x_2s_conf(wsa885x); + if (ret) + return ret; + } + + return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); +} + +static int wsa885x_unmask_interrupts(struct wsa885x_priv *wsa885x) +{ + static const struct reg_sequence regs[] = { + { WSA885X_INTR_MASK0, 0x00 }, + { WSA885X_INTR_MASK0 + 1, 0x00 }, + { WSA885X_INTR_MASK0 + 2, 0xf8 }, + }; + + return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); +} + +static int wsa885x_wait_for_pde_state(struct wsa885x_priv *wsa885x, int ps) +{ + unsigned int act_ps = 0, clock_valid = 0; + int rc = 0, cnt = 0; + + if (ps < 0 || ps > 3) + return -EINVAL; + + do { + usleep_range(1000, 1500); + rc = regmap_read(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, + &act_ps); + if (rc) { + dev_err(wsa885x->dev, "PDE state read failed: %d\n", rc); + return rc; + } + if (act_ps == ps) + return 0; + } while (++cnt < 5); + + if (regmap_read(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, + &clock_valid)) + dev_err(wsa885x->dev, + "PDE power state %d request failed, actual_ps %d, clock_valid read failed\n", + ps, act_ps); + else + dev_err(wsa885x->dev, + "PDE power state %d request failed, actual_ps %d, clock_valid:%d\n", + ps, act_ps, clock_valid); + + return -ETIMEDOUT; +} + +static void wsa885x_program_stereo_volume(struct wsa885x_priv *wsa885x, + int stereo_vol_db, bool commit) +{ + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, + (u8)(s8)stereo_vol_db); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, + (u8)(s8)stereo_vol_db); + regmap_write(wsa885x->regmap, + WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00); + + if (commit) + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); +} + +static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wsa885x_priv *wsa885x; + u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + switch (params_rate(params)) { + case 8000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_8KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_8000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_8000HZ; + break; + case 16000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_16KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_16000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_16000HZ; + break; + case 32000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_32KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_32000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; + break; + case 44100: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_44100HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_44100HZ; + break; + case 48000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_48000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; + break; + case 88200: + case 96000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_96000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_96000HZ; + break; + case 176400: + case 192000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_192000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_192000HZ; + break; + case 352800: + case 384000: + pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ; + cs21_sample_rate_idx = WSA885X_RX_RATE_384000HZ; + cs24_sample_rate_idx = WSA885X_VI_RATE_384000HZ; + break; + default: + dev_err(wsa885x->dev, "sampling rate %d is not supported\n", params_rate(params)); + return -EINVAL; + } + + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, + WSA885X_I2S_CTL0_PCM_RATE_MASK | + WSA885X_I2S_CTL0_ENABLE_MASK, + WSA885X_I2S_CTL0_PCM_RATE(pcm_rate) | + WSA885X_I2S_CTL0_ENABLE_MASK); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00); + regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, + cs21_sample_rate_idx); + regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, + cs24_sample_rate_idx); + + mutex_lock(&wsa885x->state_lock); + wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); + mutex_unlock(&wsa885x->state_lock); + + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); + + return 0; +} + +static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_slot_mask, + unsigned int rx_slot_mask, int slots, + int slot_width) +{ + static const struct wsa885x_reg_update stereo_updates[] = { + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) }, + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_ISENSE1) }, + { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, + WSA885X_I2S_CFG1_TDM_TX_SLOT2(WSA885X_I2S_TX_SLOT_CUR_SENSE0) }, + { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, + WSA885X_I2S_CFG1_TDM_TX_SLOT3(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, + }; + static const struct wsa885x_reg_update mono_left_updates[] = { + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) }, + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE0) }, + }; + static const struct wsa885x_reg_update mono_right_updates[] = { + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE1) }, + { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, + WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, + }; + struct wsa885x_priv *wsa885x; + unsigned int slot_num_val; + u32 mask; + int ret; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); + if (ret) { + dev_err(wsa885x->dev, "%s: unsupported slot count %d\n", + __func__, slots); + return ret; + } + + if (rx_slot_mask && !wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) { + dev_err(wsa885x->dev, + "%s: unsupported rx_slot_mask 0x%x\n", + __func__, rx_slot_mask); + return -EINVAL; + } + + mutex_lock(&wsa885x->state_lock); + if (rx_slot_mask) + wsa885x->rx_slot_mask = rx_slot_mask; + else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) + wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + mask = wsa885x->rx_slot_mask; + + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, + WSA885X_I2S_RESET_CTL_RESET_MASK, + WSA885X_I2S_RESET_CTL_RESET_MASK); + + if (mask == WSA885X_CHANNEL_STEREO) { + wsa885x_multi_update_bits(wsa885x->regmap, stereo_updates, + ARRAY_SIZE(stereo_updates)); + ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); + if (ret) + goto exit_unlock; + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH2_EN, + WSA885X_I2S_TDM_CH_TX_CH2_EN); + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, + WSA885X_I2S_TDM_CH_TX_CH3_EN, + WSA885X_I2S_TDM_CH_TX_CH3_EN); + } else if (mask == WSA885X_CHANNEL_MONO_LEFT) { + wsa885x_multi_update_bits(wsa885x->regmap, mono_left_updates, + ARRAY_SIZE(mono_left_updates)); + ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); + if (ret) + goto exit_unlock; + } else if (mask == WSA885X_CHANNEL_MONO_RIGHT) { + wsa885x_multi_update_bits(wsa885x->regmap, mono_right_updates, + ARRAY_SIZE(mono_right_updates)); + ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); + if (ret) + goto exit_unlock; + } + + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, + WSA885X_I2S_CTL0_ENABLE_MASK, + WSA885X_I2S_CTL0_ENABLE_MASK); + regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, + WSA885X_I2S_RESET_CTL_RESET_MASK, 0); + + ret = 0; + +exit_unlock: + mutex_unlock(&wsa885x->state_lock); + + return ret; +} + +static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + static const struct reg_sequence pll_prep[] = { + { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x03 }, + { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x04 }, + { WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xB4 }, + { WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00 }, + { WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00 }, + }; + static const struct reg_sequence pll_cleanup[] = { + { WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 }, + { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 }, + { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 }, + }; + struct wsa885x_priv *wsa885x; + u32 pll_div; + int ret = 0; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + if (!freq) + return -EINVAL; + if (WSA885X_CLK_RATE_FIXED % freq) + return -EINVAL; + pll_div = WSA885X_CLK_RATE_FIXED / freq; + if (pll_div > 0xff) + return -EINVAL; + + regmap_multi_reg_write(wsa885x->regmap, pll_prep, ARRAY_SIZE(pll_prep)); + regmap_write(wsa885x->regmap, WSA885X_ANA_PLL_DIV_CTL_0, pll_div); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x02); + + ret = wsa885x_wait_for_pll_lock(wsa885x); + if (ret) { + dev_err(wsa885x->dev, "PLL lock failed, aborting sysclk configuration\n"); + regmap_multi_reg_write(wsa885x->regmap, pll_cleanup, + ARRAY_SIZE(pll_cleanup)); + return ret; + } + + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x01); + regmap_write(wsa885x->regmap, WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00); + + return 0; +} + +static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + static const struct reg_sequence mute_regs[] = { + { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, + { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03 }, + }; + static const struct reg_sequence mute_commit_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01 }, + { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, + }; + static const struct reg_sequence unmute_prep_head_regs[] = { + { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, + }; + static const struct reg_sequence unmute_prep_tail_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01 }, + }; + static const struct reg_sequence unmute_volume_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00 }, + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00 }, + }; + static const struct reg_sequence unmute_commit_regs[] = { + { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, + { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x00 }, + }; + static const struct reg_sequence unmute_finish_regs[] = { + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x00 }, + { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x00 }, + { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, + }; + struct wsa885x_priv *wsa885x; + int ret = 0, ps0 = 0, ps3 = 3; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + mutex_lock(&wsa885x->state_lock); + + if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { + ret = -EINVAL; + goto exit_unlock; + } + + if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) + wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + + if (mute) { + regmap_multi_reg_write(wsa885x->regmap, mute_regs, + ARRAY_SIZE(mute_regs)); + ret = wsa885x_wait_for_pde_state(wsa885x, ps3); + if (ret) { + dev_err(wsa885x->dev, + "PS3 transition failed: %d\n", ret); + } else { + regmap_multi_reg_write(wsa885x->regmap, mute_commit_regs, + ARRAY_SIZE(mute_commit_regs)); + } + } else { + regmap_multi_reg_write(wsa885x->regmap, unmute_prep_head_regs, + ARRAY_SIZE(unmute_prep_head_regs)); + regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, + wsa885x->usage_mode); + regmap_multi_reg_write(wsa885x->regmap, unmute_prep_tail_regs, + ARRAY_SIZE(unmute_prep_tail_regs)); + wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); + regmap_multi_reg_write(wsa885x->regmap, unmute_volume_regs, + ARRAY_SIZE(unmute_volume_regs)); + regmap_multi_reg_write(wsa885x->regmap, unmute_commit_regs, + ARRAY_SIZE(unmute_commit_regs)); + ret = wsa885x_wait_for_pde_state(wsa885x, ps0); + if (ret) + goto exit_unlock; + + if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH0_EN | + WSA885X_I2S_TDM_CH_RX_CH3_EN); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03); + } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH3_EN); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01); + } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) { + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, + WSA885X_I2S_TDM_CH_RX_CH0_EN); + regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02); + } + + regmap_multi_reg_write(wsa885x->regmap, unmute_finish_regs, + ARRAY_SIZE(unmute_finish_regs)); + } + +exit_unlock: + mutex_unlock(&wsa885x->state_lock); + + return ret; +} + +static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + static const struct reg_sequence regs[] = { + { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, + }; + struct wsa885x_priv *wsa885x; + + wsa885x = snd_soc_component_get_drvdata(dai->component); + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + mutex_lock(&wsa885x->state_lock); + regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); + mutex_unlock(&wsa885x->state_lock); + + return 0; +} + +static const struct snd_soc_dai_ops wsa885x_dai_ops = { + .hw_params = wsa885x_codec_hw_params, + .set_tdm_slot = wsa885x_codec_set_tdm_slot, + .set_sysclk = wsa885x_codec_set_sysclk, + .mute_stream = wsa885x_codec_mute_stream, + .hw_free = wsa885x_codec_hw_free, +}; + +static struct snd_soc_dai_driver wsa885x_dai[] = { + { + .name = "wsa885x_dai_drv", + .playback = { + .stream_name = "WSA885X TDM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WSA885X_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &wsa885x_dai_ops, + }, +}; + +static void wsa885x_reset_assert(void *data) +{ + struct wsa885x_priv *wsa885x = data; + + if (wsa885x->sd_reset) + reset_control_assert(wsa885x->sd_reset); + else + gpiod_direction_output(wsa885x->sd_n, 1); +} + +static void wsa885x_reset_deassert(struct wsa885x_priv *wsa885x) +{ + if (wsa885x->sd_reset) + reset_control_deassert(wsa885x->sd_reset); + else + gpiod_direction_output(wsa885x->sd_n, 0); +} + +static int wsa885x_get_reset(struct device *dev, struct wsa885x_priv *wsa885x) +{ + wsa885x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(wsa885x->sd_reset)) + return dev_err_probe(dev, PTR_ERR(wsa885x->sd_reset), + "Failed to get reset\n"); + else if (wsa885x->sd_reset) + return 0; + + wsa885x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(wsa885x->sd_n)) + return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n), + "Shutdown Control GPIO not found\n"); + + return 0; +} + +static bool wsa885x_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WSA885X_ANA_TOP_PLL_STATUS_0: + case WSA885X_ANA_TOP_PLL_STATUS_1: + case WSA885X_DIG_CTRL0_SDCA_COMMIT: + case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: + case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: + case WSA885X_INTR_STATUS0: + case WSA885X_INTR_STATUS0 + 1: + case WSA885X_INTR_STATUS0 + 2: + case WSA885X_INTR_CLEAR0: + case WSA885X_INTR_CLEAR0 + 1: + case WSA885X_INTR_CLEAR0 + 2: + return true; + default: + return false; + } +} + +static bool wsa885x_readable_register(struct device *dev, unsigned int reg) +{ + if (reg == WSA885X_INTR_CLEAR0 || + reg == WSA885X_INTR_CLEAR0 + 1 || + reg == WSA885X_INTR_CLEAR0 + 2) + return false; + return reg <= 0x88ff; +} + +static bool wsa885x_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg > 0x88ff) + return false; + + switch (reg) { + case WSA885X_ANA_TOP_PLL_STATUS_0: + case WSA885X_ANA_TOP_PLL_STATUS_1: + case WSA885X_INTR_STATUS0: + case WSA885X_INTR_STATUS0 + 1: + case WSA885X_INTR_STATUS0 + 2: + case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: + case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: + return false; + default: + return true; + } +} + +static const struct regmap_config wsa885x_regmap_cfg = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x88FF, + .ranges = wsa885x_regmap_ranges, + .num_ranges = ARRAY_SIZE(wsa885x_regmap_ranges), + .reg_defaults = wsa885x_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wsa885x_codec_reg_defaults), + .volatile_reg = wsa885x_volatile_register, + .writeable_reg = wsa885x_writeable_register, + .readable_reg = wsa885x_readable_register, + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int wsa885x_component_probe(struct snd_soc_component *component) +{ + struct wsa885x_priv *wsa885x = + snd_soc_component_get_drvdata(component); + int ret; + + wsa885x->component = component; + snd_soc_component_init_regmap(component, wsa885x->regmap); + + ret = wsa885x_hw_init(wsa885x); + if (ret) + return ret; + + return wsa885x_unmask_interrupts(wsa885x); +} + +static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + int val; + + mutex_lock(&wsa885x->state_lock); + val = wsa885x->stereo_vol_db + 84; + mutex_unlock(&wsa885x->state_lock); + if (val < 0 || val > WSA885X_FU21_VOL_STEPS) + return -ERANGE; + + ucontrol->value.integer.value[0] = val; + return 0; +} + +static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + long val; + int stereo_vol_db; + + val = ucontrol->value.integer.value[0]; + + if (val < 0 || val > WSA885X_FU21_VOL_STEPS) { + dev_err(component->dev, "%s: Invalid range, Val: %ld\n", __func__, val); + return -EINVAL; + } + + stereo_vol_db = (int)val - 84; + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->stereo_vol_db == stereo_vol_db) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } + + wsa885x_program_stereo_volume(wsa885x, stereo_vol_db, true); + wsa885x->stereo_vol_db = stereo_vol_db; + mutex_unlock(&wsa885x->state_lock); + + return 1; +} + +static int wsa885x_usage_modes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { + mutex_unlock(&wsa885x->state_lock); + return -ERANGE; + } + + ucontrol->value.integer.value[0] = wsa885x->usage_mode; + mutex_unlock(&wsa885x->state_lock); + + return 0; +} + +static int wsa885x_usage_modes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 val = ucontrol->value.integer.value[0]; + + if (val > WSA885X_USAGE_MODE_MAX) + return -EINVAL; + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->usage_mode == val) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } + + wsa885x->usage_mode = val; + mutex_unlock(&wsa885x->state_lock); + + return 1; +} + +static int wsa885x_rx_slot_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 mask; + + mutex_lock(&wsa885x->state_lock); + mask = wsa885x->rx_slot_mask; + mutex_unlock(&wsa885x->state_lock); + if (!wsa885x_is_valid_rx_slot_mask(mask)) + return -ERANGE; + + ucontrol->value.integer.value[0] = mask; + + return 0; +} + +static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); + u32 mask = ucontrol->value.integer.value[0]; + + if (!wsa885x_is_valid_rx_slot_mask(mask)) + return -EINVAL; + + mutex_lock(&wsa885x->state_lock); + if (wsa885x->rx_slot_mask == mask) { + mutex_unlock(&wsa885x->state_lock); + return 0; + } + + wsa885x->rx_slot_mask = mask; + mutex_unlock(&wsa885x->state_lock); + + return 1; +} + +static const struct snd_kcontrol_new wsa885x_snd_controls[] = { + SOC_SINGLE_EXT("Usage Mode", SND_SOC_NOPM, 0, WSA885X_USAGE_MODE_MAX, 0, + wsa885x_usage_modes_get, + wsa885x_usage_modes_put), + + SOC_SINGLE_EXT_TLV("Speaker Volume", SND_SOC_NOPM, + 0, WSA885X_FU21_VOL_STEPS, 0, + wsa885x_stereo_gain_offset_get, + wsa885x_stereo_gain_offset_put, + wsa885x_fu21_digital_gain), + + SOC_SINGLE_EXT("Rx Slot Mask", SND_SOC_NOPM, 0, 3, 0, + wsa885x_rx_slot_mask_get, + wsa885x_rx_slot_mask_put), +}; + +static const struct snd_soc_component_driver wsa885x_component = { + .name = "wsa885x", + .probe = wsa885x_component_probe, + .controls = wsa885x_snd_controls, + .num_controls = ARRAY_SIZE(wsa885x_snd_controls), +}; + +static irqreturn_t wsa885x_handle_irq(int irq_idx, void *data) +{ + struct wsa885x_priv *wsa885x = data; + + if (irq_idx < 0 || irq_idx >= WSA885X_IRQ_MAX) + return IRQ_NONE; + + switch (irq_idx) { + case WSA885X_IRQ_INT_SAF2WAR: + case WSA885X_IRQ_INT_WAR2SAF: + case WSA885X_IRQ_INT_DISABLE: + case WSA885X_IRQ_INT_INTR_GPIO1_PIN: + case WSA885X_IRQ_INT_INTR_GPIO2_PIN: + case WSA885X_IRQ_INT_PA0_OCP: + case WSA885X_IRQ_INT_PA1_OCP: + case WSA885X_IRQ_INT_CLIP0: + case WSA885X_IRQ_INT_CLIP1: + case WSA885X_IRQ_INT_CLK_WD: + case WSA885X_IRQ_INT_BOP: + case WSA885X_IRQ_INT_UVLO: + case WSA885X_IRQ_INT_PCM_DATA0_DC: + case WSA885X_IRQ_INT_PCM_DATA1_DC: + case WSA885X_IRQ_INT_PLL_UNLOCKED: + case WSA885X_IRQ_INT_PROT_MODE_CHANGE: + case WSA885X_IRQ_INT_PB_CLOCK_VALID: + case WSA885X_IRQ_INT_SENSE_CLOCK_VALID: + break; + case WSA885X_IRQ_INT_PCM_DATA0_WD: + case WSA885X_IRQ_INT_PCM_DATA1_WD: + if (irq_idx == WSA885X_IRQ_INT_PCM_DATA0_WD) + wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1, + WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK); + else + wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1, + WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK); + break; + case WSA885X_IRQ_INT_PA0_FSM_ERR: + case WSA885X_IRQ_INT_PA1_FSM_ERR: + case WSA885X_IRQ_INT_MAIN_FSM_ERR: + if (irq_idx == WSA885X_IRQ_INT_MAIN_FSM_ERR) { + wsa885x_pulse_irq_bit(wsa885x, WSA885X_DIG_CTRL0_POWER_FSM_CTL0, + WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK); + } else if (irq_idx == WSA885X_IRQ_INT_PA0_FSM_ERR) { + wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA0_FSM_CTL0, + WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK); + } else if (irq_idx == WSA885X_IRQ_INT_PA1_FSM_ERR) { + wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA1_FSM_CTL0, + WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK); + } + break; + default: + break; + } + + return IRQ_HANDLED; +} + +static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) +{ + static const unsigned int status_reg[WSA885X_NUM_REGS] = { + WSA885X_INTR_STATUS0, + WSA885X_INTR_STATUS0 + 1, + WSA885X_INTR_STATUS0 + 2, + }; + static const unsigned int clear_reg[WSA885X_NUM_REGS] = { + WSA885X_INTR_CLEAR0, + WSA885X_INTR_CLEAR0 + 1, + WSA885X_INTR_CLEAR0 + 2, + }; + unsigned int status[WSA885X_NUM_REGS] = { 0 }; + struct wsa885x_priv *wsa885x = data; + irqreturn_t handled = IRQ_NONE; + irqreturn_t irq_ret; + int i, bit, ret, irq_num; + + for (i = 0; i < WSA885X_NUM_REGS; i++) { + ret = regmap_read(wsa885x->regmap, status_reg[i], &status[i]); + if (ret) { + dev_err(wsa885x->dev, + "Failed to read status_reg[%d] (0x%x): %d\n", + i, status_reg[i], ret); + status[i] = 0; + continue; + } + } + + for (i = 0; i < WSA885X_NUM_REGS; i++) { + for (bit = 0; bit < 8; bit++) { + if (status[i] & BIT(bit)) { + irq_num = i * 8 + bit; + regmap_write(wsa885x->regmap, clear_reg[i], BIT(bit)); + regmap_write(wsa885x->regmap, clear_reg[i], 0); + if (irq_num >= WSA885X_IRQ_MAX) { + dev_warn_ratelimited(wsa885x->dev, + "Unexpected IRQ bit %d (reg %d)\n", + bit, i); + handled = IRQ_HANDLED; + continue; + } + irq_ret = wsa885x_handle_irq(irq_num, wsa885x); + if (irq_ret == IRQ_HANDLED) + handled = IRQ_HANDLED; + } + } + } + return handled; +} + +static int wsa885x_register_irq(struct wsa885x_priv *wsa885x) +{ + if (!wsa885x->client->irq) + return dev_err_probe(wsa885x->dev, -EINVAL, + "IRQ is not configured\n"); + + return devm_request_threaded_irq(wsa885x->dev, wsa885x->client->irq, NULL, + wsa885x_interrupt_handler, + IRQF_ONESHOT, + dev_name(wsa885x->dev), wsa885x); +} + +static int wsa885x_probe(struct i2c_client *client) +{ + struct wsa885x_priv *wsa885x; + const struct snd_soc_component_driver *component_driver = &wsa885x_component; + const char *battery_config; + unsigned int i; + int ret; + struct device *dev = &client->dev; + + wsa885x = devm_kzalloc(dev, sizeof(*wsa885x), GFP_KERNEL); + if (!wsa885x) + return -ENOMEM; + + wsa885x->client = client; + wsa885x->dev = dev; + wsa885x->stereo_vol_db = -84; + wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; + mutex_init(&wsa885x->state_lock); + wsa885x->regmap = devm_regmap_init_i2c(client, &wsa885x_regmap_cfg); + + if (IS_ERR(wsa885x->regmap)) + return PTR_ERR(wsa885x->regmap); + + ret = device_property_read_string(dev, "qcom,battery-config", + &battery_config); + if (ret) { + wsa885x->batt_conf = WSA885X_BATT_1S; + } else if (!strcmp(battery_config, "1s")) { + wsa885x->batt_conf = WSA885X_BATT_1S; + } else if (!strcmp(battery_config, "2s")) { + wsa885x->batt_conf = WSA885X_BATT_2S; + } else { + return dev_err_probe(dev, -EINVAL, + "Invalid battery config %s (expected 1s or 2s)\n", + battery_config); + } + + for (i = 0; i < ARRAY_SIZE(wsa885x_supply_name); i++) { + ret = devm_regulator_get_enable(dev, wsa885x_supply_name[i]); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable regulator %s\n", + wsa885x_supply_name[i]); + } + + ret = wsa885x_get_reset(dev, wsa885x); + if (ret) + return ret; + + wsa885x_reset_deassert(wsa885x); + usleep_range(5000, 5500); + + ret = devm_add_action_or_reset(dev, wsa885x_reset_assert, wsa885x); + if (ret) + return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n"); + + i2c_set_clientdata(client, wsa885x); + + ret = wsa885x_register_irq(wsa885x); + if (ret) + return dev_err_probe(dev, ret, "wsa885x irq registration failed\n"); + + ret = devm_snd_soc_register_component(dev, component_driver, + wsa885x_dai, + ARRAY_SIZE(wsa885x_dai)); + if (ret) + return dev_err_probe(dev, ret, "Codec component registration failed\n"); + + return 0; +} + +static const struct of_device_id wsa885x_dt_match[] = { + { + .compatible = "qcom,wsa8855", + }, + {} +}; +MODULE_DEVICE_TABLE(of, wsa885x_dt_match); + +static const struct i2c_device_id wsa885x_id[] = { + { + .name = "wsa885x", + .driver_data = 0, + }, + {} +}; +MODULE_DEVICE_TABLE(i2c, wsa885x_id); + +static struct i2c_driver wsa885x_driver = { + .driver = { + .name = "wsa885x", + .of_match_table = wsa885x_dt_match, + }, + .probe = wsa885x_probe, + .id_table = wsa885x_id, +}; + +module_i2c_driver(wsa885x_driver); + +MODULE_DESCRIPTION("ASoC WSA885X Stereo Smart PA Codec Driver"); +MODULE_LICENSE("GPL"); From c143608b5602774d3c45a56d1149e21a213d70c6 Mon Sep 17 00:00:00 2001 From: Nickolay Goppen Date: Thu, 30 Jul 2026 13:43:39 -0400 Subject: [PATCH 411/438] ASoC: dt-bindings: qcom,sm8250: add compatible for sdm660 Add compatibles for sdm660 based soundcards. Signed-off-by: Nickolay Goppen Signed-off-by: Richard Acayan Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260730174353.108023-2-mailingradian@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 486780ed553c..c1bd19299763 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -48,6 +48,7 @@ properties: - qcom,qrb5165-rb5-sndcard - qcom,sc7180-qdsp6-sndcard - qcom,sc8280xp-sndcard + - qcom,sdm660-sndcard - qcom,sdm845-sndcard - qcom,sm8250-sndcard - qcom,sm8450-sndcard From 96591d7030a68ecdbb1be793d4b067d2087e0290 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:40 -0400 Subject: [PATCH 412/438] ASoC: dt-bindings: qcom: q6dsp: add support for lpi mi2s ports 5-6 There are 7 internal MI2S ports per direction found on devices with the internal sound card for Snapdragon 660. This is similar to the LPI MI2S ports, and the LPI MI2S bindings can be reused for internal MI2S. Extend the bindings for LPI MI2S ports to accommodate the internal MI2S ports. Signed-off-by: Richard Acayan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260730174353.108023-3-mailingradian@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml | 4 ++-- include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml index 2b27d6c8f58f..3b03e2acd67e 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml @@ -127,7 +127,7 @@ patternProperties: contains: # MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and # QUINARY_MI2S_RX - QUINARY_MI2S_TX and - # LPI_MI2S_RX_0 - SENARY_MI2S_TX + # LPI_MI2S_RX_0 - LPI_MI2S_TX_6 items: oneOf: - minimum: 16 @@ -135,7 +135,7 @@ patternProperties: - minimum: 127 maximum: 128 - minimum: 137 - maximum: 148 + maximum: 152 then: required: - qcom,sd-lines diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h index 7b553a73bc92..31b9ef65f903 100644 --- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h +++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h @@ -152,6 +152,10 @@ #define LPI_MI2S_TX_4 146 #define SENARY_MI2S_RX 147 #define SENARY_MI2S_TX 148 +#define LPI_MI2S_RX_5 149 +#define LPI_MI2S_TX_5 150 +#define LPI_MI2S_RX_6 151 +#define LPI_MI2S_TX_6 152 #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 #define LPASS_CLK_ID_PRI_MI2S_EBIT 2 From e70f039588492937b72d9f2f9bef8d630436c59e Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Thu, 30 Jul 2026 13:43:41 -0400 Subject: [PATCH 413/438] ASoC: dt-bindings: pm8916-wcd-analog-codec: Document pm8950/pm8953 Document pm8950 and pm8953 analog audio codecs. Signed-off-by: Adam Skladowski [richard: add back empty line] Signed-off-by: Richard Acayan Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260730174353.108023-4-mailingradian@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/qcom,pm8916-wcd-analog-codec.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml index 94e7a1860977..15389645a3e8 100644 --- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -14,7 +14,10 @@ description: properties: compatible: - const: qcom,pm8916-wcd-analog-codec + enum: + - qcom,pm8916-wcd-analog-codec + - qcom,pm8950-wcd-analog-codec + - qcom,pm8953-wcd-analog-codec reg: maxItems: 1 From 5f42d4525b43200298870999728cc90db06d4c01 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:42 -0400 Subject: [PATCH 414/438] ASoC: dt-bindings: pm8916-analog-codec: Add PM660L compatible The PM8953 (cajon 2.0) revision of the PM8916 analog codec is also found on PM660L, typically connected to the SDM660 internal sound card via the digital codec. Provide a space for specific compatibles and add the compatible for PM660L. Signed-off-by: Richard Acayan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260730174353.108023-5-mailingradian@gmail.com Signed-off-by: Mark Brown --- .../sound/qcom,pm8916-wcd-analog-codec.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml index 15389645a3e8..be47dbdb2e92 100644 --- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml @@ -14,10 +14,16 @@ description: properties: compatible: - enum: - - qcom,pm8916-wcd-analog-codec - - qcom,pm8950-wcd-analog-codec - - qcom,pm8953-wcd-analog-codec + oneOf: + - items: + - enum: + - qcom,pm660l-wcd-analog-codec + - const: qcom,pm8953-wcd-analog-codec + + - enum: + - qcom,pm8916-wcd-analog-codec + - qcom,pm8950-wcd-analog-codec + - qcom,pm8953-wcd-analog-codec reg: maxItems: 1 From 6f48a57f4bb2d24e246f975a28ab0e1ad9fd146b Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:43 -0400 Subject: [PATCH 415/438] ASoC: dt-bindings: msm8916-digital-codec: Add SDM660 compatible The MSM8916 digital codec is also found on SDM660, typically connected to the SDM660 internal sound card. Provide a space for specific compatibles and add the compatible for SDM660. Signed-off-by: Richard Acayan Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260730174353.108023-6-mailingradian@gmail.com Signed-off-by: Mark Brown --- .../bindings/sound/qcom,msm8916-wcd-digital-codec.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml index a899c4e7c1c9..33bc23b6176a 100644 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml @@ -14,7 +14,13 @@ description: properties: compatible: - const: qcom,msm8916-wcd-digital-codec + oneOf: + - items: + - enum: + - qcom,sdm660-wcd-digital-codec + - const: qcom,msm8916-wcd-digital-codec + + - const: qcom,msm8916-wcd-digital-codec reg: maxItems: 1 From 68400191e005f44c432c1b18eeca7f5527323a9f Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:44 -0400 Subject: [PATCH 416/438] ASoC: qdsp6: q6dsp-lpass-ports: add support for lpi mi2s ports 5-6 Add the extra LPI MI2S ports used for internal MI2S on SDM660. Link: https://android.googlesource.com/kernel/msm-extra/+/530cffa4cc977a348753831b163eb9d3302b954a/asoc/msm-dai-q6-v2.c#4597 Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-7-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/common.h | 2 +- sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h index ee6662885593..48b114eb46a5 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -7,7 +7,7 @@ #include #include -#define LPASS_MAX_PORT (SENARY_MI2S_TX + 1) +#define LPASS_MAX_PORT (LPI_MI2S_TX_6 + 1) int qcom_snd_parse_of(struct snd_soc_card *card); int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c index e5cd82f77b55..c3d8116ad503 100644 --- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c +++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c @@ -553,11 +553,15 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { Q6AFE_MI2S_RX_DAI("LPI RX2", LPI_MI2S_RX_2), Q6AFE_MI2S_RX_DAI("LPI RX3", LPI_MI2S_RX_3), Q6AFE_MI2S_RX_DAI("LPI RX4", LPI_MI2S_RX_4), + Q6AFE_MI2S_RX_DAI("LPI RX5", LPI_MI2S_RX_5), + Q6AFE_MI2S_RX_DAI("LPI RX6", LPI_MI2S_RX_6), Q6AFE_MI2S_TX_DAI("LPI TX0", LPI_MI2S_TX_0), Q6AFE_MI2S_TX_DAI("LPI TX1", LPI_MI2S_TX_1), Q6AFE_MI2S_TX_DAI("LPI TX2", LPI_MI2S_TX_2), Q6AFE_MI2S_TX_DAI("LPI TX3", LPI_MI2S_TX_3), Q6AFE_MI2S_TX_DAI("LPI TX4", LPI_MI2S_TX_4), + Q6AFE_MI2S_TX_DAI("LPI TX5", LPI_MI2S_TX_5), + Q6AFE_MI2S_TX_DAI("LPI TX6", LPI_MI2S_TX_6), Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0), Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1), Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2), @@ -712,6 +716,7 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: + case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: q6dsp_audio_fe_dais[i].ops = cfg->q6i2s_ops; break; case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: From bfe9098dc275a319c6b9f6e2417bb60fb8738a4b Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:45 -0400 Subject: [PATCH 417/438] ASoC: qdsp6: q6afe: add internal mi2s support The bindings for LPI MI2S ports, originally exclusive to q6apm, can be used for internal MI2S ports on q6afe. Add the port mappings for internal MI2S, found on the Snapdragon 660 internal sound card. Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-8-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe.c | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 40237267fda0..1d68a80e8e0c 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -132,6 +132,20 @@ #define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017 #define AFE_PORT_ID_SENARY_MI2S_RX 0x1018 #define AFE_PORT_ID_SENARY_MI2S_TX 0x1019 +#define AFE_PORT_ID_INT0_MI2S_RX 0x102e +#define AFE_PORT_ID_INT0_MI2S_TX 0x102f +#define AFE_PORT_ID_INT1_MI2S_RX 0x1030 +#define AFE_PORT_ID_INT1_MI2S_TX 0x1031 +#define AFE_PORT_ID_INT2_MI2S_RX 0x1032 +#define AFE_PORT_ID_INT2_MI2S_TX 0x1033 +#define AFE_PORT_ID_INT3_MI2S_RX 0x1034 +#define AFE_PORT_ID_INT3_MI2S_TX 0x1035 +#define AFE_PORT_ID_INT4_MI2S_RX 0x1036 +#define AFE_PORT_ID_INT4_MI2S_TX 0x1037 +#define AFE_PORT_ID_INT5_MI2S_RX 0x1038 +#define AFE_PORT_ID_INT5_MI2S_TX 0x1039 +#define AFE_PORT_ID_INT6_MI2S_RX 0x103a +#define AFE_PORT_ID_INT6_MI2S_TX 0x103b /* Start of the range of port IDs for TDM devices. */ #define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000 @@ -931,6 +945,34 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { [RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7, RX_CODEC_DMA_RX_7, 1, 1}, [USB_RX] = { AFE_PORT_ID_USB_RX, USB_RX, 1, 1}, + [LPI_MI2S_RX_0] = { AFE_PORT_ID_INT0_MI2S_RX, + LPI_MI2S_RX_0, 1, 1}, + [LPI_MI2S_TX_0] = { AFE_PORT_ID_INT0_MI2S_TX, + LPI_MI2S_TX_0, 0, 1}, + [LPI_MI2S_RX_1] = { AFE_PORT_ID_INT1_MI2S_RX, + LPI_MI2S_RX_1, 1, 1}, + [LPI_MI2S_TX_1] = { AFE_PORT_ID_INT1_MI2S_TX, + LPI_MI2S_TX_1, 0, 1}, + [LPI_MI2S_RX_2] = { AFE_PORT_ID_INT2_MI2S_RX, + LPI_MI2S_RX_2, 1, 1}, + [LPI_MI2S_TX_2] = { AFE_PORT_ID_INT2_MI2S_TX, + LPI_MI2S_TX_2, 0, 1}, + [LPI_MI2S_RX_3] = { AFE_PORT_ID_INT3_MI2S_RX, + LPI_MI2S_RX_3, 1, 1}, + [LPI_MI2S_TX_3] = { AFE_PORT_ID_INT3_MI2S_TX, + LPI_MI2S_TX_3, 0, 1}, + [LPI_MI2S_RX_4] = { AFE_PORT_ID_INT4_MI2S_RX, + LPI_MI2S_RX_4, 1, 1}, + [LPI_MI2S_TX_4] = { AFE_PORT_ID_INT4_MI2S_TX, + LPI_MI2S_TX_4, 0, 1}, + [LPI_MI2S_RX_5] = { AFE_PORT_ID_INT5_MI2S_RX, + LPI_MI2S_RX_5, 1, 1}, + [LPI_MI2S_TX_5] = { AFE_PORT_ID_INT5_MI2S_TX, + LPI_MI2S_TX_5, 0, 1}, + [LPI_MI2S_RX_6] = { AFE_PORT_ID_INT6_MI2S_RX, + LPI_MI2S_RX_6, 1, 1}, + [LPI_MI2S_TX_6] = { AFE_PORT_ID_INT6_MI2S_TX, + LPI_MI2S_TX_6, 0, 1}, }; static void q6afe_port_free(struct kref *ref) @@ -1785,6 +1827,20 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) case AFE_PORT_ID_QUINARY_MI2S_TX: case AFE_PORT_ID_SENARY_MI2S_RX: case AFE_PORT_ID_SENARY_MI2S_TX: + case AFE_PORT_ID_INT0_MI2S_RX: + case AFE_PORT_ID_INT0_MI2S_TX: + case AFE_PORT_ID_INT1_MI2S_RX: + case AFE_PORT_ID_INT1_MI2S_TX: + case AFE_PORT_ID_INT2_MI2S_RX: + case AFE_PORT_ID_INT2_MI2S_TX: + case AFE_PORT_ID_INT3_MI2S_RX: + case AFE_PORT_ID_INT3_MI2S_TX: + case AFE_PORT_ID_INT4_MI2S_RX: + case AFE_PORT_ID_INT4_MI2S_TX: + case AFE_PORT_ID_INT5_MI2S_RX: + case AFE_PORT_ID_INT5_MI2S_TX: + case AFE_PORT_ID_INT6_MI2S_RX: + case AFE_PORT_ID_INT6_MI2S_TX: cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7: From 0b494ae6a582b07c090839b8c62b931d6f4e2848 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:46 -0400 Subject: [PATCH 418/438] ASoC: qdsp6: q6afe-dai: add internal mi2s support The bindings for LPI MI2S ports, originally exclusive to q6apm, can be used for internal MI2S ports on q6afe. Add the internal MI2S ports found on the SDM660 internal sound card using the LPI MI2S bindings. Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-9-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe-dai.c | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index a0d21034a626..920345609d2c 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -412,6 +412,8 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, case SENARY_MI2S_RX ... SENARY_MI2S_TX: case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: + case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: rc = q6afe_i2s_port_prepare(dai_data->port[dai->id], &dai_data->port_config[dai->id].i2s_cfg); if (rc < 0) { @@ -665,6 +667,21 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { /* USB playback AFE port receives data for playback, hence use the RX port */ {"USB Playback", NULL, "USB_RX"}, + + {"LPI RX0 MI2S Playback", NULL, "LPI_MI2S_RX_0"}, + {"LPI_MI2S_TX_0", NULL, "LPI TX0 MI2S Capture"}, + {"LPI RX1 MI2S Playback", NULL, "LPI_MI2S_RX_1"}, + {"LPI_MI2S_TX_1", NULL, "LPI TX1 MI2S Capture"}, + {"LPI RX2 MI2S Playback", NULL, "LPI_MI2S_RX_2"}, + {"LPI_MI2S_TX_2", NULL, "LPI TX2 MI2S Capture"}, + {"LPI RX3 MI2S Playback", NULL, "LPI_MI2S_RX_3"}, + {"LPI_MI2S_TX_3", NULL, "LPI TX3 MI2S Capture"}, + {"LPI RX4 MI2S Playback", NULL, "LPI_MI2S_RX_4"}, + {"LPI_MI2S_TX_4", NULL, "LPI TX4 MI2S Capture"}, + {"LPI RX5 MI2S Playback", NULL, "LPI_MI2S_RX_5"}, + {"LPI_MI2S_TX_5", NULL, "LPI TX5 MI2S Capture"}, + {"LPI RX6 MI2S Playback", NULL, "LPI_MI2S_RX_6"}, + {"LPI_MI2S_TX_6", NULL, "LPI TX6 MI2S Capture"}, }; static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) @@ -1011,6 +1028,35 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("USB_RX", NULL, 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_0", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_0", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_1", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_1", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_2", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_2", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_3", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_3", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_4", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_4", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_5", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_5", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_6", NULL, + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_6", NULL, + 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_component_driver q6afe_dai_component = { @@ -1045,6 +1091,8 @@ static void of_q6afe_parse_dai_data(struct device *dev, case SENARY_MI2S_RX ... SENARY_MI2S_TX: case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: + case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: priv = &data->priv[id]; ret = of_property_read_variable_u32_array(node, "qcom,sd-lines", From 14d3cca9c2ed1ae0d647f109cfdf5d63f3f5be09 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:47 -0400 Subject: [PATCH 419/438] ASoC: qdsp6: q6routing: add lpi mi2s support Add the ASM-AFE routing for LPI MI2S ports which represent internal MI2S ports on SDM660. Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-10-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6routing.c | 78 +++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 7386226046fa..d076c99f197f 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -127,7 +127,14 @@ { mix_name, "TX_CODEC_DMA_TX_2", "TX_CODEC_DMA_TX_2"}, \ { mix_name, "TX_CODEC_DMA_TX_3", "TX_CODEC_DMA_TX_3"}, \ { mix_name, "TX_CODEC_DMA_TX_4", "TX_CODEC_DMA_TX_4"}, \ - { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"} + { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}, \ + { mix_name, "LPI_MI2S_TX_0", "LPI_MI2S_TX_0" }, \ + { mix_name, "LPI_MI2S_TX_1", "LPI_MI2S_TX_1" }, \ + { mix_name, "LPI_MI2S_TX_2", "LPI_MI2S_TX_2" }, \ + { mix_name, "LPI_MI2S_TX_3", "LPI_MI2S_TX_3" }, \ + { mix_name, "LPI_MI2S_TX_4", "LPI_MI2S_TX_4" }, \ + { mix_name, "LPI_MI2S_TX_5", "LPI_MI2S_TX_5" }, \ + { mix_name, "LPI_MI2S_TX_6", "LPI_MI2S_TX_6" } #define Q6ROUTING_TX_MIXERS(id) \ SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \ @@ -320,6 +327,27 @@ id, 1, 0, msm_routing_get_audio_mixer, \ msm_routing_put_audio_mixer), \ SOC_SINGLE_EXT("TX_CODEC_DMA_TX_5", TX_CODEC_DMA_TX_5, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_0", LPI_MI2S_TX_0, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_1", LPI_MI2S_TX_1, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_2", LPI_MI2S_TX_2, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_3", LPI_MI2S_TX_3, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_4", LPI_MI2S_TX_4, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_5", LPI_MI2S_TX_5, \ + id, 1, 0, msm_routing_get_audio_mixer, \ + msm_routing_put_audio_mixer), \ + SOC_SINGLE_EXT("LPI_MI2S_TX_6", LPI_MI2S_TX_6, \ id, 1, 0, msm_routing_get_audio_mixer, \ msm_routing_put_audio_mixer), @@ -709,6 +737,26 @@ static const struct snd_kcontrol_new rxcodec_dma_rx_6_mixer_controls[] = { static const struct snd_kcontrol_new rx_codec_dma_rx_7_mixer_controls[] = { Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_7) }; +static const struct snd_kcontrol_new lpi_mi2s_rx_0_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_0) }; + +static const struct snd_kcontrol_new lpi_mi2s_rx_1_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_1) }; + +static const struct snd_kcontrol_new lpi_mi2s_rx_2_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_2) }; + +static const struct snd_kcontrol_new lpi_mi2s_rx_3_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_3) }; + +static const struct snd_kcontrol_new lpi_mi2s_rx_4_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_4) }; + +static const struct snd_kcontrol_new lpi_mi2s_rx_5_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_5) }; + +static const struct snd_kcontrol_new lpi_mi2s_rx_6_mixer_controls[] = { + Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_6) }; static const struct snd_kcontrol_new mmul1_mixer_controls[] = { Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) }; @@ -938,6 +986,27 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("USB_RX Audio Mixer", SND_SOC_NOPM, 0, 0, usb_rx_mixer_controls, ARRAY_SIZE(usb_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_0_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_0_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_1_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_1_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_2_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_2_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_3_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_3_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_4_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_4_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_5_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_5_mixer_controls)), + SND_SOC_DAPM_MIXER("LPI_MI2S_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0, + lpi_mi2s_rx_6_mixer_controls, + ARRAY_SIZE(lpi_mi2s_rx_6_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0, mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)), SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0, @@ -1031,6 +1100,13 @@ static const struct snd_soc_dapm_route intercon[] = { Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"), Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"), Q6ROUTING_RX_DAPM_ROUTE("USB_RX Audio Mixer", "USB_RX"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_0 Audio Mixer", "LPI_MI2S_RX_0"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_1 Audio Mixer", "LPI_MI2S_RX_1"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_2 Audio Mixer", "LPI_MI2S_RX_2"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_3 Audio Mixer", "LPI_MI2S_RX_3"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_4 Audio Mixer", "LPI_MI2S_RX_4"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_5 Audio Mixer", "LPI_MI2S_RX_5"), + Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_6 Audio Mixer", "LPI_MI2S_RX_6"), Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"), Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"), Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"), From bd8216bfe24ff96211f436ffffa6a9c4adbc9d36 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:48 -0400 Subject: [PATCH 420/438] ASoC: qdsp6: common: support headphone jacks connected to lpi mi2s On SDM660, LPI MI2S ports can be connected to a WCD codec which may support headphones. Register the headphone jack on codecs connected to the playback port, LPI_MI2S_RX_0. Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-11-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index e4ff247ea47f..f8782e5cfaae 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -215,6 +215,7 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, } switch (cpu_dai->id) { + case LPI_MI2S_RX_0: case TX_CODEC_DMA_TX_0: case TX_CODEC_DMA_TX_1: case TX_CODEC_DMA_TX_2: From 5e913c10bd0d60ef93657f5c84014c998dbd4100 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:49 -0400 Subject: [PATCH 421/438] ASoC: qcom: sm8250: add support for LPI_MI2S_RX_0 and LPI_MI2S_TX_3 The LPI_MI2S_RX_0 and LPI_MI2S_TX_3 ports on SDM660 can be connected to the digital and analog WCD codecs. They can be supported with the same logic for other ports, but just need to be explicitly stated. Add support for these ports. Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-12-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index f193d0ba63d0..1952c599e004 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -112,6 +112,22 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(cpu_dai, fmt); snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; + case LPI_MI2S_RX_0: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; + case LPI_MI2S_TX_3: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE); + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; default: break; } From 84f950973d9115adceee596528f4215b89323748 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:50 -0400 Subject: [PATCH 422/438] ASoC: qcom: sm8250: add SDM660 compatible Add the compatible for SDM660 and SDM670 devices, which can use the support for WCD codecs connected to internal MI2S. Signed-off-by: Richard Acayan Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260730174353.108023-13-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/qcom/sm8250.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 1952c599e004..76dc3a3f4a31 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -210,6 +210,7 @@ static const struct of_device_id snd_sm8250_dt_match[] = { { .compatible = "qcom,qrb2210-sndcard", .data = "qcm2290" }, { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" }, { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" }, + { .compatible = "qcom,sdm660-sndcard", .data = "sdm660" }, { .compatible = "qcom,sm8250-sndcard", .data = "sm8250" }, {} }; From a3e1181e12c779a5f537302421bf9f3202cc1abe Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Thu, 30 Jul 2026 13:43:51 -0400 Subject: [PATCH 423/438] ASoC: msm8916-wcd-analog: add pm8950 codec Add regs overrides for PM8950 codec and implement matching reg overrides via compatible. Signed-off-by: Adam Skladowski Reviewed-by: Dmitry Baryshkov Signed-off-by: Richard Acayan Link: https://patch.msgid.link/20260730174353.108023-14-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 52 ++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 9ca381812975..13df60409857 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -232,6 +232,8 @@ #define RX_EAR_CTL_PA_SEL_MASK BIT(7) #define RX_EAR_CTL_PA_SEL BIT(7) +#define CDC_A_RX_EAR_STATUS (0xf1A1) + #define CDC_A_SPKR_DAC_CTL (0xf1B0) #define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4) #define SPKR_DAC_CTL_DAC_RESET_NORMAL 0 @@ -250,6 +252,7 @@ SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \ SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \ SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET) +#define CDC_A_SPKR_ANA_BIAS_SET (0xf1B3) #define CDC_A_SPKR_OCP_CTL (0xf1B4) #define CDC_A_SPKR_PWRSTG_CTL (0xf1B5) #define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0) @@ -264,6 +267,7 @@ #define CDC_A_SPKR_DRV_DBG (0xf1B7) #define CDC_A_CURRENT_LIMIT (0xf1C0) +#define CDC_A_BYPASS_MODE (0xf1C2) #define CDC_A_BOOST_EN_CTL (0xf1C3) #define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4) #define CDC_A_SEC_ACCESS (0xf1D0) @@ -286,6 +290,11 @@ static const char * const supply_names[] = { #define MBHC_MAX_BUTTONS (5) +struct wcd_reg_seq { + const struct reg_default *seq; + int seq_size; +}; + struct pm8916_wcd_analog_priv { u16 pmic_rev; u16 codec_version; @@ -715,9 +724,41 @@ static const struct reg_default wcd_reg_defaults_2_0[] = { {CDC_A_MASTER_BIAS_CTL, 0x30}, }; +static const struct wcd_reg_seq pm8916_data = { + .seq = wcd_reg_defaults_2_0, + .seq_size = ARRAY_SIZE(wcd_reg_defaults_2_0), +}; + +static const struct reg_default wcd_reg_defaults_pm8950[] = { + {CDC_A_RX_COM_OCP_CTL, 0xd1}, + {CDC_A_RX_COM_OCP_COUNT, 0xff}, + {CDC_D_SEC_ACCESS, 0xa5}, + {CDC_D_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c}, + {CDC_A_NCP_FBCTRL, 0xa8}, + {CDC_A_NCP_VCTRL, 0xa4}, + {CDC_A_SPKR_DRV_CTL, 0x69}, + {CDC_A_SPKR_DRV_DBG, 0x01}, + {CDC_A_SEC_ACCESS, 0xa5}, + {CDC_A_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_CURRENT_LIMIT, 0x82}, + {CDC_A_SPKR_ANA_BIAS_SET, 0x41}, + {CDC_A_SPKR_DAC_CTL, 0x03}, + {CDC_A_SPKR_OCP_CTL, 0xe1}, + {CDC_A_RX_HPH_BIAS_PA, 0xfa}, + {CDC_A_MASTER_BIAS_CTL, 0x30}, + {CDC_A_MICB_1_INT_RBIAS, 0x00}, +}; + +static const struct wcd_reg_seq pm8950_data = { + .seq = wcd_reg_defaults_pm8950, + .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8950), +}; + static int pm8916_wcd_analog_probe(struct snd_soc_component *component) { struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); + const struct wcd_reg_seq *wcd_reg_init_data; int err, reg; err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); @@ -738,9 +779,11 @@ static int pm8916_wcd_analog_probe(struct snd_soc_component *component) snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01); snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01); - for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++) - snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg, - wcd_reg_defaults_2_0[reg].def); + wcd_reg_init_data = of_device_get_match_data(component->dev); + + for (reg = 0; reg < wcd_reg_init_data->seq_size; reg++) + snd_soc_component_write(component, wcd_reg_init_data->seq[reg].reg, + wcd_reg_init_data->seq[reg].def); priv->component = component; @@ -1259,7 +1302,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { - { .compatible = "qcom,pm8916-wcd-analog-codec", }, + { .compatible = "qcom,pm8916-wcd-analog-codec", .data = &pm8916_data }, + { .compatible = "qcom,pm8950-wcd-analog-codec", .data = &pm8950_data }, { } }; From 4583c124538dfc591bdb08e1e0353d02d3a145bc Mon Sep 17 00:00:00 2001 From: Vladimir Lypak Date: Thu, 30 Jul 2026 13:43:52 -0400 Subject: [PATCH 424/438] ASoC: msm8916-wcd-analog: add pm8953 codec Add regs overrides for PM8953 codec. Signed-off-by: Vladimir Lypak [Adam: rename codec] Signed-off-by: Adam Skladowski Reviewed-by: Dmitry Baryshkov Signed-off-by: Richard Acayan Link: https://patch.msgid.link/20260730174353.108023-15-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 13df60409857..b9325290c28d 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -755,6 +755,34 @@ static const struct wcd_reg_seq pm8950_data = { .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8950), }; +static const struct reg_default wcd_reg_defaults_pm8953[] = { + {CDC_A_RX_COM_OCP_CTL, 0xd1}, + {CDC_A_RX_COM_OCP_COUNT, 0xff}, + {CDC_D_SEC_ACCESS, 0xa5}, + {CDC_D_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c}, + {CDC_A_NCP_FBCTRL, 0xa8}, + {CDC_A_NCP_VCTRL, 0xa4}, + {CDC_A_SPKR_DRV_CTL, 0x69}, + {CDC_A_SPKR_DRV_DBG, 0x01}, + {CDC_A_SEC_ACCESS, 0xa5}, + {CDC_A_PERPH_RESET_CTL3, 0x0f}, + {CDC_A_CURRENT_LIMIT, 0xa2}, + {CDC_A_BYPASS_MODE, 0x18}, + {CDC_A_SPKR_ANA_BIAS_SET, 0x41}, + {CDC_A_SPKR_DAC_CTL, 0x03}, + {CDC_A_SPKR_OCP_CTL, 0xe1}, + {CDC_A_RX_HPH_BIAS_PA, 0xfa}, + {CDC_A_RX_EAR_STATUS, 0x10}, + {CDC_A_MASTER_BIAS_CTL, 0x30}, + {CDC_A_MICB_1_INT_RBIAS, 0x00}, +}; + +static const struct wcd_reg_seq pm8953_data = { + .seq = wcd_reg_defaults_pm8953, + .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8953), +}; + static int pm8916_wcd_analog_probe(struct snd_soc_component *component) { struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); @@ -1304,6 +1332,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { { .compatible = "qcom,pm8916-wcd-analog-codec", .data = &pm8916_data }, { .compatible = "qcom,pm8950-wcd-analog-codec", .data = &pm8950_data }, + { .compatible = "qcom,pm8953-wcd-analog-codec", .data = &pm8953_data }, { } }; From ff01bff07665d17286a102f70087911675f72953 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 30 Jul 2026 13:43:53 -0400 Subject: [PATCH 425/438] ASoC: msm8916-wcd-analog: add quirk for cajon 2.0 The codec version CAJON_2_0 on the Snapdragon 670 requires touching the HPH test registers. Add the quirk so this driver can also support SDM670. Signed-off-by: Richard Acayan Link: https://patch.msgid.link/20260730174353.108023-16-mailingradian@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 63 ++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index b9325290c28d..87f8a47cc293 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -217,9 +217,11 @@ #define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195) #define CDC_A_RX_HPH_BIAS_CNP (0xf196) #define CDC_A_RX_HPH_CNP_EN (0xf197) +#define CDC_A_RX_HPH_L_TEST (0xf19A) #define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B) #define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1) #define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1) +#define CDC_A_RX_HPH_R_TEST (0xf19C) #define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D) #define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1) #define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1) @@ -705,6 +707,59 @@ static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w, return 0; } +static int pm8916_wcd_analog_enable_hphl_pa(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 pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); + + /* This quirk is not required for revisions prior to CAJON_2_0 */ + if (priv->codec_version < 4) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST, + 0x04, 0x04); + break; + case SND_SOC_DAPM_POST_PMD: + /* wait 20 ms after the digital codec has powered down */ + msleep(20); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST, + 0x04, 0x00); + break; + } + return 0; +} + +static int pm8916_wcd_analog_enable_hphr_pa(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 pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); + + /* This quirk is not required for revisions prior to CAJON_2_0 */ + if (priv->codec_version < 4) + return 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(7000, 7100); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST, + 0x04, 0x04); + break; + case SND_SOC_DAPM_POST_PMD: + msleep(20); + snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST, + 0x04, 0x00); + break; + } + return 0; +} + static const struct reg_default wcd_reg_defaults_2_0[] = { {CDC_A_RX_COM_OCP_CTL, 0xD1}, {CDC_A_RX_COM_OCP_COUNT, 0xFF}, @@ -954,11 +1009,15 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux), SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0, + pm8916_wcd_analog_enable_hphl_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0, + pm8916_wcd_analog_enable_hphr_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux), SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL, 0), From 07fd957b53fc97dafbf6a3f7f13e2f030bce8114 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 31 Jul 2026 17:26:23 +0100 Subject: [PATCH 426/438] ASoC: qcom: sc8280xp: tolerate -ENOTSUPP from codec set_sysclk Not all codecs implement the set_sysclk operation. When the board enables codec_sysclk_set, snd_soc_dai_set_sysclk() on the codec DAI can return -ENOTSUPP, which currently aborts hw_params and breaks playback/capture on such boards even though the missing clock setup is harmless. Ignore -ENOTSUPP for the codec set_sysclk call. Fixes: 766f3f79c312 ("ASoC: qcom: sc8280xp: enhance machine driver for board-specific config") Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260731162626.1588561-2-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index a9304784d41e..ce2b0633688c 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -202,7 +202,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN); - if (ret) + if (ret && ret != -ENOTSUPP) return ret; } break; From a2fdf929fbb491f3bf4d3cadb5a7cc7c90182c0f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 31 Jul 2026 17:26:24 +0100 Subject: [PATCH 427/438] ASoC: qcom: qdsp6: q6prm: add the missing MCLK clock IDs Add the missing MCLK ids for the q6prm DSP interface. Reviewed-by: Srinivas Kandagatla Signed-off-by: Neil Armstrong Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260731162626.1588561-3-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6prm-clocks.c | 5 +++++ sound/soc/qcom/qdsp6/q6prm.h | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c index 4c574b48ab00..51b131fa9531 100644 --- a/sound/soc/qcom/qdsp6/q6prm-clocks.c +++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c @@ -42,6 +42,11 @@ static const struct q6dsp_clk_init q6prm_clks[] = { Q6PRM_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT), Q6PRM_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT), Q6PRM_CLK(LPASS_CLK_ID_QUI_MI2S_OSR), + Q6PRM_CLK(LPASS_CLK_ID_MCLK_1), + Q6PRM_CLK(LPASS_CLK_ID_MCLK_2), + Q6PRM_CLK(LPASS_CLK_ID_MCLK_3), + Q6PRM_CLK(LPASS_CLK_ID_MCLK_4), + Q6PRM_CLK(LPASS_CLK_ID_MCLK_5), Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_MCLK), Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK), Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_MCLK), diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h index bc5b9fa13283..1800b997722f 100644 --- a/sound/soc/qcom/qdsp6/q6prm.h +++ b/sound/soc/qcom/qdsp6/q6prm.h @@ -55,6 +55,17 @@ /* Clock ID for QUINARY MI2S OSR CLK */ #define Q6PRM_LPASS_CLK_ID_QUI_MI2S_OSR 0x116 +/* Clock ID for MCLK1 */ +#define Q6PRM_LPASS_CLK_ID_MCLK_1 0x300 +/* Clock ID for MCLK2 */ +#define Q6PRM_LPASS_CLK_ID_MCLK_2 0x301 +/* Clock ID for MCLK3 */ +#define Q6PRM_LPASS_CLK_ID_MCLK_3 0x302 +/* Clock ID for MCLK4 */ +#define Q6PRM_LPASS_CLK_ID_MCLK_4 0x303 +/* Clock ID for MCLK5 */ +#define Q6PRM_LPASS_CLK_ID_MCLK_5 0x304 + #define Q6PRM_LPASS_CLK_ID_WSA_CORE_MCLK 0x305 #define Q6PRM_LPASS_CLK_ID_WSA_CORE_NPL_MCLK 0x306 From a28da0f80d056ec938157a88dc3cecef120c017a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 31 Jul 2026 17:26:25 +0100 Subject: [PATCH 428/438] ASoC: qcom: sc8280xp: rename snd_soc_common to qcom_snd_soc_common The driver-local structure was named 'snd_soc_common', which occupies the generic snd_soc_ ASoC namespace even though it is specific to the Qualcomm sc8280xp machine driver. Rename the type to qcom_snd_soc_common so the identifier is properly scoped to this driver, and rename the pointer field in sc8280xp_snd_data from 'snd_soc_common_priv' to 'priv' so the shorter name doesn't repeat the type name at every use. No functional change. Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260731162626.1588561-4-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 60 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index ce2b0633688c..d938eeda64bf 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -37,7 +37,7 @@ static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = { SND_SOC_DAPM_SPK("DP7 Jack", NULL), }; -struct snd_soc_common { +struct qcom_snd_soc_common { const char *driver_name; const struct snd_soc_dapm_widget *dapm_widgets; int num_dapm_widgets; @@ -57,7 +57,7 @@ struct sc8280xp_snd_data { struct snd_soc_card *card; struct snd_soc_jack jack; struct snd_soc_jack dp_jack[8]; - const struct snd_soc_common *snd_soc_common_priv; + const struct qcom_snd_soc_common *priv; bool jack_setup; }; @@ -121,7 +121,7 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) if (dp_jack) return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); - if (data->snd_soc_common_priv->wcd_jack) + if (data->priv->wcd_jack) return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); return 0; @@ -175,14 +175,14 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, if (ret && ret != -ENOTSUPP) return ret; - if (data->snd_soc_common_priv->codec_dai_fmt) { + if (data->priv->codec_dai_fmt) { ret = snd_soc_dai_set_fmt(codec_dai, - data->snd_soc_common_priv->codec_dai_fmt); + data->priv->codec_dai_fmt); if (ret && ret != -ENOTSUPP) return ret; } - if (data->snd_soc_common_priv->mi2s_mclk_enable) { + if (data->priv->mi2s_mclk_enable) { ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_MI2S_MCLK, mclk_freq, SND_SOC_CLOCK_OUT); @@ -190,7 +190,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, return ret; } - if (data->snd_soc_common_priv->mi2s_bclk_enable) { + if (data->priv->mi2s_bclk_enable) { ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_MI2S_BCLK, bclk_freq, SND_SOC_CLOCK_OUT); @@ -198,7 +198,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, return ret; } - if (data->snd_soc_common_priv->codec_sysclk_set) { + if (data->priv->codec_sysclk_set) { ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN); @@ -269,38 +269,38 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - data->snd_soc_common_priv = of_device_get_match_data(dev); - if (!data->snd_soc_common_priv) + data->priv = of_device_get_match_data(dev); + if (!data->priv) return -ENODEV; card->owner = THIS_MODULE; card->dev = dev; dev_set_drvdata(dev, card); snd_soc_card_set_drvdata(card, data); - card->dapm_widgets = data->snd_soc_common_priv->dapm_widgets; - card->num_dapm_widgets = data->snd_soc_common_priv->num_dapm_widgets; - card->dapm_routes = data->snd_soc_common_priv->dapm_routes; - card->num_dapm_routes = data->snd_soc_common_priv->num_dapm_routes; - card->controls = data->snd_soc_common_priv->controls; - card->num_controls = data->snd_soc_common_priv->num_controls; + card->dapm_widgets = data->priv->dapm_widgets; + card->num_dapm_widgets = data->priv->num_dapm_widgets; + card->dapm_routes = data->priv->dapm_routes; + card->num_dapm_routes = data->priv->num_dapm_routes; + card->controls = data->priv->controls; + card->num_controls = data->priv->num_controls; ret = qcom_snd_parse_of(card); if (ret) return ret; - card->driver_name = data->snd_soc_common_priv->driver_name; + card->driver_name = data->priv->driver_name; sc8280xp_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } -static const struct snd_soc_common eliza_priv_data = { +static const struct qcom_snd_soc_common eliza_priv_data = { .driver_name = "eliza", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common hawi_priv_data = { +static const struct qcom_snd_soc_common hawi_priv_data = { .driver_name = "hawi", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), @@ -309,74 +309,74 @@ static const struct snd_soc_common hawi_priv_data = { .wcd_jack = true, }; -static const struct snd_soc_common kaanapali_priv_data = { +static const struct qcom_snd_soc_common kaanapali_priv_data = { .driver_name = "kaanapali", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common qcs9100_priv_data = { +static const struct qcom_snd_soc_common qcs9100_priv_data = { .driver_name = "sa8775p", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), }; -static const struct snd_soc_common qcs615_priv_data = { +static const struct qcom_snd_soc_common qcs615_priv_data = { .driver_name = "qcs615", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), }; -static const struct snd_soc_common qcm6490_priv_data = { +static const struct qcom_snd_soc_common qcm6490_priv_data = { .driver_name = "qcm6490", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common qcs6490_priv_data = { +static const struct qcom_snd_soc_common qcs6490_priv_data = { .driver_name = "qcs6490", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common qcs8275_priv_data = { +static const struct qcom_snd_soc_common qcs8275_priv_data = { .driver_name = "qcs8300", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), }; -static const struct snd_soc_common sc8280xp_priv_data = { +static const struct qcom_snd_soc_common sc8280xp_priv_data = { .driver_name = "sc8280xp", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common sm8450_priv_data = { +static const struct qcom_snd_soc_common sm8450_priv_data = { .driver_name = "sm8450", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common sm8550_priv_data = { +static const struct qcom_snd_soc_common sm8550_priv_data = { .driver_name = "sm8550", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common sm8650_priv_data = { +static const struct qcom_snd_soc_common sm8650_priv_data = { .driver_name = "sm8650", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), .wcd_jack = true, }; -static const struct snd_soc_common sm8750_priv_data = { +static const struct qcom_snd_soc_common sm8750_priv_data = { .driver_name = "sm8750", .dapm_widgets = sc8280xp_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), From 4ba2678ad03ea21e946395d4b1476e9fb0d218fb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 31 Jul 2026 17:26:26 +0100 Subject: [PATCH 429/438] ASoC: qcom: sc8280xp: add monaco/monza controls for qcs8275 Update dai-ids and add DAPM widgets, sysclk and controls required for the VENTUNO-Q platform which uses MAX98090 codec. Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260731162626.1588561-5-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- sound/soc/qcom/sc8280xp.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index d938eeda64bf..912137566f94 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -37,6 +37,26 @@ static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = { SND_SOC_DAPM_SPK("DP7 Jack", NULL), }; +static const struct snd_kcontrol_new max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Headset Mic12"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic56"), + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Receiver"), + SOC_DAPM_PIN_SWITCH("Int Mic"), +}; + +static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic12", NULL), + SND_SOC_DAPM_MIC("Headset Mic56", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Receiver", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + struct qcom_snd_soc_common { const char *driver_name; const struct snd_soc_dapm_widget *dapm_widgets; @@ -171,6 +191,7 @@ static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: case SENARY_MI2S_RX ... SENARY_MI2S_TX: + case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); if (ret && ret != -ENOTSUPP) return ret; @@ -344,8 +365,12 @@ static const struct qcom_snd_soc_common qcs6490_priv_data = { static const struct qcom_snd_soc_common qcs8275_priv_data = { .driver_name = "qcs8300", - .dapm_widgets = sc8280xp_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .dapm_widgets = max98090_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets), + .controls = max98090_controls, + .num_controls = ARRAY_SIZE(max98090_controls), + .codec_sysclk_set = true, + .codec_dai_fmt = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC, }; static const struct qcom_snd_soc_common sc8280xp_priv_data = { From 1bd470f27f283cfcfd5c94705a2fabbe5f1e4e9f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:00:09 +0000 Subject: [PATCH 430/438] ASoC: apple: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87y0f5jgx2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/apple/mca.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index afb3754a8883..be702b2942a5 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -739,6 +739,19 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, return 0; } +static const u64 mca_fe_selectable_formats[] = +{ + /* pattern 1 */ + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF, + + /* pattern 2 */ + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF +}; + static const struct snd_soc_dai_ops mca_fe_ops = { .startup = mca_fe_startup, .set_fmt = mca_fe_set_fmt, @@ -748,6 +761,8 @@ static const struct snd_soc_dai_ops mca_fe_ops = { .trigger = mca_fe_trigger, .prepare = mca_fe_prepare, .hw_free = mca_fe_hw_free, + .auto_selectable_formats = mca_fe_selectable_formats, + .num_auto_selectable_formats = ARRAY_SIZE(mca_fe_selectable_formats), }; /* From f7726b460010c59f5af5a82897cbcf3192d2454d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:00:23 +0000 Subject: [PATCH 431/438] ASoC: atmel: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87wlupjgwp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-i2s.c | 4 ++++ sound/soc/atmel/atmel_ssc_dai.c | 7 +++++++ sound/soc/atmel/mchp-i2s-mcc.c | 9 +++++++++ sound/soc/atmel/mchp-pdmc.c | 4 ++++ 4 files changed, 24 insertions(+) diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 762199faf872..d9ad262ec44d 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -540,12 +540,16 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const u64 atmel_i2s_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_I2S; + static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { .probe = atmel_i2s_dai_probe, .prepare = atmel_i2s_prepare, .trigger = atmel_i2s_trigger, .hw_params = atmel_i2s_hw_params, .set_fmt = atmel_i2s_set_dai_fmt, + .auto_selectable_formats = &atmel_i2s_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver atmel_i2s_dai = { diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 89098f41679c..f4f886bf678d 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -825,6 +825,11 @@ static int atmel_ssc_resume(struct snd_soc_component *component) #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S32_LE) +static const u64 atmel_ssc_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A; + static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, @@ -833,6 +838,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv, + .auto_selectable_formats = &atmel_ssc_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver atmel_ssc_dai = { diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 17d138bb9064..a832dee73ac7 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -912,6 +912,13 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) return 0; } +static const u64 mchp_i2s_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_GATED | + SND_SOC_POSSIBLE_DAIFMT_NB_NF; + static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { .probe = mchp_i2s_mcc_dai_probe, .set_sysclk = mchp_i2s_mcc_set_sysclk, @@ -922,6 +929,8 @@ static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { .hw_free = mchp_i2s_mcc_hw_free, .set_fmt = mchp_i2s_mcc_set_dai_fmt, .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, + .auto_selectable_formats = &mchp_i2s_selectable_formats, + .num_auto_selectable_formats = 1, }; #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index ec7233ce1f78..a6a9b5e6cd95 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -741,6 +741,8 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd, return ret; } +static const u64 mchp_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_PDM; + static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { .probe = mchp_pdmc_dai_probe, .set_fmt = mchp_pdmc_set_fmt, @@ -748,6 +750,8 @@ static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { .hw_params = mchp_pdmc_hw_params, .trigger = mchp_pdmc_trigger, .pcm_new = &mchp_pdmc_pcm_new, + .auto_selectable_formats = &mchp_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver mchp_pdmc_dai = { From d2b8012401ea59b665493f6cbaf1553bdba34882 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:00:30 +0000 Subject: [PATCH 432/438] ASoC: au1x: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87v7a9jgwh.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/au1x/i2sc.c | 11 +++++++++++ sound/soc/au1x/psc-i2s.c | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 57735004f416..0e9c7eef9ee8 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -202,11 +202,22 @@ static int au1xi2s_startup(struct snd_pcm_substream *substream, return 0; } +static const u64 au1xi2s_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops au1xi2s_dai_ops = { .startup = au1xi2s_startup, .trigger = au1xi2s_trigger, .hw_params = au1xi2s_hw_params, .set_fmt = au1xi2s_set_fmt, + .auto_selectable_formats = &au1xi2s_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver au1xi2s_dai_driver = { diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index bf59105fcb7a..72aa5177147f 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -262,11 +262,22 @@ static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream, return 0; } +static const u64 au1xpsc_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { .startup = au1xpsc_i2s_startup, .trigger = au1xpsc_i2s_trigger, .hw_params = au1xpsc_i2s_hw_params, .set_fmt = au1xpsc_i2s_set_fmt, + .auto_selectable_formats = &au1xpsc_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = { From 9626075249c5ec181a166472c0a5c3620e2ad72d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:00:37 +0000 Subject: [PATCH 433/438] ASoC: bcm: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87tsptjgwa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 13 +++++++++++++ sound/soc/bcm/cygnus-ssp.c | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 87d2f06c2f53..208977828254 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -748,6 +748,17 @@ static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) return 0; } +static const u64 bcm2835_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .probe = bcm2835_i2s_dai_probe, .startup = bcm2835_i2s_startup, @@ -758,6 +769,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { .set_fmt = bcm2835_i2s_set_dai_fmt, .set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio, .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot, + .auto_selectable_formats = &bcm2835_selectable_formats, + .num_auto_selectable_formats = 1, }; static struct snd_soc_dai_driver bcm2835_i2s_dai = { diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 47706ae0a31f..753021789a52 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1133,6 +1133,11 @@ static int cygnus_ssp_resume(struct snd_soc_component *component) #define cygnus_ssp_resume NULL #endif +static const u64 cygnus_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B; + static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = { .startup = cygnus_ssp_startup, .shutdown = cygnus_ssp_shutdown, @@ -1141,6 +1146,8 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = { .set_fmt = cygnus_ssp_set_fmt, .set_sysclk = cygnus_ssp_set_sysclk, .set_tdm_slot = cygnus_set_dai_tdm_slot, + .auto_selectable_formats = &cygnus_selectable_formats, + .num_auto_selectable_formats = 1, }; static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = { From 01856b7ac984390302c3450b067aca97da7142e3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2026 01:00:42 +0000 Subject: [PATCH 434/438] ASoC: cirrus: use .auto_selectable_formats We can use .auto_selectable_formats. Let's adds it. Signed-off-by: Kuninori Morimoto Link: https://patch.msgid.link/87se5djgw5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/cirrus/ep93xx-i2s.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 5dba741594fa..8195ed7c6dd6 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -401,6 +401,15 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component) #define ep93xx_i2s_resume NULL #endif +static const u64 ep93xx_selectable_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { .probe = ep93xx_i2s_dai_probe, .startup = ep93xx_i2s_startup, @@ -408,6 +417,8 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { .hw_params = ep93xx_i2s_hw_params, .set_sysclk = ep93xx_i2s_set_sysclk, .set_fmt = ep93xx_i2s_set_dai_fmt, + .auto_selectable_formats = &ep93xx_selectable_formats, + .num_auto_selectable_formats = 1, }; #define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) From ae788eeb17dbcdbbe6fcdaf69f2650a71d001837 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 30 Jul 2026 16:54:04 +0700 Subject: [PATCH 435/438] ASoC: spear: spdif_in: Drop redundant error messages The called functions already log failures where appropriate. Return the original error directly and avoid duplicate error messages. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260730095407.33894-2-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index b31b120a85de..bbe016ed030e 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -218,10 +218,8 @@ static int spdif_in_probe(struct platform_device *pdev) host->io_base = io_base; host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq); + if (host->irq < 0) return host->irq; - } host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) @@ -243,10 +241,8 @@ static int spdif_in_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0, "spdif-in", host); - if (ret) { - dev_warn(&pdev->dev, "request_irq failed\n"); + if (ret) return ret; - } ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component, &spdif_in_dai, 1); From c6c14a9915d512252d79aa6d3217e76b4143cc8b Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 30 Jul 2026 16:54:05 +0700 Subject: [PATCH 436/438] ASoC: spear: spdif_in: Switch to snd_soc_dai_dma_data_set_capture() Replace the legacy direct access to dai->capture_dma_data with snd_soc_dai_dma_data_set_capture(). The capture_dma_data field no longer exists in struct snd_soc_dai, making the previous implementation incompatible with current ASoC APIs. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260730095407.33894-3-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index bbe016ed030e..d571055bfc6b 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -55,7 +55,7 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai) struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai); host->dma_params_rx.filter_data = &host->dma_params; - dai->capture_dma_data = &host->dma_params_rx; + snd_soc_dai_dma_data_set_capture(dai, &host->dma_params_rx); return 0; } From 9f2ba3a104499d97aa7ffc52c81129b16d968bf8 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 30 Jul 2026 16:54:06 +0700 Subject: [PATCH 437/438] ASoC: spear: spdif_in: Move DAI probe callback to snd_soc_dai_ops The .probe callback is no longer part of struct snd_soc_dai_driver and is now provided through struct snd_soc_dai_ops. Move spdif_in_dai_probe() accordingly so the driver follows the current ASoC API and builds correctly on modern kernels. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260730095407.33894-4-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index d571055bfc6b..dd1e176193af 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -150,12 +150,12 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd, static const struct snd_soc_dai_ops spdif_in_dai_ops = { .shutdown = spdif_in_shutdown, + .probe = spdif_in_dai_probe, .trigger = spdif_in_trigger, .hw_params = spdif_in_hw_params, }; static struct snd_soc_dai_driver spdif_in_dai = { - .probe = spdif_in_dai_probe, .capture = { .channels_min = 2, .channels_max = 2, From ad95fc2e9b3bad40d6c3c6897ecc5f853b57ef87 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Thu, 30 Jul 2026 16:54:07 +0700 Subject: [PATCH 438/438] ASoC: spear: spdif_out: Move DAI probe callback to snd_soc_dai_ops The .probe callback is no longer part of struct snd_soc_dai_driver and is now provided through struct snd_soc_dai_ops. Move spdif_soc_dai_probe() accordingly so the driver follows the current ASoC API and builds correctly on modern kernels. Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20260730095407.33894-5-phucduc.bui@gmail.com Signed-off-by: Mark Brown --- sound/soc/spear/spdif_out.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index c06f09c646a8..01dc2cef7448 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c @@ -249,6 +249,7 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai) } static const struct snd_soc_dai_ops spdif_out_dai_ops = { + .probe = spdif_soc_dai_probe, .mute_stream = spdif_mute, .startup = spdif_out_startup, .shutdown = spdif_out_shutdown, @@ -266,7 +267,6 @@ static struct snd_soc_dai_driver spdif_out_dai = { SNDRV_PCM_RATE_192000), .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .probe = spdif_soc_dai_probe, .ops = &spdif_out_dai_ops, };