mirror of https://github.com/thesofproject/sof.git
drivers: dmic: fix multi-fifo logic in interrupt handler
When the dmic driver is instantiated multiple times (e.g. for fifo-A and fifo-B), the interrupt gets registered also twice. While supported usage of interrupt interface, there is no guarantee that the interrupt context data is for the expected dai instance. It is thus not safe to modify the dai state directly or call dai_stop(). Modify the interrupt handler not to make any assumptions on which dai instance is passed as 'data' matches a specific fifo instance. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
This commit is contained in:
parent
282fe224d8
commit
76e773bb4f
|
@ -1422,18 +1422,10 @@ static void dmic_start(struct dai *dai)
|
||||||
*uncached_dmic_active_fifos);
|
*uncached_dmic_active_fifos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stop the DMIC for capture */
|
static void dmic_stop_fifo_packers(struct dai *dai, int fifo_index)
|
||||||
static void dmic_stop(struct dai *dai, bool in_active)
|
|
||||||
{
|
{
|
||||||
struct dmic_pdata *dmic = dai_get_drvdata(dai);
|
|
||||||
int *uncached_dmic_active_fifos = cache_to_uncache(&dmic_active_fifos);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
dai_dbg(dai, "dmic_stop()");
|
|
||||||
spin_lock(&dai->lock);
|
|
||||||
|
|
||||||
/* Stop FIFO packers and set FIFO initialize bits */
|
/* Stop FIFO packers and set FIFO initialize bits */
|
||||||
switch (dai->index) {
|
switch (fifo_index) {
|
||||||
case 0:
|
case 0:
|
||||||
dai_update_bits(dai, OUTCONTROL0,
|
dai_update_bits(dai, OUTCONTROL0,
|
||||||
OUTCONTROL0_SIP_BIT | OUTCONTROL0_FINIT_BIT,
|
OUTCONTROL0_SIP_BIT | OUTCONTROL0_FINIT_BIT,
|
||||||
|
@ -1445,6 +1437,19 @@ static void dmic_stop(struct dai *dai, bool in_active)
|
||||||
OUTCONTROL1_FINIT_BIT);
|
OUTCONTROL1_FINIT_BIT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop the DMIC for capture */
|
||||||
|
static void dmic_stop(struct dai *dai, bool in_active)
|
||||||
|
{
|
||||||
|
struct dmic_pdata *dmic = dai_get_drvdata(dai);
|
||||||
|
int *uncached_dmic_active_fifos = cache_to_uncache(&dmic_active_fifos);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dai_dbg(dai, "dmic_stop()");
|
||||||
|
spin_lock(&dai->lock);
|
||||||
|
|
||||||
|
dmic_stop_fifo_packers(dai, dai->index);
|
||||||
|
|
||||||
/* Set soft reset and mute on for all PDM controllers.
|
/* Set soft reset and mute on for all PDM controllers.
|
||||||
*/
|
*/
|
||||||
|
@ -1551,7 +1556,6 @@ static int dmic_trigger(struct dai *dai, int cmd, int direction)
|
||||||
static void dmic_irq_handler(void *data)
|
static void dmic_irq_handler(void *data)
|
||||||
{
|
{
|
||||||
struct dai *dai = data;
|
struct dai *dai = data;
|
||||||
struct dmic_pdata *dmic = dai_get_drvdata(dai);
|
|
||||||
uint32_t val0;
|
uint32_t val0;
|
||||||
uint32_t val1;
|
uint32_t val1;
|
||||||
|
|
||||||
|
@ -1564,15 +1568,13 @@ static void dmic_irq_handler(void *data)
|
||||||
if (val0 & OUTSTAT0_ROR_BIT) {
|
if (val0 & OUTSTAT0_ROR_BIT) {
|
||||||
dai_err(dai, "dmic_irq_handler(): full fifo A or PDM overrun");
|
dai_err(dai, "dmic_irq_handler(): full fifo A or PDM overrun");
|
||||||
dai_write(dai, OUTSTAT0, val0);
|
dai_write(dai, OUTSTAT0, val0);
|
||||||
dmic_stop(dai, dmic->state == COMP_STATE_ACTIVE);
|
dmic_stop_fifo_packers(dai, 0);
|
||||||
dmic->state = COMP_STATE_PREPARE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val1 & OUTSTAT1_ROR_BIT) {
|
if (val1 & OUTSTAT1_ROR_BIT) {
|
||||||
dai_err(dai, "dmic_irq_handler(): full fifo B or PDM overrun");
|
dai_err(dai, "dmic_irq_handler(): full fifo B or PDM overrun");
|
||||||
dai_write(dai, OUTSTAT1, val1);
|
dai_write(dai, OUTSTAT1, val1);
|
||||||
dmic_stop(dai, dmic->state == COMP_STATE_ACTIVE);
|
dmic_stop_fifo_packers(dai, 1);
|
||||||
dmic->state = COMP_STATE_PREPARE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue