Skip to content

Commit

Permalink
ASoC: cs42l42: Fix WARN in remove() if running without an interrupt
Browse files Browse the repository at this point in the history
The driver must free the IRQ in remove() to prevent the potential race
where an IRQ starts to be handled while the driver is being removed but
devres has not yet called free_irq(). However, the driver can run without
an interrupt but devm_free_irq() will hit a WARN() if no devres-managed
interrupt was ever created.

Fix this by only attempting to create the interrupt handler if the hardware
config specified an interrupt, and failing probe() if the interrupt could
not be created. This means that in cs42l42_remove() an interrupt must have
been registered if the irq number is valid and therefore it is safe to call
devm_free_irq().

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20211015133619.4698-16-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Richard Fitzgerald authored and Mark Brown committed Oct 15, 2021
1 parent 0c3d6c6 commit 4c8d49b
Showing 1 changed file with 18 additions and 12 deletions.
30 changes: 18 additions & 12 deletions sound/soc/codecs/cs42l42.c
Original file line number Diff line number Diff line change
Expand Up @@ -1975,17 +1975,21 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
}
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);

/* Request IRQ */
ret = devm_request_threaded_irq(&i2c_client->dev,
i2c_client->irq,
NULL, cs42l42_irq_thread,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
"cs42l42", cs42l42);
if (ret == -EPROBE_DEFER)
goto err_disable;
else if (ret != 0)
dev_err(&i2c_client->dev,
"Failed to request IRQ: %d\n", ret);
/* Request IRQ if one was specified */
if (i2c_client->irq) {
ret = devm_request_threaded_irq(&i2c_client->dev,
i2c_client->irq,
NULL, cs42l42_irq_thread,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
"cs42l42", cs42l42);
if (ret == -EPROBE_DEFER) {
goto err_disable;
} else if (ret != 0) {
dev_err(&i2c_client->dev,
"Failed to request IRQ: %d\n", ret);
goto err_disable;
}
}

/* initialize codec */
devid = cirrus_read_device_id(cs42l42->regmap, CS42L42_DEVID_AB);
Expand Down Expand Up @@ -2056,7 +2060,9 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client)
{
struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client);

devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42);
if (i2c_client->irq)
devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42);

pm_runtime_suspend(&i2c_client->dev);
pm_runtime_disable(&i2c_client->dev);

Expand Down

0 comments on commit 4c8d49b

Please sign in to comment.