[ALSA] ac97_codec: increase timeout for analog subsections
[safe/jmp/linux-2.6] / sound / pci / cs4281.c
index 116cdc1..f6286f8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Driver for Cirrus Logic CS4281 based PCI soundcard
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
 #include <sound/ac97_codec.h>
+#include <sound/tlv.h>
 #include <sound/opl3.h>
 #include <sound/initval.h>
 
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Cirrus Logic CS4281");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,CS4281}}");
@@ -492,7 +492,7 @@ struct cs4281 {
 
 };
 
-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
 
 static struct pci_device_id snd_cs4281_ids[] = {
        { 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4281 */
@@ -766,13 +766,13 @@ static void snd_cs4281_mode(struct cs4281 *chip, struct cs4281_dma *dma,
        if (!capture) {
                if (dma->left_slot == chip->src_left_play_slot) {
                        unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
-                       snd_assert(dma->right_slot == chip->src_right_play_slot, );
+                       snd_BUG_ON(dma->right_slot != chip->src_right_play_slot);
                        snd_cs4281_pokeBA0(chip, BA0_DACSR, val);
                }
        } else {
                if (dma->left_slot == chip->src_left_rec_slot) {
                        unsigned int val = snd_cs4281_rate(runtime->rate, NULL);
-                       snd_assert(dma->right_slot == chip->src_right_rec_slot, );
+                       snd_BUG_ON(dma->right_slot != chip->src_right_rec_slot);
                        snd_cs4281_pokeBA0(chip, BA0_ADCSR, val);
                }
        }
@@ -834,19 +834,22 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream)
        struct cs4281_dma *dma = runtime->private_data;
        struct cs4281 *chip = snd_pcm_substream_chip(substream);
 
-       // printk("DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies);
+       /*
+       printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
+              snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
+              jiffies);
+       */
        return runtime->buffer_size -
               snd_cs4281_peekBA0(chip, dma->regDCC) - 1;
 }
 
 static struct snd_pcm_hardware snd_cs4281_playback =
 {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
-                                SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_RESUME |
-                                SNDRV_PCM_INFO_SYNC_START),
+       .info =                 SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_PAUSE |
+                               SNDRV_PCM_INFO_RESUME,
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
                                SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
                                SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
@@ -867,12 +870,11 @@ static struct snd_pcm_hardware snd_cs4281_playback =
 
 static struct snd_pcm_hardware snd_cs4281_capture =
 {
-       .info =                 (SNDRV_PCM_INFO_MMAP |
-                                SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID |
-                                SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_RESUME |
-                                SNDRV_PCM_INFO_SYNC_START),
+       .info =                 SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_PAUSE |
+                               SNDRV_PCM_INFO_RESUME,
        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
                                SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
                                SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
@@ -903,7 +905,6 @@ static int snd_cs4281_playback_open(struct snd_pcm_substream *substream)
        dma->right_slot = 1;
        runtime->private_data = dma;
        runtime->hw = snd_cs4281_playback;
-       snd_pcm_set_sync(substream);
        /* should be detected from the AC'97 layer, but it seems
           that although CS4297A rev B reports 18-bit ADC resolution,
           samples are 20-bit */
@@ -923,7 +924,6 @@ static int snd_cs4281_capture_open(struct snd_pcm_substream *substream)
        dma->right_slot = 11;
        runtime->private_data = dma;
        runtime->hw = snd_cs4281_capture;
-       snd_pcm_set_sync(substream);
        /* should be detected from the AC'97 layer, but it seems
           that although CS4297A rev B reports 18-bit ADC resolution,
           samples are 20-bit */
@@ -1046,7 +1046,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
                snd_cs4281_pokeBA0(chip, regL, volL);
                change = 1;
        }
-       if (ucontrol->value.integer.value[0] != volL) {
+       if (ucontrol->value.integer.value[1] != volR) {
                volR = CS_VOL_MASK - (ucontrol->value.integer.value[1] & CS_VOL_MASK);
                snd_cs4281_pokeBA0(chip, regR, volR);
                change = 1;
@@ -1054,6 +1054,8 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
+
 static struct snd_kcontrol_new snd_cs4281_fm_vol = 
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1062,6 +1064,7 @@ static struct snd_kcontrol_new snd_cs4281_fm_vol =
        .get = snd_cs4281_get_volume,
        .put = snd_cs4281_put_volume, 
        .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC),
+       .tlv = { .p = db_scale_dsp },
 };
 
 static struct snd_kcontrol_new snd_cs4281_pcm_vol = 
@@ -1072,6 +1075,7 @@ static struct snd_kcontrol_new snd_cs4281_pcm_vol =
        .get = snd_cs4281_get_volume,
        .put = snd_cs4281_put_volume, 
        .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC),
+       .tlv = { .p = db_scale_dsp },
 };
 
 static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
@@ -1184,7 +1188,7 @@ static void __devinit snd_cs4281_proc_init(struct cs4281 * chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "cs4281", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read);
        if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_DATA;
                entry->private_data = chip;
@@ -1209,7 +1213,8 @@ static void snd_cs4281_gameport_trigger(struct gameport *gameport)
 {
        struct cs4281 *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return);
+       if (snd_BUG_ON(!chip))
+               return;
        snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);
 }
 
@@ -1217,7 +1222,8 @@ static unsigned char snd_cs4281_gameport_read(struct gameport *gameport)
 {
        struct cs4281 *chip = gameport_get_port_data(gameport);
 
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
        return snd_cs4281_peekBA0(chip, BA0_JSPT);
 }
 
@@ -1228,7 +1234,8 @@ static int snd_cs4281_gameport_cooked_read(struct gameport *gameport,
        struct cs4281 *chip = gameport_get_port_data(gameport);
        unsigned js1, js2, jst;
        
-       snd_assert(chip, return 0);
+       if (snd_BUG_ON(!chip))
+               return 0;
 
        js1 = snd_cs4281_peekBA0(chip, BA0_JSC1);
        js2 = snd_cs4281_peekBA0(chip, BA0_JSC2);
@@ -1339,10 +1346,6 @@ static int snd_cs4281_dev_free(struct snd_device *device)
 }
 
 static int snd_cs4281_chip_init(struct cs4281 *chip); /* defined below */
-#ifdef CONFIG_PM
-static int cs4281_suspend(struct snd_card *card, pm_message_t state);
-static int cs4281_resume(struct snd_card *card);
-#endif
 
 static int __devinit snd_cs4281_create(struct snd_card *card,
                                       struct pci_dev *pci,
@@ -1383,7 +1386,14 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
        chip->ba0_addr = pci_resource_start(pci, 0);
        chip->ba1_addr = pci_resource_start(pci, 1);
 
-       if (request_irq(pci->irq, snd_cs4281_interrupt, SA_INTERRUPT|SA_SHIRQ,
+       chip->ba0 = pci_ioremap_bar(pci, 0);
+       chip->ba1 = pci_ioremap_bar(pci, 1);
+       if (!chip->ba0 || !chip->ba1) {
+               snd_cs4281_free(chip);
+               return -ENOMEM;
+       }
+       
+       if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
                        "CS4281", chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                snd_cs4281_free(chip);
@@ -1391,13 +1401,6 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
        }
        chip->irq = pci->irq;
 
-       chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));
-       chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));
-       if (!chip->ba0 || !chip->ba1) {
-               snd_cs4281_free(chip);
-               return -ENOMEM;
-       }
-       
        tmp = snd_cs4281_chip_init(chip);
        if (tmp) {
                snd_cs4281_free(chip);
@@ -1411,8 +1414,6 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
 
        snd_cs4281_proc_init(chip);
 
-       snd_card_set_pm_callback(card, cs4281_suspend, cs4281_resume, chip);
-
        snd_card_set_dev(card, &pci->dev);
 
        *rchip = chip;
@@ -1422,7 +1423,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
 static int snd_cs4281_chip_init(struct cs4281 *chip)
 {
        unsigned int tmp;
-       int timeout;
+       unsigned long end_time;
        int retry_count = 2;
 
        /* Having EPPMC.FPDN=1 prevent proper chip initialisation */
@@ -1502,7 +1503,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
        /*
         * Wait for the DLL ready signal from the clock logic.
         */
-       timeout = 100;
+       end_time = jiffies + HZ;
        do {
                /*
                 *  Read the AC97 status register to see if we've seen a CODEC
@@ -1510,8 +1511,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                 */
                if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY)
                        goto __ok0;
-               msleep(1);
-       } while (timeout-- > 0);
+               schedule_timeout_uninterruptible(1);
+       } while (time_after_eq(end_time, jiffies));
 
        snd_printk(KERN_ERR "DLLRDY not seen\n");
        return -EIO;
@@ -1528,7 +1529,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
        /*
         * Wait for the codec ready signal from the AC97 codec.
         */
-       timeout = 100;
+       end_time = jiffies + HZ;
        do {
                /*
                 *  Read the AC97 status register to see if we've seen a CODEC
@@ -1536,20 +1537,20 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                 */
                if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY)
                        goto __ok1;
-               msleep(1);
-       } while (timeout-- > 0);
+               schedule_timeout_uninterruptible(1);
+       } while (time_after_eq(end_time, jiffies));
 
        snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS));
        return -EIO;
 
       __ok1:
        if (chip->dual_codec) {
-               timeout = 100;
+               end_time = jiffies + HZ;
                do {
                        if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY)
                                goto __codec2_ok;
-                       msleep(1);
-               } while (timeout-- > 0);
+                       schedule_timeout_uninterruptible(1);
+               } while (time_after_eq(end_time, jiffies));
                snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n");
                chip->dual_codec = 0;
        __codec2_ok: ;
@@ -1567,7 +1568,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
         *  the codec is pumping ADC data across the AC-link.
         */
 
-       timeout = 100;
+       end_time = jiffies + HZ;
        do {
                /*
                 *  Read the input slot valid register and see if input slots 3
@@ -1575,8 +1576,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip)
                 */
                 if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4)))
                         goto __ok2;
-               msleep(1);
-       } while (timeout-- > 0);
+               schedule_timeout_uninterruptible(1);
+       } while (time_after_eq(end_time, jiffies));
 
        if (--retry_count > 0)
                goto __retry;
@@ -1815,7 +1816,7 @@ static int __devinit snd_cs4281_midi(struct cs4281 * chip, int device,
  *  Interrupt handler
  */
 
-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
 {
        struct cs4281 *chip = dev_id;
        unsigned int status, dma, val;
@@ -1928,14 +1929,15 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (card == NULL)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        if ((err = snd_cs4281_create(card, pci, &chip, dual_codec[dev])) < 0) {
                snd_card_free(card);
                return err;
        }
+       card->private_data = chip;
 
        if ((err = snd_cs4281_mixer(chip)) < 0) {
                snd_card_free(card);
@@ -2007,18 +2009,18 @@ static int saved_regs[SUSPEND_REGISTERS] = {
 
 #define CLKCR1_CKRA                             0x00010000L
 
-static int cs4281_suspend(struct snd_card *card, pm_message_t state)
+static int cs4281_suspend(struct pci_dev *pci, pm_message_t state)
 {
-       struct cs4281 *chip = card->pm_private_data;
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct cs4281 *chip = card->private_data;
        u32 ulCLK;
        unsigned int i;
 
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        snd_pcm_suspend_all(chip->pcm);
 
-       if (chip->ac97)
-               snd_ac97_suspend(chip->ac97);
-       if (chip->ac97_secondary)
-               snd_ac97_suspend(chip->ac97_secondary);
+       snd_ac97_suspend(chip->ac97);
+       snd_ac97_suspend(chip->ac97_secondary);
 
        ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
        ulCLK |= CLKCR1_CKRA;
@@ -2048,18 +2050,28 @@ static int cs4281_suspend(struct snd_card *card, pm_message_t state)
        ulCLK &= ~CLKCR1_CKRA;
        snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
 
-       pci_disable_device(chip->pci);
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       pci_set_power_state(pci, pci_choose_state(pci, state));
        return 0;
 }
 
-static int cs4281_resume(struct snd_card *card)
+static int cs4281_resume(struct pci_dev *pci)
 {
-       struct cs4281 *chip = card->pm_private_data;
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct cs4281 *chip = card->private_data;
        unsigned int i;
        u32 ulCLK;
 
-       pci_enable_device(chip->pci);
-       pci_set_master(chip->pci);
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
+       if (pci_enable_device(pci) < 0) {
+               printk(KERN_ERR "cs4281: pci_enable_device failed, "
+                      "disabling device\n");
+               snd_card_disconnect(card);
+               return -EIO;
+       }
+       pci_set_master(pci);
 
        ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
        ulCLK |= CLKCR1_CKRA;
@@ -2072,15 +2084,14 @@ static int cs4281_resume(struct snd_card *card)
                if (saved_regs[i])
                        snd_cs4281_pokeBA0(chip, saved_regs[i], chip->suspend_regs[i]);
 
-       if (chip->ac97)
-               snd_ac97_resume(chip->ac97);
-       if (chip->ac97_secondary)
-               snd_ac97_resume(chip->ac97_secondary);
+       snd_ac97_resume(chip->ac97);
+       snd_ac97_resume(chip->ac97_secondary);
 
        ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
        ulCLK &= ~CLKCR1_CKRA;
        snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
 
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -2090,7 +2101,10 @@ static struct pci_driver driver = {
        .id_table = snd_cs4281_ids,
        .probe = snd_cs4281_probe,
        .remove = __devexit_p(snd_cs4281_remove),
-       SND_PCI_PM_CALLBACKS
+#ifdef CONFIG_PM
+       .suspend = cs4281_suspend,
+       .resume = cs4281_resume,
+#endif
 };
        
 static int __init alsa_card_cs4281_init(void)