/* * SSI PIO */ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) { struct rsnd_ssi *ssi = data; struct rsnd_dai_stream *io = ssi->io; u32 status = rsnd_mod_read(&ssi->mod, SSISR); irqreturn_t ret = IRQ_NONE; if (io && (status & DIRQ)) { struct rsnd_dai *rdai = ssi->rdai; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 *buf = (u32 *)(runtime->dma_area + rsnd_dai_pointer_offset(io, 0)); rsnd_ssi_record_error(ssi, status); /* * 8/16/32 data can be assesse to TDR/RDR register * directly as 32bit data * see rsnd_ssi_init() */ if (rsnd_dai_is_play(rdai, io)) rsnd_mod_write(&ssi->mod, SSITDR, *buf); else *buf = rsnd_mod_read(&ssi->mod, SSIRDR); rsnd_dai_pointer_update(io, sizeof(*buf)); ret = IRQ_HANDLED; } return ret; }
static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) { struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); struct rsnd_dai_stream *io = ssi->io; u32 status = rsnd_mod_read(&ssi->mod, SSISR); rsnd_ssi_record_error(ssi, status); rsnd_dai_pointer_update(ssi->io, io->byte_per_period); return 0; }
static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) { struct rsnd_ssi *ssi = data; struct rsnd_mod *mod = &ssi->mod; struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); int is_dma = rsnd_ssi_is_dma_mode(mod); u32 status = rsnd_mod_read(mod, SSISR); if (!io) return IRQ_NONE; /* PIO only */ if (!is_dma && (status & DIRQ)) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 *buf = (u32 *)(runtime->dma_area + rsnd_dai_pointer_offset(io, 0)); /* * 8/16/32 data can be assesse to TDR/RDR register * directly as 32bit data * see rsnd_ssi_init() */ if (rsnd_io_is_play(io)) rsnd_mod_write(mod, SSITDR, *buf); else *buf = rsnd_mod_read(mod, SSIRDR); rsnd_dai_pointer_update(io, sizeof(*buf)); } /* PIO / DMA */ if (status & (UIRQ | OIRQ)) { struct device *dev = rsnd_priv_to_dev(priv); /* * restart SSI */ dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); rsnd_ssi_stop(mod, priv); if (ssi->err < 1024) rsnd_ssi_start(mod, priv); else dev_warn(dev, "no more SSI restart\n"); } rsnd_ssi_record_error(ssi, status); return IRQ_HANDLED; }
static int rsnd_ssi_stop(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); rsnd_src_ssi_irq_disable(mod); rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); rsnd_ssi_hw_stop(ssi); rsnd_src_ssiu_stop(mod); return 0; }
static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); ssi->cr_etc = 0; rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); rsnd_ssi_hw_stop(ssi, rdai); rsnd_dma_stop(dma); return 0; }