summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2008-01-21 08:53:30 +0100
committerJaroslav Kysela <perex@perex.cz>2008-01-31 17:30:08 +0100
commit7f0b89465bb94eb3273ea5af5e009332351a54c9 (patch)
tree9ea524a7c9ecaf37f60edc5838aa1887221b0f75 /sound
parent5a256f862c2a9155456b718edb303e37cda2d153 (diff)
downloadlinux-7f0b89465bb94eb3273ea5af5e009332351a54c9.tar.gz
[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')
-rw-r--r--sound/pci/oxygen/oxygen_lib.c75
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c12
2 files changed, 63 insertions, 24 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)
 	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 |
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 31b0ccdca9a8..200290099cbc 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -85,12 +85,16 @@ static struct snd_pcm_hardware oxygen_hardware[PCM_COUNT] = {
 			SNDRV_PCM_INFO_SYNC_START,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			   SNDRV_PCM_FMTBIT_S32_LE,
-		.rates = SNDRV_PCM_RATE_44100 |
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 |
 			 SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_64000 |
 			 SNDRV_PCM_RATE_88200 |
-			 SNDRV_PCM_RATE_96000,
-		.rate_min = 44100,
-		.rate_max = 96000,
+			 SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 |
+			 SNDRV_PCM_RATE_192000,
+		.rate_min = 32000,
+		.rate_max = 192000,
 		.channels_min = 2,
 		.channels_max = 2,
 		.buffer_bytes_max = 256 * 1024,