Skip to content

Commit 3d21ef0

Browse files
committed
ALSA: pcm: Suspend streams globally via device type PM ops
Until now we rely on each driver calling snd_pcm_suspend*() explicitly at its own PM handling. However, this can be done far more easily by setting the PM ops to each actual snd_pcm device object. This patch adds the device_type object for PCM stream and assigns to each PCM stream object. The type contains only the PM ops for system suspend; we don't need to deal with the resume in general. The suspend hook simply calls snd_pcm_suspend_all() for the given PCM streams. This implies that the PM order is correctly put, i.e. PCM is suspended before the main (or codec) driver, which should be true in general. If a special ordering is needed, you'd need to adjust the device PM order manually later. This patch introduces a new flag, snd_pcm.no_device_suspend, too. With this flag set, the PCM device object won't invoke snd_pcm_suspend_all() by itself. This is needed for ASoC who wants to manage the PM call orders in its serialized way, and the flag is set in soc_new_pcm() as default. For the non-ASoC world, we can get rid of the manual snd_pcm_suspend calls. This will be done in the later patches. Reviewed-by: Jaroslav Kysela <perex@perex.cz> Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent bfeffd1 commit 3d21ef0

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

include/sound/pcm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ struct snd_pcm {
538538
void (*private_free) (struct snd_pcm *pcm);
539539
bool internal; /* pcm is for internal use only */
540540
bool nonatomic; /* whole PCM operations are in non-atomic context */
541+
bool no_device_suspend; /* don't invoke device PM suspend */
541542
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
542543
struct snd_pcm_oss oss;
543544
#endif

sound/core/pcm.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,31 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea
683683

684684
static const struct attribute_group *pcm_dev_attr_groups[];
685685

686+
/*
687+
* PM callbacks: we need to deal only with suspend here, as the resume is
688+
* triggered either from user-space or the driver's resume callback
689+
*/
690+
#ifdef CONFIG_PM_SLEEP
691+
static int do_pcm_suspend(struct device *dev)
692+
{
693+
struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev);
694+
695+
if (!pstr->pcm->no_device_suspend)
696+
snd_pcm_suspend_all(pstr->pcm);
697+
return 0;
698+
}
699+
#endif
700+
701+
static const struct dev_pm_ops pcm_dev_pm_ops = {
702+
SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL)
703+
};
704+
705+
/* device type for PCM -- basically only for passing PM callbacks */
706+
static const struct device_type pcm_dev_type = {
707+
.name = "pcm",
708+
.pm = &pcm_dev_pm_ops,
709+
};
710+
686711
/**
687712
* snd_pcm_new_stream - create a new PCM stream
688713
* @pcm: the pcm instance
@@ -713,6 +738,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
713738

714739
snd_device_initialize(&pstr->dev, pcm->card);
715740
pstr->dev.groups = pcm_dev_attr_groups;
741+
pstr->dev.type = &pcm_dev_type;
716742
dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
717743
stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
718744

sound/soc/soc-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3155,6 +3155,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
31553155
}
31563156

31573157
pcm->private_free = soc_pcm_private_free;
3158+
pcm->no_device_suspend = true;
31583159
out:
31593160
dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
31603161
(rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,

0 commit comments

Comments
 (0)