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; /* * 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); 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); 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); chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 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); } }
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; msleep(1); 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) { reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK; oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); spin_unlock_irq(&chip->reg_lock); msleep(1); 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 ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK) == OXYGEN_SPDIF_IN_CLOCK_192) { 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); chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); spin_unlock_irq(&chip->reg_lock); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id); } }
static snd_pcm_uframes_t oxygen_pointer(struct snd_pcm_substream *substream) { struct oxygen *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int channel = oxygen_substream_channel(substream); u32 curr_addr; /* no spinlock, this read should be atomic */ curr_addr = oxygen_read32(chip, channel_base_registers[channel]); return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr); }
static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) { struct oxygen *chip = dev_id; unsigned int status, clear, elapsed_streams, i; status = oxygen_read16(chip, OXYGEN_INTERRUPT_STATUS); if (!status) return IRQ_NONE; spin_lock(&chip->reg_lock); clear = status & (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B | OXYGEN_CHANNEL_C | OXYGEN_CHANNEL_SPDIF | OXYGEN_CHANNEL_MULTICH | OXYGEN_CHANNEL_AC97 | OXYGEN_INT_SPDIF_IN_DETECT | OXYGEN_INT_GPIO | OXYGEN_INT_AC97); if (clear) { if (clear & OXYGEN_INT_SPDIF_IN_DETECT) chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask & ~clear); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); } elapsed_streams = status & chip->pcm_running; spin_unlock(&chip->reg_lock); for (i = 0; i < PCM_COUNT; ++i) if ((elapsed_streams & (1 << i)) && chip->streams[i]) snd_pcm_period_elapsed(chip->streams[i]); if (status & OXYGEN_INT_SPDIF_IN_DETECT) { spin_lock(&chip->reg_lock); i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); 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); } spin_unlock(&chip->reg_lock); } if (status & OXYGEN_INT_GPIO) schedule_work(&chip->gpio_work); if (status & OXYGEN_INT_MIDI) { if (chip->midi) snd_mpu401_uart_interrupt(0, chip->midi->private_data); else oxygen_read_uart(chip); } if (status & OXYGEN_INT_AC97) wake_up(&chip->ac97_waitqueue); return IRQ_HANDLED; }