diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-02-18 09:39:59 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-02-23 03:16:07 -0500 |
commit | 59ed1eade1d6ec24751baca99305f9713a5d779e (patch) | |
tree | 47846571754cc487fcc5eb17e03cf91b7b258301 /sound/pci/hda | |
parent | d8a766a16ed90c4b3bd7afa6e1417f8d715db507 (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.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 93 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_controller.c | 11 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_tegra.c | 6 |
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 | } |
144 | EXPORT_SYMBOL_GPL(__hda_codec_driver_register); | 145 | EXPORT_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 | |||
3975 | static 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 | |||
3987 | static 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 */ | ||
3995 | const 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 | } |
5506 | EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); | 5530 | EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); |
5507 | 5531 | ||
5508 | |||
5509 | #ifdef CONFIG_PM | ||
5510 | /* | ||
5511 | * power management | ||
5512 | */ | ||
5513 | |||
5514 | |||
5515 | static void hda_async_suspend(void *data, async_cookie_t cookie) | ||
5516 | { | ||
5517 | hda_call_codec_suspend(data, false); | ||
5518 | } | ||
5519 | |||
5520 | static 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 | */ |
5531 | int snd_hda_suspend(struct hda_bus *bus) | 5536 | void 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 | } | ||
5552 | EXPORT_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 | */ | ||
5560 | int 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 | } |
5577 | EXPORT_SYMBOL_GPL(snd_hda_resume); | 5551 | EXPORT_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 | ||
568 | int snd_hda_lock_devices(struct hda_bus *bus); | 568 | int snd_hda_lock_devices(struct hda_bus *bus); |
569 | void snd_hda_unlock_devices(struct hda_bus *bus); | 569 | void snd_hda_unlock_devices(struct hda_bus *bus); |
570 | void snd_hda_bus_reset(struct hda_bus *bus); | ||
570 | 571 | ||
571 | /* | 572 | /* |
572 | * power management | 573 | * power management |
573 | */ | 574 | */ |
574 | #ifdef CONFIG_PM | 575 | extern const struct dev_pm_ops hda_codec_driver_pm; |
575 | int snd_hda_suspend(struct hda_bus *bus); | ||
576 | int snd_hda_resume(struct hda_bus *bus); | ||
577 | #endif | ||
578 | 576 | ||
579 | static inline | 577 | static inline |
580 | int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) | 578 | int 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; |