aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2009-04-13 14:45:42 -0400
committerJaroslav Kysela <perex@perex.cz>2009-04-13 15:28:27 -0400
commit920e4ae31cb113328e617f4a0663fb17d7b09124 (patch)
tree1e58bfffcb3b244d056e26026a1a73a43bb5f385 /sound/pci
parentbbf6ad1399e9516b0a95de3ad58ffbaed670e4cc (diff)
[ALSA] intel8x0: an attempt to make ac97_clock measurement more reliable
- use monotonic posix clock to measure time - try to avoid reading zero from PICB (position in current buffer) register - show also measured samples - when clock is near 41000 or 44100, use exactly these values (they appears to be reference clocks for hardware manufacturers) Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/intel8x0.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 57648810eaf1..c86ff499460b 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -2661,8 +2661,9 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2661 struct snd_pcm_substream *subs; 2661 struct snd_pcm_substream *subs;
2662 struct ichdev *ichdev; 2662 struct ichdev *ichdev;
2663 unsigned long port; 2663 unsigned long port;
2664 unsigned long pos, t; 2664 unsigned long pos, pos1, t;
2665 struct timeval start_time, stop_time; 2665 int civ, timeout = 1000;
2666 struct timespec start_time, stop_time;
2666 2667
2667 if (chip->ac97_bus->clock != 48000) 2668 if (chip->ac97_bus->clock != 48000)
2668 return; /* specified in module option */ 2669 return; /* specified in module option */
@@ -2693,16 +2694,27 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2693 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); 2694 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
2694 iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); 2695 iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
2695 } 2696 }
2696 do_gettimeofday(&start_time); 2697 do_posix_clock_monotonic_gettime(&start_time);
2697 spin_unlock_irq(&chip->reg_lock); 2698 spin_unlock_irq(&chip->reg_lock);
2698 msleep(50); 2699 msleep(50);
2699 spin_lock_irq(&chip->reg_lock); 2700 spin_lock_irq(&chip->reg_lock);
2700 /* check the position */ 2701 /* check the position */
2702 do {
2703 civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
2704 pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
2705 if (pos1 == 0) {
2706 udelay(10);
2707 continue;
2708 }
2709 if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
2710 pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
2711 break;
2712 } while (timeout--);
2701 pos = ichdev->fragsize1; 2713 pos = ichdev->fragsize1;
2702 pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift; 2714 pos -= pos1 << ichdev->pos_shift;
2703 pos += ichdev->position; 2715 pos += ichdev->position;
2704 chip->in_measurement = 0; 2716 chip->in_measurement = 0;
2705 do_gettimeofday(&stop_time); 2717 do_posix_clock_monotonic_gettime(&stop_time);
2706 /* stop */ 2718 /* stop */
2707 if (chip->device_type == DEVICE_ALI) { 2719 if (chip->device_type == DEVICE_ALI) {
2708 iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); 2720 iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
@@ -2717,19 +2729,26 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
2717 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); 2729 iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
2718 spin_unlock_irq(&chip->reg_lock); 2730 spin_unlock_irq(&chip->reg_lock);
2719 2731
2732 pos /= 4;
2720 t = stop_time.tv_sec - start_time.tv_sec; 2733 t = stop_time.tv_sec - start_time.tv_sec;
2721 t *= 1000000; 2734 t *= 1000000;
2722 t += stop_time.tv_usec - start_time.tv_usec; 2735 t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000;
2723 printk(KERN_INFO "%s: measured %lu usecs\n", __func__, t); 2736 printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
2724 if (t == 0) { 2737 if (t == 0) {
2725 snd_printk(KERN_ERR "?? calculation error..\n"); 2738 snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n");
2726 return; 2739 return;
2727 } 2740 }
2728 pos = (pos / 4) * 1000; 2741 pos *= 1000;
2729 pos = (pos / t) * 1000 + ((pos % t) * 1000) / t; 2742 pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
2730 if (pos < 40000 || pos >= 60000) 2743 if (pos < 40000 || pos >= 60000)
2731 /* abnormal value. hw problem? */ 2744 /* abnormal value. hw problem? */
2732 printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); 2745 printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
2746 else if (pos > 40500 || pos < 41500)
2747 /* first exception - 41000Hz reference clock */
2748 chip->ac97_bus->clock = 41000;
2749 else if (pos > 43600 || pos < 44600)
2750 /* second exception - 44100HZ reference clock */
2751 chip->ac97_bus->clock = 44100;
2733 else if (pos < 47500 || pos > 48500) 2752 else if (pos < 47500 || pos > 48500)
2734 /* not 48000Hz, tuning the clock.. */ 2753 /* not 48000Hz, tuning the clock.. */
2735 chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; 2754 chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;