aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-zpodd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-zpodd.c')
-rw-r--r--drivers/ata/libata-zpodd.c34
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 {
12struct zpodd { 14struct 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
77static 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
90static 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
97static 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
71void zpodd_init(struct ata_device *dev) 103void 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
96void zpodd_exit(struct ata_device *dev) 129void 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}