[PATCH v3] mfd: intel_soc_pmic_crc: Balance IRQ wake enable
From: Myeonghun Pak
Date: Thu Sep 17 2026 - 19:32:37 EST
The INT33FD Crystal Cove driver enables the parent IRQ as a wake source
after registering its regmap IRQ chip. When that succeeds, a later
mfd_add_devices() failure or driver removal leaves the wake enable
unbalanced.
Record whether enable_irq_wake() succeeded and disable IRQ wake on a
subsequent mfd_add_devices() failure or driver removal. On removal, do
this after removing the MFD children and before the managed regmap IRQ
chip is released. Keep warning and continuing when enable_irq_wake()
itself fails, without attempting to disable wake in that case.
This is limited to the Bay Trail and Cherry Trail Crystal Cove PMIC
variants using the INT33FD ACPI ID.
This issue was identified during our ongoing static-analysis research while
reviewing kernel code.
Fixes: 516523846006 ("mfd: intel_soc_pmic: Core driver")
Assisted-by: LLM
Co-developed-by: Ijae Kim <ae878000@xxxxxxxxx>
Signed-off-by: Ijae Kim <ae878000@xxxxxxxxx>
Signed-off-by: Myeonghun Pak <mhun512@xxxxxxxxx>
---
Changes in v3:
- Replace the wake-disable devm action with a per-device success flag and
explicit cleanup on probe failure and removal, as suggested by Andy.
- Drop the shutdown changes and the shutdown cleanup rationale. Preserve
the existing shutdown behavior.
Changes in v2:
- Capitalize the subject description.
- Use Assisted-by: LLM as requested.
- Keep devm_add_action_or_reset() on a single line.
- Release the registered wake-disable action at shutdown, skipping it if
enabling IRQ wake failed and removing it to avoid duplicate cleanup.
drivers/mfd/intel_soc_pmic_crc.c | 11 ++++++++++-
include/linux/mfd/intel_soc_pmic.h | 2 ++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c
index 627a89334908116a7e1924f9d78121284d1316b0..2679061f449558e327b65abb2bb4d2ae2e3d9a10
100644
--- a/drivers/mfd/intel_soc_pmic_crc.c
+++ b/drivers/mfd/intel_soc_pmic_crc.c
@@ -197,6 +197,8 @@ static int crystal_cove_i2c_probe(struct i2c_client *i2c)
ret = enable_irq_wake(pmic->irq);
if (ret)
dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret);
+ else
+ pmic->irq_wake_enabled = true;
/* Add lookup table for crc-pwm */
pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
@@ -208,18 +210,25 @@ static int crystal_cove_i2c_probe(struct i2c_client *i2c)
ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, config->cell_dev,
config->n_cell_devs, NULL, 0,
regmap_irq_get_domain(pmic->irq_chip_data));
- if (ret)
+ if (ret) {
pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
+ if (pmic->irq_wake_enabled)
+ disable_irq_wake(pmic->irq);
+ }
return ret;
}
static void crystal_cove_i2c_remove(struct i2c_client *i2c)
{
+ struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c);
+
/* remove crc-pwm lookup table */
pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
mfd_remove_devices(&i2c->dev);
+ if (pmic->irq_wake_enabled)
+ disable_irq_wake(pmic->irq);
}
static void crystal_cove_shutdown(struct i2c_client *i2c)
diff --git a/include/linux/mfd/intel_soc_pmic.h
b/include/linux/mfd/intel_soc_pmic.h
index 9ba2c1a8d836756a255487f6dceccb441b500549..07308245da28bc0d3f916ee65313ebff808ba86b
100644
--- a/include/linux/mfd/intel_soc_pmic.h
+++ b/include/linux/mfd/intel_soc_pmic.h
@@ -24,6 +24,7 @@ enum intel_cht_wc_models {
/**
* struct intel_soc_pmic - Intel SoC PMIC data
* @irq: Master interrupt number of the parent PMIC device
+ * @irq_wake_enabled: Whether Crystal Cove enabled wake on the parent IRQ
* @regmap: Pointer to the parent PMIC device regmap structure
* @irq_chip_data: IRQ chip data for the PMIC itself
* @irq_chip_data_pwrbtn: Chained IRQ chip data for the Power Button
@@ -37,6 +38,7 @@ enum intel_cht_wc_models {
*/
struct intel_soc_pmic {
int irq;
+ bool irq_wake_enabled;
struct regmap *regmap;
struct regmap_irq_chip_data *irq_chip_data;
struct regmap_irq_chip_data *irq_chip_data_pwrbtn;