aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2008-05-13 03:24:39 -0400
committerJaroslav Kysela <perex@perex.cz>2008-05-19 07:19:17 -0400
commit4a4bc53bc52978dd6c918531921da925fd047d95 (patch)
tree3705801799fa4673f8ced7640e4bcf66049e38fd
parent92215f3a178080bd9d7c65879499e9474e54d55c (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.c5
-rw-r--r--sound/pci/oxygen/oxygen.c12
-rw-r--r--sound/pci/oxygen/oxygen.h6
-rw-r--r--sound/pci/oxygen/oxygen_lib.c100
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c1
-rw-r--r--sound/pci/oxygen/virtuoso.c22
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
191static int __init alsa_card_hifier_init(void) 196static 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
195static void generic_resume(struct oxygen *chip)
196{
197 ak4396_registers_init(chip);
198 wm8785_registers_init(chip);
199}
200
195static void set_ak4396_params(struct oxygen *chip, 201static 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
358static int __init alsa_card_oxygen_init(void) 370static 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 {
125int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, 127int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
126 const struct oxygen_model *model); 128 const struct oxygen_model *model);
127void oxygen_pci_remove(struct pci_dev *pci); 129void oxygen_pci_remove(struct pci_dev *pci);
130#ifdef CONFIG_PM
131int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
132int 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}
536EXPORT_SYMBOL(oxygen_pci_remove); 540EXPORT_SYMBOL(oxygen_pci_remove);
541
542#ifdef CONFIG_PM
543int 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}
574EXPORT_SYMBOL(oxygen_pci_suspend);
575
576static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = {
577 0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff,
578 0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000
579};
580static const u32 ac97_registers_to_restore[2][0x40 / 32] = {
581 { 0x18284fa2, 0x03060000 },
582 { 0x00007fa6, 0x00200000 }
583};
584
585static inline int is_bit_set(const u32 *bitmap, unsigned int bit)
586{
587 return bitmap[bit / 32] & (1 << (bit & 31));
588}
589
590static 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
602int 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}
635EXPORT_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
362static void xonar_d2_resume(struct oxygen *chip)
363{
364 pcm1796_init(chip);
365 xonar_enable_output(chip);
366}
367
368static void xonar_dx_resume(struct oxygen *chip)
369{
370 cs43xx_init(chip);
371 xonar_enable_output(chip);
372}
373
362static void set_pcm1796_params(struct oxygen *chip, 374static 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
657static int __init alsa_card_xonar_init(void) 679static int __init alsa_card_xonar_init(void)