[alsa-devel] Patch for suspend/resume in ICE1724 for Audiotrak Prodigy HD2
Igor Chernyshev
igor.ch75+alsa at gmail.com
Mon Jun 22 21:46:48 CEST 2009
Hi Takashi,
here is the patch for:
Supported suspend/resume in Audiotrak Prodigy HD2
Please, let me know if you want some special testing, patch
formatting, etc on my part. So far I did suspend-resume with MythTV
playing AVI and DVD through RCA. In original ALSA 1.0.20, MythTV
playback upon resume would start ~20% faster than before suspend,
volume would go to max (or above? given how awfully loud the noises
were) and there would be ton of noises. After the change, resume gives
clean playback in MythTV. I suspect that I may not have covered
different scenarios (e.g. driver implies there may be 3 pcm's, ac97,
and mic) in my testing.
Thanks,
Igor
Here is the part I know about : : )))
Signed-off-by: Igor Chernyshev <igor.ch75+alsa at gmail.com>
-----
diff -uN alsa-driver-1.0.20.orig/alsa-kernel/pci/ice1712/ice1712.h
alsa-driver-1.0.20/alsa-kernel/pci/ice1712/ice1712.h
--- alsa-driver-1.0.20.orig/alsa-kernel/pci/ice1712/ice1712.h 2009-05-06
00:06:04.000000000 -0700
+++ alsa-driver-1.0.20/alsa-kernel/pci/ice1712/ice1712.h 2009-06-19
22:27:12.000000000 -0700
@@ -378,6 +378,15 @@
unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
void (*set_spdif_clock)(struct snd_ice1712 *ice);
+#ifdef CONFIG_PM
+ int (*pm_suspend)(struct snd_ice1712 *);
+ int (*pm_resume)(struct snd_ice1712 *);
+ int pm_suspend_enabled:1;
+ int pm_saved_is_spdif_master:1;
+ unsigned int pm_saved_spdif_ctrl;
+ unsigned char pm_saved_spdif_cfg;
+ unsigned long pm_saved_route;
+#endif
};
diff -uN alsa-driver-1.0.20.orig/alsa-kernel/pci/ice1712/ice1724.c
alsa-driver-1.0.20/alsa-kernel/pci/ice1712/ice1724.c
--- alsa-driver-1.0.20.orig/alsa-kernel/pci/ice1712/ice1724.c 2009-05-06
00:06:04.000000000 -0700
+++ alsa-driver-1.0.20/alsa-kernel/pci/ice1712/ice1724.c 2009-06-22
12:13:26.000000000 -0700
@@ -568,6 +568,10 @@
spin_unlock(&ice->reg_lock);
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ break;
+
default:
return -EINVAL;
}
@@ -2266,6 +2270,14 @@
outb(0, ICEREG1724(ice, POWERDOWN));
+ /* MPU_RX and TX irq masks are cleared later dynamically */
+ outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
+
+ /* don't handle FIFO overrun/underruns (just yet),
+ * since they cause machine lockups
+ */
+ outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
+
return 0;
}
@@ -2407,6 +2419,8 @@
snd_vt1724_proc_init(ice);
synchronize_irq(pci->irq);
+ card->private_data = ice;
+
err = pci_request_regions(pci, "ICE1724");
if (err < 0) {
kfree(ice);
@@ -2435,14 +2449,6 @@
return -EIO;
}
- /* MPU_RX and TX irq masks are cleared later dynamically */
- outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
-
- /* don't handle FIFO overrun/underruns (just yet),
- * since they cause machine lockups
- */
- outb(VT1724_MULTI_FIFO_ERR, ICEMT1724(ice, DMA_INT_MASK));
-
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops);
if (err < 0) {
snd_vt1724_free(ice);
@@ -2626,11 +2632,104 @@
pci_set_drvdata(pci, NULL);
}
+#ifdef CONFIG_PM
+static int snd_vt1724_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_ice1712 *ice = card->private_data;
+
+ if (!ice->pm_suspend_enabled)
+ return 0;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+ if (ice->pcm)
+ snd_pcm_suspend_all(ice->pcm);
+ if (ice->pcm_pro)
+ snd_pcm_suspend_all(ice->pcm_pro);
+ if (ice->pcm_ds)
+ snd_pcm_suspend_all(ice->pcm_ds);
+ if (ice->ac97)
+ snd_ac97_suspend(ice->ac97);
+
+ spin_lock_irq(&ice->reg_lock);
+ ice->pm_saved_is_spdif_master = ice->is_spdif_master(ice);
+ ice->pm_saved_spdif_ctrl = inw(ICEMT1724(ice, SPDIF_CTRL));
+ ice->pm_saved_spdif_cfg = inb(ICEREG1724(ice, SPDIF_CFG));
+ ice->pm_saved_route = inl(ICEMT1724(ice, ROUTE_PLAYBACK));
+ spin_unlock_irq(&ice->reg_lock);
+
+ if (ice->pm_suspend)
+ ice->pm_suspend(ice);
+
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ pci_set_power_state(pci, pci_choose_state(pci, state));
+ return 0;
+}
+
+static int snd_vt1724_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_ice1712 *ice = card->private_data;
+
+ if (!ice->pm_suspend_enabled)
+ return 0;
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+
+ if (pci_enable_device(pci) < 0) {
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ pci_set_master(pci);
+
+ snd_vt1724_chip_reset(ice);
+
+ if (snd_vt1724_chip_init(ice) < 0) {
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+
+ if (ice->pm_resume)
+ ice->pm_resume(ice);
+
+ spin_lock_irq(&ice->reg_lock);
+ if (ice->pm_saved_is_spdif_master) {
+ /* switching to external clock via SPDIF */
+ ice->set_spdif_clock(ice);
+ } else {
+ /* internal on-card clock */
+ spin_unlock_irq(&ice->reg_lock);
+ snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+ spin_lock_irq(&ice->reg_lock);
+ }
+
+ update_spdif_bits(ice, ice->pm_saved_spdif_ctrl);
+
+ outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG));
+ outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK));
+ spin_unlock_irq(&ice->reg_lock);
+
+ if (ice->ac97)
+ snd_ac97_resume(ice->ac97);
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif
+
static struct pci_driver driver = {
.name = "ICE1724",
.id_table = snd_vt1724_ids,
.probe = snd_vt1724_probe,
.remove = __devexit_p(snd_vt1724_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_vt1724_suspend,
+ .resume = snd_vt1724_resume,
+#endif
};
static int __init alsa_card_ice1724_init(void)
diff -uN alsa-driver-1.0.20.orig/alsa-kernel/pci/ice1712/prodigy_hifi.c
alsa-driver-1.0.20/alsa-kernel/pci/ice1712/prodigy_hifi.c
--- alsa-driver-1.0.20.orig/alsa-kernel/pci/ice1712/prodigy_hifi.c 2009-05-06
00:06:04.000000000 -0700
+++ alsa-driver-1.0.20/alsa-kernel/pci/ice1712/prodigy_hifi.c 2009-06-22
12:06:28.000000000 -0700
@@ -1077,8 +1077,7 @@
/*
* initialize the chip
*/
-static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
-{
+static void ak4396_init(struct snd_ice1712 *ice) {
static unsigned short ak4396_inits[] = {
AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */
AK4396_CTRL2, 0x02,
@@ -1087,9 +1086,38 @@
AK4396_RCH_ATT, 0x00,
};
- struct prodigy_hifi_spec *spec;
unsigned int i;
+ /* initialize ak4396 codec */
+ /* reset codec */
+ ak4396_write(ice, AK4396_CTRL1, 0x86);
+ msleep(100);
+ ak4396_write(ice, AK4396_CTRL1, 0x87);
+
+ for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
+ ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
+}
+
+#ifdef CONFIG_PM
+static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice)
+{
+ /* initialize ak4396 codec and restore previous mixer volumes */
+ struct prodigy_hifi_spec *spec = ice->spec;
+ int i;
+ mutex_lock(&ice->gpio_mutex);
+ ak4396_init(ice);
+ for (i = 0; i < 2; i++) {
+ ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
+ }
+ mutex_unlock(&ice->gpio_mutex);
+ return 0;
+}
+#endif
+
+static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
+{
+ struct prodigy_hifi_spec *spec;
+
ice->vt1720 = 0;
ice->vt1724 = 1;
@@ -1112,14 +1140,12 @@
return -ENOMEM;
ice->spec = spec;
- /* initialize ak4396 codec */
- /* reset codec */
- ak4396_write(ice, AK4396_CTRL1, 0x86);
- msleep(100);
- ak4396_write(ice, AK4396_CTRL1, 0x87);
-
- for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
- ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
+#ifdef CONFIG_PM
+ ice->pm_resume = &prodigy_hd2_resume;
+ ice->pm_suspend_enabled = 1;
+#endif
+
+ ak4396_init(ice);
return 0;
}
On Mon, Jun 22, 2009 at 9:42 AM, Takashi Iwai <tiwai at suse.de> wrote:
>
> At Fri, 19 Jun 2009 23:37:16 -0700,
> Igor Chernyshev wrote:
> >
> > Hi Alsa Developers!
> >
> > I've built a small HTPC and had to add suspend/resume support in ice1724
> > driver. There seem to be 3 existing bugs related to that:
> >
> > https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4413
> > https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3748
> > https://bugtrack.alsa-project.org/alsa-bug/view.php?id=2314
> >
> > Due to hardware (un)availability, I only enabled the fix for Audiotrak
> > Prodigy HD2 card, which is installed in my HTPC. However, most of my code
> > should be reusable in the future on other ice1724-based cards as well (as
> > long as people add card-specific peices of code). The fix is currently based
> > on ALSA 1.0.20 and works on my MythBuntu 9.04 HTPC (using 2.6.28-11 kernel).
> >
> > The following files have been modified:
> > alsa-kernel/pci/ice1712/ice1712.h
> > alsa-kernel/pci/ice1712/ice1724.c
> > alsa-kernel/pci/ice1712/prodigy_hifi.c
> >
> > Now, I'm a complete newbie in Linux development and not sure I can safely
> > rebuild latest Linux Kernel under MythBuntu, etc. Are there any resources
> > for people like me to read? I want to provide the patch without destroying
> > my computer a hunder times, but also make it more convenient and safer for
> > ALSA maintainers.
>
> Well, I'd like to see the patch before anything else :)
> Could you just post your patch for review?
>
>
> thanks,
>
> Takashi
More information about the Alsa-devel
mailing list