Loading sound/soc/sh/Kconfig +2 −1 Original line number Diff line number Diff line menu "SoC Audio support for SuperH" depends on SUPERH || ARCH_SHMOBILE depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST config SND_SOC_PCM_SH7760 tristate "SoC Audio support for Renesas SH7760" Loading Loading @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK depends on OF || COMPILE_TEST select SND_SIMPLE_CARD select REGMAP_MMIO help Loading sound/soc/sh/rcar/adg.c +37 −24 Original line number Diff line number Diff line Loading @@ -34,6 +34,9 @@ struct rsnd_adg { struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags; u32 ckr; u32 rbga; u32 rbgb; int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */ Loading Loading @@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; u32 data; u32 ckr = 0; int sel_table[] = { [CLKA] = 0x1, [CLKB] = 0x2, Loading Loading @@ -360,15 +365,14 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) rsnd_adg_set_ssi_clk(ssi_mod, data); if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { struct rsnd_mod *adg_mod = rsnd_mod_get(adg); u32 ckr = 0; if (0 == (rate % 8000)) ckr = 0x80000000; rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr); } rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr); rsnd_mod_write(adg_mod, BRRA, adg->rbga); rsnd_mod_write(adg_mod, BRRB, adg->rbgb); dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), data, rate); Loading @@ -376,6 +380,25 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) return 0; } void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; int i, ret; for_each_rsnd_clk(clk, adg, i) { ret = 0; if (enable) ret = clk_prepare_enable(clk); else clk_disable_unprepare(clk); if (ret < 0) dev_warn(dev, "can't use clk %d\n", i); } } static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { Loading @@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; int i, ret; int i; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; } for_each_rsnd_clk(clk, adg, i) { ret = clk_prepare_enable(clk); if (ret < 0) dev_warn(dev, "can't use clk %d\n", i); for_each_rsnd_clk(clk, adg, i) dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); } } static void rsnd_adg_get_clkout(struct rsnd_priv *priv, struct rsnd_adg *adg) { struct clk *clk; struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; u32 ckr, rbgx, rbga, rbgb; Loading Loading @@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } } rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); rsnd_mod_write(adg_mod, BRRA, rbga); rsnd_mod_write(adg_mod, BRRB, rbgb); adg->ckr = ckr; adg->rbga = rbga; adg->rbgb = rbgb; for_each_rsnd_clkout(clk, adg, i) dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", ckr, rbga, rbgb); } Loading @@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv) priv->adg = adg; rsnd_adg_clk_enable(priv); return 0; } void rsnd_adg_remove(struct rsnd_priv *priv) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct clk *clk; int i; for_each_rsnd_clk(clk, adg, i) { clk_disable_unprepare(clk); } rsnd_adg_clk_disable(priv); } sound/soc/sh/rcar/core.c +128 −47 Original line number Diff line number Diff line Loading @@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; Loading @@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (rsnd_io_is_play(io)) { struct rsnd_mod *src = rsnd_io_to_mod_src(io); target = src ? src : ssi; target = src ? src : ssiu; } else { struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); target = cmd ? cmd : ssi; target = cmd ? cmd : ssiu; } mask <<= runtime->channels * 4; Loading Loading @@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ #define rsnd_mod_call(idx, io, func, param...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ struct rsnd_mod *mod = (io)->mod[idx]; \ struct device *dev = rsnd_priv_to_dev(priv); \ u32 *status = mod->get_status(io, mod, idx); \ u32 mask = 0xF << __rsnd_mod_shift_##func; \ u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ int ret = 0; \ int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ if (add == 0xF) \ call = 0; \ else \ *status = (*status & ~mask) + \ (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ *status, call ? #func : ""); \ if (call) \ ret = (mod)->ops->func(mod, io, param); \ if (ret) \ dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ ret; \ }) struct rsnd_mod *rsnd_mod_next(int *iterator, struct rsnd_dai_stream *io, enum rsnd_mod_type *array, int array_size) { struct rsnd_mod *mod; enum rsnd_mod_type type; int max = array ? array_size : RSND_MOD_MAX; for (; *iterator < max; (*iterator)++) { type = (array) ? array[*iterator] : *iterator; mod = io->mod[type]; if (!mod) continue; (*iterator)++; return mod; } return NULL; } static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { { Loading Loading @@ -409,17 +405,47 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, }; static int rsnd_status_update(u32 *status, int shift, int add, int timing) { u32 mask = 0xF << shift; u8 val = (*status >> shift) & 0xF; u8 next_val = (val + add) & 0xF; int func_call = (val == timing); if (next_val == 0xF) /* underflow case */ func_call = 0; else *status = (*status & ~mask) + (next_val << shift); return func_call; } #define rsnd_dai_call(fn, io, param...) \ ({ \ struct rsnd_priv *priv = rsnd_io_to_priv(io); \ struct device *dev = rsnd_priv_to_dev(priv); \ struct rsnd_mod *mod; \ int type, is_play = rsnd_io_is_play(io); \ int is_play = rsnd_io_is_play(io); \ int ret = 0, i; \ for (i = 0; i < RSND_MOD_MAX; i++) { \ type = rsnd_mod_sequence[is_play][i]; \ mod = (io)->mod[type]; \ if (!mod) \ continue; \ ret |= rsnd_mod_call(type, io, fn, param); \ enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ int tmp = 0; \ u32 *status = mod->get_status(io, mod, types[i]); \ int func_call = rsnd_status_update(status, \ __rsnd_mod_shift_##fn, \ __rsnd_mod_add_##fn, \ __rsnd_mod_call_##fn); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ (func_call && (mod)->ops->fn) ? #fn : ""); \ if (func_call && (mod)->ops->fn) \ tmp = (mod)->ops->fn(mod, io, param); \ if (tmp) \ dev_err(dev, "%s[%d] : %s error %d\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ #fn, tmp); \ ret |= tmp; \ } \ ret; \ }) Loading Loading @@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); /* * call rsnd_dai_call without spinlock */ return rsnd_dai_call(nolock_start, io, priv); } static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); /* * call rsnd_dai_call without spinlock */ rsnd_dai_call(nolock_stop, io, priv); } static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .startup = rsnd_soc_dai_startup, .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, Loading Loading @@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) { if (cfg->card && cfg->kctrl) snd_ctl_remove(cfg->card, cfg->kctrl); cfg->card = NULL; cfg->kctrl = NULL; } int rsnd_kctrl_new_m(struct rsnd_mod *mod, Loading Loading @@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, SNDRV_DMA_TYPE_DEV, rtd->card->snd_card->dev, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } Loading @@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *mod; int i; /* Loading @@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, * remove all mod from io * and, re connect ssi */ for (i = 0; i < RSND_MOD_MAX; i++) rsnd_dai_disconnect((io)->mod[i], io, i); for_each_rsnd_mod(i, mod, io) rsnd_dai_disconnect(mod, io, i); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* Loading Loading @@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev) return ret; } static int rsnd_suspend(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); rsnd_adg_clk_disable(priv); return 0; } static int rsnd_resume(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); rsnd_adg_clk_enable(priv); return 0; } static struct dev_pm_ops rsnd_pm_ops = { .suspend = rsnd_suspend, .resume = rsnd_resume, }; static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", .pm = &rsnd_pm_ops, .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, Loading sound/soc/sh/rcar/dma.c +195 −100 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ struct rsnd_dmaen { struct dma_chan *chan; dma_addr_t dma_buf; unsigned int dma_len; unsigned int dma_period; unsigned int dma_cnt; }; struct rsnd_dmapp { Loading @@ -34,6 +38,8 @@ struct rsnd_dmapp { struct rsnd_dma { struct rsnd_mod mod; struct rsnd_mod *mod_from; struct rsnd_mod *mod_to; dma_addr_t src_addr; dma_addr_t dst_addr; union { Loading @@ -56,10 +62,38 @@ struct rsnd_dma_ctrl { /* * Audio DMAC */ #define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) #define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, int i, int sync) { struct device *dev = dmaen->chan->device->dev; enum dma_data_direction dir; int is_play = rsnd_io_is_play(io); dma_addr_t buf; int len, max; size_t period; len = dmaen->dma_len; period = dmaen->dma_period; max = len / period; i = i % max; buf = dmaen->dma_buf + (period * i); dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; if (sync) dma_sync_single_for_device(dev, buf, period, dir); else dma_sync_single_for_cpu(dev, buf, period, dir); } static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); bool elapsed = false; unsigned long flags; Loading @@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ spin_lock_irqsave(&priv->lock, flags); if (rsnd_io_is_working(io)) if (rsnd_io_is_working(io)) { rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); /* * Next period is already started. * Let's sync Next Next period * see * rsnd_dmaen_start() */ rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); dmaen->dma_cnt++; } spin_unlock_irqrestore(&priv->lock, flags); if (elapsed) Loading @@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { if ((!mod_from && !mod_to) || (mod_from && mod_to)) return NULL; if (mod_from) return rsnd_mod_dma_req(io, mod_from); else return rsnd_mod_dma_req(io, mod_to); } static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) Loading @@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); if (dmaen->chan) { int is_play = rsnd_io_is_play(io); dmaengine_terminate_all(dmaen->chan); dma_unmap_single(dmaen->chan->device->dev, dmaen->dma_buf, dmaen->dma_len, is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } return 0; } static int rsnd_dmaen_nolock_stop(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); /* * DMAEngine release uses mutex lock. * Thus, it shouldn't be called under spinlock. * Let's call it under nolock_start */ if (dmaen->chan) dma_release_channel(dmaen->chan); dmaen->chan = NULL; return 0; } static int rsnd_dmaen_nolock_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 device *dev = rsnd_priv_to_dev(priv); if (dmaen->chan) { dev_err(dev, "it already has dma channel\n"); return -EIO; } /* * DMAEngine request uses mutex lock. * Thus, it shouldn't be called under spinlock. * Let's call it under nolock_start */ dmaen->chan = rsnd_dmaen_request_channel(io, dma->mod_from, dma->mod_to); if (IS_ERR_OR_NULL(dmaen->chan)) { int ret = PTR_ERR(dmaen->chan); dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); return ret; } return 0; } Loading @@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; dma_addr_t buf; size_t len; size_t period; int is_play = rsnd_io_is_play(io); int i; int ret; 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, "%s[%d] %pad -> %pad\n", rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) return ret; len = snd_pcm_lib_buffer_bytes(substream); period = snd_pcm_lib_period_bytes(substream); buf = dma_map_single(dmaen->chan->device->dev, substream->runtime->dma_area, len, is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_mapping_error(dmaen->chan->device->dev, buf)) { dev_err(dev, "dma map failed\n"); return -EIO; } desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), buf, len, period, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); Loading @@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma); dmaen->dma_buf = buf; dmaen->dma_len = len; dmaen->dma_period = period; dmaen->dma_cnt = 0; /* * synchronize this and next period * see * __rsnd_dmaen_complete() */ for (i = 0; i < 2; i++) rsnd_dmaen_sync(dmaen, io, i); if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO; Loading @@ -143,110 +305,33 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name) { struct dma_chan *chan; struct dma_chan *chan = NULL; struct device_node *np; int i = 0; for_each_child_of_node(of_node, np) { if (i == rsnd_mod_id(mod)) break; if (i == rsnd_mod_id(mod) && (!chan)) chan = of_dma_request_slave_channel(np, name); i++; } chan = of_dma_request_slave_channel(np, name); of_node_put(np); /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ of_node_put(of_node); return chan; } static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { if ((!mod_from && !mod_to) || (mod_from && mod_to)) return NULL; if (mod_from) return rsnd_mod_dma_req(io, mod_from); else return rsnd_mod_dma_req(io, mod_to); } static int rsnd_dmaen_remove(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); if (dmaen->chan) dma_release_channel(dmaen->chan); dmaen->chan = NULL; return 0; } static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 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 *)(uintptr_t)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, "%s[%d] %pad -> %pad\n", rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) goto rsnd_dma_attach_err; dmac->dmaen_num++; return 0; rsnd_dma_attach_err: rsnd_dmaen_remove(mod, io, priv); rsnd_dma_channel_err: struct dma_chan *chan; /* try to get DMAEngine channel */ chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); if (IS_ERR_OR_NULL(chan)) { /* * DMA failed. try to PIO mode * see Loading @@ -256,11 +341,19 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return -EAGAIN; } dma_release_channel(chan); dmac->dmaen_num++; return 0; } static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", .nolock_start = rsnd_dmaen_nolock_start, .nolock_stop = rsnd_dmaen_nolock_stop, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, .remove = rsnd_dmaen_remove, }; /* Loading Loading @@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, } static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); Loading Loading @@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id) struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; Loading @@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret, dma_id; Loading Loading @@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, *dma_mod = rsnd_mod_get(dma); dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, rsnd_mod_get_status, type, dma_id); if (ret < 0) Loading @@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); ret = attach(io, dma, id, mod_from, mod_to); ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); dma->mod_from = mod_from; dma->mod_to = mod_to; } ret = rsnd_dai_connect(*dma_mod, io, type); Loading sound/soc/sh/rcar/dvc.c +0 −2 Original line number Diff line number Diff line Loading @@ -48,8 +48,6 @@ struct rsnd_dvc { #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") #define rsnd_mod_to_dvc(_mod) \ container_of((_mod), struct rsnd_dvc, mod) Loading Loading
sound/soc/sh/Kconfig +2 −1 Original line number Diff line number Diff line menu "SoC Audio support for SuperH" depends on SUPERH || ARCH_SHMOBILE depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST config SND_SOC_PCM_SH7760 tristate "SoC Audio support for Renesas SH7760" Loading Loading @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK depends on OF || COMPILE_TEST select SND_SIMPLE_CARD select REGMAP_MMIO help Loading
sound/soc/sh/rcar/adg.c +37 −24 Original line number Diff line number Diff line Loading @@ -34,6 +34,9 @@ struct rsnd_adg { struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags; u32 ckr; u32 rbga; u32 rbgb; int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */ Loading Loading @@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; u32 data; u32 ckr = 0; int sel_table[] = { [CLKA] = 0x1, [CLKB] = 0x2, Loading Loading @@ -360,15 +365,14 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) rsnd_adg_set_ssi_clk(ssi_mod, data); if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { struct rsnd_mod *adg_mod = rsnd_mod_get(adg); u32 ckr = 0; if (0 == (rate % 8000)) ckr = 0x80000000; rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr); } rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr); rsnd_mod_write(adg_mod, BRRA, adg->rbga); rsnd_mod_write(adg_mod, BRRB, adg->rbgb); dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), data, rate); Loading @@ -376,6 +380,25 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) return 0; } void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; int i, ret; for_each_rsnd_clk(clk, adg, i) { ret = 0; if (enable) ret = clk_prepare_enable(clk); else clk_disable_unprepare(clk); if (ret < 0) dev_warn(dev, "can't use clk %d\n", i); } } static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { Loading @@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; int i, ret; int i; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; } for_each_rsnd_clk(clk, adg, i) { ret = clk_prepare_enable(clk); if (ret < 0) dev_warn(dev, "can't use clk %d\n", i); for_each_rsnd_clk(clk, adg, i) dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); } } static void rsnd_adg_get_clkout(struct rsnd_priv *priv, struct rsnd_adg *adg) { struct clk *clk; struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; u32 ckr, rbgx, rbga, rbgb; Loading Loading @@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } } rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); rsnd_mod_write(adg_mod, BRRA, rbga); rsnd_mod_write(adg_mod, BRRB, rbgb); adg->ckr = ckr; adg->rbga = rbga; adg->rbgb = rbgb; for_each_rsnd_clkout(clk, adg, i) dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", ckr, rbga, rbgb); } Loading @@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv) priv->adg = adg; rsnd_adg_clk_enable(priv); return 0; } void rsnd_adg_remove(struct rsnd_priv *priv) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct clk *clk; int i; for_each_rsnd_clk(clk, adg, i) { clk_disable_unprepare(clk); } rsnd_adg_clk_disable(priv); }
sound/soc/sh/rcar/core.c +128 −47 Original line number Diff line number Diff line Loading @@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; Loading @@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (rsnd_io_is_play(io)) { struct rsnd_mod *src = rsnd_io_to_mod_src(io); target = src ? src : ssi; target = src ? src : ssiu; } else { struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); target = cmd ? cmd : ssi; target = cmd ? cmd : ssiu; } mask <<= runtime->channels * 4; Loading Loading @@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ #define rsnd_mod_call(idx, io, func, param...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ struct rsnd_mod *mod = (io)->mod[idx]; \ struct device *dev = rsnd_priv_to_dev(priv); \ u32 *status = mod->get_status(io, mod, idx); \ u32 mask = 0xF << __rsnd_mod_shift_##func; \ u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ int ret = 0; \ int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ if (add == 0xF) \ call = 0; \ else \ *status = (*status & ~mask) + \ (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ *status, call ? #func : ""); \ if (call) \ ret = (mod)->ops->func(mod, io, param); \ if (ret) \ dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ ret; \ }) struct rsnd_mod *rsnd_mod_next(int *iterator, struct rsnd_dai_stream *io, enum rsnd_mod_type *array, int array_size) { struct rsnd_mod *mod; enum rsnd_mod_type type; int max = array ? array_size : RSND_MOD_MAX; for (; *iterator < max; (*iterator)++) { type = (array) ? array[*iterator] : *iterator; mod = io->mod[type]; if (!mod) continue; (*iterator)++; return mod; } return NULL; } static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { { Loading Loading @@ -409,17 +405,47 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, }; static int rsnd_status_update(u32 *status, int shift, int add, int timing) { u32 mask = 0xF << shift; u8 val = (*status >> shift) & 0xF; u8 next_val = (val + add) & 0xF; int func_call = (val == timing); if (next_val == 0xF) /* underflow case */ func_call = 0; else *status = (*status & ~mask) + (next_val << shift); return func_call; } #define rsnd_dai_call(fn, io, param...) \ ({ \ struct rsnd_priv *priv = rsnd_io_to_priv(io); \ struct device *dev = rsnd_priv_to_dev(priv); \ struct rsnd_mod *mod; \ int type, is_play = rsnd_io_is_play(io); \ int is_play = rsnd_io_is_play(io); \ int ret = 0, i; \ for (i = 0; i < RSND_MOD_MAX; i++) { \ type = rsnd_mod_sequence[is_play][i]; \ mod = (io)->mod[type]; \ if (!mod) \ continue; \ ret |= rsnd_mod_call(type, io, fn, param); \ enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ int tmp = 0; \ u32 *status = mod->get_status(io, mod, types[i]); \ int func_call = rsnd_status_update(status, \ __rsnd_mod_shift_##fn, \ __rsnd_mod_add_##fn, \ __rsnd_mod_call_##fn); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ (func_call && (mod)->ops->fn) ? #fn : ""); \ if (func_call && (mod)->ops->fn) \ tmp = (mod)->ops->fn(mod, io, param); \ if (tmp) \ dev_err(dev, "%s[%d] : %s error %d\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ #fn, tmp); \ ret |= tmp; \ } \ ret; \ }) Loading Loading @@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); /* * call rsnd_dai_call without spinlock */ return rsnd_dai_call(nolock_start, io, priv); } static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); /* * call rsnd_dai_call without spinlock */ rsnd_dai_call(nolock_stop, io, priv); } static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .startup = rsnd_soc_dai_startup, .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, Loading Loading @@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) { if (cfg->card && cfg->kctrl) snd_ctl_remove(cfg->card, cfg->kctrl); cfg->card = NULL; cfg->kctrl = NULL; } int rsnd_kctrl_new_m(struct rsnd_mod *mod, Loading Loading @@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, SNDRV_DMA_TYPE_DEV, rtd->card->snd_card->dev, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } Loading @@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *mod; int i; /* Loading @@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, * remove all mod from io * and, re connect ssi */ for (i = 0; i < RSND_MOD_MAX; i++) rsnd_dai_disconnect((io)->mod[i], io, i); for_each_rsnd_mod(i, mod, io) rsnd_dai_disconnect(mod, io, i); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* Loading Loading @@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev) return ret; } static int rsnd_suspend(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); rsnd_adg_clk_disable(priv); return 0; } static int rsnd_resume(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); rsnd_adg_clk_enable(priv); return 0; } static struct dev_pm_ops rsnd_pm_ops = { .suspend = rsnd_suspend, .resume = rsnd_resume, }; static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", .pm = &rsnd_pm_ops, .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, Loading
sound/soc/sh/rcar/dma.c +195 −100 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ struct rsnd_dmaen { struct dma_chan *chan; dma_addr_t dma_buf; unsigned int dma_len; unsigned int dma_period; unsigned int dma_cnt; }; struct rsnd_dmapp { Loading @@ -34,6 +38,8 @@ struct rsnd_dmapp { struct rsnd_dma { struct rsnd_mod mod; struct rsnd_mod *mod_from; struct rsnd_mod *mod_to; dma_addr_t src_addr; dma_addr_t dst_addr; union { Loading @@ -56,10 +62,38 @@ struct rsnd_dma_ctrl { /* * Audio DMAC */ #define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) #define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, int i, int sync) { struct device *dev = dmaen->chan->device->dev; enum dma_data_direction dir; int is_play = rsnd_io_is_play(io); dma_addr_t buf; int len, max; size_t period; len = dmaen->dma_len; period = dmaen->dma_period; max = len / period; i = i % max; buf = dmaen->dma_buf + (period * i); dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; if (sync) dma_sync_single_for_device(dev, buf, period, dir); else dma_sync_single_for_cpu(dev, buf, period, dir); } static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); bool elapsed = false; unsigned long flags; Loading @@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ spin_lock_irqsave(&priv->lock, flags); if (rsnd_io_is_working(io)) if (rsnd_io_is_working(io)) { rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); /* * Next period is already started. * Let's sync Next Next period * see * rsnd_dmaen_start() */ rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); dmaen->dma_cnt++; } spin_unlock_irqrestore(&priv->lock, flags); if (elapsed) Loading @@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { if ((!mod_from && !mod_to) || (mod_from && mod_to)) return NULL; if (mod_from) return rsnd_mod_dma_req(io, mod_from); else return rsnd_mod_dma_req(io, mod_to); } static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) Loading @@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); if (dmaen->chan) { int is_play = rsnd_io_is_play(io); dmaengine_terminate_all(dmaen->chan); dma_unmap_single(dmaen->chan->device->dev, dmaen->dma_buf, dmaen->dma_len, is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } return 0; } static int rsnd_dmaen_nolock_stop(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); /* * DMAEngine release uses mutex lock. * Thus, it shouldn't be called under spinlock. * Let's call it under nolock_start */ if (dmaen->chan) dma_release_channel(dmaen->chan); dmaen->chan = NULL; return 0; } static int rsnd_dmaen_nolock_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 device *dev = rsnd_priv_to_dev(priv); if (dmaen->chan) { dev_err(dev, "it already has dma channel\n"); return -EIO; } /* * DMAEngine request uses mutex lock. * Thus, it shouldn't be called under spinlock. * Let's call it under nolock_start */ dmaen->chan = rsnd_dmaen_request_channel(io, dma->mod_from, dma->mod_to); if (IS_ERR_OR_NULL(dmaen->chan)) { int ret = PTR_ERR(dmaen->chan); dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); return ret; } return 0; } Loading @@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; dma_addr_t buf; size_t len; size_t period; int is_play = rsnd_io_is_play(io); int i; int ret; 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, "%s[%d] %pad -> %pad\n", rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) return ret; len = snd_pcm_lib_buffer_bytes(substream); period = snd_pcm_lib_period_bytes(substream); buf = dma_map_single(dmaen->chan->device->dev, substream->runtime->dma_area, len, is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_mapping_error(dmaen->chan->device->dev, buf)) { dev_err(dev, "dma map failed\n"); return -EIO; } desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), buf, len, period, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); Loading @@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma); dmaen->dma_buf = buf; dmaen->dma_len = len; dmaen->dma_period = period; dmaen->dma_cnt = 0; /* * synchronize this and next period * see * __rsnd_dmaen_complete() */ for (i = 0; i < 2; i++) rsnd_dmaen_sync(dmaen, io, i); if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO; Loading @@ -143,110 +305,33 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name) { struct dma_chan *chan; struct dma_chan *chan = NULL; struct device_node *np; int i = 0; for_each_child_of_node(of_node, np) { if (i == rsnd_mod_id(mod)) break; if (i == rsnd_mod_id(mod) && (!chan)) chan = of_dma_request_slave_channel(np, name); i++; } chan = of_dma_request_slave_channel(np, name); of_node_put(np); /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ of_node_put(of_node); return chan; } static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { if ((!mod_from && !mod_to) || (mod_from && mod_to)) return NULL; if (mod_from) return rsnd_mod_dma_req(io, mod_from); else return rsnd_mod_dma_req(io, mod_to); } static int rsnd_dmaen_remove(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); if (dmaen->chan) dma_release_channel(dmaen->chan); dmaen->chan = NULL; return 0; } static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 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 *)(uintptr_t)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, "%s[%d] %pad -> %pad\n", rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) goto rsnd_dma_attach_err; dmac->dmaen_num++; return 0; rsnd_dma_attach_err: rsnd_dmaen_remove(mod, io, priv); rsnd_dma_channel_err: struct dma_chan *chan; /* try to get DMAEngine channel */ chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); if (IS_ERR_OR_NULL(chan)) { /* * DMA failed. try to PIO mode * see Loading @@ -256,11 +341,19 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return -EAGAIN; } dma_release_channel(chan); dmac->dmaen_num++; return 0; } static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", .nolock_start = rsnd_dmaen_nolock_start, .nolock_stop = rsnd_dmaen_nolock_stop, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, .remove = rsnd_dmaen_remove, }; /* Loading Loading @@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, } static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); Loading Loading @@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id) struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; Loading @@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret, dma_id; Loading Loading @@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, *dma_mod = rsnd_mod_get(dma); dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, rsnd_mod_get_status, type, dma_id); if (ret < 0) Loading @@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); ret = attach(io, dma, id, mod_from, mod_to); ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); dma->mod_from = mod_from; dma->mod_to = mod_to; } ret = rsnd_dai_connect(*dma_mod, io, type); Loading
sound/soc/sh/rcar/dvc.c +0 −2 Original line number Diff line number Diff line Loading @@ -48,8 +48,6 @@ struct rsnd_dvc { #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") #define rsnd_mod_to_dvc(_mod) \ container_of((_mod), struct rsnd_dvc, mod) Loading