aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen/oxygen_lib.c
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2008-01-21 02:53:30 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:30:08 -0500
commit7f0b89465bb94eb3273ea5af5e009332351a54c9 (patch)
tree9ea524a7c9ecaf37f60edc5838aa1887221b0f75 /sound/pci/oxygen/oxygen_lib.c
parent5a256f862c2a9155456b718edb303e37cda2d153 (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.c75
1 files changed, 55 insertions, 20 deletions
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 0927e0423777..49eabdadc679 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)
74 if (status & OXYGEN_INT_SPDIF_IN_DETECT) { 74 if (status & OXYGEN_INT_SPDIF_IN_DETECT) {
75 spin_lock(&chip->reg_lock); 75 spin_lock(&chip->reg_lock);
76 i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); 76 i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
77 if (i & OXYGEN_SPDIF_RATE_INT) { 77 if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT |
78 OXYGEN_SPDIF_RATE_INT)) {
79 /* write the interrupt bit(s) to clear */
78 oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i); 80 oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i);
79 schedule_work(&chip->spdif_input_bits_work); 81 schedule_work(&chip->spdif_input_bits_work);
80 } 82 }
@@ -94,30 +96,46 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work)
94{ 96{
95 struct oxygen *chip = container_of(work, struct oxygen, 97 struct oxygen *chip = container_of(work, struct oxygen,
96 spdif_input_bits_work); 98 spdif_input_bits_work);
99 u32 reg;
97 100
98 spin_lock_irq(&chip->reg_lock); 101 /*
99 oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, 102 * This function gets called when there is new activity on the SPDIF
100 OXYGEN_SPDIF_IN_CLOCK_96, 103 * input, or when we lose lock on the input signal, or when the rate
101 OXYGEN_SPDIF_IN_CLOCK_MASK); 104 * changes.
102 spin_unlock_irq(&chip->reg_lock); 105 */
103 msleep(1); 106 msleep(1);
104 if (!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) 107 spin_lock_irq(&chip->reg_lock);
105 & OXYGEN_SPDIF_LOCK_STATUS)) { 108 reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
106 spin_lock_irq(&chip->reg_lock); 109 if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
107 oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, 110 OXYGEN_SPDIF_LOCK_STATUS))
108 OXYGEN_SPDIF_IN_CLOCK_192, 111 == OXYGEN_SPDIF_SENSE_STATUS) {
109 OXYGEN_SPDIF_IN_CLOCK_MASK); 112 /*
113 * If we detect activity on the SPDIF input but cannot lock to
114 * a signal, the clock bit is likely to be wrong.
115 */
116 reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK;
117 oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
110 spin_unlock_irq(&chip->reg_lock); 118 spin_unlock_irq(&chip->reg_lock);
111 msleep(1); 119 msleep(1);
112 if (!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) 120 spin_lock_irq(&chip->reg_lock);
113 & OXYGEN_SPDIF_LOCK_STATUS)) { 121 reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
114 spin_lock_irq(&chip->reg_lock); 122 if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
115 oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, 123 OXYGEN_SPDIF_LOCK_STATUS))
116 OXYGEN_SPDIF_IN_CLOCK_96, 124 == OXYGEN_SPDIF_SENSE_STATUS) {
117 OXYGEN_SPDIF_IN_CLOCK_MASK); 125 /* nothing detected with either clock; give up */
118 spin_unlock_irq(&chip->reg_lock); 126 if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK)
127 == OXYGEN_SPDIF_IN_CLOCK_192) {
128 /*
129 * Reset clock to <= 96 kHz because this is
130 * more likely to be received next time.
131 */
132 reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK;
133 reg |= OXYGEN_SPDIF_IN_CLOCK_96;
134 oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
135 }
119 } 136 }
120 } 137 }
138 spin_unlock_irq(&chip->reg_lock);
121 139
122 if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) { 140 if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) {
123 spin_lock_irq(&chip->reg_lock); 141 spin_lock_irq(&chip->reg_lock);
@@ -126,6 +144,10 @@ static void oxygen_spdif_input_bits_changed(struct work_struct *work)
126 chip->interrupt_mask); 144 chip->interrupt_mask);
127 spin_unlock_irq(&chip->reg_lock); 145 spin_unlock_irq(&chip->reg_lock);
128 146
147 /*
148 * We don't actually know that any channel status bits have
149 * changed, but let's send a notification just to be sure.
150 */
129 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 151 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
130 &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id); 152 &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id);
131 } 153 }
@@ -225,7 +247,20 @@ static void __devinit oxygen_init(struct oxygen *chip)
225 OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | 247 OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
226 OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | 248 OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
227 OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); 249 OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
228 oxygen_set_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_RATE_MASK); 250 oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
251 OXYGEN_SPDIF_SENSE_MASK |
252 OXYGEN_SPDIF_LOCK_MASK |
253 OXYGEN_SPDIF_RATE_MASK |
254 OXYGEN_SPDIF_LOCK_PAR |
255 OXYGEN_SPDIF_IN_CLOCK_96,
256 OXYGEN_SPDIF_OUT_ENABLE |
257 OXYGEN_SPDIF_LOOPBACK |
258 OXYGEN_SPDIF_SENSE_MASK |
259 OXYGEN_SPDIF_LOCK_MASK |
260 OXYGEN_SPDIF_RATE_MASK |
261 OXYGEN_SPDIF_SENSE_PAR |
262 OXYGEN_SPDIF_LOCK_PAR |
263 OXYGEN_SPDIF_IN_CLOCK_MASK);
229 oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); 264 oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits);
230 oxygen_write16(chip, OXYGEN_PLAY_ROUTING, 265 oxygen_write16(chip, OXYGEN_PLAY_ROUTING,
231 OXYGEN_PLAY_MULTICH_I2S_DAC | OXYGEN_PLAY_SPDIF_SPDIF | 266 OXYGEN_PLAY_MULTICH_I2S_DAC | OXYGEN_PLAY_SPDIF_SPDIF |