static int rsnd_dmaen_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; int is_play = rsnd_io_is_play(io); desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); return -EIO; } desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma); if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO; } dma_async_issue_pending(dmaen->chan); return 0; }
static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { int ret; ret = rsnd_ssiu_init(mod, io, priv); if (ret < 0) return ret; if (rsnd_runtime_is_ssi_tdm(io)) { /* * TDM Extend Mode * see * rsnd_ssi_config_init() */ rsnd_mod_write(mod, SSI_MODE, 0x1); } if (rsnd_ssi_use_busif(io)) { rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(mod, io) | (rsnd_io_is_play(io) ? rsnd_runtime_channel_after_ctu(io) : rsnd_runtime_channel_original(io))); rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(mod, SSI_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); } return 0; }
int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) { struct rsnd_mod *mod_from; struct rsnd_mod *mod_to; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); int is_play = rsnd_io_is_play(io); /* * DMA failed. try to PIO mode * see * rsnd_ssi_fallback() * rsnd_rdai_continuance_probe() */ if (!dmac) return -EAGAIN; rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); /* for Gen2 */ if (mod_from && mod_to) dma->ops = &rsnd_dmapp_ops; else dma->ops = &rsnd_dmaen_ops; /* for Gen1, overwrite */ if (rsnd_is_gen1(priv)) dma->ops = &rsnd_dmaen_ops; return dma->ops->init(io, dma, id, mod_from, mod_to); }
static int rsnd_dmaen_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg = {}; int is_play = rsnd_io_is_play(io); int ret; if (dmaen->chan) { dev_err(dev, "it already has dma channel\n"); return -EIO; } if (dev->of_node) { dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); } else { dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dmaen->chan = dma_request_channel(mask, shdma_chan_filter, (void *)id); } if (IS_ERR_OR_NULL(dmaen->chan)) { dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); goto rsnd_dma_channel_err; } cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; cfg.src_addr = dma->src_addr; cfg.dst_addr = dma->dst_addr; cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; dev_dbg(dev, "dma : %pad -> %pad\n", &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) goto rsnd_dma_init_err; return 0; rsnd_dma_init_err: rsnd_dma_quit(io, dma); rsnd_dma_channel_err: /* * DMA failed. try to PIO mode * see * rsnd_ssi_fallback() * rsnd_rdai_continuance_probe() */ return -EAGAIN; }
static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); int is_play = rsnd_io_is_play(io); int slots = rsnd_get_slot(io); int ret; /* Volume */ ret = rsnd_kctrl_new_m(mod, io, rtd, is_play ? "DVC Out Playback Volume" : "DVC In Capture Volume", rsnd_dvc_volume_update, &dvc->volume, slots, 0x00800000 - 1); if (ret < 0) return ret; /* Mute */ ret = rsnd_kctrl_new_m(mod, io, rtd, is_play ? "DVC Out Mute Switch" : "DVC In Mute Switch", rsnd_dvc_volume_update, &dvc->mute, slots, 1); if (ret < 0) return ret; /* Ramp */ ret = rsnd_kctrl_new_s(mod, io, rtd, is_play ? "DVC Out Ramp Switch" : "DVC In Ramp Switch", rsnd_dvc_volume_update, &dvc->ren, 1); if (ret < 0) return ret; ret = rsnd_kctrl_new_e(mod, io, rtd, is_play ? "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", &dvc->rup, rsnd_dvc_volume_update, dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); if (ret < 0) return ret; ret = rsnd_kctrl_new_e(mod, io, rtd, is_play ? "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", &dvc->rdown, rsnd_dvc_volume_update, dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); if (ret < 0) return ret; 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 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); }
/* * SSI mod common functions */ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 cr; cr = FORCE; /* * always use 32bit system word for easy clock calculation. * see also rsnd_ssi_master_clk_enable() */ cr |= SWL_32; /* * init clock settings for SSICR */ switch (runtime->sample_bits) { case 16: cr |= DWL_16; break; case 32: cr |= DWL_24; break; default: return -EIO; } if (rdai->bit_clk_inv) cr |= SCKP; if (rdai->frm_clk_inv) cr |= SWSP; if (rdai->data_alignment) cr |= SDTA; if (rdai->sys_delay) cr |= DEL; if (rsnd_io_is_play(io)) cr |= TRMD; /* * set ssi parameter */ ssi->cr_own = cr; ssi->err = -1; /* ignore 1st error */ return 0; }
static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod, struct rsnd_dai_stream *io, u32 timsel) { struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); int is_play = rsnd_io_is_play(io); int id = rsnd_mod_id(src_mod); int shift = (id % 2) ? 16 : 0; u32 mask, ws; u32 in, out; rsnd_mod_confirm_src(src_mod); ws = rsnd_adg_ssi_ws_timing_gen2(io); in = (is_play) ? timsel : ws; out = (is_play) ? ws : timsel; in = in << shift; out = out << shift; mask = 0xffff << shift; switch (id / 2) { case 0: rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0, mask, in); rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out); break; case 1: rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1, mask, in); rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out); break; case 2: rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2, mask, in); rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out); break; case 3: rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3, mask, in); rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out); break; case 4: rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4, mask, in); rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out); break; } return 0; }
static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_mod *mod) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); int is_play = rsnd_io_is_play(io); char *name; if (rsnd_ssi_use_busif(mod)) name = is_play ? "rxu" : "txu"; else name = is_play ? "rx" : "tx"; return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), mod, name); }
/* * Gen1 functions */ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod) { struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct src_route_config { u32 mask; int shift; } routes[] = { { 0xF, 0, }, /* 0 */ { 0xF, 4, }, /* 1 */ { 0xF, 8, }, /* 2 */ { 0x7, 12, }, /* 3 */ { 0x7, 16, }, /* 4 */ { 0x7, 20, }, /* 5 */ { 0x7, 24, }, /* 6 */ { 0x3, 28, }, /* 7 */ { 0x3, 30, }, /* 8 */ }; u32 mask; u32 val; int id; id = rsnd_mod_id(mod); if (id < 0 || id >= ARRAY_SIZE(routes)) return -EIO; /* * SRC_ROUTE_SELECT */ val = rsnd_io_is_play(io) ? 0x1 : 0x2; val = val << routes[id].shift; mask = routes[id].mask << routes[id].shift; rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); return 0; }
static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { int hdmi = rsnd_ssi_hdmi_port(io); int ret; u32 mode = 0; ret = rsnd_ssiu_init(mod, io, priv); if (ret < 0) return ret; if (rsnd_runtime_is_ssi_tdm(io)) { /* * TDM Extend Mode * see * rsnd_ssi_config_init() */ mode = 0x1; } rsnd_mod_write(mod, SSI_MODE, mode); if (rsnd_ssi_use_busif(io)) { rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(mod, io) | (rsnd_io_is_play(io) ? rsnd_runtime_channel_after_ctu(io) : rsnd_runtime_channel_original(io))); rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1); rsnd_mod_write(mod, SSI_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); } if (hdmi) { enum rsnd_mod_type rsnd_ssi_array[] = { RSND_MOD_SSIM1, RSND_MOD_SSIM2, RSND_MOD_SSIM3, }; struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *pos; u32 val; int i, shift; i = rsnd_mod_id(ssi_mod); /* output all same SSI as default */ val = i << 16 | i << 20 | i << 24 | i << 28 | i; for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { shift = (i * 4) + 16; val = (val & ~(0xF << shift)) | rsnd_mod_id(pos) << shift; } switch (hdmi) { case RSND_SSI_HDMI_PORT0: rsnd_mod_write(mod, HDMI0_SEL, val); break; case RSND_SSI_HDMI_PORT1: rsnd_mod_write(mod, HDMI1_SEL, val); break; } }
static void rsnd_ssi_config_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); u32 cr_own; u32 cr_mode; u32 wsr; int is_tdm; is_tdm = rsnd_runtime_is_ssi_tdm(io); /* * always use 32bit system word. * see also rsnd_ssi_master_clk_enable() */ cr_own = FORCE | SWL_32 | PDTA; if (rdai->bit_clk_inv) cr_own |= SCKP; if (rdai->frm_clk_inv ^ is_tdm) cr_own |= SWSP; if (rdai->data_alignment) cr_own |= SDTA; if (rdai->sys_delay) cr_own |= DEL; if (rsnd_io_is_play(io)) cr_own |= TRMD; switch (runtime->sample_bits) { case 16: cr_own |= DWL_16; break; case 32: cr_own |= DWL_24; break; } if (rsnd_ssi_is_dma_mode(mod)) { cr_mode = UIEN | OIEN | /* over/under run */ DMEN; /* DMA : enable DMA */ } else { cr_mode = DIEN; /* PIO : enable Data interrupt */ } /* * TDM Extend Mode * see * rsnd_ssiu_init_gen2() */ wsr = ssi->wsr; if (is_tdm) { wsr |= WS_MODE; cr_own |= CHNL_8; } ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; ssi->wsr = wsr; }
static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_io_to_priv(io); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); int chan = rsnd_runtime_channel_for_ssi(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, }; unsigned int main_rate; unsigned int rate = rsnd_io_is_play(io) ? rsnd_src_get_out_rate(priv, io) : rsnd_src_get_in_rate(priv, io); if (!rsnd_rdai_is_clk_master(rdai)) return 0; if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) return 0; if (rsnd_ssi_is_multi_slave(mod, io)) return 0; if (ssi->usrcnt > 1) { if (ssi->rate != rate) { dev_err(dev, "SSI parent/child should use same rate\n"); return -EINVAL; } return 0; } /* * Find best clock, and try to start ADG */ for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { /* * this driver is assuming that * system word is 32bit x chan * see rsnd_ssi_init() */ main_rate = rate * 32 * chan * ssi_clk_mul_table[j]; ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); if (0 == ret) { ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(j); ssi->wsr = CONT; ssi->rate = rate; dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), rsnd_mod_id(mod), rate); return 0; } } dev_err(dev, "unsupported clock rate\n"); return -EIO; }