mbox series

[00/10] ASoC: codec: add pm runtime support for Qualcomm codecs

Message ID 20220221131037.8809-1-srinivas.kandagatla@linaro.org
Headers show
Series ASoC: codec: add pm runtime support for Qualcomm codecs | expand

Message

Srinivas Kandagatla Feb. 21, 2022, 1:10 p.m. UTC
This patchset adds support for runtime pm on tx/rx/wsa/wcd lpass macro, wsa881x
and wcd938x codecs that are wired up on SoundWire bus.
During pm testing it was also found that soundwire clks enabled by lpass macros
are not enabling all the required clocks correctly, so last 3 patches corrects them.

Tested this on SM8250 MTP along SoundWire In band Headset Button wakeup interrupts.

Srinivas Kandagatla (10):
  ASoC: codecs: va-macro: add runtime pm support
  ASoC: codecs: wsa-macro: add runtime pm support
  ASoC: codecs: rx-macro: add runtime pm support
  ASoC: codecs: tx-macro: add runtime pm support
  ASoC: codecs: wsa881x: add runtime pm support
  ASoC: codecs: wcd938x: add simple clk stop support
  ASoC: codecs: wcd-mbhc: add runtime pm support
  ASoC: codecs: wsa-macro: setup soundwire clks correctly
  ASoC: codecs: tx-macro: setup soundwire clks correctly
  ASoC: codecs: rx-macro: setup soundwire clks correctly

 sound/soc/codecs/lpass-rx-macro.c  | 49 +++++++++++++++++++++++++--
 sound/soc/codecs/lpass-tx-macro.c  | 45 ++++++++++++++++++++++++-
 sound/soc/codecs/lpass-va-macro.c  | 36 ++++++++++++++++++++
 sound/soc/codecs/lpass-wsa-macro.c | 43 +++++++++++++++++++++++-
 sound/soc/codecs/wcd-mbhc-v2.c     | 26 ++++++++++++++
 sound/soc/codecs/wcd938x-sdw.c     |  1 +
 sound/soc/codecs/wsa881x.c         | 54 ++++++++++++++++++++++++++++++
 7 files changed, 250 insertions(+), 4 deletions(-)

Comments

Mark Brown Feb. 21, 2022, 3:24 p.m. UTC | #1
On Mon, Feb 21, 2022 at 01:10:28PM +0000, Srinivas Kandagatla wrote:

> +static int __maybe_unused va_macro_runtime_resume(struct device *dev)
> +{
> +	struct va_macro *va = dev_get_drvdata(dev);
> +
> +	clk_prepare_enable(va->clks[2].clk);

This magic number stuff is going to be excessively fragile, and the fact
that this is sometimes managed via the bulk APIs and sometimes not isn't
going to help either.  Either all the clocks should be managed here or
this should be pulled out of the array.

Also consider error checking.
Srinivas Kandagatla Feb. 21, 2022, 3:27 p.m. UTC | #2
Thanks Mark,

On 21/02/2022 15:24, Mark Brown wrote:
> On Mon, Feb 21, 2022 at 01:10:28PM +0000, Srinivas Kandagatla wrote:
> 
>> +static int __maybe_unused va_macro_runtime_resume(struct device *dev)
>> +{
>> +	struct va_macro *va = dev_get_drvdata(dev);
>> +
>> +	clk_prepare_enable(va->clks[2].clk);
> 
> This magic number stuff is going to be excessively fragile, and the fact

I agree, will try to clean this up properly in next spin.

> that this is sometimes managed via the bulk APIs and sometimes not isn't
> going to help either.  Either all the clocks should be managed here or
> this should be pulled out of the array.
> 
> Also consider error checking.
will do,

--srin
Pierre-Louis Bossart Feb. 22, 2022, 7:53 p.m. UTC | #3
On 2/21/22 07:10, Srinivas Kandagatla wrote:
> WSA881x codecs can not cope up with clk stop and requires a full reset after suspend.

isn't clock stop mode0 a peripheral requirement in SoundWire 1.x? I
don't see any permission to skip this mode, the only thing I see in the
spec is the permission to implement an always-ready capability (SCSP_SM)

The current assumption is that ALL peripherals support that mode, but
that Managers may or may not support clock stop.

It wouldn't be a big deal to add a quirk, but IMHO this needs to be
captured at the bus/manager level since the decision to enter this mode
is made at that level.

> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>  sound/soc/codecs/wsa881x.c | 54 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 54 insertions(+)
> 
> diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
> index 0222370ff95d..d851ba14fbdd 100644
> --- a/sound/soc/codecs/wsa881x.c
> +++ b/sound/soc/codecs/wsa881x.c
> @@ -11,6 +11,7 @@
>  #include <linux/of_gpio.h>
>  #include <linux/regmap.h>
>  #include <linux/slab.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/soundwire/sdw.h>
>  #include <linux/soundwire/sdw_registers.h>
>  #include <linux/soundwire/sdw_type.h>
> @@ -198,6 +199,7 @@
>  #define WSA881X_OCP_CTL_TIMER_SEC 2
>  #define WSA881X_OCP_CTL_TEMP_CELSIUS 25
>  #define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
> +#define WSA881X_PROBE_TIMEOUT 1000
>  
>  #define WSA881X_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
>  {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
> @@ -747,6 +749,12 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
>  	unsigned int mask = (1 << fls(max)) - 1;
>  	int val, ret, min_gain, max_gain;
>  
> +	ret = pm_runtime_get_sync(comp->dev);
> +	if (ret < 0 && ret != -EACCES) {
> +		pm_runtime_put_noidle(comp->dev);
> +		return ret;
> +	}
> +
>  	max_gain = (max - ucontrol->value.integer.value[0]) & mask;
>  	/*
>  	 * Gain has to set incrementally in 4 steps
> @@ -773,6 +781,9 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
>  		usleep_range(1000, 1010);
>  	}
>  
> +	pm_runtime_mark_last_busy(comp->dev);
> +	pm_runtime_put_autosuspend(comp->dev);
> +
>  	return 1;
>  }
>  
> @@ -1101,6 +1112,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
>  			 const struct sdw_device_id *id)
>  {
>  	struct wsa881x_priv *wsa881x;
> +	struct device *dev = &pdev->dev;
>  
>  	wsa881x = devm_kzalloc(&pdev->dev, sizeof(*wsa881x), GFP_KERNEL);
>  	if (!wsa881x)
> @@ -1124,6 +1136,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
>  	pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0);
>  	pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
>  	pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
> +	pdev->prop.simple_clk_stop_capable = true;
>  	gpiod_direction_output(wsa881x->sd_n, 1);
>  
>  	wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
> @@ -1132,12 +1145,52 @@ static int wsa881x_probe(struct sdw_slave *pdev,
>  		return PTR_ERR(wsa881x->regmap);
>  	}
>  
> +	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);
> +
>  	return devm_snd_soc_register_component(&pdev->dev,
>  					       &wsa881x_component_drv,
>  					       wsa881x_dais,
>  					       ARRAY_SIZE(wsa881x_dais));
>  }
>  
> +static int __maybe_unused wsa881x_runtime_suspend(struct device *dev)
> +{
> +	struct regmap *regmap = dev_get_regmap(dev, NULL);
> +	struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
> +
> +	gpiod_direction_output(wsa881x->sd_n, 0);
> +
> +	regcache_cache_only(regmap, true);
> +	regcache_mark_dirty(regmap);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused wsa881x_runtime_resume(struct device *dev)
> +{
> +	struct sdw_slave *slave = dev_to_sdw_dev(dev);
> +	struct regmap *regmap = dev_get_regmap(dev, NULL);
> +	struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
> +
> +	gpiod_direction_output(wsa881x->sd_n, 1);
> +
> +	wait_for_completion_timeout(&slave->initialization_complete,
> +				    msecs_to_jiffies(WSA881X_PROBE_TIMEOUT));
> +
> +	regcache_cache_only(regmap, false);
> +	regcache_sync(regmap);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops wsa881x_pm_ops = {
> +	SET_RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL)
> +};
> +
>  static const struct sdw_device_id wsa881x_slave_id[] = {
>  	SDW_SLAVE_ENTRY(0x0217, 0x2010, 0),
>  	SDW_SLAVE_ENTRY(0x0217, 0x2110, 0),
> @@ -1151,6 +1204,7 @@ static struct sdw_driver wsa881x_codec_driver = {
>  	.id_table = wsa881x_slave_id,
>  	.driver = {
>  		.name	= "wsa881x-codec",
> +		.pm = &wsa881x_pm_ops,
>  	}
>  };
>  module_sdw_driver(wsa881x_codec_driver);