diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D0 | 13 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D1 | 14 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D2 | 14 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power_resources_D3hot | 14 | ||||
-rw-r--r-- | drivers/acpi/power.c | 104 |
5 files changed, 146 insertions, 13 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D0 b/Documentation/ABI/testing/sysfs-devices-power_resources_D0 new file mode 100644 index 000000000000..73b77a6be196 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D0 | |||
@@ -0,0 +1,13 @@ | |||
1 | What: /sys/devices/.../power_resources_D0/ | ||
2 | Date: January 2013 | ||
3 | Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
4 | Description: | ||
5 | The /sys/devices/.../power_resources_D0/ directory is only | ||
6 | present for device objects representing ACPI device nodes that | ||
7 | use ACPI power resources for power management. | ||
8 | |||
9 | If present, it contains symbolic links to device directories | ||
10 | representing ACPI power resources that need to be turned on for | ||
11 | the given device node to be in ACPI power state D0. The names | ||
12 | of the links are the same as the names of the directories they | ||
13 | point to. | ||
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D1 b/Documentation/ABI/testing/sysfs-devices-power_resources_D1 new file mode 100644 index 000000000000..30c20703fb8c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D1 | |||
@@ -0,0 +1,14 @@ | |||
1 | What: /sys/devices/.../power_resources_D1/ | ||
2 | Date: January 2013 | ||
3 | Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
4 | Description: | ||
5 | The /sys/devices/.../power_resources_D1/ directory is only | ||
6 | present for device objects representing ACPI device nodes that | ||
7 | use ACPI power resources for power management and support ACPI | ||
8 | power state D1. | ||
9 | |||
10 | If present, it contains symbolic links to device directories | ||
11 | representing ACPI power resources that need to be turned on for | ||
12 | the given device node to be in ACPI power state D1. The names | ||
13 | of the links are the same as the names of the directories they | ||
14 | point to. | ||
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D2 b/Documentation/ABI/testing/sysfs-devices-power_resources_D2 new file mode 100644 index 000000000000..fd9d84b421e1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D2 | |||
@@ -0,0 +1,14 @@ | |||
1 | What: /sys/devices/.../power_resources_D2/ | ||
2 | Date: January 2013 | ||
3 | Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
4 | Description: | ||
5 | The /sys/devices/.../power_resources_D2/ directory is only | ||
6 | present for device objects representing ACPI device nodes that | ||
7 | use ACPI power resources for power management and support ACPI | ||
8 | power state D2. | ||
9 | |||
10 | If present, it contains symbolic links to device directories | ||
11 | representing ACPI power resources that need to be turned on for | ||
12 | the given device node to be in ACPI power state D2. The names | ||
13 | of the links are the same as the names of the directories they | ||
14 | point to. | ||
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot b/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot new file mode 100644 index 000000000000..3df32c20addf --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot | |||
@@ -0,0 +1,14 @@ | |||
1 | What: /sys/devices/.../power_resources_D3hot/ | ||
2 | Date: January 2013 | ||
3 | Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
4 | Description: | ||
5 | The /sys/devices/.../power_resources_D3hot/ directory is only | ||
6 | present for device objects representing ACPI device nodes that | ||
7 | use ACPI power resources for power management and support ACPI | ||
8 | power state D3hot. | ||
9 | |||
10 | If present, it contains symbolic links to device directories | ||
11 | representing ACPI power resources that need to be turned on for | ||
12 | the given device node to be in ACPI power state D3hot. The | ||
13 | names of the links are the same as the names of the directories | ||
14 | they point to. | ||
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 946720a4db57..9466f56b938f 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/types.h> | 41 | #include <linux/types.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/pm_runtime.h> | 43 | #include <linux/pm_runtime.h> |
44 | #include <linux/sysfs.h> | ||
44 | #include <acpi/acpi_bus.h> | 45 | #include <acpi/acpi_bus.h> |
45 | #include <acpi/acpi_drivers.h> | 46 | #include <acpi/acpi_drivers.h> |
46 | #include "sleep.h" | 47 | #include "sleep.h" |
@@ -417,24 +418,101 @@ static void acpi_power_remove_dependent(struct acpi_power_resource *resource, | |||
417 | } | 418 | } |
418 | } | 419 | } |
419 | 420 | ||
420 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add) | 421 | static struct attribute *attrs[] = { |
422 | NULL, | ||
423 | }; | ||
424 | |||
425 | static struct attribute_group attr_groups[] = { | ||
426 | [ACPI_STATE_D0] = { | ||
427 | .name = "power_resources_D0", | ||
428 | .attrs = attrs, | ||
429 | }, | ||
430 | [ACPI_STATE_D1] = { | ||
431 | .name = "power_resources_D1", | ||
432 | .attrs = attrs, | ||
433 | }, | ||
434 | [ACPI_STATE_D2] = { | ||
435 | .name = "power_resources_D2", | ||
436 | .attrs = attrs, | ||
437 | }, | ||
438 | [ACPI_STATE_D3_HOT] = { | ||
439 | .name = "power_resources_D3hot", | ||
440 | .attrs = attrs, | ||
441 | }, | ||
442 | }; | ||
443 | |||
444 | static void acpi_power_hide_list(struct acpi_device *adev, int state) | ||
445 | { | ||
446 | struct acpi_device_power_state *ps = &adev->power.states[state]; | ||
447 | struct acpi_power_resource_entry *entry; | ||
448 | |||
449 | if (list_empty(&ps->resources)) | ||
450 | return; | ||
451 | |||
452 | list_for_each_entry_reverse(entry, &ps->resources, node) { | ||
453 | struct acpi_device *res_dev = &entry->resource->device; | ||
454 | |||
455 | sysfs_remove_link_from_group(&adev->dev.kobj, | ||
456 | attr_groups[state].name, | ||
457 | dev_name(&res_dev->dev)); | ||
458 | } | ||
459 | sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]); | ||
460 | } | ||
461 | |||
462 | static void acpi_power_expose_list(struct acpi_device *adev, int state) | ||
421 | { | 463 | { |
422 | if (adev->power.flags.power_resources) { | 464 | struct acpi_device_power_state *ps = &adev->power.states[state]; |
423 | struct acpi_device_power_state *ps; | 465 | struct acpi_power_resource_entry *entry; |
424 | struct acpi_power_resource_entry *entry; | 466 | int ret; |
425 | 467 | ||
426 | ps = &adev->power.states[ACPI_STATE_D0]; | 468 | if (list_empty(&ps->resources)) |
427 | list_for_each_entry(entry, &ps->resources, node) { | 469 | return; |
428 | struct acpi_power_resource *resource = entry->resource; | 470 | |
429 | 471 | ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]); | |
430 | if (add) | 472 | if (ret) |
431 | acpi_power_add_dependent(resource, adev); | 473 | return; |
432 | else | 474 | |
433 | acpi_power_remove_dependent(resource, adev); | 475 | list_for_each_entry(entry, &ps->resources, node) { |
476 | struct acpi_device *res_dev = &entry->resource->device; | ||
477 | |||
478 | ret = sysfs_add_link_to_group(&adev->dev.kobj, | ||
479 | attr_groups[state].name, | ||
480 | &res_dev->dev.kobj, | ||
481 | dev_name(&res_dev->dev)); | ||
482 | if (ret) { | ||
483 | acpi_power_hide_list(adev, state); | ||
484 | break; | ||
434 | } | 485 | } |
435 | } | 486 | } |
436 | } | 487 | } |
437 | 488 | ||
489 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add) | ||
490 | { | ||
491 | struct acpi_device_power_state *ps; | ||
492 | struct acpi_power_resource_entry *entry; | ||
493 | int state; | ||
494 | |||
495 | if (!adev->power.flags.power_resources) | ||
496 | return; | ||
497 | |||
498 | ps = &adev->power.states[ACPI_STATE_D0]; | ||
499 | list_for_each_entry(entry, &ps->resources, node) { | ||
500 | struct acpi_power_resource *resource = entry->resource; | ||
501 | |||
502 | if (add) | ||
503 | acpi_power_add_dependent(resource, adev); | ||
504 | else | ||
505 | acpi_power_remove_dependent(resource, adev); | ||
506 | } | ||
507 | |||
508 | for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) { | ||
509 | if (add) | ||
510 | acpi_power_expose_list(adev, state); | ||
511 | else | ||
512 | acpi_power_hide_list(adev, state); | ||
513 | } | ||
514 | } | ||
515 | |||
438 | int acpi_power_min_system_level(struct list_head *list) | 516 | int acpi_power_min_system_level(struct list_head *list) |
439 | { | 517 | { |
440 | struct acpi_power_resource_entry *entry; | 518 | struct acpi_power_resource_entry *entry; |