diff options
-rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 1 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 19 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 1 |
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); |