aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-02-18 09:39:59 -0500
committerTakashi Iwai <tiwai@suse.de>2015-02-23 03:16:07 -0500
commit59ed1eade1d6ec24751baca99305f9713a5d779e (patch)
tree47846571754cc487fcc5eb17e03cf91b7b258301 /sound/pci/hda
parentd8a766a16ed90c4b3bd7afa6e1417f8d715db507 (diff)
ALSA: hda - Move codec suspend/resume to codec driver
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>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_bind.c3
-rw-r--r--sound/pci/hda/hda_codec.c93
-rw-r--r--sound/pci/hda/hda_codec.h6
-rw-r--r--sound/pci/hda/hda_controller.c11
-rw-r--r--sound/pci/hda/hda_intel.c6
-rw-r--r--sound/pci/hda/hda_tegra.c6
6 files changed, 39 insertions, 86 deletions
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index adf6b475dee1..ce2dd7b0dc07 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -8,6 +8,7 @@
8#include <linux/mutex.h> 8#include <linux/mutex.h>
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/export.h> 10#include <linux/export.h>
11#include <linux/pm.h>
11#include <sound/core.h> 12#include <sound/core.h>
12#include "hda_codec.h" 13#include "hda_codec.h"
13#include "hda_local.h" 14#include "hda_local.h"
@@ -138,7 +139,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
138 drv->driver.bus = &snd_hda_bus_type; 139 drv->driver.bus = &snd_hda_bus_type;
139 drv->driver.probe = hda_codec_driver_probe; 140 drv->driver.probe = hda_codec_driver_probe;
140 drv->driver.remove = hda_codec_driver_remove; 141 drv->driver.remove = hda_codec_driver_remove;
141 /* TODO: PM and others */ 142 drv->driver.pm = &hda_codec_driver_pm;
142 return driver_register(&drv->driver); 143 return driver_register(&drv->driver);
143} 144}
144EXPORT_SYMBOL_GPL(__hda_codec_driver_register); 145EXPORT_SYMBOL_GPL(__hda_codec_driver_register);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 61c8174e8013..3d6ff60e6c14 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1250,6 +1250,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
1250 dev->groups = snd_hda_dev_attr_groups; 1250 dev->groups = snd_hda_dev_attr_groups;
1251 dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr); 1251 dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr);
1252 dev_set_drvdata(dev, codec); /* for sysfs */ 1252 dev_set_drvdata(dev, codec); /* for sysfs */
1253 device_enable_async_suspend(dev);
1253 1254
1254 codec->bus = bus; 1255 codec->bus = bus;
1255 codec->addr = codec_addr; 1256 codec->addr = codec_addr;
@@ -3970,8 +3971,31 @@ static void hda_call_codec_resume(struct hda_codec *codec)
3970 codec->in_pm = 0; 3971 codec->in_pm = 0;
3971 snd_hda_power_down(codec); /* flag down before returning */ 3972 snd_hda_power_down(codec); /* flag down before returning */
3972} 3973}
3974
3975static int hda_codec_driver_suspend(struct device *dev)
3976{
3977 struct hda_codec *codec = dev_to_hda_codec(dev);
3978 int i;
3979
3980 cancel_delayed_work_sync(&codec->jackpoll_work);
3981 for (i = 0; i < codec->num_pcms; i++)
3982 snd_pcm_suspend_all(codec->pcm_info[i].pcm);
3983 hda_call_codec_suspend(codec, false);
3984 return 0;
3985}
3986
3987static int hda_codec_driver_resume(struct device *dev)
3988{
3989 hda_call_codec_resume(dev_to_hda_codec(dev));
3990 return 0;
3991}
3973#endif /* CONFIG_PM */ 3992#endif /* CONFIG_PM */
3974 3993
3994/* referred in hda_bind.c */
3995const struct dev_pm_ops hda_codec_driver_pm = {
3996 SET_SYSTEM_SLEEP_PM_OPS(hda_codec_driver_suspend,
3997 hda_codec_driver_resume)
3998};
3975 3999
3976/** 4000/**
3977 * snd_hda_build_controls - build mixer controls 4001 * snd_hda_build_controls - build mixer controls
@@ -5505,77 +5529,26 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
5505} 5529}
5506EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); 5530EXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
5507 5531
5508
5509#ifdef CONFIG_PM
5510/*
5511 * power management
5512 */
5513
5514
5515static void hda_async_suspend(void *data, async_cookie_t cookie)
5516{
5517 hda_call_codec_suspend(data, false);
5518}
5519
5520static void hda_async_resume(void *data, async_cookie_t cookie)
5521{
5522 hda_call_codec_resume(data);
5523}
5524
5525/** 5532/**
5526 * snd_hda_suspend - suspend the codecs 5533 * snd_hda_bus_reset - Reset the bus
5527 * @bus: the HDA bus 5534 * @bus: HD-audio bus
5528 *
5529 * Returns 0 if successful.
5530 */ 5535 */
5531int snd_hda_suspend(struct hda_bus *bus) 5536void snd_hda_bus_reset(struct hda_bus *bus)
5532{ 5537{
5533 struct hda_codec *codec; 5538 struct hda_codec *codec;
5534 ASYNC_DOMAIN_EXCLUSIVE(domain);
5535 5539
5536 list_for_each_entry(codec, &bus->codec_list, list) { 5540 list_for_each_entry(codec, &bus->codec_list, list) {
5541 /* FIXME: maybe a better way needed for forced reset */
5537 cancel_delayed_work_sync(&codec->jackpoll_work); 5542 cancel_delayed_work_sync(&codec->jackpoll_work);
5543#ifdef CONFIG_PM
5538 if (hda_codec_is_power_on(codec)) { 5544 if (hda_codec_is_power_on(codec)) {
5539 if (bus->num_codecs > 1) 5545 hda_call_codec_suspend(codec, false);
5540 async_schedule_domain(hda_async_suspend, codec,
5541 &domain);
5542 else
5543 hda_call_codec_suspend(codec, false);
5544 }
5545 }
5546
5547 if (bus->num_codecs > 1)
5548 async_synchronize_full_domain(&domain);
5549
5550 return 0;
5551}
5552EXPORT_SYMBOL_GPL(snd_hda_suspend);
5553
5554/**
5555 * snd_hda_resume - resume the codecs
5556 * @bus: the HDA bus
5557 *
5558 * Returns 0 if successful.
5559 */
5560int snd_hda_resume(struct hda_bus *bus)
5561{
5562 struct hda_codec *codec;
5563 ASYNC_DOMAIN_EXCLUSIVE(domain);
5564
5565 list_for_each_entry(codec, &bus->codec_list, list) {
5566 if (bus->num_codecs > 1)
5567 async_schedule_domain(hda_async_resume, codec, &domain);
5568 else
5569 hda_call_codec_resume(codec); 5546 hda_call_codec_resume(codec);
5547 }
5548#endif
5570 } 5549 }
5571
5572 if (bus->num_codecs > 1)
5573 async_synchronize_full_domain(&domain);
5574
5575 return 0;
5576} 5550}
5577EXPORT_SYMBOL_GPL(snd_hda_resume); 5551EXPORT_SYMBOL_GPL(snd_hda_bus_reset);
5578#endif /* CONFIG_PM */
5579 5552
5580/* 5553/*
5581 * generic arrays 5554 * generic arrays
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 3d42717e0e65..1fa3dd9baf52 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -567,14 +567,12 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
567 567
568int snd_hda_lock_devices(struct hda_bus *bus); 568int snd_hda_lock_devices(struct hda_bus *bus);
569void snd_hda_unlock_devices(struct hda_bus *bus); 569void snd_hda_unlock_devices(struct hda_bus *bus);
570void snd_hda_bus_reset(struct hda_bus *bus);
570 571
571/* 572/*
572 * power management 573 * power management
573 */ 574 */
574#ifdef CONFIG_PM 575extern const struct dev_pm_ops hda_codec_driver_pm;
575int snd_hda_suspend(struct hda_bus *bus);
576int snd_hda_resume(struct hda_bus *bus);
577#endif
578 576
579static inline 577static inline
580int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) 578int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 4c7a6f9bfcde..30ddb751806a 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -1780,15 +1780,8 @@ static void azx_bus_reset(struct hda_bus *bus)
1780 bus->in_reset = 1; 1780 bus->in_reset = 1;
1781 azx_stop_chip(chip); 1781 azx_stop_chip(chip);
1782 azx_init_chip(chip, true); 1782 azx_init_chip(chip, true);
1783#ifdef CONFIG_PM 1783 if (chip->initialized)
1784 if (chip->initialized) { 1784 snd_hda_bus_reset(chip->bus);
1785 struct azx_pcm *p;
1786 list_for_each_entry(p, &chip->pcm_list, list)
1787 snd_pcm_suspend_all(p->pcm);
1788 snd_hda_suspend(chip->bus);
1789 snd_hda_resume(chip->bus);
1790 }
1791#endif
1792 bus->in_reset = 0; 1785 bus->in_reset = 0;
1793} 1786}
1794 1787
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 5e00cc4a722f..9db1b078801f 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -772,7 +772,6 @@ static int azx_suspend(struct device *dev)
772 struct snd_card *card = dev_get_drvdata(dev); 772 struct snd_card *card = dev_get_drvdata(dev);
773 struct azx *chip; 773 struct azx *chip;
774 struct hda_intel *hda; 774 struct hda_intel *hda;
775 struct azx_pcm *p;
776 775
777 if (!card) 776 if (!card)
778 return 0; 777 return 0;
@@ -784,10 +783,6 @@ static int azx_suspend(struct device *dev)
784 783
785 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 784 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
786 azx_clear_irq_pending(chip); 785 azx_clear_irq_pending(chip);
787 list_for_each_entry(p, &chip->pcm_list, list)
788 snd_pcm_suspend_all(p->pcm);
789 if (chip->initialized)
790 snd_hda_suspend(chip->bus);
791 azx_stop_chip(chip); 786 azx_stop_chip(chip);
792 azx_enter_link_reset(chip); 787 azx_enter_link_reset(chip);
793 if (chip->irq >= 0) { 788 if (chip->irq >= 0) {
@@ -830,7 +825,6 @@ static int azx_resume(struct device *dev)
830 825
831 azx_init_chip(chip, true); 826 azx_init_chip(chip, true);
832 827
833 snd_hda_resume(chip->bus);
834 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 828 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
835 return 0; 829 return 0;
836} 830}
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 1bd7a9e04046..f6949e413a50 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -249,14 +249,9 @@ static int hda_tegra_suspend(struct device *dev)
249{ 249{
250 struct snd_card *card = dev_get_drvdata(dev); 250 struct snd_card *card = dev_get_drvdata(dev);
251 struct azx *chip = card->private_data; 251 struct azx *chip = card->private_data;
252 struct azx_pcm *p;
253 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); 252 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
254 253
255 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 254 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
256 list_for_each_entry(p, &chip->pcm_list, list)
257 snd_pcm_suspend_all(p->pcm);
258 if (chip->initialized)
259 snd_hda_suspend(chip->bus);
260 255
261 azx_stop_chip(chip); 256 azx_stop_chip(chip);
262 azx_enter_link_reset(chip); 257 azx_enter_link_reset(chip);
@@ -277,7 +272,6 @@ static int hda_tegra_resume(struct device *dev)
277 272
278 azx_init_chip(chip, 1); 273 azx_init_chip(chip, 1);
279 274
280 snd_hda_resume(chip->bus);
281 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 275 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
282 276
283 return 0; 277 return 0;