[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250903094549.271068-4-ckeepax@opensource.cirrus.com>
Date: Wed, 3 Sep 2025 10:45:46 +0100
From: Charles Keepax <ckeepax@...nsource.cirrus.com>
To: broonie@...nel.org, lee@...nel.org
Cc: lgirdwood@...il.com, linux-sound@...r.kernel.org,
linux-kernel@...r.kernel.org, patches@...nsource.cirrus.com
Subject: [PATCH 3/6] ASoC: cs42l43: Disable IRQs in system suspend
Currently the MFD driver disables all the IRQs upon entering system
suspend, however there are some issues with this approach. As this
device uses runtime force suspend.
The regmap IRQ handler can run, claim a PM runtime reference and get
scheduled, the MFD can then force suspend. When the IRQ thread gets
rescheduled it will try to access volatile registers on the
suspended device. Furthermore, this race also applies to work queue
items scheduled by the IRQ handlers.
As the MFD code doesn't know about the individual work queue items, the
end drivers must mask their own IRQs and sync in any work queues as part
of entering system suspend. Update the code here to do so.
Signed-off-by: Charles Keepax <ckeepax@...nsource.cirrus.com>
---
sound/soc/codecs/cs42l43.c | 78 ++++++++++++++++++++++++++++++--------
sound/soc/codecs/cs42l43.h | 1 +
2 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 241f7d013189c..405926149a137 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -2229,12 +2229,29 @@ static int cs42l43_request_irq(struct cs42l43_codec *priv,
return 0;
}
+static void cs42l43_disable_irq(struct cs42l43_codec *priv, unsigned int irq)
+{
+ int ret;
+
+ ret = irq_find_mapping(priv->dom, irq);
+ if (ret > 0)
+ disable_irq(ret);
+}
+
+static void cs42l43_enable_irq(struct cs42l43_codec *priv, unsigned int irq)
+{
+ int ret;
+
+ ret = irq_find_mapping(priv->dom, irq);
+ if (ret > 0)
+ enable_irq(ret);
+}
+
static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter,
- const char * const open_name,
- const char * const close_name,
+ const char * const open_name, unsigned int *open_irq,
+ const char * const close_name, unsigned int *close_irq,
irq_handler_t handler)
{
- unsigned int open_irq, close_irq;
int ret;
switch (shutter) {
@@ -2242,26 +2259,26 @@ static int cs42l43_shutter_irq(struct cs42l43_codec *priv, unsigned int shutter,
dev_warn(priv->dev, "Manual shutters, notifications not available\n");
return 0;
case 0x2:
- open_irq = CS42L43_GPIO1_RISE;
- close_irq = CS42L43_GPIO1_FALL;
+ *open_irq = CS42L43_GPIO1_RISE;
+ *close_irq = CS42L43_GPIO1_FALL;
break;
case 0x4:
- open_irq = CS42L43_GPIO2_RISE;
- close_irq = CS42L43_GPIO2_FALL;
+ *open_irq = CS42L43_GPIO2_RISE;
+ *close_irq = CS42L43_GPIO2_FALL;
break;
case 0x8:
- open_irq = CS42L43_GPIO3_RISE;
- close_irq = CS42L43_GPIO3_FALL;
+ *open_irq = CS42L43_GPIO3_RISE;
+ *close_irq = CS42L43_GPIO3_FALL;
break;
default:
return 0;
}
- ret = cs42l43_request_irq(priv, close_name, close_irq, handler, IRQF_SHARED);
+ ret = cs42l43_request_irq(priv, close_name, *close_irq, handler, IRQF_SHARED);
if (ret)
return ret;
- return cs42l43_request_irq(priv, open_name, open_irq, handler, IRQF_SHARED);
+ return cs42l43_request_irq(priv, open_name, *open_irq, handler, IRQF_SHARED);
}
static int cs42l43_codec_probe(struct platform_device *pdev)
@@ -2325,14 +2342,16 @@ static int cs42l43_codec_probe(struct platform_device *pdev)
}
ret = cs42l43_shutter_irq(priv, val & CS42L43_MIC_SHUTTER_CFG_MASK,
- "mic shutter open", "mic shutter close",
+ "mic shutter open", &priv->shutter_irqs[0],
+ "mic shutter close", &priv->shutter_irqs[1],
cs42l43_mic_shutter);
if (ret)
goto err_pm;
ret = cs42l43_shutter_irq(priv, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >>
CS42L43_SPK_SHUTTER_CFG_SHIFT,
- "spk shutter open", "spk shutter close",
+ "spk shutter open", &priv->shutter_irqs[2],
+ "spk shutter close", &priv->shutter_irqs[3],
cs42l43_spk_shutter);
if (ret)
goto err_pm;
@@ -2386,19 +2405,48 @@ static int cs42l43_codec_runtime_resume(struct device *dev)
static int cs42l43_codec_suspend(struct device *dev)
{
struct cs42l43_codec *priv = dev_get_drvdata(dev);
+ int i;
dev_dbg(priv->dev, "System suspend\n");
priv->suspend_jack_debounce = true;
- pm_runtime_force_suspend(dev);
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++)
+ cs42l43_disable_irq(priv, cs42l43_irqs[i].irq);
+
+ for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++)
+ if (priv->shutter_irqs[i])
+ cs42l43_disable_irq(priv, priv->shutter_irqs[i]);
+
+ cancel_delayed_work_sync(&priv->bias_sense_timeout);
+ cancel_delayed_work_sync(&priv->tip_sense_work);
+ cancel_delayed_work_sync(&priv->hp_ilimit_clear_work);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int cs42l43_codec_resume(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+ int ret, i;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++)
+ cs42l43_enable_irq(priv, cs42l43_irqs[i].irq);
+
+ for (i = 0; i < ARRAY_SIZE(priv->shutter_irqs); i++)
+ if (priv->shutter_irqs[i])
+ cs42l43_enable_irq(priv, priv->shutter_irqs[i]);
return 0;
}
static const struct dev_pm_ops cs42l43_codec_pm_ops = {
RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
- SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, pm_runtime_force_resume)
+ SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume)
};
static const struct platform_device_id cs42l43_codec_id_table[] = {
diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h
index f4ef93d1fc2a4..0951ad3525efe 100644
--- a/sound/soc/codecs/cs42l43.h
+++ b/sound/soc/codecs/cs42l43.h
@@ -45,6 +45,7 @@ struct cs42l43_codec {
struct cs42l43 *core;
struct snd_soc_component *component;
struct irq_domain *dom;
+ unsigned int shutter_irqs[4];
struct clk *mclk;
--
2.47.2
Powered by blists - more mailing lists