diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2008-01-21 08:53:30 +0100 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 17:30:08 +0100 |
commit | 7f0b89465bb94eb3273ea5af5e009332351a54c9 (patch) | |
tree | 9ea524a7c9ecaf37f60edc5838aa1887221b0f75 /sound/pci/oxygen/oxygen_lib.c | |
parent | 5a256f862c2a9155456b718edb303e37cda2d153 (diff) |
[ALSA] oxygen: add 192 kHz SPDIF input support
Change the oxygen_spdif_input_bits_changed() function so that clock
changes on the SPDIF input are correctly detected. This means that
sample rates greater than 96 kHz are now supported.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/oxygen/oxygen_lib.c')
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 75 |
1 files changed, 55 insertions, 20 deletions
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 0927e042377..49eabdadc67 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -74,7 +74,9 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) if (status & OXYGEN_INT_SPDIF_IN_DETECT) { spin_lock(&chip->reg_lock); i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); - if (i & OXYGEN_SPDIF_RATE_INT) { + if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT | + OXYGEN_SPDIF_RATE_INT)) { + /* write the interrupt bit(s) to clear */ oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i); schedule_work(&chip->spdif_input_bits_work); } @@ -94,30 +96,46 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work) { struct oxygen *chip = container_of(work, struct oxygen, spdif_input_bits_work); + u32 reg; - spin_lock_irq(&chip->reg_lock); - oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, - OXYGEN_SPDIF_IN_CLOCK_96, - OXYGEN_SPDIF_IN_CLOCK_MASK); - spin_unlock_irq(&chip->reg_lock); + /* + * This function gets called when there is new activity on the SPDIF + * input, or when we lose lock on the input signal, or when the rate + * changes. + */ msleep(1); - if (!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) - & OXYGEN_SPDIF_LOCK_STATUS)) { - spin_lock_irq(&chip->reg_lock); - oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, - OXYGEN_SPDIF_IN_CLOCK_192, - OXYGEN_SPDIF_IN_CLOCK_MASK); + spin_lock_irq(&chip->reg_lock); + reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); + if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | + OXYGEN_SPDIF_LOCK_STATUS)) + == OXYGEN_SPDIF_SENSE_STATUS) { + /* + * If we detect activity on the SPDIF input but cannot lock to + * a signal, the clock bit is likely to be wrong. + */ + reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK; + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); spin_unlock_irq(&chip->reg_lock); msleep(1); - if (!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) - & OXYGEN_SPDIF_LOCK_STATUS)) { - spin_lock_irq(&chip->reg_lock); - oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, - OXYGEN_SPDIF_IN_CLOCK_96, - OXYGEN_SPDIF_IN_CLOCK_MASK); - spin_unlock_irq(&chip->reg_lock); + spin_lock_irq(&chip->reg_lock); + reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); + if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | + OXYGEN_SPDIF_LOCK_STATUS)) + == OXYGEN_SPDIF_SENSE_STATUS) { + /* nothing detected with either clock; give up */ + if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK) + == OXYGEN_SPDIF_IN_CLOCK_192) { + /* + * Reset clock to <= 96 kHz because this is + * more likely to be received next time. + */ + reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK; + reg |= OXYGEN_SPDIF_IN_CLOCK_96; + oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); + } } } + spin_unlock_irq(&chip->reg_lock); if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) { spin_lock_irq(&chip->reg_lock); @@ -126,6 +144,10 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work) chip->interrupt_mask); spin_unlock_irq(&chip->reg_lock); + /* + * We don't actually know that any channel status bits have + * changed, but let's send a notification just to be sure. + */ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id); } @@ -225,7 +247,20 @@ static void __devinit oxygen_init(struct oxygen *chip) OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); - oxygen_set_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_RATE_MASK); + oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, + OXYGEN_SPDIF_SENSE_MASK | + OXYGEN_SPDIF_LOCK_MASK | + OXYGEN_SPDIF_RATE_MASK | + OXYGEN_SPDIF_LOCK_PAR | + OXYGEN_SPDIF_IN_CLOCK_96, + OXYGEN_SPDIF_OUT_ENABLE | + OXYGEN_SPDIF_LOOPBACK | + OXYGEN_SPDIF_SENSE_MASK | + OXYGEN_SPDIF_LOCK_MASK | + OXYGEN_SPDIF_RATE_MASK | + OXYGEN_SPDIF_SENSE_PAR | + OXYGEN_SPDIF_LOCK_PAR | + OXYGEN_SPDIF_IN_CLOCK_MASK); oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); oxygen_write16(chip, OXYGEN_PLAY_ROUTING, OXYGEN_PLAY_MULTICH_I2S_DAC | OXYGEN_PLAY_SPDIF_SPDIF | |