ALSA: pcm: Suspend streams globally via device type PM ops
authorTakashi Iwai <tiwai@suse.de>
Fri, 11 Jan 2019 14:58:39 +0000 (15:58 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 15 Jan 2019 16:46:36 +0000 (17:46 +0100)
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>
include/sound/pcm.h
sound/core/pcm.c
sound/soc/soc-pcm.c

index d6bd3caf68787490074cd859f980dcac057abf28..04e97564949c196820030aca9bebead22e89069a 100644 (file)
@@ -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
index 01b9d62eef14db9f22bd1fb67bcaf5456f791d38..ca1ea3cf93508ef8e10537803ad42acfd723ab74 100644 (file)
@@ -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');
 
index 03f36e534050f49cf9c4a859a9bc6e93f1798503..485eec5be608bef53473756d5ec7cbd66d9d305a 100644 (file)
@@ -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,