Skip to content

Commit fd3b958

Browse files
TE-N-ShengjiuWangbroonie
authored andcommitted
ASoC: fsl_sai: Eliminate possible interrupt storm during probe
When the SAI peripheral is left in a running state by the bootloader, the driver can experience an interrupt storm during probe that prevents successful initialization. This occurs because the current code registers the IRQ handler before resetting the hardware to a known state. The issue manifests as: - Continuous interrupts firing immediately after devm_request_irq() - Driver probe failure or system hang - Error messages about unhandled interrupts This is particularly problematic on systems where U-Boot or other bootloaders enable SAI for boot-time audio feedback or diagnostics and don't properly disable it before handing control to Linux. Fix this by reordering the probe sequence: 1. Add fsl_sai_reset_hw() to clear TCSR/RCSR control registers, which disables the transmitter/receiver and all interrupt sources 2. Move devm_request_irq() to after hardware initialization This ensures the SAI is in a clean reset state before the interrupt handler can be invoked, preventing the storm while maintaining proper error handling and cleanup paths. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Link: https://patch.msgid.link/20260512065252.75859-1-shengjiu.wang@nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 6e4bfd9 commit fd3b958

1 file changed

Lines changed: 36 additions & 7 deletions

File tree

sound/soc/fsl/fsl_sai.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,31 @@ static int fsl_sai_check_version(struct device *dev)
13701370
return 0;
13711371
}
13721372

1373+
static int fsl_sai_reset_hw(struct device *dev)
1374+
{
1375+
struct fsl_sai *sai = dev_get_drvdata(dev);
1376+
unsigned char ofs = sai->soc_data->reg_offset;
1377+
int ret;
1378+
1379+
/*
1380+
* Clear TCSR/RCSR to reset SAI and disable all interrupts.
1381+
* Bootloader may leave SAI running causing interrupt storm.
1382+
*/
1383+
ret = regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
1384+
if (ret) {
1385+
dev_err(dev, "Failed to clear TCSR: %d\n", ret);
1386+
return ret;
1387+
}
1388+
1389+
ret = regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
1390+
if (ret) {
1391+
dev_err(dev, "Failed to clear RCSR: %d\n", ret);
1392+
return ret;
1393+
}
1394+
1395+
return 0;
1396+
}
1397+
13731398
/*
13741399
* Calculate the offset between first two datalines, don't
13751400
* different offset in one case.
@@ -1575,13 +1600,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
15751600
if (irq < 0)
15761601
return irq;
15771602

1578-
ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
1579-
np->name, sai);
1580-
if (ret) {
1581-
dev_err(dev, "failed to claim irq %u\n", irq);
1582-
return ret;
1583-
}
1584-
15851603
memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template,
15861604
sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template));
15871605

@@ -1656,6 +1674,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
16561674
if (ret < 0)
16571675
dev_warn(dev, "Error reading SAI version: %d\n", ret);
16581676

1677+
ret = fsl_sai_reset_hw(dev);
1678+
if (ret < 0)
1679+
dev_warn(dev, "Failed to reset hardware: %d\n", ret);
1680+
16591681
/* Select MCLK direction */
16601682
if (sai->mclk_direction_output &&
16611683
sai->soc_data->max_register >= FSL_SAI_MCTL) {
@@ -1667,6 +1689,13 @@ static int fsl_sai_probe(struct platform_device *pdev)
16671689
if (ret < 0 && ret != -ENOSYS)
16681690
goto err_pm_get_sync;
16691691

1692+
ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
1693+
np->name, sai);
1694+
if (ret) {
1695+
dev_err(dev, "failed to claim irq %u\n", irq);
1696+
goto err_pm_get_sync;
1697+
}
1698+
16701699
if (of_device_is_compatible(np, "fsl,imx952-sai") &&
16711700
!of_property_read_string(np, "fsl,sai-amix-mode", &str)) {
16721701
if (!strcmp(str, "bypass"))

0 commit comments

Comments
 (0)