return mod->ops->dma_req(io, mod);
}
+u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod,
+ enum rsnd_mod_type type)
+{
+ return &mod->status;
+}
+
int rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod,
- struct rsnd_mod_ops *ops,
- struct clk *clk,
- enum rsnd_mod_type type,
- int id)
+ struct rsnd_mod_ops *ops,
+ struct clk *clk,
+ u32* (*get_status)(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod,
+ enum rsnd_mod_type type),
+ enum rsnd_mod_type type,
+ int id)
{
int ret = clk_prepare(clk);
mod->type = type;
mod->clk = clk;
mod->priv = priv;
+ mod->get_status = get_status;
return ret;
}
{
if (mod->clk)
clk_unprepare(mod->clk);
+ mod->clk = NULL;
}
void rsnd_mod_interrupt(struct rsnd_mod *mod,
int chan = runtime->channels;
/* Multi channel Mode */
- if (rsnd_ssi_multi_slaves(io))
+ if (rsnd_ssi_multi_slaves_runtime(io))
chan /= rsnd_get_slot_num(io);
/* TDM Extend Mode needs 8ch */
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 = (io)->mod_status + idx; \
+ 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; \
- *status = (*status & ~mask) + \
- (add << __rsnd_mod_shift_##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; \
})
+static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
+ {
+ /* CAPTURE */
+ RSND_MOD_AUDMAPP,
+ RSND_MOD_AUDMA,
+ RSND_MOD_DVC,
+ RSND_MOD_MIX,
+ RSND_MOD_CTU,
+ RSND_MOD_CMD,
+ RSND_MOD_SRC,
+ RSND_MOD_SSIU,
+ RSND_MOD_SSIM3,
+ RSND_MOD_SSIM2,
+ RSND_MOD_SSIM1,
+ RSND_MOD_SSIP,
+ RSND_MOD_SSI,
+ }, {
+ /* PLAYBACK */
+ RSND_MOD_AUDMAPP,
+ RSND_MOD_AUDMA,
+ RSND_MOD_SSIM3,
+ RSND_MOD_SSIM2,
+ RSND_MOD_SSIM1,
+ RSND_MOD_SSIP,
+ RSND_MOD_SSI,
+ RSND_MOD_SSIU,
+ RSND_MOD_DVC,
+ RSND_MOD_MIX,
+ RSND_MOD_CTU,
+ RSND_MOD_CMD,
+ RSND_MOD_SRC,
+ },
+};
+
#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++) { \
- mod = (io)->mod[i]; \
+ type = rsnd_mod_sequence[is_play][i]; \
+ mod = (io)->mod[type]; \
if (!mod) \
continue; \
- ret |= rsnd_mod_call(i, io, fn, param); \
+ ret |= rsnd_mod_call(type, io, fn, param); \
} \
ret; \
})
if (!mod)
return -EIO;
+ if (io->mod[type] == mod)
+ return 0;
+
if (io->mod[type])
return -EINVAL;
ret = rsnd_dai_call(start, io, priv);
if (ret < 0)
goto dai_trigger_end;
+
+ ret = rsnd_dai_call(irq, io, priv, 1);
+ if (ret < 0)
+ goto dai_trigger_end;
+
break;
case SNDRV_PCM_TRIGGER_STOP:
- ret = rsnd_dai_call(stop, io, priv);
+ ret = rsnd_dai_call(irq, io, priv, 0);
+
+ ret |= rsnd_dai_call(stop, io, priv);
ret |= rsnd_dai_call(quit, io, priv);
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod))
{
- struct snd_soc_card *soc_card = rtd->card;
struct snd_card *card = rtd->card->snd_card;
struct snd_kcontrol *kctrl;
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = name,
.info = rsnd_kctrl_info,
- .index = rtd - soc_card->rtd,
+ .index = rtd->num,
.get = rsnd_kctrl_get,
.put = rsnd_kctrl_put,
.private_value = (unsigned long)cfg,
int ch_size,
u32 max)
{
- if (ch_size > RSND_DVC_CHANNELS)
+ if (ch_size > RSND_MAX_CHANNELS)
return -EINVAL;
_cfg->cfg.max = max;
RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
- RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4),
+ RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
+ RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100),
RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100),
RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100),
+ RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100),
+ RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100),
+ RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100),
+ RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100),
+ RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100),
+ RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100),
+ RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100),
+ RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100),
+ RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100),
+ RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100),
+ RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100),
+ RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100),
+ RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100),
+ RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100),
+ RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100),
+ RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100),
+ RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100),
+ RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100),
+ RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100),
+ RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100),
+ RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100),
+ RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100),
+ RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100),
+ RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100),
+ RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100),
+ RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100),
+ RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100),
+ RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100),
+ RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100),
+ RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100),
+ RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100),
+ RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100),
+ RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100),
+ RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100),
RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40),
RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40),
RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40),
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
u32 convert_rate; /* sampling rate convert */
- int err;
int irq;
};
break;
}
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+
rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */
rsnd_mod_write(mod, SRC_ADINR, adinr);
rsnd_mod_write(mod, SRC_IFSCR, ifscr);
rsnd_mod_write(mod, SRC_BSISR, bsisr);
rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1);
rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
rsnd_adg_set_convert_timing_gen2(mod, io);
}
-#define rsnd_src_irq_enable(mod) rsnd_src_irq_ctrol(mod, 1)
-#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0)
-static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable)
+static int rsnd_src_irq(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv,
+ int enable)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 sys_int_val, int_val, sys_int_mask;
rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
+
+ return 0;
}
static void rsnd_src_status_clear(struct rsnd_mod *mod)
rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
}
-static bool rsnd_src_record_error(struct rsnd_mod *mod)
+static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
u32 val0, val1;
val0 = val0 & 0xffff;
if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
- (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) {
- struct rsnd_src *src = rsnd_mod_to_src(mod);
-
- src->err++;
+ (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1))
ret = true;
- }
return ret;
}
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- /*
- * stop SRC output only
- * see rsnd_src_quit
- */
- rsnd_mod_write(mod, SRC_CTRL, 0x01);
+ rsnd_mod_write(mod, SRC_CTRL, 0);
return 0;
}
rsnd_src_status_clear(mod);
- rsnd_src_irq_enable(mod);
-
- src->err = 0;
-
/* reset sync convert_rate */
src->sync.val = 0;
struct rsnd_priv *priv)
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- rsnd_src_irq_disable(mod);
-
- /* stop both out/in */
- rsnd_mod_write(mod, SRC_CTRL, 0);
rsnd_src_halt(mod);
rsnd_mod_power_off(mod);
- if (src->err)
- dev_warn(dev, "%s[%d] under/over flow err = %d\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
-
src->convert_rate = 0;
/* reset sync convert_rate */
struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_src *src = rsnd_mod_to_src(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
+ bool stop = false;
spin_lock(&priv->lock);
if (!rsnd_io_is_working(io))
goto rsnd_src_interrupt_out;
- if (rsnd_src_record_error(mod)) {
-
- dev_dbg(dev, "%s[%d] restart\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
-
- rsnd_src_stop(mod, io, priv);
- rsnd_src_start(mod, io, priv);
- }
-
- if (src->err > 1024) {
- rsnd_src_irq_disable(mod);
-
- dev_warn(dev, "no more %s[%d] restart\n",
- rsnd_mod_name(mod), rsnd_mod_id(mod));
- }
+ if (rsnd_src_error_occurred(mod))
+ stop = true;
rsnd_src_status_clear(mod);
rsnd_src_interrupt_out:
spin_unlock(&priv->lock);
+
+ if (stop)
+ snd_pcm_stop_xrun(io->substream);
}
static irqreturn_t rsnd_src_interrupt(int irq, void *data)
/*
* IRQ is not supported on non-DT
* see
- * rsnd_src_irq_enable()
+ * rsnd_src_irq()
*/
ret = devm_request_irq(dev, irq,
rsnd_src_interrupt,
return ret;
}
- src->dma = rsnd_dma_attach(io, mod, 0);
- if (IS_ERR(src->dma))
- return PTR_ERR(src->dma);
+ ret = rsnd_dma_attach(io, mod, &src->dma, 0);
return ret;
}
struct snd_soc_pcm_runtime *rtd)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
int ret;
if (!rsnd_rdai_is_clk_master(rdai))
return 0;
+ /*
+ * SRC In doesn't work if DVC was enabled
+ */
+ if (dvc && !rsnd_io_is_play(io))
+ return 0;
+
/*
* enable sync convert
*/
.quit = rsnd_src_quit,
.start = rsnd_src_start,
.stop = rsnd_src_stop,
+ .irq = rsnd_src_irq,
.hw_params = rsnd_src_hw_params,
.pcm_new = rsnd_src_pcm_new,
};
}
ret = rsnd_mod_init(priv, rsnd_mod_get(src),
- &rsnd_src_ops, clk, RSND_MOD_SRC, i);
+ &rsnd_src_ops, clk, rsnd_mod_get_status,
+ RSND_MOD_SRC, i);
if (ret)
goto rsnd_src_probe_done;