diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d6bd3caf6878..04e97564949c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -538,6 +538,7 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); bool internal; /* pcm is for internal use only */ bool nonatomic; /* whole PCM operations are in non-atomic context */ + bool no_device_suspend; /* don't invoke device PM suspend */ #if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss oss; #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 01b9d62eef14..ca1ea3cf9350 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -683,6 +683,31 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea static const struct attribute_group *pcm_dev_attr_groups[]; +/* + * PM callbacks: we need to deal only with suspend here, as the resume is + * triggered either from user-space or the driver's resume callback + */ +#ifdef CONFIG_PM_SLEEP +static int do_pcm_suspend(struct device *dev) +{ + struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); + + if (!pstr->pcm->no_device_suspend) + snd_pcm_suspend_all(pstr->pcm); + return 0; +} +#endif + +static const struct dev_pm_ops pcm_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL) +}; + +/* device type for PCM -- basically only for passing PM callbacks */ +static const struct device_type pcm_dev_type = { + .name = "pcm", + .pm = &pcm_dev_pm_ops, +}; + /** * snd_pcm_new_stream - create a new PCM stream * @pcm: the pcm instance @@ -713,6 +738,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) snd_device_initialize(&pstr->dev, pcm->card); pstr->dev.groups = pcm_dev_attr_groups; + pstr->dev.type = &pcm_dev_type; dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 03f36e534050..485eec5be608 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3155,6 +3155,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } pcm->private_free = soc_pcm_private_free; + pcm->no_device_suspend = true; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,