X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=sound%2Fpci%2Fcs46xx%2Fcs46xx_lib.c;h=8c44fefd15fc85828c43229ccffe94f895954435;hb=5dbc94791005608c57674fba04dd6b5e19ba9342;hp=2807b9756ef09d96e2f48646084d201aa7daefd0;hpb=0bb78c3715ec9ee528d92177bc94ffcc94bed5a8;p=linux-2.6-block.git diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 2807b9756ef0..8c44fefd15fc 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * Abramo Bagnara * Cirrus Logic, Inc. * Routines for control of Cirrus Logic CS461x chips @@ -1818,15 +1818,7 @@ static int snd_cs46xx_vol_iec958_put(struct snd_kcontrol *kcontrol, struct snd_c } #endif -static int snd_mixer_boolean_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_mixer_boolean_info snd_ctl_boolean_mono_info static int snd_cs46xx_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2092,71 +2084,6 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, #endif /* CONFIG_SND_CS46XX_NEW_DSP */ -#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO -static int snd_cs46xx_egpio_select_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 8; - return 0; -} - -static int snd_cs46xx_egpio_select_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = chip->current_gpio; - - return 0; -} - -static int snd_cs46xx_egpio_select_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); - int change = (chip->current_gpio != ucontrol->value.integer.value[0]); - chip->current_gpio = ucontrol->value.integer.value[0]; - - return change; -} - - -static int snd_cs46xx_egpio_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value; - - snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio); - ucontrol->value.integer.value[0] = - (snd_cs46xx_peekBA0(chip, reg) & (1 << chip->current_gpio)) ? 1 : 0; - - return 0; -} - -static int snd_cs46xx_egpio_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value; - int val = snd_cs46xx_peekBA0(chip, reg); - int oldval = val; - snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio); - - if (ucontrol->value.integer.value[0]) - val |= (1 << chip->current_gpio); - else - val &= ~(1 << chip->current_gpio); - - snd_cs46xx_pokeBA0(chip, reg,val); - snd_printdd ("put: val %08x oldval %08x\n",val,oldval); - - return (oldval != val); -} -#endif /* CONFIG_SND_CS46XX_DEBUG_GPIO */ - static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2248,40 +2175,6 @@ static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { .put = snd_cs46xx_spdif_stream_put }, -#endif -#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "EGPIO select", - .info = snd_cs46xx_egpio_select_info, - .get = snd_cs46xx_egpio_select_get, - .put = snd_cs46xx_egpio_select_put, - .private_value = 0, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "EGPIO Input/Output", - .info = snd_mixer_boolean_info, - .get = snd_cs46xx_egpio_get, - .put = snd_cs46xx_egpio_put, - .private_value = BA0_EGPIODR, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "EGPIO CMOS/Open drain", - .info = snd_mixer_boolean_info, - .get = snd_cs46xx_egpio_get, - .put = snd_cs46xx_egpio_put, - .private_value = BA0_EGPIOPTR, -}, -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "EGPIO On/Off", - .info = snd_mixer_boolean_info, - .get = snd_cs46xx_egpio_get, - .put = snd_cs46xx_egpio_put, - .private_value = BA0_EGPIOSR, -}, #endif }; @@ -2897,6 +2790,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) } #endif +#ifdef CONFIG_PM + kfree(chip->saved_regs); +#endif + pci_disable_device(chip->pci); kfree(chip); return 0; @@ -3107,7 +3004,7 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip) snd_printk(KERN_ERR "ERROR: snd-cs46xx: never read ISV3 & ISV4 from AC'97\n"); snd_printk(KERN_ERR " Try reloading the ALSA driver, if you find something\n"); snd_printk(KERN_ERR " broken or not working on your soundcard upon\n"); - snd_printk(KERN_ERR " this message please report to alsa-devel@lists.sourceforge.net\n"); + snd_printk(KERN_ERR " this message please report to alsa-devel@alsa-project.org\n"); return -EIO; #endif @@ -3140,6 +3037,23 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip) /* * start and load DSP */ + +static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip) +{ + unsigned int tmp; + + snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM); + + tmp = snd_cs46xx_peek(chip, BA1_PFIE); + tmp &= ~0x0000f03f; + snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */ + + tmp = snd_cs46xx_peek(chip, BA1_CIE); + tmp &= ~0x0000003f; + tmp |= 0x00000001; + snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */ +} + int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip) { unsigned int tmp; @@ -3214,19 +3128,7 @@ int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip) snd_cs46xx_proc_start(chip); - /* - * Enable interrupts on the part. - */ - snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM); - - tmp = snd_cs46xx_peek(chip, BA1_PFIE); - tmp &= ~0x0000f03f; - snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */ - - tmp = snd_cs46xx_peek(chip, BA1_CIE); - tmp &= ~0x0000003f; - tmp |= 0x00000001; - snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */ + cs46xx_enable_stream_irqs(chip); #ifndef CONFIG_SND_CS46XX_NEW_DSP /* set the attenuation to 0dB */ @@ -3665,11 +3567,19 @@ static struct cs_card_type __devinitdata cards[] = { * APM support */ #ifdef CONFIG_PM +static unsigned int saved_regs[] = { + BA0_ACOSV, + BA0_ASER_FADDR, + BA0_ASER_MASTER, + BA1_PVOL, + BA1_CVOL, +}; + int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_cs46xx *chip = card->private_data; - int amp_saved; + int i, amp_saved; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->in_suspend = 1; @@ -3680,6 +3590,10 @@ int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state) snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); + /* save some registers */ + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) + chip->saved_regs[i] = snd_cs46xx_peekBA0(chip, saved_regs[i]); + amp_saved = chip->amplifier; /* turn off amp */ chip->amplifier_ctrl(chip, -chip->amplifier); @@ -3698,7 +3612,7 @@ int snd_cs46xx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_cs46xx *chip = card->private_data; - int amp_saved; + int i, amp_saved; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -3716,6 +3630,16 @@ int snd_cs46xx_resume(struct pci_dev *pci) snd_cs46xx_chip_init(chip); + snd_cs46xx_reset(chip); +#ifdef CONFIG_SND_CS46XX_NEW_DSP + cs46xx_dsp_resume(chip); + /* restore some registers */ + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) + snd_cs46xx_pokeBA0(chip, saved_regs[i], chip->saved_regs[i]); +#else + snd_cs46xx_download_image(chip); +#endif + #if 0 snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, chip->ac97_general_purpose); @@ -3730,6 +3654,13 @@ int snd_cs46xx_resume(struct pci_dev *pci) snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); + /* reset playback/capture */ + snd_cs46xx_set_play_sample_rate(chip, 8000); + snd_cs46xx_set_capture_sample_rate(chip, 8000); + snd_cs46xx_proc_start(chip); + + cs46xx_enable_stream_irqs(chip); + if (amp_saved) chip->amplifier_ctrl(chip, 1); /* turn amp on */ else @@ -3867,7 +3798,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card, } } - if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_DISABLED|IRQF_SHARED, + if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED, "CS46XX", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs46xx_free(chip); @@ -3896,6 +3827,15 @@ int __devinit snd_cs46xx_create(struct snd_card *card, snd_cs46xx_proc_init(card, chip); +#ifdef CONFIG_PM + chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) * + ARRAY_SIZE(saved_regs), GFP_KERNEL); + if (!chip->saved_regs) { + snd_cs46xx_free(chip); + return -ENOMEM; + } +#endif + chip->active_ctrl(chip, -1); /* disable CLKRUN */ snd_card_set_dev(card, &pci->dev);