diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2008-05-13 03:24:39 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-05-19 07:19:17 -0400 |
commit | 4a4bc53bc52978dd6c918531921da925fd047d95 (patch) | |
tree | 3705801799fa4673f8ced7640e4bcf66049e38fd | |
parent | 92215f3a178080bd9d7c65879499e9474e54d55c (diff) |
[ALSA] oxygen: add PM support
Add suspend/resume support.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | sound/pci/oxygen/hifier.c | 5 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.c | 12 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen.h | 6 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 100 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_pcm.c | 1 | ||||
-rw-r--r-- | sound/pci/oxygen/virtuoso.c | 22 |
6 files changed, 146 insertions, 0 deletions
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 6e45a58ad14b..7442460583dd 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c | |||
@@ -146,6 +146,7 @@ static const struct oxygen_model model_hifier = { | |||
146 | .init = hifier_init, | 146 | .init = hifier_init, |
147 | .control_filter = hifier_control_filter, | 147 | .control_filter = hifier_control_filter, |
148 | .cleanup = hifier_cleanup, | 148 | .cleanup = hifier_cleanup, |
149 | .resume = hifier_registers_init, | ||
149 | .set_dac_params = set_ak4396_params, | 150 | .set_dac_params = set_ak4396_params, |
150 | .set_adc_params = set_cs5340_params, | 151 | .set_adc_params = set_cs5340_params, |
151 | .update_dac_volume = update_ak4396_volume, | 152 | .update_dac_volume = update_ak4396_volume, |
@@ -186,6 +187,10 @@ static struct pci_driver hifier_driver = { | |||
186 | .id_table = hifier_ids, | 187 | .id_table = hifier_ids, |
187 | .probe = hifier_probe, | 188 | .probe = hifier_probe, |
188 | .remove = __devexit_p(oxygen_pci_remove), | 189 | .remove = __devexit_p(oxygen_pci_remove), |
190 | #ifdef CONFIG_PM | ||
191 | .suspend = oxygen_pci_suspend, | ||
192 | .resume = oxygen_pci_resume, | ||
193 | #endif | ||
189 | }; | 194 | }; |
190 | 195 | ||
191 | static int __init alsa_card_hifier_init(void) | 196 | static int __init alsa_card_hifier_init(void) |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 800ae304a247..7c8ae31eb468 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -192,6 +192,12 @@ static void generic_cleanup(struct oxygen *chip) | |||
192 | { | 192 | { |
193 | } | 193 | } |
194 | 194 | ||
195 | static void generic_resume(struct oxygen *chip) | ||
196 | { | ||
197 | ak4396_registers_init(chip); | ||
198 | wm8785_registers_init(chip); | ||
199 | } | ||
200 | |||
195 | static void set_ak4396_params(struct oxygen *chip, | 201 | static void set_ak4396_params(struct oxygen *chip, |
196 | struct snd_pcm_hw_params *params) | 202 | struct snd_pcm_hw_params *params) |
197 | { | 203 | { |
@@ -278,6 +284,7 @@ static const struct oxygen_model model_generic = { | |||
278 | .owner = THIS_MODULE, | 284 | .owner = THIS_MODULE, |
279 | .init = generic_init, | 285 | .init = generic_init, |
280 | .cleanup = generic_cleanup, | 286 | .cleanup = generic_cleanup, |
287 | .resume = generic_resume, | ||
281 | .set_dac_params = set_ak4396_params, | 288 | .set_dac_params = set_ak4396_params, |
282 | .set_adc_params = set_wm8785_params, | 289 | .set_adc_params = set_wm8785_params, |
283 | .update_dac_volume = update_ak4396_volume, | 290 | .update_dac_volume = update_ak4396_volume, |
@@ -305,6 +312,7 @@ static const struct oxygen_model model_meridian = { | |||
305 | .owner = THIS_MODULE, | 312 | .owner = THIS_MODULE, |
306 | .init = meridian_init, | 313 | .init = meridian_init, |
307 | .cleanup = generic_cleanup, | 314 | .cleanup = generic_cleanup, |
315 | .resume = ak4396_registers_init, | ||
308 | .set_dac_params = set_ak4396_params, | 316 | .set_dac_params = set_ak4396_params, |
309 | .set_adc_params = set_ak5385_params, | 317 | .set_adc_params = set_ak5385_params, |
310 | .update_dac_volume = update_ak4396_volume, | 318 | .update_dac_volume = update_ak4396_volume, |
@@ -353,6 +361,10 @@ static struct pci_driver oxygen_driver = { | |||
353 | .id_table = oxygen_ids, | 361 | .id_table = oxygen_ids, |
354 | .probe = generic_oxygen_probe, | 362 | .probe = generic_oxygen_probe, |
355 | .remove = __devexit_p(oxygen_pci_remove), | 363 | .remove = __devexit_p(oxygen_pci_remove), |
364 | #ifdef CONFIG_PM | ||
365 | .suspend = oxygen_pci_suspend, | ||
366 | .resume = oxygen_pci_resume, | ||
367 | #endif | ||
356 | }; | 368 | }; |
357 | 369 | ||
358 | static int __init alsa_card_oxygen_init(void) | 370 | static int __init alsa_card_oxygen_init(void) |
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 29c9fa4964b2..74a644880074 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -97,6 +97,8 @@ struct oxygen_model { | |||
97 | int (*control_filter)(struct snd_kcontrol_new *template); | 97 | int (*control_filter)(struct snd_kcontrol_new *template); |
98 | int (*mixer_init)(struct oxygen *chip); | 98 | int (*mixer_init)(struct oxygen *chip); |
99 | void (*cleanup)(struct oxygen *chip); | 99 | void (*cleanup)(struct oxygen *chip); |
100 | void (*suspend)(struct oxygen *chip); | ||
101 | void (*resume)(struct oxygen *chip); | ||
100 | void (*pcm_hardware_filter)(unsigned int channel, | 102 | void (*pcm_hardware_filter)(unsigned int channel, |
101 | struct snd_pcm_hardware *hardware); | 103 | struct snd_pcm_hardware *hardware); |
102 | void (*set_dac_params)(struct oxygen *chip, | 104 | void (*set_dac_params)(struct oxygen *chip, |
@@ -125,6 +127,10 @@ struct oxygen_model { | |||
125 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | 127 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, |
126 | const struct oxygen_model *model); | 128 | const struct oxygen_model *model); |
127 | void oxygen_pci_remove(struct pci_dev *pci); | 129 | void oxygen_pci_remove(struct pci_dev *pci); |
130 | #ifdef CONFIG_PM | ||
131 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); | ||
132 | int oxygen_pci_resume(struct pci_dev *pci); | ||
133 | #endif | ||
128 | 134 | ||
129 | /* oxygen_mixer.c */ | 135 | /* oxygen_mixer.c */ |
130 | 136 | ||
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 60bc15917349..22f37851045e 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -314,6 +314,10 @@ static void oxygen_init(struct oxygen *chip) | |||
314 | OXYGEN_SPDIF_LOCK_MASK | | 314 | OXYGEN_SPDIF_LOCK_MASK | |
315 | OXYGEN_SPDIF_RATE_MASK); | 315 | OXYGEN_SPDIF_RATE_MASK); |
316 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); | 316 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); |
317 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
318 | OXYGEN_2WIRE_LENGTH_8 | | ||
319 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
320 | OXYGEN_2WIRE_SPEED_STANDARD); | ||
317 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); | 321 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); |
318 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); | 322 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); |
319 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); | 323 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); |
@@ -534,3 +538,99 @@ void oxygen_pci_remove(struct pci_dev *pci) | |||
534 | pci_set_drvdata(pci, NULL); | 538 | pci_set_drvdata(pci, NULL); |
535 | } | 539 | } |
536 | EXPORT_SYMBOL(oxygen_pci_remove); | 540 | EXPORT_SYMBOL(oxygen_pci_remove); |
541 | |||
542 | #ifdef CONFIG_PM | ||
543 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) | ||
544 | { | ||
545 | struct snd_card *card = pci_get_drvdata(pci); | ||
546 | struct oxygen *chip = card->private_data; | ||
547 | unsigned int i, saved_interrupt_mask; | ||
548 | |||
549 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
550 | |||
551 | for (i = 0; i < PCM_COUNT; ++i) | ||
552 | if (chip->streams[i]) | ||
553 | snd_pcm_suspend(chip->streams[i]); | ||
554 | |||
555 | if (chip->model->suspend) | ||
556 | chip->model->suspend(chip); | ||
557 | |||
558 | spin_lock_irq(&chip->reg_lock); | ||
559 | saved_interrupt_mask = chip->interrupt_mask; | ||
560 | chip->interrupt_mask = 0; | ||
561 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
562 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
563 | spin_unlock_irq(&chip->reg_lock); | ||
564 | |||
565 | synchronize_irq(chip->irq); | ||
566 | flush_scheduled_work(); | ||
567 | chip->interrupt_mask = saved_interrupt_mask; | ||
568 | |||
569 | pci_disable_device(pci); | ||
570 | pci_save_state(pci); | ||
571 | pci_set_power_state(pci, pci_choose_state(pci, state)); | ||
572 | return 0; | ||
573 | } | ||
574 | EXPORT_SYMBOL(oxygen_pci_suspend); | ||
575 | |||
576 | static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = { | ||
577 | 0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff, | ||
578 | 0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000 | ||
579 | }; | ||
580 | static const u32 ac97_registers_to_restore[2][0x40 / 32] = { | ||
581 | { 0x18284fa2, 0x03060000 }, | ||
582 | { 0x00007fa6, 0x00200000 } | ||
583 | }; | ||
584 | |||
585 | static inline int is_bit_set(const u32 *bitmap, unsigned int bit) | ||
586 | { | ||
587 | return bitmap[bit / 32] & (1 << (bit & 31)); | ||
588 | } | ||
589 | |||
590 | static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec) | ||
591 | { | ||
592 | unsigned int i; | ||
593 | |||
594 | oxygen_write_ac97(chip, codec, AC97_RESET, 0); | ||
595 | msleep(1); | ||
596 | for (i = 1; i < 0x40; ++i) | ||
597 | if (is_bit_set(ac97_registers_to_restore[codec], i)) | ||
598 | oxygen_write_ac97(chip, codec, i * 2, | ||
599 | chip->saved_ac97_registers[codec][i]); | ||
600 | } | ||
601 | |||
602 | int oxygen_pci_resume(struct pci_dev *pci) | ||
603 | { | ||
604 | struct snd_card *card = pci_get_drvdata(pci); | ||
605 | struct oxygen *chip = card->private_data; | ||
606 | unsigned int i; | ||
607 | |||
608 | pci_set_power_state(pci, PCI_D0); | ||
609 | pci_restore_state(pci); | ||
610 | if (pci_enable_device(pci) < 0) { | ||
611 | snd_printk(KERN_ERR "cannot reenable device"); | ||
612 | snd_card_disconnect(card); | ||
613 | return -EIO; | ||
614 | } | ||
615 | pci_set_master(pci); | ||
616 | |||
617 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
618 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
619 | for (i = 0; i < OXYGEN_IO_SIZE; ++i) | ||
620 | if (is_bit_set(registers_to_restore, i)) | ||
621 | oxygen_write8(chip, i, chip->saved_registers._8[i]); | ||
622 | if (chip->has_ac97_0) | ||
623 | oxygen_restore_ac97(chip, 0); | ||
624 | if (chip->has_ac97_1) | ||
625 | oxygen_restore_ac97(chip, 1); | ||
626 | |||
627 | if (chip->model->resume) | ||
628 | chip->model->resume(chip); | ||
629 | |||
630 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
631 | |||
632 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
633 | return 0; | ||
634 | } | ||
635 | EXPORT_SYMBOL(oxygen_pci_resume); | ||
636 | #endif /* CONFIG_PM */ | ||
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index b17c405e069d..9680aa35f81f 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -517,6 +517,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) | |||
517 | switch (cmd) { | 517 | switch (cmd) { |
518 | case SNDRV_PCM_TRIGGER_STOP: | 518 | case SNDRV_PCM_TRIGGER_STOP: |
519 | case SNDRV_PCM_TRIGGER_START: | 519 | case SNDRV_PCM_TRIGGER_START: |
520 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
520 | pausing = 0; | 521 | pausing = 0; |
521 | break; | 522 | break; |
522 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 523 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index abd5313d19b5..9a2c16bf94e0 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -359,6 +359,18 @@ static void xonar_dx_cleanup(struct oxygen *chip) | |||
359 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); | 359 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); |
360 | } | 360 | } |
361 | 361 | ||
362 | static void xonar_d2_resume(struct oxygen *chip) | ||
363 | { | ||
364 | pcm1796_init(chip); | ||
365 | xonar_enable_output(chip); | ||
366 | } | ||
367 | |||
368 | static void xonar_dx_resume(struct oxygen *chip) | ||
369 | { | ||
370 | cs43xx_init(chip); | ||
371 | xonar_enable_output(chip); | ||
372 | } | ||
373 | |||
362 | static void set_pcm1796_params(struct oxygen *chip, | 374 | static void set_pcm1796_params(struct oxygen *chip, |
363 | struct snd_pcm_hw_params *params) | 375 | struct snd_pcm_hw_params *params) |
364 | { | 376 | { |
@@ -551,6 +563,8 @@ static const struct oxygen_model xonar_models[] = { | |||
551 | .control_filter = xonar_d2_control_filter, | 563 | .control_filter = xonar_d2_control_filter, |
552 | .mixer_init = xonar_mixer_init, | 564 | .mixer_init = xonar_mixer_init, |
553 | .cleanup = xonar_cleanup, | 565 | .cleanup = xonar_cleanup, |
566 | .suspend = xonar_cleanup, | ||
567 | .resume = xonar_d2_resume, | ||
554 | .set_dac_params = set_pcm1796_params, | 568 | .set_dac_params = set_pcm1796_params, |
555 | .set_adc_params = set_cs53x1_params, | 569 | .set_adc_params = set_cs53x1_params, |
556 | .update_dac_volume = update_pcm1796_volume, | 570 | .update_dac_volume = update_pcm1796_volume, |
@@ -579,6 +593,8 @@ static const struct oxygen_model xonar_models[] = { | |||
579 | .control_filter = xonar_d2_control_filter, | 593 | .control_filter = xonar_d2_control_filter, |
580 | .mixer_init = xonar_mixer_init, | 594 | .mixer_init = xonar_mixer_init, |
581 | .cleanup = xonar_cleanup, | 595 | .cleanup = xonar_cleanup, |
596 | .suspend = xonar_cleanup, | ||
597 | .resume = xonar_d2_resume, | ||
582 | .set_dac_params = set_pcm1796_params, | 598 | .set_dac_params = set_pcm1796_params, |
583 | .set_adc_params = set_cs53x1_params, | 599 | .set_adc_params = set_cs53x1_params, |
584 | .update_dac_volume = update_pcm1796_volume, | 600 | .update_dac_volume = update_pcm1796_volume, |
@@ -608,6 +624,8 @@ static const struct oxygen_model xonar_models[] = { | |||
608 | .control_filter = xonar_dx_control_filter, | 624 | .control_filter = xonar_dx_control_filter, |
609 | .mixer_init = xonar_dx_mixer_init, | 625 | .mixer_init = xonar_dx_mixer_init, |
610 | .cleanup = xonar_dx_cleanup, | 626 | .cleanup = xonar_dx_cleanup, |
627 | .suspend = xonar_dx_cleanup, | ||
628 | .resume = xonar_dx_resume, | ||
611 | .set_dac_params = set_cs43xx_params, | 629 | .set_dac_params = set_cs43xx_params, |
612 | .set_adc_params = set_cs53x1_params, | 630 | .set_adc_params = set_cs53x1_params, |
613 | .update_dac_volume = update_cs43xx_volume, | 631 | .update_dac_volume = update_cs43xx_volume, |
@@ -652,6 +670,10 @@ static struct pci_driver xonar_driver = { | |||
652 | .id_table = xonar_ids, | 670 | .id_table = xonar_ids, |
653 | .probe = xonar_probe, | 671 | .probe = xonar_probe, |
654 | .remove = __devexit_p(oxygen_pci_remove), | 672 | .remove = __devexit_p(oxygen_pci_remove), |
673 | #ifdef CONFIG_PM | ||
674 | .suspend = oxygen_pci_suspend, | ||
675 | .resume = oxygen_pci_resume, | ||
676 | #endif | ||
655 | }; | 677 | }; |
656 | 678 | ||
657 | static int __init alsa_card_xonar_init(void) | 679 | static int __init alsa_card_xonar_init(void) |