/* * 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 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 bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) { u32 val = OUF_SRC(rsnd_mod_id(mod)); bool ret = false; if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) || (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) { struct rsnd_src *src = rsnd_mod_to_src(mod); src->err++; ret = true; } /* clear error static */ rsnd_src_error_clear_gen2(mod); return ret; }
/* * Gen2 functions */ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) { int ret; ret = rsnd_src_set_convert_rate(mod, rdai, io); if (ret < 0) return ret; rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR)); rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_mod_read(mod, SRC_BUSIF_MODE)); rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); rsnd_mod_write(mod, SRC_BSISR, 0x00100060); return 0; }
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 void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); int is_dma = rsnd_ssi_is_dma_mode(mod); u32 status; bool elapsed = false; bool stop = false; spin_lock(&priv->lock); /* ignore all cases if not working */ if (!rsnd_io_is_working(io)) goto rsnd_ssi_interrupt_out; status = rsnd_ssi_status_get(mod); /* 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); elapsed = rsnd_dai_pointer_update(io, sizeof(*buf)); } /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) stop = true; rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: spin_unlock(&priv->lock); if (elapsed) rsnd_dai_period_elapsed(io); if (stop) snd_pcm_stop_xrun(io->substream); }
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; }
static void rsnd_ssi_status_check(struct rsnd_mod *mod, u32 bit) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); u32 status; int i; for (i = 0; i < 1024; i++) { status = rsnd_mod_read(mod, SSISR); if (status & bit) return; udelay(50); } dev_warn(dev, "status check failed\n"); }
static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, struct rsnd_dai *rdai) { int ret; ret = rsnd_src_set_convert_rate(mod, rdai); if (ret < 0) return ret; /* Select SRC mode (fixed value) */ rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); /* Set the restriction value of the FS ratio (98%) */ rsnd_mod_write(mod, SRC_MNFSR, rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ return 0; }
static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod) { struct rsnd_src *src = rsnd_mod_to_src(mod); int ret; ret = rsnd_src_set_convert_rate(mod); if (ret < 0) return ret; /* Select SRC mode (fixed value) */ rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); /* Set the restriction value of the FS ratio (98%) */ rsnd_mod_write(mod, SRC_MNFSR, rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); /* Gen1/Gen2 are not compatible */ if (rsnd_src_convert_rate(src)) rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ return 0; }
static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) { return rsnd_mod_read(mod, SSISR); }