Commit 43b64af5 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next

parents 52708d05 b99258a3
menu "SoC Audio support for SuperH" menu "SoC Audio support for SuperH"
depends on SUPERH || ARCH_SHMOBILE depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
config SND_SOC_PCM_SH7760 config SND_SOC_PCM_SH7760
tristate "SoC Audio support for Renesas SH7760" tristate "SoC Audio support for Renesas SH7760"
...@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU ...@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support" tristate "R-Car series SRU/SCU/SSIU/SSI support"
depends on COMMON_CLK depends on COMMON_CLK
depends on OF || COMPILE_TEST
select SND_SIMPLE_CARD select SND_SIMPLE_CARD
select REGMAP_MMIO select REGMAP_MMIO
help help
......
...@@ -34,6 +34,9 @@ struct rsnd_adg { ...@@ -34,6 +34,9 @@ struct rsnd_adg {
struct clk_onecell_data onecell; struct clk_onecell_data onecell;
struct rsnd_mod mod; struct rsnd_mod mod;
u32 flags; u32 flags;
u32 ckr;
u32 rbga;
u32 rbgb;
int rbga_rate_for_441khz; /* RBGA */ int rbga_rate_for_441khz; /* RBGA */
int rbgb_rate_for_48khz; /* RBGB */ int rbgb_rate_for_48khz; /* RBGB */
...@@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ...@@ -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_priv *priv = rsnd_mod_to_priv(ssi_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct clk *clk; struct clk *clk;
int i; int i;
u32 data; u32 data;
u32 ckr = 0;
int sel_table[] = { int sel_table[] = {
[CLKA] = 0x1, [CLKA] = 0x1,
[CLKB] = 0x2, [CLKB] = 0x2,
...@@ -360,15 +365,14 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ...@@ -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); rsnd_adg_set_ssi_clk(ssi_mod, data);
if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) {
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
u32 ckr = 0;
if (0 == (rate % 8000)) if (0 == (rate % 8000))
ckr = 0x80000000; 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", dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
data, rate); data, rate);
...@@ -376,6 +380,25 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ...@@ -376,6 +380,25 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
return 0; 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, static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
struct rsnd_adg *adg) struct rsnd_adg *adg)
{ {
...@@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, ...@@ -387,27 +410,21 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
[CLKC] = "clk_c", [CLKC] = "clk_c",
[CLKI] = "clk_i", [CLKI] = "clk_i",
}; };
int i, ret; int i;
for (i = 0; i < CLKMAX; i++) { for (i = 0; i < CLKMAX; i++) {
clk = devm_clk_get(dev, clk_name[i]); clk = devm_clk_get(dev, clk_name[i]);
adg->clk[i] = IS_ERR(clk) ? NULL : clk; adg->clk[i] = IS_ERR(clk) ? NULL : clk;
} }
for_each_rsnd_clk(clk, adg, i) { 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);
dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
}
} }
static void rsnd_adg_get_clkout(struct rsnd_priv *priv, static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
struct rsnd_adg *adg) struct rsnd_adg *adg)
{ {
struct clk *clk; struct clk *clk;
struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 ckr, rbgx, rbga, rbgb; u32 ckr, rbgx, rbga, rbgb;
...@@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ...@@ -532,13 +549,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
} }
} }
rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); adg->ckr = ckr;
rsnd_mod_write(adg_mod, BRRA, rbga); adg->rbga = rbga;
rsnd_mod_write(adg_mod, BRRB, rbgb); adg->rbgb = rbgb;
for_each_rsnd_clkout(clk, adg, i) for_each_rsnd_clkout(clk, adg, i)
dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); 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); ckr, rbga, rbgb);
} }
...@@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv) ...@@ -565,16 +582,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
priv->adg = adg; priv->adg = adg;
rsnd_adg_clk_enable(priv);
return 0; return 0;
} }
void rsnd_adg_remove(struct rsnd_priv *priv) void rsnd_adg_remove(struct rsnd_priv *priv)
{ {
struct rsnd_adg *adg = rsnd_priv_to_adg(priv); rsnd_adg_clk_disable(priv);
struct clk *clk;
int i;
for_each_rsnd_clk(clk, adg, i) {
clk_disable_unprepare(clk);
}
} }
...@@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ...@@ -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) 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 rsnd_mod *target;
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 val = 0x76543210; u32 val = 0x76543210;
...@@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ...@@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
if (rsnd_io_is_play(io)) { if (rsnd_io_is_play(io)) {
struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io);
target = src ? src : ssi; target = src ? src : ssiu;
} else { } else {
struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
target = cmd ? cmd : ssi; target = cmd ? cmd : ssiu;
} }
mask <<= runtime->channels * 4; mask <<= runtime->channels * 4;
...@@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) ...@@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
/* /*
* rsnd_dai functions * rsnd_dai functions
*/ */
#define rsnd_mod_call(idx, io, func, param...) \ struct rsnd_mod *rsnd_mod_next(int *iterator,
({ \ struct rsnd_dai_stream *io,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ enum rsnd_mod_type *array,
struct rsnd_mod *mod = (io)->mod[idx]; \ int array_size)
struct device *dev = rsnd_priv_to_dev(priv); \ {
u32 *status = mod->get_status(io, mod, idx); \ struct rsnd_mod *mod;
u32 mask = 0xF << __rsnd_mod_shift_##func; \ enum rsnd_mod_type type;
u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ int max = array ? array_size : RSND_MOD_MAX;
u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \
int ret = 0; \ for (; *iterator < max; (*iterator)++) {
int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ type = (array) ? array[*iterator] : *iterator;
if (add == 0xF) \ mod = io->mod[type];
call = 0; \ if (!mod)
else \ continue;
*status = (*status & ~mask) + \
(add << __rsnd_mod_shift_##func); \ (*iterator)++;
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), \ return mod;
*status, call ? #func : ""); \ }
if (call) \
ret = (mod)->ops->func(mod, io, param); \ return NULL;
if (ret) \ }
dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \
ret; \
})
static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
{ {
...@@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { ...@@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
}, },
}; };
#define rsnd_dai_call(fn, io, param...) \ static int rsnd_status_update(u32 *status,
({ \ int shift, int add, int timing)
struct rsnd_mod *mod; \ {
int type, is_play = rsnd_io_is_play(io); \ u32 mask = 0xF << shift;
int ret = 0, i; \ u8 val = (*status >> shift) & 0xF;
for (i = 0; i < RSND_MOD_MAX; i++) { \ u8 next_val = (val + add) & 0xF;
type = rsnd_mod_sequence[is_play][i]; \ int func_call = (val == timing);
mod = (io)->mod[type]; \
if (!mod) \ if (next_val == 0xF) /* underflow case */
continue; \ func_call = 0;
ret |= rsnd_mod_call(type, io, fn, param); \ else
} \ *status = (*status & ~mask) + (next_val << shift);
ret; \
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 is_play = rsnd_io_is_play(io); \
int ret = 0, i; \
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; \
}) })
int rsnd_dai_connect(struct rsnd_mod *mod, int rsnd_dai_connect(struct rsnd_mod *mod,
...@@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0; 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 = { 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, .trigger = rsnd_soc_dai_trigger,
.set_fmt = rsnd_soc_dai_set_fmt, .set_fmt = rsnd_soc_dai_set_fmt,
.set_tdm_slot = rsnd_soc_set_dai_tdm_slot, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
...@@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, ...@@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)
{ {
snd_ctl_remove(cfg->card, cfg->kctrl); 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, int rsnd_kctrl_new_m(struct rsnd_mod *mod,
...@@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
return snd_pcm_lib_preallocate_pages_for_all( return snd_pcm_lib_preallocate_pages_for_all(
rtd->pcm, rtd->pcm,
SNDRV_DMA_TYPE_DEV, SNDRV_DMA_TYPE_CONTINUOUS,
rtd->card->snd_card->dev, snd_dma_continuous_data(GFP_KERNEL),
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
} }
...@@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ...@@ -1092,6 +1148,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
ret = rsnd_dai_call(probe, io, priv); ret = rsnd_dai_call(probe, io, priv);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *mod;
int i; int i;
/* /*
...@@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ...@@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
* remove all mod from io * remove all mod from io
* and, re connect ssi * and, re connect ssi
*/ */
for (i = 0; i < RSND_MOD_MAX; i++) for_each_rsnd_mod(i, mod, io)
rsnd_dai_disconnect((io)->mod[i], io, i); rsnd_dai_disconnect(mod, io, i);
rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
/* /*
...@@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev) ...@@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev)
return ret; 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 = { static struct platform_driver rsnd_driver = {
.driver = { .driver = {
.name = "rcar_sound", .name = "rcar_sound",
.pm = &rsnd_pm_ops,
.of_match_table = rsnd_of_match, .of_match_table = rsnd_of_match,
}, },
.probe = rsnd_probe, .probe = rsnd_probe,
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
struct rsnd_dmaen { struct rsnd_dmaen {
struct dma_chan *chan; struct dma_chan *chan;
dma_addr_t dma_buf;
unsigned int dma_len;
unsigned int dma_period;
unsigned int dma_cnt;
}; };
struct rsnd_dmapp { struct rsnd_dmapp {
...@@ -34,6 +38,8 @@ struct rsnd_dmapp { ...@@ -34,6 +38,8 @@ struct rsnd_dmapp {
struct rsnd_dma { struct rsnd_dma {
struct rsnd_mod mod; struct rsnd_mod mod;
struct rsnd_mod *mod_from;
struct rsnd_mod *mod_to;
dma_addr_t src_addr; dma_addr_t src_addr;
dma_addr_t dst_addr; dma_addr_t dst_addr;
union { union {
...@@ -56,10 +62,38 @@ struct rsnd_dma_ctrl { ...@@ -56,10 +62,38 @@ struct rsnd_dma_ctrl {
/* /*
* Audio DMAC * 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, static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
struct rsnd_dai_stream *io) struct rsnd_dai_stream *io)
{ {
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 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; bool elapsed = false;
unsigned long flags; unsigned long flags;
...@@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, ...@@ -76,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
*/ */
spin_lock_irqsave(&priv->lock, flags); 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); elapsed = rsnd_dai_pointer_update(io, io->byte_per_period);
dmaen->dma_cnt++;
}
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
if (elapsed) if (elapsed)
...@@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data) ...@@ -92,6 +139,20 @@ static void rsnd_dmaen_complete(void *data)
rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); 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, static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct rsnd_priv *priv) struct rsnd_priv *priv)
...@@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, ...@@ -99,7 +160,66 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
dmaengine_terminate_all(dmaen->chan); 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; return 0;
} }
...@@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, ...@@ -113,12 +233,41 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct snd_pcm_substream *substream = io->substream; struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc; 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 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, desc = dmaengine_prep_dma_cyclic(dmaen->chan,
substream->runtime->dma_addr, buf, len, period,
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream),
is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
...@@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, ...@@ -130,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
desc->callback = rsnd_dmaen_complete; desc->callback = rsnd_dmaen_complete;
desc->callback_param = rsnd_mod_get(dma); 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) { if (dmaengine_submit(desc) < 0) {
dev_err(dev, "dmaengine_submit() fail\n"); dev_err(dev, "dmaengine_submit() fail\n");
return -EIO; return -EIO;
...@@ -143,124 +305,55 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, ...@@ -143,124 +305,55 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name) struct rsnd_mod *mod, char *name)
{ {
struct dma_chan *chan; struct dma_chan *chan = NULL;
struct device_node *np; struct device_node *np;
int i = 0; int i = 0;
for_each_child_of_node(of_node, np) { for_each_child_of_node(of_node, np) {
if (i == rsnd_mod_id(mod)) if (i == rsnd_mod_id(mod) && (!chan))
break; chan = of_dma_request_slave_channel(np, name);
i++; i++;
} }
chan = of_dma_request_slave_channel(np, name); /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
of_node_put(np);
of_node_put(of_node); of_node_put(of_node);
return chan; 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, 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_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_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
struct device *dev = rsnd_priv_to_dev(priv); struct dma_chan *chan;
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, /* try to get DMAEngine channel */
(void *)(uintptr_t)id); chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
} if (IS_ERR_OR_NULL(chan)) {
if (IS_ERR_OR_NULL(dmaen->chan)) { /*
dmaen->chan = NULL; * DMA failed. try to PIO mode
dev_err(dev, "can't get dma channel\n"); * see
goto rsnd_dma_channel_err; * rsnd_ssi_fallback()
* rsnd_rdai_continuance_probe()
*/
return -EAGAIN;
} }
cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; dma_release_channel(chan);
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++; dmac->dmaen_num++;
return 0; return 0;
rsnd_dma_attach_err:
rsnd_dmaen_remove(mod, io, priv);
rsnd_dma_channel_err:
/*
* DMA failed. try to PIO mode
* see
* rsnd_ssi_fallback()
* rsnd_rdai_continuance_probe()
*/
return -EAGAIN;
} }
static struct rsnd_mod_ops rsnd_dmaen_ops = { static struct rsnd_mod_ops rsnd_dmaen_ops = {
.name = "audmac", .name = "audmac",
.nolock_start = rsnd_dmaen_nolock_start,
.nolock_stop = rsnd_dmaen_nolock_stop,
.start = rsnd_dmaen_start, .start = rsnd_dmaen_start,
.stop = rsnd_dmaen_stop, .stop = rsnd_dmaen_stop,
.remove = rsnd_dmaen_remove,
}; };
/* /*
...@@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, ...@@ -394,7 +487,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod,
} }
static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, 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_mod *mod_from, struct rsnd_mod *mod_to)
{ {
struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
...@@ -627,7 +720,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, ...@@ -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, 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_from = NULL;
struct rsnd_mod *mod_to = NULL; struct rsnd_mod *mod_to = NULL;
...@@ -636,7 +729,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, ...@@ -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 device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod_ops *ops; struct rsnd_mod_ops *ops;
enum rsnd_mod_type type; 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); struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
int is_play = rsnd_io_is_play(io); int is_play = rsnd_io_is_play(io);
int ret, dma_id; int ret, dma_id;
...@@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, ...@@ -682,9 +775,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
*dma_mod = rsnd_mod_get(dma); *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, ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
rsnd_mod_get_status, type, dma_id); rsnd_mod_get_status, type, dma_id);
if (ret < 0) if (ret < 0)
...@@ -695,9 +785,14 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, ...@@ -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_from), rsnd_mod_id(mod_from),
rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); 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) if (ret < 0)
return ret; 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); ret = rsnd_dai_connect(*dma_mod, io, type);
......
...@@ -48,8 +48,6 @@ struct rsnd_dvc { ...@@ -48,8 +48,6 @@ struct rsnd_dvc {
#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #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) \ #define rsnd_mod_to_dvc(_mod) \
container_of((_mod), struct rsnd_dvc, mod) container_of((_mod), struct rsnd_dvc, mod)
......
...@@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) ...@@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG(SSI_MODE1, 0x804), RSND_GEN_S_REG(SSI_MODE1, 0x804),
RSND_GEN_S_REG(SSI_MODE2, 0x808), RSND_GEN_S_REG(SSI_MODE2, 0x808),
RSND_GEN_S_REG(SSI_CONTROL, 0x810), RSND_GEN_S_REG(SSI_CONTROL, 0x810),
RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844),
RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c),
RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
/* FIXME: it needs SSI_MODE2/3 in the future */ /* FIXME: it needs SSI_MODE2/3 in the future */
RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
...@@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) ...@@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
static const struct rsnd_regmap_field_conf conf_adg[] = { static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(BRRB, 0x04),
RSND_GEN_S_REG(SSICKR, 0x08), RSND_GEN_S_REG(BRGCKR, 0x08),
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
...@@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv) ...@@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv)
static const struct rsnd_regmap_field_conf conf_adg[] = { static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(BRRB, 0x04),
RSND_GEN_S_REG(SSICKR, 0x08), RSND_GEN_S_REG(BRGCKR, 0x08),
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
}; };
......
...@@ -43,17 +43,7 @@ ...@@ -43,17 +43,7 @@
* see gen1/gen2 for detail * see gen1/gen2 for detail
*/ */
enum rsnd_reg { enum rsnd_reg {
/* SCU (SRC/SSIU/MIX/CTU/DVC) */ /* SCU (MIX/CTU/DVC) */
RSND_REG_SSI_MODE, /* Gen2 only */
RSND_REG_SSI_MODE0,
RSND_REG_SSI_MODE1,
RSND_REG_SSI_MODE2,
RSND_REG_SSI_CONTROL,
RSND_REG_SSI_CTRL, /* Gen2 only */
RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */
RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */
RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */
RSND_REG_SSI_INT_ENABLE, /* Gen2 only */
RSND_REG_SRC_I_BUSIF_MODE, RSND_REG_SRC_I_BUSIF_MODE,
RSND_REG_SRC_O_BUSIF_MODE, RSND_REG_SRC_O_BUSIF_MODE,
RSND_REG_SRC_ROUTE_MODE0, RSND_REG_SRC_ROUTE_MODE0,
...@@ -63,29 +53,29 @@ enum rsnd_reg { ...@@ -63,29 +53,29 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSCR,
RSND_REG_SRC_IFSVR, RSND_REG_SRC_IFSVR,
RSND_REG_SRC_SRCCR, RSND_REG_SRC_SRCCR,
RSND_REG_SRC_CTRL, /* Gen2 only */ RSND_REG_SRC_CTRL,
RSND_REG_SRC_BSDSR, /* Gen2 only */ RSND_REG_SRC_BSDSR,
RSND_REG_SRC_BSISR, /* Gen2 only */ RSND_REG_SRC_BSISR,
RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */ RSND_REG_SRC_INT_ENABLE0,
RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_SRC_BUSIF_DALIGN,
RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */ RSND_REG_SRCIN_TIMSEL0,
RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */ RSND_REG_SRCIN_TIMSEL1,
RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */ RSND_REG_SRCIN_TIMSEL2,
RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */ RSND_REG_SRCIN_TIMSEL3,
RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */ RSND_REG_SRCIN_TIMSEL4,
RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */ RSND_REG_SRCOUT_TIMSEL0,
RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */ RSND_REG_SRCOUT_TIMSEL1,
RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */ RSND_REG_SRCOUT_TIMSEL2,
RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */ RSND_REG_SRCOUT_TIMSEL3,
RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */ RSND_REG_SRCOUT_TIMSEL4,
RSND_REG_SCU_SYS_STATUS0, RSND_REG_SCU_SYS_STATUS0,
RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */ RSND_REG_SCU_SYS_STATUS1,
RSND_REG_SCU_SYS_INT_EN0, RSND_REG_SCU_SYS_INT_EN0,
RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ RSND_REG_SCU_SYS_INT_EN1,
RSND_REG_CMD_CTRL, /* Gen2 only */ RSND_REG_CMD_CTRL,
RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_CMD_BUSIF_DALIGN,
RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CMD_ROUTE_SLCT,
RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ RSND_REG_CMDOUT_TIMSEL,
RSND_REG_CTU_SWRSR, RSND_REG_CTU_SWRSR,
RSND_REG_CTU_CTUIR, RSND_REG_CTU_CTUIR,
RSND_REG_CTU_ADINR, RSND_REG_CTU_ADINR,
...@@ -147,18 +137,38 @@ enum rsnd_reg { ...@@ -147,18 +137,38 @@ enum rsnd_reg {
RSND_REG_DVC_VOL6R, RSND_REG_DVC_VOL6R,
RSND_REG_DVC_VOL7R, RSND_REG_DVC_VOL7R,
RSND_REG_DVC_DVUER, RSND_REG_DVC_DVUER,
RSND_REG_DVC_VRCTR, /* Gen2 only */ RSND_REG_DVC_VRCTR,
RSND_REG_DVC_VRPDR, /* Gen2 only */ RSND_REG_DVC_VRPDR,
RSND_REG_DVC_VRDBR, /* Gen2 only */ RSND_REG_DVC_VRDBR,
/* ADG */ /* ADG */
RSND_REG_BRRA, RSND_REG_BRRA,
RSND_REG_BRRB, RSND_REG_BRRB,
RSND_REG_SSICKR, RSND_REG_BRGCKR,
RSND_REG_DIV_EN, /* Gen2 only */ RSND_REG_DIV_EN,
RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL0,
RSND_REG_AUDIO_CLK_SEL1, RSND_REG_AUDIO_CLK_SEL1,
RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */ RSND_REG_AUDIO_CLK_SEL2,
/* SSIU */
RSND_REG_SSI_MODE,
RSND_REG_SSI_MODE0,
RSND_REG_SSI_MODE1,
RSND_REG_SSI_MODE2,
RSND_REG_SSI_CONTROL,
RSND_REG_SSI_CTRL,
RSND_REG_SSI_BUSIF_MODE,
RSND_REG_SSI_BUSIF_ADINR,
RSND_REG_SSI_BUSIF_DALIGN,
RSND_REG_SSI_INT_ENABLE,
RSND_REG_SSI_SYS_STATUS0,
RSND_REG_SSI_SYS_STATUS1,
RSND_REG_SSI_SYS_STATUS2,
RSND_REG_SSI_SYS_STATUS3,
RSND_REG_SSI_SYS_STATUS4,
RSND_REG_SSI_SYS_STATUS5,
RSND_REG_SSI_SYS_STATUS6,
RSND_REG_SSI_SYS_STATUS7,
/* SSI */ /* SSI */
RSND_REG_SSICR, RSND_REG_SSICR,
...@@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); ...@@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
* R-Car DMA * R-Car DMA
*/ */
int rsnd_dma_attach(struct rsnd_dai_stream *io, int rsnd_dma_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
int rsnd_dma_probe(struct rsnd_priv *priv); int rsnd_dma_probe(struct rsnd_priv *priv);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name); struct rsnd_mod *mod, char *name);
...@@ -259,6 +269,12 @@ struct rsnd_mod_ops { ...@@ -259,6 +269,12 @@ struct rsnd_mod_ops {
int (*fallback)(struct rsnd_mod *mod, int (*fallback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct rsnd_priv *priv); struct rsnd_priv *priv);
int (*nolock_start)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
int (*nolock_stop)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv);
}; };
struct rsnd_dai_stream; struct rsnd_dai_stream;
...@@ -278,7 +294,7 @@ struct rsnd_mod { ...@@ -278,7 +294,7 @@ struct rsnd_mod {
* *
* 0xH0000CBA * 0xH0000CBA
* *
* A 0: probe 1: remove * A 0: nolock_start 1: nolock_stop
* B 0: init 1: quit * B 0: init 1: quit
* C 0: start 1: stop * C 0: start 1: stop
* *
...@@ -288,19 +304,23 @@ struct rsnd_mod { ...@@ -288,19 +304,23 @@ struct rsnd_mod {
* H 0: fallback * H 0: fallback
* H 0: hw_params * H 0: hw_params
*/ */
#define __rsnd_mod_shift_probe 0 #define __rsnd_mod_shift_nolock_start 0
#define __rsnd_mod_shift_remove 0 #define __rsnd_mod_shift_nolock_stop 0
#define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_start 8
#define __rsnd_mod_shift_stop 8 #define __rsnd_mod_shift_stop 8
#define __rsnd_mod_shift_probe 28 /* always called */
#define __rsnd_mod_shift_remove 28 /* always called */
#define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_irq 28 /* always called */
#define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */
#define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */
#define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */
#define __rsnd_mod_add_probe 1 #define __rsnd_mod_add_probe 0
#define __rsnd_mod_add_remove -1 #define __rsnd_mod_add_remove 0
#define __rsnd_mod_add_nolock_start 1
#define __rsnd_mod_add_nolock_stop -1
#define __rsnd_mod_add_init 1 #define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1 #define __rsnd_mod_add_start 1
...@@ -311,7 +331,7 @@ struct rsnd_mod { ...@@ -311,7 +331,7 @@ struct rsnd_mod {
#define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_call_probe 0 #define __rsnd_mod_call_probe 0
#define __rsnd_mod_call_remove 1 #define __rsnd_mod_call_remove 0
#define __rsnd_mod_call_init 0 #define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0 #define __rsnd_mod_call_start 0
...@@ -320,6 +340,8 @@ struct rsnd_mod { ...@@ -320,6 +340,8 @@ struct rsnd_mod {
#define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_fallback 0
#define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_hw_params 0
#define __rsnd_mod_call_nolock_start 0
#define __rsnd_mod_call_nolock_stop 1
#define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
...@@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, ...@@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, struct rsnd_mod *mod,
enum rsnd_mod_type type); enum rsnd_mod_type type);
struct rsnd_mod *rsnd_mod_next(int *iterator,
struct rsnd_dai_stream *io,
enum rsnd_mod_type *array,
int array_size);
#define for_each_rsnd_mod(iterator, pos, io) \
for (iterator = 0; \
(pos = rsnd_mod_next(&iterator, io, NULL, 0));)
#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \
for (iterator = 0; \
(pos = rsnd_mod_next(&iterator, io, array, size));)
#define for_each_rsnd_mod_array(iterator, pos, io, array) \
for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
void rsnd_parse_connect_common(struct rsnd_dai *rdai, void rsnd_parse_connect_common(struct rsnd_dai *rdai,
struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
...@@ -364,6 +398,18 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); ...@@ -364,6 +398,18 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
/*
* DT
*/
#define rsnd_parse_of_node(priv, node) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
#define RSND_NODE_DAI "rcar_sound,dai"
#define RSND_NODE_SSI "rcar_sound,ssi"
#define RSND_NODE_SRC "rcar_sound,src"
#define RSND_NODE_CTU "rcar_sound,ctu"
#define RSND_NODE_MIX "rcar_sound,mix"
#define RSND_NODE_DVC "rcar_sound,dvc"
/* /*
* R-Car sound DAI * R-Car sound DAI
*/ */
...@@ -382,6 +428,7 @@ struct rsnd_dai_stream { ...@@ -382,6 +428,7 @@ struct rsnd_dai_stream {
}; };
#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU)
#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP)
#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
...@@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); ...@@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
int rsnd_dai_connect(struct rsnd_mod *mod, int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
enum rsnd_mod_type type); enum rsnd_mod_type type);
#define rsnd_dai_of_node(priv) \ #define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
/* /*
* R-Car Gen1/Gen2 * R-Car Gen1/Gen2
...@@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, ...@@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
unsigned int out_rate); unsigned int out_rate);
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io); struct rsnd_dai_stream *io);
#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1)
#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0)
void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
/* /*
* R-Car sound priv * R-Car sound priv
...@@ -606,8 +655,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); ...@@ -606,8 +655,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
#define rsnd_ssi_of_node(priv) \ #define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *playback, struct device_node *playback,
struct device_node *capture); struct device_node *capture);
...@@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, ...@@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
int is_in); int is_in);
#define rsnd_src_of_node(priv) \ #define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
#define rsnd_parse_connect_src(rdai, playback, capture) \ #define rsnd_parse_connect_src(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \
rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
...@@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv); ...@@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv);
void rsnd_ctu_remove(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv);
int rsnd_ctu_converted_channel(struct rsnd_mod *mod); int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) \ #define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
#define rsnd_parse_connect_ctu(rdai, playback, capture) \ #define rsnd_parse_connect_ctu(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \
rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
...@@ -660,8 +706,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); ...@@ -660,8 +706,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
int rsnd_mix_probe(struct rsnd_priv *priv); int rsnd_mix_probe(struct rsnd_priv *priv);
void rsnd_mix_remove(struct rsnd_priv *priv); void rsnd_mix_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_mix_of_node(priv) \ #define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
#define rsnd_parse_connect_mix(rdai, playback, capture) \ #define rsnd_parse_connect_mix(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \
rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
...@@ -673,8 +718,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); ...@@ -673,8 +718,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
int rsnd_dvc_probe(struct rsnd_priv *priv); int rsnd_dvc_probe(struct rsnd_priv *priv);
void rsnd_dvc_remove(struct rsnd_priv *priv); void rsnd_dvc_remove(struct rsnd_priv *priv);
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_dvc_of_node(priv) \ #define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
#define rsnd_parse_connect_dvc(rdai, playback, capture) \ #define rsnd_parse_connect_dvc(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \
rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
......
...@@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, ...@@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
int use_src = 0;
u32 fin, fout; u32 fin, fout;
u32 ifscr, fsrate, adinr; u32 ifscr, fsrate, adinr;
u32 cr, route; u32 cr, route;
...@@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, ...@@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
return; return;
} }
use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
/* /*
* SRC_ADINR * SRC_ADINR
*/ */
...@@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, ...@@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
*/ */
ifscr = 0; ifscr = 0;
fsrate = 0; fsrate = 0;
if (fin != fout) { if (use_src) {
u64 n; u64 n;
ifscr = 1; ifscr = 1;
...@@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, ...@@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
*/ */
cr = 0x00011110; cr = 0x00011110;
route = 0x0; route = 0x0;
if (fin != fout) { if (use_src) {
route = 0x1; route = 0x1;
if (rsnd_src_sync_is_enabled(mod)) { if (rsnd_src_sync_is_enabled(mod)) {
...@@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod) ...@@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)
{ {
u32 val = OUF_SRC(rsnd_mod_id(mod)); u32 val = OUF_SRC(rsnd_mod_id(mod));
rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val); rsnd_mod_write(mod, SCU_SYS_STATUS0, val);
rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); rsnd_mod_write(mod, SCU_SYS_STATUS1, val);
} }
static bool rsnd_src_error_occurred(struct rsnd_mod *mod) static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
...@@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, ...@@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod,
return ret; return ret;
} }
ret = rsnd_dma_attach(io, mod, &src->dma, 0); ret = rsnd_dma_attach(io, mod, &src->dma);
return ret; return ret;
} }
......
...@@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, ...@@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
int chan = params_channels(params); int chan = params_channels(params);
/* /*
* Already working. * snd_pcm_ops::hw_params will be called *before*
* It will happen if SSI has parent/child connection. * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0
* in 1st call.
*/ */
if (ssi->usrcnt > 1) { if (ssi->usrcnt) {
/* /*
* Already working.
* It will happen if SSI has parent/child connection.
* it is error if child <-> parent SSI uses * it is error if child <-> parent SSI uses
* different channels. * different channels.
*/ */
...@@ -644,10 +647,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, ...@@ -644,10 +647,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = devm_request_irq(dev, ssi->irq, /*
rsnd_ssi_interrupt, * SSI might be called again as PIO fallback
IRQF_SHARED, * It is easy to manual handling for IRQ request/free
dev_name(dev), mod); */
ret = request_irq(ssi->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
return ret; return ret;
} }
...@@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, ...@@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int dma_id = 0; /* not needed */
int ret; int ret;
/* /*
...@@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, ...@@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
return ret; return ret;
/* SSI probe might be called many times in MUX multi path */ /* SSI probe might be called many times in MUX multi path */
ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); ret = rsnd_dma_attach(io, mod, &ssi->dma);
return ret; return ret;
} }
...@@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, ...@@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
int irq = ssi->irq;
/* PIO will request IRQ again */ /* PIO will request IRQ again */
devm_free_irq(dev, irq, mod); free_irq(ssi->irq, mod);
return 0; return 0;
} }
......
...@@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, ...@@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
u32 mask1, val1; u32 mask1, val1;
u32 mask2, val2; u32 mask2, val2;
/* clear status */
switch (id) {
case 0:
case 1:
case 2:
case 3:
case 4:
rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
break;
case 9:
rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
break;
}
/* /*
* SSI_MODE0 * SSI_MODE0
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment