|
@@ -110,8 +110,10 @@ void dev_pm_clear_wake_irq(struct device *dev)
|
|
|
dev->power.wakeirq = NULL;
|
|
|
spin_unlock_irqrestore(&dev->power.lock, flags);
|
|
|
|
|
|
- if (wirq->dedicated_irq)
|
|
|
+ if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) {
|
|
|
free_irq(wirq->irq, wirq);
|
|
|
+ wirq->status &= ~WAKE_IRQ_DEDICATED_MASK;
|
|
|
+ }
|
|
|
kfree(wirq);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
|
|
@@ -179,7 +181,6 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
|
|
|
|
|
|
wirq->dev = dev;
|
|
|
wirq->irq = irq;
|
|
|
- wirq->dedicated_irq = true;
|
|
|
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
|
|
|
|
|
/*
|
|
@@ -195,6 +196,8 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
|
|
|
if (err)
|
|
|
goto err_free_irq;
|
|
|
|
|
|
+ wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED;
|
|
|
+
|
|
|
return err;
|
|
|
|
|
|
err_free_irq:
|
|
@@ -210,9 +213,9 @@ EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
|
|
|
* dev_pm_enable_wake_irq - Enable device wake-up interrupt
|
|
|
* @dev: Device
|
|
|
*
|
|
|
- * Called from the bus code or the device driver for
|
|
|
- * runtime_suspend() to enable the wake-up interrupt while
|
|
|
- * the device is running.
|
|
|
+ * Optionally called from the bus code or the device driver for
|
|
|
+ * runtime_resume() to override the PM runtime core managed wake-up
|
|
|
+ * interrupt handling to enable the wake-up interrupt.
|
|
|
*
|
|
|
* Note that for runtime_suspend()) the wake-up interrupts
|
|
|
* should be unconditionally enabled unlike for suspend()
|
|
@@ -222,7 +225,7 @@ void dev_pm_enable_wake_irq(struct device *dev)
|
|
|
{
|
|
|
struct wake_irq *wirq = dev->power.wakeirq;
|
|
|
|
|
|
- if (wirq && wirq->dedicated_irq)
|
|
|
+ if (wirq && (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED))
|
|
|
enable_irq(wirq->irq);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
|
|
@@ -231,19 +234,72 @@ EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
|
|
|
* dev_pm_disable_wake_irq - Disable device wake-up interrupt
|
|
|
* @dev: Device
|
|
|
*
|
|
|
- * Called from the bus code or the device driver for
|
|
|
- * runtime_resume() to disable the wake-up interrupt while
|
|
|
- * the device is running.
|
|
|
+ * Optionally called from the bus code or the device driver for
|
|
|
+ * runtime_suspend() to override the PM runtime core managed wake-up
|
|
|
+ * interrupt handling to disable the wake-up interrupt.
|
|
|
*/
|
|
|
void dev_pm_disable_wake_irq(struct device *dev)
|
|
|
{
|
|
|
struct wake_irq *wirq = dev->power.wakeirq;
|
|
|
|
|
|
- if (wirq && wirq->dedicated_irq)
|
|
|
+ if (wirq && (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED))
|
|
|
disable_irq_nosync(wirq->irq);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
|
|
|
|
|
|
+/**
|
|
|
+ * dev_pm_enable_wake_irq_check - Checks and enables wake-up interrupt
|
|
|
+ * @dev: Device
|
|
|
+ * @can_change_status: Can change wake-up interrupt status
|
|
|
+ *
|
|
|
+ * Enables wakeirq conditionally. We need to enable wake-up interrupt
|
|
|
+ * lazily on the first rpm_suspend(). This is needed as the consumer device
|
|
|
+ * starts in RPM_SUSPENDED state, and the the first pm_runtime_get() would
|
|
|
+ * otherwise try to disable already disabled wakeirq. The wake-up interrupt
|
|
|
+ * starts disabled with IRQ_NOAUTOEN set.
|
|
|
+ *
|
|
|
+ * Should be only called from rpm_suspend() and rpm_resume() path.
|
|
|
+ * Caller must hold &dev->power.lock to change wirq->status
|
|
|
+ */
|
|
|
+void dev_pm_enable_wake_irq_check(struct device *dev,
|
|
|
+ bool can_change_status)
|
|
|
+{
|
|
|
+ struct wake_irq *wirq = dev->power.wakeirq;
|
|
|
+
|
|
|
+ if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (likely(wirq->status & WAKE_IRQ_DEDICATED_MANAGED)) {
|
|
|
+ goto enable;
|
|
|
+ } else if (can_change_status) {
|
|
|
+ wirq->status |= WAKE_IRQ_DEDICATED_MANAGED;
|
|
|
+ goto enable;
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+enable:
|
|
|
+ enable_irq(wirq->irq);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt
|
|
|
+ * @dev: Device
|
|
|
+ *
|
|
|
+ * Disables wake-up interrupt conditionally based on status.
|
|
|
+ * Should be only called from rpm_suspend() and rpm_resume() path.
|
|
|
+ */
|
|
|
+void dev_pm_disable_wake_irq_check(struct device *dev)
|
|
|
+{
|
|
|
+ struct wake_irq *wirq = dev->power.wakeirq;
|
|
|
+
|
|
|
+ if (!wirq || !((wirq->status & WAKE_IRQ_DEDICATED_MASK)))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED)
|
|
|
+ disable_irq_nosync(wirq->irq);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* dev_pm_arm_wake_irq - Arm device wake-up
|
|
|
* @wirq: Device wake-up interrupt
|