aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Fitzgerald <[email protected]>2021-10-15 14:36:18 +0100
committerMark Brown <[email protected]>2021-10-15 16:14:23 +0100
commit4c8d49bc476c7cf1fb7377b469ced43ced470027 (patch)
tree464272722f7ec93f417b48eb694a439638e8e59e
parent0c3d6c6ff75aa6b21cd4ac872dd3050b6525c75c (diff)
ASoC: cs42l42: Fix WARN in remove() if running without an interrupt
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
-rw-r--r--sound/soc/codecs/cs42l42.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 390cd7ea3a7f..c6d91ad996e0 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -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);
@@ -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);