diff options
Diffstat (limited to 'drivers/ata/libata-zpodd.c')
-rw-r--r-- | drivers/ata/libata-zpodd.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 27eed2f09a8a..9a0d90d09d81 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c | |||
@@ -1,5 +1,7 @@ | |||
1 | #include <linux/libata.h> | 1 | #include <linux/libata.h> |
2 | #include <linux/cdrom.h> | 2 | #include <linux/cdrom.h> |
3 | #include <linux/pm_runtime.h> | ||
4 | #include <scsi/scsi_device.h> | ||
3 | 5 | ||
4 | #include "libata.h" | 6 | #include "libata.h" |
5 | 7 | ||
@@ -12,6 +14,10 @@ enum odd_mech_type { | |||
12 | struct zpodd { | 14 | struct zpodd { |
13 | enum odd_mech_type mech_type; /* init during probe, RO afterwards */ | 15 | enum odd_mech_type mech_type; /* init during probe, RO afterwards */ |
14 | struct ata_device *dev; | 16 | struct ata_device *dev; |
17 | |||
18 | /* The following fields are synchronized by PM core. */ | ||
19 | bool from_notify; /* resumed as a result of | ||
20 | * acpi wake notification */ | ||
15 | }; | 21 | }; |
16 | 22 | ||
17 | /* Per the spec, only slot type and drawer type ODD can be supported */ | 23 | /* Per the spec, only slot type and drawer type ODD can be supported */ |
@@ -68,6 +74,32 @@ static bool odd_can_poweroff(struct ata_device *ata_dev) | |||
68 | return acpi_device_can_poweroff(acpi_dev); | 74 | return acpi_device_can_poweroff(acpi_dev); |
69 | } | 75 | } |
70 | 76 | ||
77 | static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) | ||
78 | { | ||
79 | struct ata_device *ata_dev = context; | ||
80 | struct zpodd *zpodd = ata_dev->zpodd; | ||
81 | struct device *dev = &ata_dev->sdev->sdev_gendev; | ||
82 | |||
83 | if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev && | ||
84 | pm_runtime_suspended(dev)) { | ||
85 | zpodd->from_notify = true; | ||
86 | pm_runtime_resume(dev); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static void ata_acpi_add_pm_notifier(struct ata_device *dev) | ||
91 | { | ||
92 | acpi_handle handle = ata_dev_acpi_handle(dev); | ||
93 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
94 | zpodd_wake_dev, dev); | ||
95 | } | ||
96 | |||
97 | static void ata_acpi_remove_pm_notifier(struct ata_device *dev) | ||
98 | { | ||
99 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->sdev->sdev_gendev); | ||
100 | acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev); | ||
101 | } | ||
102 | |||
71 | void zpodd_init(struct ata_device *dev) | 103 | void zpodd_init(struct ata_device *dev) |
72 | { | 104 | { |
73 | enum odd_mech_type mech_type; | 105 | enum odd_mech_type mech_type; |
@@ -89,12 +121,14 @@ void zpodd_init(struct ata_device *dev) | |||
89 | 121 | ||
90 | zpodd->mech_type = mech_type; | 122 | zpodd->mech_type = mech_type; |
91 | 123 | ||
124 | ata_acpi_add_pm_notifier(dev); | ||
92 | zpodd->dev = dev; | 125 | zpodd->dev = dev; |
93 | dev->zpodd = zpodd; | 126 | dev->zpodd = zpodd; |
94 | } | 127 | } |
95 | 128 | ||
96 | void zpodd_exit(struct ata_device *dev) | 129 | void zpodd_exit(struct ata_device *dev) |
97 | { | 130 | { |
131 | ata_acpi_remove_pm_notifier(dev); | ||
98 | kfree(dev->zpodd); | 132 | kfree(dev->zpodd); |
99 | dev->zpodd = NULL; | 133 | dev->zpodd = NULL; |
100 | } | 134 | } |