/* 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 void lola_stream_reset(struct lola *chip, struct lola_stream *str) { if (str->prepared) { if (str->paused) lola_sync_pause(chip, str->substream); str->prepared = 0; lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); lola_stream_wait_for_fifo(chip, str, false); lola_stream_clear_pending_irq(chip, str); lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRST); lola_dsd_write(chip, str->dsd, LVI, 0); lola_dsd_write(chip, str->dsd, BDPU, 0); lola_dsd_write(chip, str->dsd, BDPL, 0); wait_for_srst_clear(chip, str); } }
static void lola_stream_stop(struct lola *chip, struct lola_stream *str, unsigned int tstamp) { lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_VLRCV | tstamp); lola_stream_clear_pending_irq(chip, str); }
/* * set up the SD for streaming */ static int lola_setup_controller(struct lola *chip, struct lola_pcm *pcm, struct lola_stream *str) { dma_addr_t bdl; if (str->prepared) return -EINVAL; /* set up BDL */ bdl = pcm->bdl.addr + LOLA_BDL_ENTRY_SIZE * str->index; lola_dsd_write(chip, str->dsd, BDPL, (u32)bdl); lola_dsd_write(chip, str->dsd, BDPU, upper_32_bits(bdl)); /* program the stream LVI (last valid index) of the BDL */ lola_dsd_write(chip, str->dsd, LVI, str->frags - 1); lola_stream_clear_pending_irq(chip, str); lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE | LOLA_DSD_CTL_SRUN); str->prepared = 1; return lola_stream_wait_for_fifo(chip, str, true); }
/* finish pause - prepare for a new resume */ static void lola_sync_pause(struct lola *chip, struct snd_pcm_substream *substream) { struct snd_pcm_substream *s; lola_sync_wait_for_fifo(chip, substream, false); 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->paused && str->prepared) lola_dsd_write(chip, str->dsd, CTL, LOLA_DSD_CTL_SRUN | LOLA_DSD_CTL_IOCE | LOLA_DSD_CTL_DEIE); } lola_sync_wait_for_fifo(chip, substream, true); }
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); }