]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/ac97/ac97_codec.c
[ALSA] Fix pm_message_t in PXA2XX-AC97 driver
[linux-2.6-omap-h63xx.git] / sound / pci / ac97 / ac97_codec.c
index a4b72cd2eea065e0501c8307387897f18af64dee..f221eba5c32f8baaca11219a54b42a3dca08f199 100644 (file)
@@ -112,6 +112,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
 { 0x414c4723, 0xffffffff, "ALC650F",           NULL,   NULL }, /* already patched */
 { 0x414c4720, 0xfffffff0, "ALC650",            patch_alc650,   NULL },
 { 0x414c4760, 0xfffffff0, "ALC655",            patch_alc655,   NULL },
+{ 0x414c4781, 0xffffffff, "ALC658D",           NULL,   NULL }, /* already patched */
 { 0x414c4780, 0xfffffff0, "ALC658",            patch_alc655,   NULL },
 { 0x414c4790, 0xfffffff0, "ALC850",            patch_alc850,   NULL },
 { 0x414c4730, 0xffffffff, "ALC101",            NULL,           NULL },
@@ -157,6 +158,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
+{ 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
 { 0x57454301, 0xffffffff, "W83971D",           NULL,           NULL },
 { 0x574d4c00, 0xffffffff, "WM9701A",           NULL,           NULL },
 { 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -367,6 +369,7 @@ int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
                ac97->regs[reg] = value;
                ac97->bus->ops->write(ac97, reg, value);
        }
+       set_bit(reg, ac97->reg_accessed);
        up(&ac97->reg_mutex);
        return change;
 }
@@ -410,6 +413,7 @@ int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg,
                ac97->regs[reg] = new;
                ac97->bus->ops->write(ac97, reg, new);
        }
+       set_bit(reg, ac97->reg_accessed);
        return change;
 }
 
@@ -1076,6 +1080,11 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max
        for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {
                unsigned short val;
                snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
+               /* Do the read twice due to buffers on some ac97 codecs.
+                * e.g. The STAC9704 returns exactly what you wrote the the register
+                * if you read it immediately. This causes the detect routine to fail.
+                */
+               val = snd_ac97_read(ac97, reg);
                val = snd_ac97_read(ac97, reg);
                if (! *lo_max && (val & 0x7f) == cbit[i])
                        *lo_max = max[i];
@@ -1300,16 +1309,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build master tone controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
-               for (idx = 0; idx < 2; idx++) {
-                       if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
-                               return err;
-                       if (ac97->id == AC97_ID_YMF753) {
-                               kctl->private_value &= ~(0xff << 16);
-                               kctl->private_value |= 7 << 16;
+       if (!(ac97->flags & AC97_HAS_NO_TONE)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
+                       for (idx = 0; idx < 2; idx++) {
+                               if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
+                                       return err;
+                               if (ac97->id == AC97_ID_YMF753) {
+                                       kctl->private_value &= ~(0xff << 16);
+                                       kctl->private_value |= 7 << 16;
+                               }
                        }
+                       snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
                }
-               snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
        }
        
        /* build PC Speaker controls */
@@ -1332,11 +1343,13 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build MIC controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
-               if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
-                       return err;
-               if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
-                       return err;
+       if (!(ac97->flags & AC97_HAS_NO_MIC)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+                       if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
+                               return err;
+                       if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
+                               return err;
+               }
        }
 
        /* build Line controls */
@@ -1395,12 +1408,14 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
                }
                snd_ac97_write_cache(ac97, AC97_PCM, init_val);
        } else {
-               if (ac97->flags & AC97_HAS_NO_PCM_VOL)
-                       err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
-               else
-                       err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
-               if (err < 0)
-                       return err;
+               if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
+                       if (ac97->flags & AC97_HAS_NO_PCM_VOL)
+                               err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
+                       else
+                               err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        /* build Capture controls */
@@ -1542,7 +1557,7 @@ static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
 
        /* build modem switches */
        for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++)
-               if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)
+               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)
                        return err;
 
        /* build chip specific controls */
@@ -1782,7 +1797,7 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
 
        snd_assert(card != NULL, return -EINVAL);
        snd_assert(rbus != NULL, return -EINVAL);
-       bus = kcalloc(1, sizeof(*bus), GFP_KERNEL);
+       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
        if (bus == NULL)
                return -ENOMEM;
        bus->card = card;
@@ -1800,6 +1815,39 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
        return 0;
 }
 
+/* stop no dev release warning */
+static void ac97_device_release(struct device * dev)
+{
+}
+
+/* register ac97 codec to bus */
+static int snd_ac97_dev_register(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       int err;
+
+       ac97->dev.bus = &ac97_bus_type;
+       ac97->dev.parent = ac97->bus->card->dev;
+       ac97->dev.platform_data = ac97;
+       ac97->dev.release = ac97_device_release;
+       snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "card%d-%d", ac97->bus->card->number, ac97->num);
+       if ((err = device_register(&ac97->dev)) < 0) {
+               snd_printk(KERN_ERR "Can't register ac97 bus\n");
+               ac97->dev.bus = NULL;
+               return err;
+       }
+       return 0;
+}
+
+/* unregister ac97 codec */
+static int snd_ac97_dev_unregister(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       if (ac97->dev.bus)
+               device_unregister(&ac97->dev);
+       return snd_ac97_free(ac97);
+}
+
 /* build_ops to do nothing */
 static struct snd_ac97_build_ops null_build_ops;
 
@@ -1833,6 +1881,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
        const ac97_codec_id_t *pid;
        static snd_device_ops_t ops = {
                .dev_free =     snd_ac97_dev_free,
+               .dev_register = snd_ac97_dev_register,
+               .dev_unregister =       snd_ac97_dev_unregister,
        };
 
        snd_assert(rac97 != NULL, return -EINVAL);
@@ -1856,7 +1906,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
        }
 
        card = bus->card;
-       ac97 = kcalloc(1, sizeof(*ac97), GFP_KERNEL);
+       ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL);
        if (ac97 == NULL)
                return -ENOMEM;
        ac97->private_data = template->private_data;
@@ -2224,7 +2274,7 @@ void snd_ac97_restore_iec958(ac97_t *ac97)
  */
 void snd_ac97_resume(ac97_t *ac97)
 {
-       int i;
+       unsigned long end_time;
 
        if (ac97->bus->ops->reset) {
                ac97->bus->ops->reset(ac97);
@@ -2242,26 +2292,26 @@ void snd_ac97_resume(ac97_t *ac97)
        snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
        if (ac97_is_audio(ac97)) {
                ac97->bus->ops->write(ac97, AC97_MASTER, 0x8101);
-               for (i = HZ/10; i >= 0; i--) {
+               end_time = jiffies + msecs_to_jiffies(100);
+               do {
                        if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
                                break;
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(1);
-               }
+               } while (time_after_eq(end_time, jiffies));
                /* FIXME: extra delay */
                ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000);
-               if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/4);
-               }
+               if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000)
+                       msleep(250);
        } else {
-               for (i = HZ/10; i >= 0; i--) {
+               end_time = jiffies + msecs_to_jiffies(100);
+               do {
                        unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID);
                        if (val != 0xffff && (val & 1) != 0)
                                break;
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(1);
-               }
+               } while (time_after_eq(end_time, jiffies));
        }
 __reset_ready:
 
@@ -2532,8 +2582,6 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
 {
        int result;
 
-       snd_assert(quirk, return -EINVAL);
-
        /* quirk overriden? */
        if (override && strcmp(override, "-1") && strcmp(override, "default")) {
                result = apply_quirk_str(ac97, override);
@@ -2542,6 +2590,9 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
                return result;
        }
 
+       if (! quirk)
+               return -EINVAL;
+
        for (; quirk->subvendor; quirk++) {
                if (quirk->subvendor != ac97->subsystem_vendor)
                        continue;