Merge branch 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / base / power / main.c
index 052dc53..aa63202 100644 (file)
@@ -63,6 +63,7 @@ void device_pm_init(struct device *dev)
        dev->power.wakeup = NULL;
        spin_lock_init(&dev->power.lock);
        pm_runtime_init(dev);
+       INIT_LIST_HEAD(&dev->power.entry);
 }
 
 /**
@@ -233,7 +234,7 @@ static int pm_op(struct device *dev,
                }
                break;
 #endif /* CONFIG_SUSPEND */
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
        case PM_EVENT_FREEZE:
        case PM_EVENT_QUIESCE:
                if (ops->freeze) {
@@ -260,7 +261,7 @@ static int pm_op(struct device *dev,
                        suspend_report_result(ops->restore, error);
                }
                break;
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
        default:
                error = -EINVAL;
        }
@@ -308,7 +309,7 @@ static int pm_noirq_op(struct device *dev,
                }
                break;
 #endif /* CONFIG_SUSPEND */
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_HIBERNATE_CALLBACKS
        case PM_EVENT_FREEZE:
        case PM_EVENT_QUIESCE:
                if (ops->freeze_noirq) {
@@ -335,7 +336,7 @@ static int pm_noirq_op(struct device *dev,
                        suspend_report_result(ops->restore_noirq, error);
                }
                break;
-#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
        default:
                error = -EINVAL;
        }
@@ -425,10 +426,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 
        if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "EARLY power domain ");
-               pm_noirq_op(dev, &dev->pwr_domain->ops, state);
-       }
-
-       if (dev->type && dev->type->pm) {
+               error = pm_noirq_op(dev, &dev->pwr_domain->ops, state);
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "EARLY type ");
                error = pm_noirq_op(dev, dev->type->pm, state);
        } else if (dev->class && dev->class->pm) {
@@ -516,7 +515,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
        if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "power domain ");
-               pm_op(dev, &dev->pwr_domain->ops, state);
+               error = pm_op(dev, &dev->pwr_domain->ops, state);
+               goto End;
        }
 
        if (dev->type && dev->type->pm) {
@@ -579,11 +579,13 @@ static bool is_async(struct device *dev)
  * Execute the appropriate "resume" callback for all devices whose status
  * indicates that they are suspended.
  */
-static void dpm_resume(pm_message_t state)
+void dpm_resume(pm_message_t state)
 {
        struct device *dev;
        ktime_t starttime = ktime_get();
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
@@ -628,12 +630,11 @@ static void device_complete(struct device *dev, pm_message_t state)
 {
        device_lock(dev);
 
-       if (dev->pwr_domain && dev->pwr_domain->ops.complete) {
+       if (dev->pwr_domain) {
                pm_dev_dbg(dev, state, "completing power domain ");
-               dev->pwr_domain->ops.complete(dev);
-       }
-
-       if (dev->type && dev->type->pm) {
+               if (dev->pwr_domain->ops.complete)
+                       dev->pwr_domain->ops.complete(dev);
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "completing type ");
                if (dev->type->pm->complete)
                        dev->type->pm->complete(dev);
@@ -657,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state)
  * Execute the ->complete() callbacks for all devices whose PM status is not
  * DPM_ON (this allows new devices to be registered).
  */
-static void dpm_complete(pm_message_t state)
+void dpm_complete(pm_message_t state)
 {
        struct list_head list;
 
+       might_sleep();
+
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_prepared_list)) {
@@ -689,7 +692,6 @@ static void dpm_complete(pm_message_t state)
  */
 void dpm_resume_end(pm_message_t state)
 {
-       might_sleep();
        dpm_resume(state);
        dpm_complete(state);
 }
@@ -731,7 +733,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
 {
        int error;
 
-       if (dev->type && dev->type->pm) {
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "LATE power domain ");
+               error = pm_noirq_op(dev, &dev->pwr_domain->ops, state);
+               if (error)
+                       return error;
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "LATE type ");
                error = pm_noirq_op(dev, dev->type->pm, state);
                if (error)
@@ -748,11 +755,6 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
                        return error;
        }
 
-       if (dev->pwr_domain) {
-               pm_dev_dbg(dev, state, "LATE power domain ");
-               pm_noirq_op(dev, &dev->pwr_domain->ops, state);
-       }
-
        return 0;
 }
 
@@ -840,21 +842,27 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto End;
        }
 
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "power domain ");
+               error = pm_op(dev, &dev->pwr_domain->ops, state);
+               goto End;
+       }
+
        if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "type ");
                error = pm_op(dev, dev->type->pm, state);
-               goto Domain;
+               goto End;
        }
 
        if (dev->class) {
                if (dev->class->pm) {
                        pm_dev_dbg(dev, state, "class ");
                        error = pm_op(dev, dev->class->pm, state);
-                       goto Domain;
+                       goto End;
                } else if (dev->class->suspend) {
                        pm_dev_dbg(dev, state, "legacy class ");
                        error = legacy_suspend(dev, state, dev->class->suspend);
-                       goto Domain;
+                       goto End;
                }
        }
 
@@ -868,12 +876,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                }
        }
 
- Domain:
-       if (!error && dev->pwr_domain) {
-               pm_dev_dbg(dev, state, "power domain ");
-               pm_op(dev, &dev->pwr_domain->ops, state);
-       }
-
  End:
        device_unlock(dev);
        complete_all(&dev->power.completion);
@@ -913,11 +915,13 @@ static int device_suspend(struct device *dev)
  * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
  * @state: PM transition of the system being carried out.
  */
-static int dpm_suspend(pm_message_t state)
+int dpm_suspend(pm_message_t state)
 {
        ktime_t starttime = ktime_get();
        int error = 0;
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
        async_error = 0;
@@ -964,7 +968,14 @@ static int device_prepare(struct device *dev, pm_message_t state)
 
        device_lock(dev);
 
-       if (dev->type && dev->type->pm) {
+       if (dev->pwr_domain) {
+               pm_dev_dbg(dev, state, "preparing power domain ");
+               if (dev->pwr_domain->ops.prepare)
+                       error = dev->pwr_domain->ops.prepare(dev);
+               suspend_report_result(dev->pwr_domain->ops.prepare, error);
+               if (error)
+                       goto End;
+       } else if (dev->type && dev->type->pm) {
                pm_dev_dbg(dev, state, "preparing type ");
                if (dev->type->pm->prepare)
                        error = dev->type->pm->prepare(dev);
@@ -983,13 +994,6 @@ static int device_prepare(struct device *dev, pm_message_t state)
                if (dev->bus->pm->prepare)
                        error = dev->bus->pm->prepare(dev);
                suspend_report_result(dev->bus->pm->prepare, error);
-               if (error)
-                       goto End;
-       }
-
-       if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {
-               pm_dev_dbg(dev, state, "preparing power domain ");
-               dev->pwr_domain->ops.prepare(dev);
        }
 
  End:
@@ -1004,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state)
  *
  * Execute the ->prepare() callback(s) for all devices.
  */
-static int dpm_prepare(pm_message_t state)
+int dpm_prepare(pm_message_t state)
 {
        int error = 0;
 
+       might_sleep();
+
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_list)) {
                struct device *dev = to_device(dpm_list.next);
@@ -1056,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state)
 {
        int error;
 
-       might_sleep();
        error = dpm_prepare(state);
        if (!error)
                error = dpm_suspend(state);