diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/power/domain.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 84f4beefa4f8..b6ff6ecf519d 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -366,7 +366,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
366 | not_suspended = 0; | 366 | not_suspended = 0; |
367 | list_for_each_entry(pdd, &genpd->dev_list, list_node) | 367 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
368 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) | 368 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) |
369 | || pdd->dev->power.irq_safe)) | 369 | || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on)) |
370 | not_suspended++; | 370 | not_suspended++; |
371 | 371 | ||
372 | if (not_suspended > genpd->in_progress) | 372 | if (not_suspended > genpd->in_progress) |
@@ -503,6 +503,9 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
503 | 503 | ||
504 | might_sleep_if(!genpd->dev_irq_safe); | 504 | might_sleep_if(!genpd->dev_irq_safe); |
505 | 505 | ||
506 | if (dev_gpd_data(dev)->always_on) | ||
507 | return -EBUSY; | ||
508 | |||
506 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; | 509 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; |
507 | if (stop_ok && !stop_ok(dev)) | 510 | if (stop_ok && !stop_ok(dev)) |
508 | return -EBUSY; | 511 | return -EBUSY; |
@@ -859,7 +862,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
859 | if (IS_ERR(genpd)) | 862 | if (IS_ERR(genpd)) |
860 | return -EINVAL; | 863 | return -EINVAL; |
861 | 864 | ||
862 | if (genpd->suspend_power_off | 865 | if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on |
863 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 866 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
864 | return 0; | 867 | return 0; |
865 | 868 | ||
@@ -892,7 +895,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
892 | if (IS_ERR(genpd)) | 895 | if (IS_ERR(genpd)) |
893 | return -EINVAL; | 896 | return -EINVAL; |
894 | 897 | ||
895 | if (genpd->suspend_power_off | 898 | if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on |
896 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 899 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
897 | return 0; | 900 | return 0; |
898 | 901 | ||
@@ -1012,7 +1015,8 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
1012 | if (IS_ERR(genpd)) | 1015 | if (IS_ERR(genpd)) |
1013 | return -EINVAL; | 1016 | return -EINVAL; |
1014 | 1017 | ||
1015 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); | 1018 | return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? |
1019 | 0 : genpd_stop_dev(genpd, dev); | ||
1016 | } | 1020 | } |
1017 | 1021 | ||
1018 | /** | 1022 | /** |
@@ -1032,7 +1036,8 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
1032 | if (IS_ERR(genpd)) | 1036 | if (IS_ERR(genpd)) |
1033 | return -EINVAL; | 1037 | return -EINVAL; |
1034 | 1038 | ||
1035 | return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); | 1039 | return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? |
1040 | 0 : genpd_start_dev(genpd, dev); | ||
1036 | } | 1041 | } |
1037 | 1042 | ||
1038 | /** | 1043 | /** |
@@ -1124,7 +1129,7 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1124 | 1129 | ||
1125 | pm_genpd_poweron(genpd); | 1130 | pm_genpd_poweron(genpd); |
1126 | 1131 | ||
1127 | return genpd_start_dev(genpd, dev); | 1132 | return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev); |
1128 | } | 1133 | } |
1129 | 1134 | ||
1130 | /** | 1135 | /** |
@@ -1320,6 +1325,26 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1320 | } | 1325 | } |
1321 | 1326 | ||
1322 | /** | 1327 | /** |
1328 | * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device. | ||
1329 | * @dev: Device to set/unset the flag for. | ||
1330 | * @val: The new value of the device's "always on" flag. | ||
1331 | */ | ||
1332 | void pm_genpd_dev_always_on(struct device *dev, bool val) | ||
1333 | { | ||
1334 | struct pm_subsys_data *psd; | ||
1335 | unsigned long flags; | ||
1336 | |||
1337 | spin_lock_irqsave(&dev->power.lock, flags); | ||
1338 | |||
1339 | psd = dev_to_psd(dev); | ||
1340 | if (psd && psd->domain_data) | ||
1341 | to_gpd_data(psd->domain_data)->always_on = val; | ||
1342 | |||
1343 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
1344 | } | ||
1345 | EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on); | ||
1346 | |||
1347 | /** | ||
1323 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. | 1348 | * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. |
1324 | * @genpd: Master PM domain to add the subdomain to. | 1349 | * @genpd: Master PM domain to add the subdomain to. |
1325 | * @subdomain: Subdomain to be added. | 1350 | * @subdomain: Subdomain to be added. |