aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen/oxygen_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/oxygen/oxygen_lib.c')
-rw-r--r--sound/pci/oxygen/oxygen_lib.c100
1 files changed, 100 insertions, 0 deletions
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 */