/* sync for FIFO ready/empty for all linked streams; * clear paused flag when FIFO gets ready again */ static int lola_sync_wait_for_fifo(struct lola *chip, struct snd_pcm_substream *substream, bool ready) { unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; unsigned long end_time = jiffies + msecs_to_jiffies(200); struct snd_pcm_substream *s; int pending = 0; while (time_before(jiffies, end_time)) { pending = 0; snd_pcm_group_for_each_entry(s, substream) { struct lola_stream *str; if (s->pcm->card != substream->pcm->card) continue; str = lola_get_stream(s); if (str->prepared && str->paused) { unsigned int reg; reg = lola_dsd_read(chip, str->dsd, STS); if ((reg & LOLA_DSD_STS_FIFORDY) != val) { pending = str->dsd + 1; break; } if (ready) str->paused = 0; } } if (!pending) return 0; msleep(1); } printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1); return -EIO; }
/* clear any pending interrupt status */ static void lola_stream_clear_pending_irq(struct lola *chip, struct lola_stream *str) { unsigned int val = lola_dsd_read(chip, str->dsd, STS); val &= LOLA_DSD_STS_DESE | LOLA_DSD_STS_BCIS; if (val) lola_dsd_write(chip, str->dsd, STS, val); }
static snd_pcm_uframes_t lola_pcm_pointer(struct snd_pcm_substream *substream) { struct lola *chip = snd_pcm_substream_chip(substream); struct lola_stream *str = lola_get_stream(substream); unsigned int pos = lola_dsd_read(chip, str->dsd, LPIB); if (pos >= str->bufsize) pos = 0; return bytes_to_frames(substream->runtime, pos); }
static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) { unsigned long end_time = jiffies + msecs_to_jiffies(200); while (time_before(jiffies, end_time)) { unsigned int val; val = lola_dsd_read(chip, str->dsd, CTL); if (!(val & LOLA_DSD_CTL_SRST)) return; msleep(1); } printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd); }
static int lola_stream_wait_for_fifo(struct lola *chip, struct lola_stream *str, bool ready) { unsigned int val = ready ? LOLA_DSD_STS_FIFORDY : 0; unsigned long end_time = jiffies + msecs_to_jiffies(200); while (time_before(jiffies, end_time)) { unsigned int reg = lola_dsd_read(chip, str->dsd, STS); if ((reg & LOLA_DSD_STS_FIFORDY) == val) return 0; msleep(1); } printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd); return -EIO; }
static irqreturn_t lola_interrupt(int irq, void *dev_id) { struct lola *chip = dev_id; unsigned int notify_ins, notify_outs, error_ins, error_outs; int handled = 0; int i; notify_ins = notify_outs = error_ins = error_outs = 0; spin_lock(&chip->reg_lock); for (;;) { unsigned int status, in_sts, out_sts; unsigned int reg; status = lola_readl(chip, BAR1, DINTSTS); if (!status || status == -1) break; in_sts = lola_readl(chip, BAR1, DIINTSTS); out_sts = lola_readl(chip, BAR1, DOINTSTS); /* */ for (i = 0; in_sts && i < chip->pcm[CAPT].num_streams; i++) { if (!(in_sts & (1 << i))) continue; in_sts &= ~(1 << i); reg = lola_dsd_read(chip, i, STS); if (reg & LOLA_DSD_STS_DESE) /* */ error_ins |= (1 << i); if (reg & LOLA_DSD_STS_BCIS) /* */ notify_ins |= (1 << i); /* */ lola_dsd_write(chip, i, STS, reg); } /* */ for (i = 0; out_sts && i < chip->pcm[PLAY].num_streams; i++) { if (!(out_sts & (1 << i))) continue; out_sts &= ~(1 << i); reg = lola_dsd_read(chip, i + MAX_STREAM_IN_COUNT, STS); if (reg & LOLA_DSD_STS_DESE) /* */ error_outs |= (1 << i); if (reg & LOLA_DSD_STS_BCIS) /* */ notify_outs |= (1 << i); lola_dsd_write(chip, i + MAX_STREAM_IN_COUNT, STS, reg); } if (status & LOLA_DINT_CTRL) { unsigned char rbsts; /* */ rbsts = lola_readb(chip, BAR0, RIRBSTS); rbsts &= LOLA_RIRB_INT_MASK; if (rbsts) lola_writeb(chip, BAR0, RIRBSTS, rbsts); rbsts = lola_readb(chip, BAR0, CORBSTS); rbsts &= LOLA_CORB_INT_MASK; if (rbsts) lola_writeb(chip, BAR0, CORBSTS, rbsts); lola_update_rirb(chip); } if (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR)) { /* */ lola_writel(chip, BAR1, DINTSTS, (status & (LOLA_DINT_FIFOERR | LOLA_DINT_MUERR))); } handled = 1; } spin_unlock(&chip->reg_lock); lola_pcm_update(chip, &chip->pcm[CAPT], notify_ins); lola_pcm_update(chip, &chip->pcm[PLAY], notify_outs); return IRQ_RETVAL(handled); }