All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
To: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>,
	Mark Brown <broonie@kernel.org>
Cc: Srinivas Kandagatla <srini@kernel.org>,
	Liam Girdwood <lgirdwood@gmail.com>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
	Julian Braha <julianbraha@gmail.com>,
	Vinod Koul <vkoul@kernel.org>,
	Bard Liao <yung-chuan.liao@linux.intel.com>,
	Luca Weiss <luca.weiss@fairphone.com>,
	Mohammad Rafi Shaik <mohammad.rafi.shaik@oss.qualcomm.com>,
	Ravi Hothi <ravi.hothi@oss.qualcomm.com>,
	linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/2] ASoC: codecs: wcd9378: add TX/capture codec driver
Date: Wed, 29 Jul 2026 13:33:22 +0200	[thread overview]
Message-ID: <40c7a0c9-de85-4b11-86fc-53b48e42462c@linux.dev> (raw)
In-Reply-To: <20260729000649.263426-3-jorijnvdgraaf@catcrafts.net>

Looks mostly good, I only have comments on confusing explanations
related to the two-peripheral split and pm_runtime support, see below.

On 7/29/26 02:06, Jorijn van der Graaf wrote:
> The Qualcomm WCD9378 is the audio codec found on SM7635 boards such as
> the Fairphone 6. It pairs a WCD937x-compatible analog core with SDCA
> function blocks (SmartMIC0/1/2, SmartJACK, SmartAMP) whose built-in
> sequencers perform the analog power-up/down autonomously: capture is
> started by programming the ADC usage mode, requesting power state 0 on
> the function's power domain entity and letting the sequencer ramp the
> ADC and the mic bias selected through SMx_MB_SEL.
> 
> Like the other codecs of the family the WCD9378 presents two SoundWire
> slaves (manufacturer 0x0217, part 0x0110); a platform device created

same part with two different unique_id or two different parts?

> from the codec DT node acts as component master over the two slave
> devices, reusing the wcd-common helpers. Unlike the older family
> members, all control registers - the SDCA function blocks and the
> analog core alike - live in a 32-bit paged SDCA control address space
> accessed through the TX slave, so the slave regmap needs
> prop.paging_support (on Qualcomm controllers this in turn needs SCP
> address paging support in the controller driver). The sequencers clock
> off the SoundWire bus clock and stall without the SCP bus-clock
> base/scale indication; the slaves declare prop.clock_reg_supported so
> the core programs those registers at enumeration (on Qualcomm
> controllers this in turn needs the controller driver to declare the
> bus clock in prop.mclk_freq).
> 
> Compute platforms wire the same chip as a single aggregated SDCA-mode
> slave instead; probe declines nodes marked qcom,compute-mode, so an
> SDCA class driver for that presentation can share the SoundWire ID
> table with this driver.
> 
> Two hardware behaviours deserve a note:
> 
>  - The SDCA function engine does not survive SoundWire bus clock-stop.
>    Every register keeps its value (so a regcache sync restores
>    nothing), but the sequencers ignore all subsequent power requests,
>    including forced trigger and soft-reset writes; only a codec reset
>    revives the engine. The downstream stack sidesteps this by marking
>    the TX SoundWire master "qcom,is-always-on" in its devicetree; do
>    the equivalent and hold a runtime PM reference on the TX slave for
>    as long as the codec is bound. 

The write-up seems to suggest that the manager and peripheral devices
remain pm_active and the bus clock is never stopped then? IWO there is
no pm_runtime suspend support for this SoundWire link.

> +static const struct sdw_device_id wcd9378_sdw_id[] = {
> +	SDW_SLAVE_ENTRY(0x0217, 0x0110, 0),
> +	{ },

presumably it's the same part_id for RX and TX, so there must be a
unique_id to make the difference between RX and TX.

> +static int wcd9378_sdw_runtime_suspend(struct device *dev)
> +{
> +	struct wcd9378_sdw_priv *wcd = dev_get_drvdata(dev);
> +
> +	if (wcd->regmap) {
> +		regcache_cache_only(wcd->regmap, true);
> +		regcache_mark_dirty(wcd->regmap);
> +	}
> +
> +	return 0;
> +}
> +
> +static int wcd9378_sdw_runtime_resume(struct device *dev)
> +{
> +	struct wcd9378_sdw_priv *wcd = dev_get_drvdata(dev);
> +
> +	if (wcd->regmap) {
> +		regcache_cache_only(wcd->regmap, false);
> +		regcache_sync(wcd->regmap);
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops wcd9378_sdw_pm_ops = {
> +	RUNTIME_PM_OPS(wcd9378_sdw_runtime_suspend, wcd9378_sdw_runtime_resume, NULL)
> +};

not able to reconcile the definition of those pm_runtime routines with
the earlier assertion that a pm_runtime reference it takes to prevent
the bus clock from suspending.


> +static int wcd9378_bind(struct device *dev)
> +{
> +	struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev);
> +	int ret;
> +
> +	/* Give the SDW subdevices some more time to settle */
> +	usleep_range(5000, 5010);

you may want to describe what those values refer to, experiments or
actual time expected from the documentation.

> +	ret = component_bind_all(dev, wcd9378);
> +	if (ret) {
> +		dev_err(dev, "Slave bind failed, ret = %d\n", ret);
> +		return ret;
> +	}
> +
> +	wcd9378->rxdev = of_sdw_find_device_by_node(wcd9378->rxnode);
> +	if (!wcd9378->rxdev) {
> +		dev_err(dev, "could not find rx slave with matching of node\n");
> +		ret = -EINVAL;
> +		goto err_component_unbind;
> +	}
> +
> +	wcd9378->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd9378->rxdev);
> +	wcd9378->sdw_priv[AIF1_PB]->wcd9378 = wcd9378;
> +
> +	wcd9378->txdev = of_sdw_find_device_by_node(wcd9378->txnode);
> +	if (!wcd9378->txdev) {
> +		dev_err(dev, "could not find tx slave with matching of node\n");
> +		ret = -EINVAL;
> +		goto err_put_rxdev;
> +	}
> +
> +	wcd9378->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd9378->txdev);
> +	wcd9378->sdw_priv[AIF1_CAP]->wcd9378 = wcd9378;
> +	wcd9378->tx_sdw_dev = dev_to_sdw_dev(wcd9378->txdev);
> +
> +	/*
> +	 * As TX is the main CSR reg interface, it should not be suspended
> +	 * first. Explicitly add the dependency link.
> +	 */
> +	if (!device_link_add(wcd9378->rxdev, wcd9378->txdev,
> +			     DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
> +		dev_err(dev, "Could not devlink TX and RX\n");
> +		ret = -EINVAL;
> +		goto err_put_txdev;
> +	}
> +
> +	if (!device_link_add(dev, wcd9378->txdev,
> +			     DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
> +		dev_err(dev, "Could not devlink WCD and TX\n");
> +		ret = -EINVAL;
> +		goto err_remove_link1;
> +	}
> +
> +	if (!device_link_add(dev, wcd9378->rxdev,
> +			     DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) {
> +		dev_err(dev, "Could not devlink WCD and RX\n");
> +		ret = -EINVAL;
> +		goto err_remove_link2;
> +	}
> +
> +	wcd9378->regmap = wcd9378->sdw_priv[AIF1_CAP]->regmap;
> +	if (!wcd9378->regmap) {
> +		dev_err(dev, "could not get TX device regmap\n");
> +		ret = -EINVAL;
> +		goto err_remove_link3;
> +	}
> +
> +	/*
> +	 * The SDCA function engine dies when the TX bus enters clock-stop
> +	 * and only a codec reset revives it - registers keep their values
> +	 * so a regcache sync or a FUNC_ACT re-toggle does not help. The
> +	 * downstream stack sidesteps the same problem by marking the TX
> +	 * SoundWire master "qcom,is-always-on"; do the equivalent and
> +	 * keep the TX slave (and thus its bus) runtime-active while the
> +	 * codec is bound.

So in practice only the RX peripheral can do a pm_runtime suspend?

> +	 */
> +	ret = pm_runtime_resume_and_get(wcd9378->txdev);
> +	if (ret < 0) {
> +		dev_err(dev, "could not resume TX device\n");
> +		goto err_remove_link3;
> +	}
> +
> +	ret = snd_soc_register_component(dev, &soc_codec_dev_wcd9378,
> +					 wcd9378_dais, ARRAY_SIZE(wcd9378_dais));
> +	if (ret) {
> +		dev_err(dev, "Codec registration failed\n");
> +		pm_runtime_put(wcd9378->txdev);
> +		goto err_remove_link3;
> +	}
> +
> +	return ret;
> +
> +err_remove_link3:
> +	device_link_remove(dev, wcd9378->rxdev);
> +err_remove_link2:
> +	device_link_remove(dev, wcd9378->txdev);
> +err_remove_link1:
> +	device_link_remove(wcd9378->rxdev, wcd9378->txdev);
> +err_put_txdev:
> +	put_device(wcd9378->txdev);
> +err_put_rxdev:
> +	put_device(wcd9378->rxdev);
> +err_component_unbind:
> +	component_unbind_all(dev, wcd9378);
> +	return ret;
> +}
> +
> +static void wcd9378_unbind(struct device *dev)
> +{
> +	struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev);
> +
> +	snd_soc_unregister_component(dev);
> +	pm_runtime_put(wcd9378->txdev);

pm_runtime_put_sync() to make sure the idle routine is called
immediately and not later?

> +	device_link_remove(dev, wcd9378->txdev);
> +	device_link_remove(dev, wcd9378->rxdev);
> +	device_link_remove(wcd9378->rxdev, wcd9378->txdev);
> +	component_unbind_all(dev, wcd9378);
> +	put_device(wcd9378->txdev);
> +	put_device(wcd9378->rxdev);
> +}

      parent reply	other threads:[~2026-07-29 11:34 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-29  0:06 [PATCH v2 0/2] ASoC: codecs: add the Qualcomm WCD9378 audio codec Jorijn van der Graaf
2026-07-29  0:06 ` [PATCH v2 1/2] ASoC: dt-bindings: " Jorijn van der Graaf
2026-07-29  0:06 ` [PATCH v2 2/2] ASoC: codecs: wcd9378: add TX/capture codec driver Jorijn van der Graaf
2026-07-29  0:20   ` sashiko-bot
2026-07-29 11:33   ` Pierre-Louis Bossart [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=40c7a0c9-de85-4b11-86fc-53b48e42462c@linux.dev \
    --to=pierre-louis.bossart@linux.dev \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jorijnvdgraaf@catcrafts.net \
    --cc=julianbraha@gmail.com \
    --cc=krzk+dt@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=luca.weiss@fairphone.com \
    --cc=mohammad.rafi.shaik@oss.qualcomm.com \
    --cc=perex@perex.cz \
    --cc=ravi.hothi@oss.qualcomm.com \
    --cc=robh@kernel.org \
    --cc=srini@kernel.org \
    --cc=tiwai@suse.com \
    --cc=vkoul@kernel.org \
    --cc=yung-chuan.liao@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.