diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup b/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup
new file mode 100644
index 000000000000..e0588feeb6e1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup
@@ -0,0 +1,13 @@
+What:		/sys/devices/.../power_resources_wakeup/
+Date:		April 2013
+Contact:	Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+		The /sys/devices/.../power_resources_wakeup/ directory is only
+		present for device objects representing ACPI device nodes that
+		require ACPI power resources for wakeup signaling.
+
+		If present, it contains symbolic links to device directories
+		representing ACPI power resources that need to be turned on for
+		the given device node to be able to signal wakeup.  The names of
+		the links are the same as the names of the directories they
+		point to.
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index dd314ef9bff1..96de787e6104 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -145,27 +145,36 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
 	}
 
 	/*
-	 * Get the device's power state either directly (via _PSC) or
-	 * indirectly (via power resources).
+	 * Get the device's power state from power resources settings and _PSC,
+	 * if available.
 	 */
-	if (device->power.flags.explicit_get) {
-		unsigned long long psc;
-		acpi_status status = acpi_evaluate_integer(device->handle,
-							   "_PSC", NULL, &psc);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		result = psc;
-	}
-	/* The test below covers ACPI_STATE_UNKNOWN too. */
-	if (result <= ACPI_STATE_D2) {
-	  ; /* Do nothing. */
-	} else if (device->power.flags.power_resources) {
+	if (device->power.flags.power_resources) {
 		int error = acpi_power_get_inferred_state(device, &result);
 		if (error)
 			return error;
-	} else if (result == ACPI_STATE_D3_HOT) {
-		result = ACPI_STATE_D3;
+	}
+	if (device->power.flags.explicit_get) {
+		acpi_handle handle = device->handle;
+		unsigned long long psc;
+		acpi_status status;
+
+		status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		/*
+		 * The power resources settings may indicate a power state
+		 * shallower than the actual power state of the device.
+		 *
+		 * Moreover, on systems predating ACPI 4.0, if the device
+		 * doesn't depend on any power resources and _PSC returns 3,
+		 * that means "power off".  We need to maintain compatibility
+		 * with those systems.
+		 */
+		if (psc > result && psc < ACPI_STATE_D3_COLD)
+			result = psc;
+		else if (result == ACPI_STATE_UNKNOWN)
+			result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc;
 	}
 
 	/*
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 0481b1b1d2aa..f962047c6c85 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -459,57 +459,79 @@ static struct attribute_group attr_groups[] = {
 	},
 };
 
-static void acpi_power_hide_list(struct acpi_device *adev, int state)
+static struct attribute_group wakeup_attr_group = {
+	.name = "power_resources_wakeup",
+	.attrs = attrs,
+};
+
+static void acpi_power_hide_list(struct acpi_device *adev,
+				 struct list_head *resources,
+				 struct attribute_group *attr_group)
 {
-	struct acpi_device_power_state *ps = &adev->power.states[state];
 	struct acpi_power_resource_entry *entry;
 
-	if (list_empty(&ps->resources))
+	if (list_empty(resources))
 		return;
 
-	list_for_each_entry_reverse(entry, &ps->resources, node) {
+	list_for_each_entry_reverse(entry, resources, node) {
 		struct acpi_device *res_dev = &entry->resource->device;
 
 		sysfs_remove_link_from_group(&adev->dev.kobj,
-					     attr_groups[state].name,
+					     attr_group->name,
 					     dev_name(&res_dev->dev));
 	}
-	sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
+	sysfs_remove_group(&adev->dev.kobj, attr_group);
 }
 
-static void acpi_power_expose_list(struct acpi_device *adev, int state)
+static void acpi_power_expose_list(struct acpi_device *adev,
+				   struct list_head *resources,
+				   struct attribute_group *attr_group)
 {
-	struct acpi_device_power_state *ps = &adev->power.states[state];
 	struct acpi_power_resource_entry *entry;
 	int ret;
 
-	if (list_empty(&ps->resources))
+	if (list_empty(resources))
 		return;
 
-	ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
+	ret = sysfs_create_group(&adev->dev.kobj, attr_group);
 	if (ret)
 		return;
 
-	list_for_each_entry(entry, &ps->resources, node) {
+	list_for_each_entry(entry, resources, node) {
 		struct acpi_device *res_dev = &entry->resource->device;
 
 		ret = sysfs_add_link_to_group(&adev->dev.kobj,
-					      attr_groups[state].name,
+					      attr_group->name,
 					      &res_dev->dev.kobj,
 					      dev_name(&res_dev->dev));
 		if (ret) {
-			acpi_power_hide_list(adev, state);
+			acpi_power_hide_list(adev, resources, attr_group);
 			break;
 		}
 	}
 }
 
+static void acpi_power_expose_hide(struct acpi_device *adev,
+				   struct list_head *resources,
+				   struct attribute_group *attr_group,
+				   bool expose)
+{
+	if (expose)
+		acpi_power_expose_list(adev, resources, attr_group);
+	else
+		acpi_power_hide_list(adev, resources, attr_group);
+}
+
 void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
 {
 	struct acpi_device_power_state *ps;
 	struct acpi_power_resource_entry *entry;
 	int state;
 
+	if (adev->wakeup.flags.valid)
+		acpi_power_expose_hide(adev, &adev->wakeup.resources,
+				       &wakeup_attr_group, add);
+
 	if (!adev->power.flags.power_resources)
 		return;
 
@@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
 			acpi_power_remove_dependent(resource, adev);
 	}
 
-	for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
-		if (add)
-			acpi_power_expose_list(adev, state);
-		else
-			acpi_power_hide_list(adev, state);
-	}
+	for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
+		acpi_power_expose_hide(adev,
+				       &adev->power.states[state].resources,
+				       &attr_groups[state], add);
 }
 
 int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)