Skip to content

Commit a3950d4

Browse files
committed
WORKAROUND: i2c: qcom-geni: Fix -EACCES error during system resume
When other drivers attempt I2C transfers during early resume phase, the I2C controller is still runtime suspended, causing pm_runtime_get_sync() to fail with -EACCES (-13): [ 101.914202] geni_i2c 980000.i2c: error turning SE resources:-13 The PM runtime core returns -EACCES when runtime PM is disabled (dev->power.disable_depth > 0). This occurs because: 1. During suspend_noirq, I2C driver calls geni_i2c_runtime_suspend() and then pm_runtime_disable() 2. I2C driver's noirq_resume only marks adapter as resumed but doesn't re-enable runtime PM or power up the hardware 3. Other drivers resuming later attempt I2C transfers 4. pm_runtime_get_sync() returns -EACCES because runtime PM is still disabled Fix this by calling pm_runtime_force_resume() in geni_i2c_resume_noirq() to properly resume the hardware and re-enable runtime PM during the noirq phase. This ensures the I2C controller is powered and ready for use when other drivers need it during resume. Upstream-Status: Pending Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
1 parent 0cf570b commit a3950d4

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

drivers/i2c/busses/i2c-qcom-geni.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,8 +831,14 @@ static int geni_i2c_probe(struct platform_device *pdev)
831831
spin_lock_init(&gi2c->lock);
832832
platform_set_drvdata(pdev, gi2c);
833833

834-
/* Keep interrupts disabled initially to allow for low-power modes */
835-
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN,
834+
/*
835+
* Keep interrupts disabled initially to allow for low-power modes.
836+
* IRQF_NO_SUSPEND: Keep IRQ enabled during suspend to handle I2C transfers
837+
* in noirq phase (e.g., from PCIe driver's noirq_resume).
838+
* IRQF_EARLY_RESUME: Enable IRQ early during resume sequence.
839+
*/
840+
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq,
841+
IRQF_NO_AUTOEN | IRQF_NO_SUSPEND | IRQF_EARLY_RESUME,
836842
dev_name(dev), gi2c);
837843
if (ret)
838844
return dev_err_probe(dev, ret,
@@ -1044,6 +1050,20 @@ static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
10441050
static int __maybe_unused geni_i2c_resume_noirq(struct device *dev)
10451051
{
10461052
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
1053+
int ret = 0;
1054+
1055+
/*
1056+
* Resume hardware to handle I2C transfers from other drivers'
1057+
* noirq_resume callbacks (e.g., PCIe driver).
1058+
* pm_runtime_force_resume() properly handles PM state and usage_count.
1059+
*/
1060+
if (gi2c->suspended) {
1061+
ret = pm_runtime_force_resume(dev);
1062+
if (ret) {
1063+
dev_err(dev, "Failed to resume I2C during noirq: %d\n", ret);
1064+
return ret;
1065+
}
1066+
}
10471067

10481068
i2c_mark_adapter_resumed(&gi2c->adap);
10491069
return 0;

0 commit comments

Comments
 (0)