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

This commit is contained in:
Mark Brown 2016-12-12 15:52:47 +00:00
commit 43b64af535
10 changed files with 531 additions and 264 deletions

View File

@ -1,5 +1,5 @@
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"
@ -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

View File

@ -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 */
@ -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,
@ -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);
@ -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)
{
@ -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;
@ -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);
}
@ -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);
}

View File

@ -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;
@ -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;
@ -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] = {
{
@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
},
};
#define rsnd_dai_call(fn, io, param...) \
({ \
struct rsnd_mod *mod; \
int type, 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); \
} \
ret; \
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 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,
@ -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,
@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
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,
@ -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);
}
@ -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;
/*
@ -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);
/*
@ -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,

View File

@ -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 {
@ -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 {
@ -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;
@ -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)
@ -92,75 +139,6 @@ static void rsnd_dmaen_complete(void *data)
rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
}
static int rsnd_dmaen_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_terminate_all(dmaen->chan);
return 0;
}
static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc;
int is_play = rsnd_io_is_play(io);
desc = dmaengine_prep_dma_cyclic(dmaen->chan,
substream->runtime->dma_addr,
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream),
is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
return -EIO;
}
desc->callback = rsnd_dmaen_complete;
desc->callback_param = rsnd_mod_get(dma);
if (dmaengine_submit(desc) < 0) {
dev_err(dev, "dmaengine_submit() fail\n");
return -EIO;
}
dma_async_issue_pending(dmaen->chan);
return 0;
}
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name)
{
struct dma_chan *chan;
struct device_node *np;
int i = 0;
for_each_child_of_node(of_node, np) {
if (i == rsnd_mod_id(mod))
break;
i++;
}
chan = of_dma_request_slave_channel(np, name);
of_node_put(np);
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)
@ -175,13 +153,37 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
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)
static int rsnd_dmaen_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);
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);
@ -190,41 +192,55 @@ static int rsnd_dmaen_remove(struct rsnd_mod *mod,
return 0;
}
static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
struct rsnd_dma *dma, int id,
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
struct rsnd_mod *mod = rsnd_mod_get(dma);
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
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);
}
/*
* 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");
goto rsnd_dma_channel_err;
return ret;
}
return 0;
}
static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc;
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;
@ -237,30 +253,107 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
ret = dmaengine_slave_config(dmaen->chan, &cfg);
if (ret < 0)
goto rsnd_dma_attach_err;
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,
buf, len, period,
is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
return -EIO;
}
desc->callback = rsnd_dmaen_complete;
desc->callback_param = rsnd_mod_get(dma);
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;
}
dma_async_issue_pending(dmaen->chan);
return 0;
}
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name)
{
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) && (!chan))
chan = of_dma_request_slave_channel(np, name);
i++;
}
/* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
of_node_put(of_node);
return chan;
}
static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
struct rsnd_dma *dma,
struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
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
* rsnd_ssi_fallback()
* rsnd_rdai_continuance_probe()
*/
return -EAGAIN;
}
dma_release_channel(chan);
dmac->dmaen_num++;
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 = {
.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,
};
/*
@ -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);
@ -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;
@ -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;
@ -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)
@ -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);

View File

@ -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)

View File

@ -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_MODE2, 0x808),
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 */
RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
@ -311,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
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_SEL1, 0x10),
RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
@ -362,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv)
static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
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_SEL1, 0x10),
};

View File

@ -43,17 +43,7 @@
* see gen1/gen2 for detail
*/
enum rsnd_reg {
/* SCU (SRC/SSIU/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 */
/* SCU (MIX/CTU/DVC) */
RSND_REG_SRC_I_BUSIF_MODE,
RSND_REG_SRC_O_BUSIF_MODE,
RSND_REG_SRC_ROUTE_MODE0,
@ -63,29 +53,29 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR,
RSND_REG_SRC_IFSVR,
RSND_REG_SRC_SRCCR,
RSND_REG_SRC_CTRL, /* Gen2 only */
RSND_REG_SRC_BSDSR, /* Gen2 only */
RSND_REG_SRC_BSISR, /* Gen2 only */
RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */
RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */
RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */
RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */
RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */
RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */
RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */
RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */
RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */
RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */
RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */
RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */
RSND_REG_SRC_CTRL,
RSND_REG_SRC_BSDSR,
RSND_REG_SRC_BSISR,
RSND_REG_SRC_INT_ENABLE0,
RSND_REG_SRC_BUSIF_DALIGN,
RSND_REG_SRCIN_TIMSEL0,
RSND_REG_SRCIN_TIMSEL1,
RSND_REG_SRCIN_TIMSEL2,
RSND_REG_SRCIN_TIMSEL3,
RSND_REG_SRCIN_TIMSEL4,
RSND_REG_SRCOUT_TIMSEL0,
RSND_REG_SRCOUT_TIMSEL1,
RSND_REG_SRCOUT_TIMSEL2,
RSND_REG_SRCOUT_TIMSEL3,
RSND_REG_SRCOUT_TIMSEL4,
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_EN1, /* Gen2 only */
RSND_REG_CMD_CTRL, /* Gen2 only */
RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */
RSND_REG_SCU_SYS_INT_EN1,
RSND_REG_CMD_CTRL,
RSND_REG_CMD_BUSIF_DALIGN,
RSND_REG_CMD_ROUTE_SLCT,
RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */
RSND_REG_CMDOUT_TIMSEL,
RSND_REG_CTU_SWRSR,
RSND_REG_CTU_CTUIR,
RSND_REG_CTU_ADINR,
@ -147,18 +137,38 @@ enum rsnd_reg {
RSND_REG_DVC_VOL6R,
RSND_REG_DVC_VOL7R,
RSND_REG_DVC_DVUER,
RSND_REG_DVC_VRCTR, /* Gen2 only */
RSND_REG_DVC_VRPDR, /* Gen2 only */
RSND_REG_DVC_VRDBR, /* Gen2 only */
RSND_REG_DVC_VRCTR,
RSND_REG_DVC_VRPDR,
RSND_REG_DVC_VRDBR,
/* ADG */
RSND_REG_BRRA,
RSND_REG_BRRB,
RSND_REG_SSICKR,
RSND_REG_DIV_EN, /* Gen2 only */
RSND_REG_BRGCKR,
RSND_REG_DIV_EN,
RSND_REG_AUDIO_CLK_SEL0,
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 */
RSND_REG_SSICR,
@ -199,7 +209,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
* R-Car DMA
*/
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);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name);
@ -259,6 +269,12 @@ struct rsnd_mod_ops {
int (*fallback)(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
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;
@ -278,7 +294,7 @@ struct rsnd_mod {
*
* 0xH0000CBA
*
* A 0: probe 1: remove
* A 0: nolock_start 1: nolock_stop
* B 0: init 1: quit
* C 0: start 1: stop
*
@ -288,19 +304,23 @@ struct rsnd_mod {
* H 0: fallback
* H 0: hw_params
*/
#define __rsnd_mod_shift_probe 0
#define __rsnd_mod_shift_remove 0
#define __rsnd_mod_shift_nolock_start 0
#define __rsnd_mod_shift_nolock_stop 0
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 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_pcm_new 28 /* always called */
#define __rsnd_mod_shift_fallback 28 /* always called */
#define __rsnd_mod_shift_hw_params 28 /* always called */
#define __rsnd_mod_add_probe 1
#define __rsnd_mod_add_remove -1
#define __rsnd_mod_add_probe 0
#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_quit -1
#define __rsnd_mod_add_start 1
@ -311,7 +331,7 @@ struct rsnd_mod {
#define __rsnd_mod_add_hw_params 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_quit 1
#define __rsnd_mod_call_start 0
@ -320,6 +340,8 @@ struct rsnd_mod {
#define __rsnd_mod_call_pcm_new 0
#define __rsnd_mod_call_fallback 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_id(mod) ((mod) ? (mod)->id : -1)
@ -346,6 +368,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
struct rsnd_mod *mod,
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,
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);
int rsnd_runtime_is_ssi_multi(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
*/
@ -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_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_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)
@ -428,8 +475,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
enum rsnd_mod_type type);
#define rsnd_dai_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai")
#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI)
/*
* R-Car Gen1/Gen2
@ -453,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
unsigned int out_rate);
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
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
@ -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))
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
#define rsnd_ssi_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)
void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *playback,
struct device_node *capture);
@ -633,8 +681,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
int is_in);
#define rsnd_src_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
#define rsnd_parse_connect_src(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \
rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
@ -647,8 +694,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv);
void rsnd_ctu_remove(struct rsnd_priv *priv);
int rsnd_ctu_converted_channel(struct rsnd_mod *mod);
struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
#define rsnd_ctu_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu")
#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
#define rsnd_parse_connect_ctu(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \
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);
int rsnd_mix_probe(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);
#define rsnd_mix_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix")
#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
#define rsnd_parse_connect_mix(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \
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);
int rsnd_dvc_probe(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);
#define rsnd_dvc_of_node(priv) \
of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
#define rsnd_parse_connect_dvc(rdai, playback, capture) \
rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \
rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \

View File

@ -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 device *dev = rsnd_priv_to_dev(priv);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
int use_src = 0;
u32 fin, fout;
u32 ifscr, fsrate, adinr;
u32 cr, route;
@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
return;
}
use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
/*
* SRC_ADINR
*/
@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
*/
ifscr = 0;
fsrate = 0;
if (fin != fout) {
if (use_src) {
u64 n;
ifscr = 1;
@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
*/
cr = 0x00011110;
route = 0x0;
if (fin != fout) {
if (use_src) {
route = 0x1;
if (rsnd_src_sync_is_enabled(mod)) {
@ -327,8 +330,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod)
{
u32 val = OUF_SRC(rsnd_mod_id(mod));
rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val);
rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
rsnd_mod_write(mod, SCU_SYS_STATUS0, val);
rsnd_mod_write(mod, SCU_SYS_STATUS1, val);
}
static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
@ -475,7 +478,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod,
return ret;
}
ret = rsnd_dma_attach(io, mod, &src->dma, 0);
ret = rsnd_dma_attach(io, mod, &src->dma);
return ret;
}

View File

@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
int chan = params_channels(params);
/*
* Already working.
* It will happen if SSI has parent/child connection.
* snd_pcm_ops::hw_params will be called *before*
* 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
* different channels.
*/
@ -644,10 +647,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
if (ret < 0)
return ret;
ret = devm_request_irq(dev, ssi->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
/*
* SSI might be called again as PIO fallback
* It is easy to manual handling for IRQ request/free
*/
ret = request_irq(ssi->irq,
rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), mod);
return ret;
}
@ -669,7 +676,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
int dma_id = 0; /* not needed */
int ret;
/*
@ -684,7 +690,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
return ret;
/* 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;
}
@ -694,11 +700,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
struct rsnd_priv *priv)
{
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 */
devm_free_irq(dev, irq, mod);
free_irq(ssi->irq, mod);
return 0;
}

View File

@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
u32 mask1, val1;
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
*/