ASoC: sh: fsi: Add over/under run counter
Current FSI driver had printed under/over run error
if status register have its error bit.
But runtime print cause the next error
because print out is slow.
This patch add error counter and print error when sound stop
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 9ab8593..2b06402 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -134,6 +134,9 @@
int buff_len;
int period_len;
int period_num;
+
+ int uerr_num;
+ int oerr_num;
};
struct fsi_priv {
@@ -326,17 +329,29 @@
io->buff_offset = 0;
io->period_len = period_len;
io->period_num = 0;
+ io->oerr_num = -1; /* ignore 1st err */
+ io->uerr_num = -1; /* ignore 1st err */
}
static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
{
struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+ struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+
+
+ if (io->oerr_num > 0)
+ dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
+
+ if (io->uerr_num > 0)
+ dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
io->substream = NULL;
io->buff_len = 0;
io->buff_offset = 0;
io->period_len = 0;
io->period_num = 0;
+ io->oerr_num = 0;
+ io->uerr_num = 0;
}
static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
@@ -375,6 +390,27 @@
return frames_to_bytes(runtime, 1) / io->chan_num;
}
+static void fsi_count_fifo_err(struct fsi_priv *fsi)
+{
+ u32 ostatus = fsi_reg_read(fsi, DOFF_ST);
+ u32 istatus = fsi_reg_read(fsi, DIFF_ST);
+
+ if (ostatus & ERR_OVER)
+ fsi->playback.oerr_num++;
+
+ if (ostatus & ERR_UNDER)
+ fsi->playback.uerr_num++;
+
+ if (istatus & ERR_OVER)
+ fsi->capture.oerr_num++;
+
+ if (istatus & ERR_UNDER)
+ fsi->capture.uerr_num++;
+
+ fsi_reg_write(fsi, DOFF_ST, 0);
+ fsi_reg_write(fsi, DIFF_ST, 0);
+}
+
/*
* dma function
*/
@@ -574,7 +610,7 @@
mdelay(10);
}
-static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
{
struct snd_pcm_runtime *runtime;
struct snd_pcm_substream *substream = NULL;
@@ -667,37 +703,20 @@
/* update buff_offset */
io->buff_offset += fsi_num2offset(data_num, ch_width);
- /* check fifo status */
- if (!startup) {
- struct snd_soc_dai *dai = fsi_get_dai(substream);
- u32 status = is_play ?
- fsi_reg_read(fsi, DOFF_ST) :
- fsi_reg_read(fsi, DIFF_ST);
-
- if (status & ERR_OVER)
- dev_err(dai->dev, "over run\n");
- if (status & ERR_UNDER)
- dev_err(dai->dev, "under run\n");
- }
-
- is_play ?
- fsi_reg_write(fsi, DOFF_ST, 0) :
- fsi_reg_write(fsi, DIFF_ST, 0);
-
if (over_period)
snd_pcm_period_elapsed(substream);
return 0;
}
-static int fsi_data_pop(struct fsi_priv *fsi, int startup)
+static int fsi_data_pop(struct fsi_priv *fsi)
{
- return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+ return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_CAPTURE);
}
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_data_push(struct fsi_priv *fsi)
{
- return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
+ return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_PLAYBACK);
}
static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -710,13 +729,16 @@
fsi_master_mask_set(master, SOFT_RST, IR, IR);
if (int_st & AB_IO(1, AO_SHIFT))
- fsi_data_push(&master->fsia, 0);
+ fsi_data_push(&master->fsia);
if (int_st & AB_IO(1, BO_SHIFT))
- fsi_data_push(&master->fsib, 0);
+ fsi_data_push(&master->fsib);
if (int_st & AB_IO(1, AI_SHIFT))
- fsi_data_pop(&master->fsia, 0);
+ fsi_data_pop(&master->fsia);
if (int_st & AB_IO(1, BI_SHIFT))
- fsi_data_pop(&master->fsib, 0);
+ fsi_data_pop(&master->fsib);
+
+ fsi_count_fifo_err(&master->fsia);
+ fsi_count_fifo_err(&master->fsib);
fsi_irq_clear_status(&master->fsia);
fsi_irq_clear_status(&master->fsib);
@@ -855,7 +877,7 @@
fsi_stream_push(fsi, is_play, substream,
frames_to_bytes(runtime, runtime->buffer_size),
frames_to_bytes(runtime, runtime->period_size));
- ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
+ ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
fsi_irq_enable(fsi, is_play);
break;
case SNDRV_PCM_TRIGGER_STOP: