}
 }
 
-static int ata_acpi_choose_suspend_state(struct ata_device *dev)
+static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime)
 {
        int d_max_in = ACPI_STATE_D3_COLD;
+       if (!runtime)
+               goto out;
 
        /*
         * For ATAPI, runtime D3 cold is only allowed
            !(zpodd_dev_enabled(dev) && zpodd_zpready(dev)))
                d_max_in = ACPI_STATE_D3_HOT;
 
+out:
        return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev,
                                          NULL, d_max_in);
 }
 
-/**
- * ata_acpi_set_state - set the port power state
- * @ap: target ATA port
- * @state: state, on/off
- *
- * This function executes the _PS0/_PS3 ACPI method to set the power state.
- * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
- */
-void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state)
 {
+       bool runtime = PMSG_IS_AUTO(state);
        struct ata_device *dev;
        acpi_handle handle;
        int acpi_state;
 
-       /* channel first and then drives for power on and vica versa
-          for power off */
-       handle = ata_ap_acpi_handle(ap);
-       if (handle && state.event == PM_EVENT_ON)
-               acpi_bus_set_power(handle, ACPI_STATE_D0);
-
        ata_for_each_dev(dev, &ap->link, ENABLED) {
                handle = ata_dev_acpi_handle(dev);
                if (!handle)
                        continue;
 
-               if (state.event != PM_EVENT_ON) {
-                       acpi_state = ata_acpi_choose_suspend_state(dev);
+               if (!(state.event & PM_EVENT_RESUME)) {
+                       acpi_state = ata_acpi_choose_suspend_state(dev, runtime);
                        if (acpi_state == ACPI_STATE_D0)
                                continue;
-                       if (zpodd_dev_enabled(dev) &&
+                       if (runtime && zpodd_dev_enabled(dev) &&
                            acpi_state == ACPI_STATE_D3_COLD)
                                zpodd_enable_run_wake(dev);
                        acpi_bus_set_power(handle, acpi_state);
                } else {
-                       if (zpodd_dev_enabled(dev))
+                       if (runtime && zpodd_dev_enabled(dev))
                                zpodd_disable_run_wake(dev);
                        acpi_bus_set_power(handle, ACPI_STATE_D0);
                }
        }
+}
+
+/* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */
+static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+       struct ata_device *dev;
+       acpi_handle port_handle;
+
+       port_handle = ata_ap_acpi_handle(ap);
+       if (!port_handle)
+               return;
+
+       /* channel first and then drives for power on and vica versa
+          for power off */
+       if (state.event & PM_EVENT_RESUME)
+               acpi_bus_set_power(port_handle, ACPI_STATE_D0);
+
+       ata_for_each_dev(dev, &ap->link, ENABLED) {
+               acpi_handle dev_handle = ata_dev_acpi_handle(dev);
+               if (!dev_handle)
+                       continue;
+
+               acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ?
+                                               ACPI_STATE_D0 : ACPI_STATE_D3);
+       }
+
+       if (!(state.event & PM_EVENT_RESUME))
+               acpi_bus_set_power(port_handle, ACPI_STATE_D3);
+}
 
-       handle = ata_ap_acpi_handle(ap);
-       if (handle && state.event != PM_EVENT_ON)
-               acpi_bus_set_power(handle, ACPI_STATE_D3);
+/**
+ * ata_acpi_set_state - set the port power state
+ * @ap: target ATA port
+ * @state: state, on/off
+ *
+ * This function sets a proper ACPI D state for the device on
+ * system and runtime PM operations.
+ */
+void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+       if (ap->flags & ATA_FLAG_ACPI_SATA)
+               sata_acpi_set_state(ap, state);
+       else
+               pata_acpi_set_state(ap, state);
 }
 
 /**
 
         *
         * http://thread.gmane.org/gmane.linux.ide/46764
         */
-       if (mesg.event == PM_EVENT_SUSPEND)
+       if (mesg.event & PM_EVENT_SUSPEND)
                ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
 
        rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
        return ata_port_suspend_common(dev, PMSG_HIBERNATE);
 }
 
-static int __ata_port_resume_common(struct ata_port *ap, int *async)
+static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
+                                   int *async)
 {
        int rc;
 
-       rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
+       rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
                ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
        return rc;
 }
 
-static int ata_port_resume_common(struct device *dev)
+static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
 {
        struct ata_port *ap = to_ata_port(dev);
 
-       return __ata_port_resume_common(ap, NULL);
+       return __ata_port_resume_common(ap, mesg, NULL);
 }
 
 static int ata_port_resume(struct device *dev)
 {
        int rc;
 
-       rc = ata_port_resume_common(dev);
+       rc = ata_port_resume_common(dev, PMSG_RESUME);
        if (!rc) {
                pm_runtime_disable(dev);
                pm_runtime_set_active(dev);
        return pm_runtime_suspend(dev);
 }
 
+static int ata_port_runtime_suspend(struct device *dev)
+{
+       return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+}
+
+static int ata_port_runtime_resume(struct device *dev)
+{
+       return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+}
+
 static const struct dev_pm_ops ata_port_pm_ops = {
        .suspend = ata_port_suspend,
        .resume = ata_port_resume,
        .poweroff = ata_port_poweroff,
        .restore = ata_port_resume,
 
-       .runtime_suspend = ata_port_suspend,
-       .runtime_resume = ata_port_resume_common,
+       .runtime_suspend = ata_port_runtime_suspend,
+       .runtime_resume = ata_port_runtime_resume,
        .runtime_idle = ata_port_runtime_idle,
 };
 
 
 int ata_sas_port_async_resume(struct ata_port *ap, int *async)
 {
-       return __ata_port_resume_common(ap, async);
+       return __ata_port_resume_common(ap, PMSG_RESUME, async);
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
 
 
        /* are we suspending? */
        spin_lock_irqsave(ap->lock, flags);
        if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
-           ap->pm_mesg.event == PM_EVENT_ON) {
+           ap->pm_mesg.event & PM_EVENT_RESUME) {
                spin_unlock_irqrestore(ap->lock, flags);
                return;
        }
        /*
         * If we have a ZPODD attached, check its zero
         * power ready status before the port is frozen.
+        * Only needed for runtime suspend.
         */
-       ata_for_each_dev(dev, &ap->link, ENABLED) {
-               if (zpodd_dev_enabled(dev))
-                       zpodd_on_suspend(dev);
+       if (PMSG_IS_AUTO(ap->pm_mesg)) {
+               ata_for_each_dev(dev, &ap->link, ENABLED) {
+                       if (zpodd_dev_enabled(dev))
+                               zpodd_on_suspend(dev);
+               }
        }
 
        /* tell ACPI we're suspending */
        if (ap->ops->port_suspend)
                rc = ap->ops->port_suspend(ap, ap->pm_mesg);
 
-       ata_acpi_set_state(ap, PMSG_SUSPEND);
+       ata_acpi_set_state(ap, ap->pm_mesg);
  out:
        /* report result */
        spin_lock_irqsave(ap->lock, flags);
        /* are we resuming? */
        spin_lock_irqsave(ap->lock, flags);
        if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
-           ap->pm_mesg.event != PM_EVENT_ON) {
+           !(ap->pm_mesg.event & PM_EVENT_RESUME)) {
                spin_unlock_irqrestore(ap->lock, flags);
                return;
        }
                ata_for_each_dev(dev, link, ALL)
                        ata_ering_clear(&dev->ering);
 
-       ata_acpi_set_state(ap, PMSG_ON);
+       ata_acpi_set_state(ap, ap->pm_mesg);
 
        if (ap->ops->port_resume)
                rc = ap->ops->port_resume(ap);