aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c1
-rw-r--r--drivers/base/power/domain.c19
-rw-r--r--include/linux/pm_domain.h1
3 files changed, 20 insertions, 1 deletions
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 5d35831e4fb..ac47bfcd287 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -103,6 +103,7 @@ void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
103 pm_genpd_init(genpd, NULL, false); 103 pm_genpd_init(genpd, NULL, false);
104 genpd->stop_device = pm_clk_suspend; 104 genpd->stop_device = pm_clk_suspend;
105 genpd->start_device = pm_clk_resume; 105 genpd->start_device = pm_clk_resume;
106 genpd->dev_irq_safe = true;
106 genpd->active_wakeup = pd_active_wakeup; 107 genpd->active_wakeup = pd_active_wakeup;
107 genpd->power_off = pd_power_down; 108 genpd->power_off = pd_power_down;
108 genpd->power_on = pd_power_up; 109 genpd->power_on = pd_power_up;
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 339eb2d9bdd..c2468a7e5b2 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -309,7 +309,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
309 309
310 not_suspended = 0; 310 not_suspended = 0;
311 list_for_each_entry(pdd, &genpd->dev_list, list_node) 311 list_for_each_entry(pdd, &genpd->dev_list, list_node)
312 if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev)) 312 if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
313 || pdd->dev->power.irq_safe))
313 not_suspended++; 314 not_suspended++;
314 315
315 if (not_suspended > genpd->in_progress) 316 if (not_suspended > genpd->in_progress)
@@ -417,12 +418,21 @@ static int pm_genpd_runtime_suspend(struct device *dev)
417 if (IS_ERR(genpd)) 418 if (IS_ERR(genpd))
418 return -EINVAL; 419 return -EINVAL;
419 420
421 might_sleep_if(!genpd->dev_irq_safe);
422
420 if (genpd->stop_device) { 423 if (genpd->stop_device) {
421 int ret = genpd->stop_device(dev); 424 int ret = genpd->stop_device(dev);
422 if (ret) 425 if (ret)
423 return ret; 426 return ret;
424 } 427 }
425 428
429 /*
430 * If power.irq_safe is set, this routine will be run with interrupts
431 * off, so it can't use mutexes.
432 */
433 if (dev->power.irq_safe)
434 return 0;
435
426 mutex_lock(&genpd->lock); 436 mutex_lock(&genpd->lock);
427 genpd->in_progress++; 437 genpd->in_progress++;
428 pm_genpd_poweroff(genpd); 438 pm_genpd_poweroff(genpd);
@@ -452,6 +462,12 @@ static int pm_genpd_runtime_resume(struct device *dev)
452 if (IS_ERR(genpd)) 462 if (IS_ERR(genpd))
453 return -EINVAL; 463 return -EINVAL;
454 464
465 might_sleep_if(!genpd->dev_irq_safe);
466
467 /* If power.irq_safe, the PM domain is never powered off. */
468 if (dev->power.irq_safe)
469 goto out;
470
455 mutex_lock(&genpd->lock); 471 mutex_lock(&genpd->lock);
456 ret = __pm_genpd_poweron(genpd); 472 ret = __pm_genpd_poweron(genpd);
457 if (ret) { 473 if (ret) {
@@ -483,6 +499,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
483 wake_up_all(&genpd->status_wait_queue); 499 wake_up_all(&genpd->status_wait_queue);
484 mutex_unlock(&genpd->lock); 500 mutex_unlock(&genpd->lock);
485 501
502 out:
486 if (genpd->start_device) 503 if (genpd->start_device)
487 genpd->start_device(dev); 504 genpd->start_device(dev);
488 505
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 5cce46c2d92..2538d906bcd 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -42,6 +42,7 @@ struct generic_pm_domain {
42 unsigned int suspended_count; /* System suspend device counter */ 42 unsigned int suspended_count; /* System suspend device counter */
43 unsigned int prepared_count; /* Suspend counter of prepared devices */ 43 unsigned int prepared_count; /* Suspend counter of prepared devices */
44 bool suspend_power_off; /* Power status before system suspend */ 44 bool suspend_power_off; /* Power status before system suspend */
45 bool dev_irq_safe; /* Device callbacks are IRQ-safe */
45 int (*power_off)(struct generic_pm_domain *domain); 46 int (*power_off)(struct generic_pm_domain *domain);
46 int (*power_on)(struct generic_pm_domain *domain); 47 int (*power_on)(struct generic_pm_domain *domain);
47 int (*start_device)(struct device *dev); 48 int (*start_device)(struct device *dev);