forked from Minki/linux
ASoC: rsnd: don't auto-recover when under/over run error
Renesas R-Car sound needs recovery (= restart) when under/over run error occurred, and current driver tries it on under/over run error handler automatically. But this recovery should be handled by userland, not kernel. This patch stops XRUN when under/over run error occur, and will leave the recovery of HW in userland. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
31739a689f
commit
6a25c8da00
@ -25,7 +25,6 @@ struct rsnd_src {
|
||||
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;
|
||||
};
|
||||
|
||||
@ -316,7 +315,7 @@ 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;
|
||||
@ -333,12 +332,8 @@ static bool rsnd_src_record_error(struct rsnd_mod *mod)
|
||||
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;
|
||||
}
|
||||
@ -388,8 +383,6 @@ static int rsnd_src_init(struct rsnd_mod *mod,
|
||||
|
||||
rsnd_src_irq_enable(mod);
|
||||
|
||||
src->err = 0;
|
||||
|
||||
/* reset sync convert_rate */
|
||||
src->sync.val = 0;
|
||||
|
||||
@ -401,7 +394,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
|
||||
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);
|
||||
|
||||
@ -409,10 +401,6 @@ static int rsnd_src_quit(struct rsnd_mod *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 */
|
||||
@ -425,8 +413,7 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod,
|
||||
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);
|
||||
|
||||
@ -434,26 +421,16 @@ static void __rsnd_src_interrupt(struct rsnd_mod *mod,
|
||||
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)
|
||||
|
@ -74,7 +74,6 @@ struct rsnd_ssi {
|
||||
u32 wsr;
|
||||
int chan;
|
||||
int rate;
|
||||
int err;
|
||||
int irq;
|
||||
unsigned int usrcnt;
|
||||
};
|
||||
@ -385,8 +384,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ssi->err = -1; /* ignore 1st error */
|
||||
|
||||
/* clear error status */
|
||||
rsnd_ssi_status_clear(mod);
|
||||
|
||||
@ -409,13 +406,7 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
if (!rsnd_ssi_is_parent(mod, io)) {
|
||||
if (ssi->err > 0)
|
||||
dev_warn(dev, "%s[%d] under/over flow err = %d\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod),
|
||||
ssi->err);
|
||||
|
||||
ssi->cr_own = 0;
|
||||
ssi->err = 0;
|
||||
|
||||
rsnd_ssi_irq_disable(mod);
|
||||
}
|
||||
@ -455,21 +446,9 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi)
|
||||
{
|
||||
struct rsnd_mod *mod = rsnd_mod_get(ssi);
|
||||
u32 status = rsnd_ssi_status_get(mod);
|
||||
|
||||
/* under/over flow error */
|
||||
if (status & (UIRQ | OIRQ))
|
||||
ssi->err++;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __rsnd_ssi_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
static int rsnd_ssi_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
||||
u32 cr;
|
||||
@ -491,26 +470,22 @@ static int __rsnd_ssi_start(struct rsnd_mod *mod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_ssi_start(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
/*
|
||||
* no limit to start
|
||||
* see also
|
||||
* rsnd_ssi_stop
|
||||
* rsnd_ssi_interrupt
|
||||
*/
|
||||
return __rsnd_ssi_start(mod, io, priv);
|
||||
}
|
||||
|
||||
static int __rsnd_ssi_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
static int rsnd_ssi_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
||||
u32 cr;
|
||||
|
||||
/*
|
||||
* don't stop if not last user
|
||||
* see also
|
||||
* rsnd_ssi_start
|
||||
* rsnd_ssi_interrupt
|
||||
*/
|
||||
if (ssi->usrcnt > 1)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* disable all IRQ,
|
||||
* and, wait all data was sent
|
||||
@ -531,33 +506,14 @@ static int __rsnd_ssi_stop(struct rsnd_mod *mod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rsnd_ssi_stop(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io,
|
||||
struct rsnd_priv *priv)
|
||||
{
|
||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
||||
|
||||
/*
|
||||
* don't stop if not last user
|
||||
* see also
|
||||
* rsnd_ssi_start
|
||||
* rsnd_ssi_interrupt
|
||||
*/
|
||||
if (ssi->usrcnt > 1)
|
||||
return 0;
|
||||
|
||||
return __rsnd_ssi_stop(mod, io, priv);
|
||||
}
|
||||
|
||||
static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
|
||||
struct rsnd_dai_stream *io)
|
||||
{
|
||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
int is_dma = rsnd_ssi_is_dma_mode(mod);
|
||||
u32 status;
|
||||
bool elapsed = false;
|
||||
bool stop = false;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
@ -565,7 +521,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
|
||||
if (!rsnd_io_is_working(io))
|
||||
goto rsnd_ssi_interrupt_out;
|
||||
|
||||
status = rsnd_ssi_record_error(ssi);
|
||||
status = rsnd_ssi_status_get(mod);
|
||||
|
||||
/* PIO only */
|
||||
if (!is_dma && (status & DIRQ)) {
|
||||
@ -587,23 +543,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
|
||||
}
|
||||
|
||||
/* DMA only */
|
||||
if (is_dma && (status & (UIRQ | OIRQ))) {
|
||||
/*
|
||||
* restart SSI
|
||||
*/
|
||||
dev_dbg(dev, "%s[%d] restart\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod));
|
||||
|
||||
__rsnd_ssi_stop(mod, io, priv);
|
||||
__rsnd_ssi_start(mod, io, priv);
|
||||
}
|
||||
|
||||
if (ssi->err > 1024) {
|
||||
rsnd_ssi_irq_disable(mod);
|
||||
|
||||
dev_warn(dev, "no more %s[%d] restart\n",
|
||||
rsnd_mod_name(mod), rsnd_mod_id(mod));
|
||||
}
|
||||
if (is_dma && (status & (UIRQ | OIRQ)))
|
||||
stop = true;
|
||||
|
||||
rsnd_ssi_status_clear(mod);
|
||||
rsnd_ssi_interrupt_out:
|
||||
@ -611,6 +552,10 @@ rsnd_ssi_interrupt_out:
|
||||
|
||||
if (elapsed)
|
||||
rsnd_dai_period_elapsed(io);
|
||||
|
||||
if (stop)
|
||||
snd_pcm_stop_xrun(io->substream);
|
||||
|
||||
}
|
||||
|
||||
static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
|
||||
|
Loading…
Reference in New Issue
Block a user