ALSA: hda - Move codec suspend/resume to codec driver
authorTakashi Iwai <tiwai@suse.de>
Wed, 18 Feb 2015 14:39:59 +0000 (15:39 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 23 Feb 2015 08:16:07 +0000 (09:16 +0100)
This patch moves the suspend/resume mechanisms down to each codec
driver level, as we have a proper codec driver bound on the bus now.
Then we get the asynchronous PM gratis without fiddling much in the
driver level.

As a soft-landing transition, implement the common suspend/resume pm
ops for hda_codec_driver and keep the each codec driver intact.  Only
the callers of suspend/resume in the controller side (azx_suspend()
and azx_resume()) are removed.

Another involved place is azx_bus_reset() calling the temporary
suspend and resume as a hackish method of bus reset.  The HD-audio
core provide a helper function snd_hda_bus_reset() instead.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_tegra.c

index adf6b475dee1359b8eb56e2472b2168142fd9402..ce2dd7b0dc078fe02712b482e88bd6af635335b2 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/export.h>
+#include <linux/pm.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -138,7 +139,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
        drv->driver.bus = &snd_hda_bus_type;
        drv->driver.probe = hda_codec_driver_probe;
        drv->driver.remove = hda_codec_driver_remove;
-       /* TODO: PM and others */
+       drv->driver.pm = &hda_codec_driver_pm;
        return driver_register(&drv->driver);
 }
 EXPORT_SYMBOL_GPL(__hda_codec_driver_register);
index 61c8174e8013c4d95433d0f78da7997eb49e41f2..3d6ff60e6c144b7dd258d1283853b5e15afc9831 100644 (file)
@@ -1250,6 +1250,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
        dev->groups = snd_hda_dev_attr_groups;
        dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr);
        dev_set_drvdata(dev, codec); /* for sysfs */
+       device_enable_async_suspend(dev);
 
        codec->bus = bus;
        codec->addr = codec_addr;
@@ -3970,8 +3971,31 @@ static void hda_call_codec_resume(struct hda_codec *codec)
        codec->in_pm = 0;
        snd_hda_power_down(codec); /* flag down before returning */
 }
+
+static int hda_codec_driver_suspend(struct device *dev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+       int i;
+
+       cancel_delayed_work_sync(&codec->jackpoll_work);
+       for (i = 0; i < codec->num_pcms; i++)
+               snd_pcm_suspend_all(codec->pcm_info[i].pcm);
+       hda_call_codec_suspend(codec, false);
+       return 0;
+}
+
+static int hda_codec_driver_resume(struct device *dev)
+{
+       hda_call_codec_resume(dev_to_hda_codec(dev));
+       return 0;
+}
 #endif /* CONFIG_PM */
 
+/* referred in hda_bind.c */
+const struct dev_pm_ops hda_codec_driver_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(hda_codec_driver_suspend,
+                               hda_codec_driver_resume)
+};
 
 /**
  * snd_hda_build_controls - build mixer controls
@@ -5505,77 +5529,26 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
 
-
-#ifdef CONFIG_PM
-/*
- * power management
- */
-
-
-static void hda_async_suspend(void *data, async_cookie_t cookie)
-{
-       hda_call_codec_suspend(data, false);
-}
-
-static void hda_async_resume(void *data, async_cookie_t cookie)
-{
-       hda_call_codec_resume(data);
-}
-
 /**
- * snd_hda_suspend - suspend the codecs
- * @bus: the HDA bus
- *
- * Returns 0 if successful.
+ * snd_hda_bus_reset - Reset the bus
+ * @bus: HD-audio bus
  */
-int snd_hda_suspend(struct hda_bus *bus)
+void snd_hda_bus_reset(struct hda_bus *bus)
 {
        struct hda_codec *codec;
-       ASYNC_DOMAIN_EXCLUSIVE(domain);
 
        list_for_each_entry(codec, &bus->codec_list, list) {
+               /* FIXME: maybe a better way needed for forced reset */
                cancel_delayed_work_sync(&codec->jackpoll_work);
+#ifdef CONFIG_PM
                if (hda_codec_is_power_on(codec)) {
-                       if (bus->num_codecs > 1)
-                               async_schedule_domain(hda_async_suspend, codec,
-                                                     &domain);
-                       else
-                               hda_call_codec_suspend(codec, false);
-               }
-       }
-
-       if (bus->num_codecs > 1)
-               async_synchronize_full_domain(&domain);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_suspend);
-
-/**
- * snd_hda_resume - resume the codecs
- * @bus: the HDA bus
- *
- * Returns 0 if successful.
- */
-int snd_hda_resume(struct hda_bus *bus)
-{
-       struct hda_codec *codec;
-       ASYNC_DOMAIN_EXCLUSIVE(domain);
-
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               if (bus->num_codecs > 1)
-                       async_schedule_domain(hda_async_resume, codec, &domain);
-               else
+                       hda_call_codec_suspend(codec, false);
                        hda_call_codec_resume(codec);
+               }
+#endif
        }
-
-       if (bus->num_codecs > 1)
-               async_synchronize_full_domain(&domain);
-
-       return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hda_resume);
-#endif /* CONFIG_PM */
+EXPORT_SYMBOL_GPL(snd_hda_bus_reset);
 
 /*
  * generic arrays
index 3d42717e0e653a11bb9c607a1bb8f0a120cbb078..1fa3dd9baf5225b5dba1573e3bafdda671ebb35e 100644 (file)
@@ -567,14 +567,12 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
 
 int snd_hda_lock_devices(struct hda_bus *bus);
 void snd_hda_unlock_devices(struct hda_bus *bus);
+void snd_hda_bus_reset(struct hda_bus *bus);
 
 /*
  * power management
  */
-#ifdef CONFIG_PM
-int snd_hda_suspend(struct hda_bus *bus);
-int snd_hda_resume(struct hda_bus *bus);
-#endif
+extern const struct dev_pm_ops hda_codec_driver_pm;
 
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
index 4c7a6f9bfcde04d835abc47ed7ca9c5d819f31e1..30ddb751806accd3f9fbcc88c6ca79458a319c0c 100644 (file)
@@ -1780,15 +1780,8 @@ static void azx_bus_reset(struct hda_bus *bus)
        bus->in_reset = 1;
        azx_stop_chip(chip);
        azx_init_chip(chip, true);
-#ifdef CONFIG_PM
-       if (chip->initialized) {
-               struct azx_pcm *p;
-               list_for_each_entry(p, &chip->pcm_list, list)
-                       snd_pcm_suspend_all(p->pcm);
-               snd_hda_suspend(chip->bus);
-               snd_hda_resume(chip->bus);
-       }
-#endif
+       if (chip->initialized)
+               snd_hda_bus_reset(chip->bus);
        bus->in_reset = 0;
 }
 
index 5e00cc4a722f4c447f7c0dac96c694d44d9223e7..9db1b078801f29391cec03d6f2f3d40fd16391d8 100644 (file)
@@ -772,7 +772,6 @@ static int azx_suspend(struct device *dev)
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
        struct hda_intel *hda;
-       struct azx_pcm *p;
 
        if (!card)
                return 0;
@@ -784,10 +783,6 @@ static int azx_suspend(struct device *dev)
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        azx_clear_irq_pending(chip);
-       list_for_each_entry(p, &chip->pcm_list, list)
-               snd_pcm_suspend_all(p->pcm);
-       if (chip->initialized)
-               snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
        azx_enter_link_reset(chip);
        if (chip->irq >= 0) {
@@ -830,7 +825,6 @@ static int azx_resume(struct device *dev)
 
        azx_init_chip(chip, true);
 
-       snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
index 1bd7a9e040465b26558c1875ab7d6f862f512d53..f6949e413a501abf45b9584693c651e99158a4c4 100644 (file)
@@ -249,14 +249,9 @@ static int hda_tegra_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip = card->private_data;
-       struct azx_pcm *p;
        struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       list_for_each_entry(p, &chip->pcm_list, list)
-               snd_pcm_suspend_all(p->pcm);
-       if (chip->initialized)
-               snd_hda_suspend(chip->bus);
 
        azx_stop_chip(chip);
        azx_enter_link_reset(chip);
@@ -277,7 +272,6 @@ static int hda_tegra_resume(struct device *dev)
 
        azx_init_chip(chip, 1);
 
-       snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
        return 0;