case UFS_ACTIVE_PWR_MODE:       return "ACTIVE";
        case UFS_SLEEP_PWR_MODE:        return "SLEEP";
        case UFS_POWERDOWN_PWR_MODE:    return "POWERDOWN";
+       case UFS_DEEPSLEEP_PWR_MODE:    return "DEEPSLEEP";
        default:                        return "UNKNOWN";
        }
 }
                                             bool rpm)
 {
        struct ufs_hba *hba = dev_get_drvdata(dev);
+       struct ufs_dev_info *dev_info = &hba->dev_info;
        unsigned long flags, value;
 
        if (kstrtoul(buf, 0, &value))
        if (value >= UFS_PM_LVL_MAX)
                return -EINVAL;
 
+       if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE &&
+           (!(hba->caps & UFSHCD_CAP_DEEPSLEEP) ||
+            !(dev_info->wspecversion >= 0x310)))
+               return -EINVAL;
+
        spin_lock_irqsave(hba->host->host_lock, flags);
        if (rpm)
                hba->rpm_lvl = value;
 
        {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE},
        {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE},
        {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE},
+       /*
+        * For DeepSleep, the link is first put in hibern8 and then off.
+        * Leaving the link in hibern8 is not supported.
+        */
+       {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE},
 };
 
 static inline enum ufs_dev_pwr_mode
        }
        /*
         * If autobkops is enabled, link can't be turned off because
-        * turning off the link would also turn off the device.
+        * turning off the link would also turn off the device, except in the
+        * case of DeepSleep where the device is expected to remain powered.
         */
        else if ((req_link_state == UIC_LINK_OFF_STATE) &&
                 (!check_for_bkops || !hba->auto_bkops_enabled)) {
                 * put the link in low power mode is to send the DME end point
                 * to device and then send the DME reset command to local
                 * unipro. But putting the link in hibern8 is much faster.
+                *
+                * Note also that putting the link in Hibern8 is a requirement
+                * for entering DeepSleep.
                 */
                ret = ufshcd_uic_hibern8_enter(hba);
                if (ret) {
 static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 {
        int ret = 0;
+       int check_for_bkops;
        enum ufs_pm_level pm_lvl;
        enum ufs_dev_pwr_mode req_dev_pwr_mode;
        enum uic_link_state req_link_state;
        }
 
        flush_work(&hba->eeh_work);
-       ret = ufshcd_link_state_transition(hba, req_link_state, 1);
+
+       /*
+        * In the case of DeepSleep, the device is expected to remain powered
+        * with the link off, so do not check for bkops.
+        */
+       check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba);
+       ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops);
        if (ret)
                goto set_dev_active;
 
        if (hba->clk_scaling.is_allowed)
                ufshcd_resume_clkscaling(hba);
        ufshcd_vreg_set_hpm(hba);
+       /*
+        * Device hardware reset is required to exit DeepSleep. Also, for
+        * DeepSleep, the link is off so host reset and restore will be done
+        * further below.
+        */
+       if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+               ufshcd_vops_device_reset(hba);
+               WARN_ON(!ufshcd_is_link_off(hba));
+       }
        if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
                ufshcd_set_link_active(hba);
        else if (ufshcd_is_link_off(hba))
                ufshcd_host_reset_and_restore(hba);
 set_dev_active:
+       /* Can also get here needing to exit DeepSleep */
+       if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+               ufshcd_vops_device_reset(hba);
+               ufshcd_host_reset_and_restore(hba);
+       }
        if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
                ufshcd_disable_auto_bkops(hba);
 enable_gating:
        if (ret)
                goto disable_vreg;
 
+       /* For DeepSleep, the only supported option is to have the link off */
+       WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba));
+
        if (ufshcd_is_link_hibern8(hba)) {
                ret = ufshcd_uic_hibern8_exit(hba);
                if (!ret) {
                /*
                 * A full initialization of the host and the device is
                 * required since the link was put to off during suspend.
+                * Note, in the case of DeepSleep, the device will exit
+                * DeepSleep due to device reset.
                 */
                ret = ufshcd_reset_and_restore(hba);
                /*
 
        ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)
 #define ufshcd_set_ufs_dev_poweroff(h) \
        ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE)
+#define ufshcd_set_ufs_dev_deepsleep(h) \
+       ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE)
 #define ufshcd_is_ufs_dev_active(h) \
        ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)
 #define ufshcd_is_ufs_dev_sleep(h) \
        ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)
 #define ufshcd_is_ufs_dev_poweroff(h) \
        ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
+#define ufshcd_is_ufs_dev_deepsleep(h) \
+       ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE)
 
 /*
  * UFS Power management levels.
- * Each level is in increasing order of power savings.
+ * Each level is in increasing order of power savings, except DeepSleep
+ * which is lower than PowerDown with power on but not PowerDown with
+ * power off.
  */
 enum ufs_pm_level {
        UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */
        UFS_PM_LVL_3, /* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */
        UFS_PM_LVL_4, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */
        UFS_PM_LVL_5, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */
+       UFS_PM_LVL_6, /* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */
        UFS_PM_LVL_MAX
 };
 
         * This would increase power savings.
         */
        UFSHCD_CAP_AGGR_POWER_COLLAPSE                  = 1 << 9,
+
+       /*
+        * This capability allows the host controller driver to use DeepSleep,
+        * if it is supported by the UFS device. The host controller driver must
+        * support device hardware reset via the hba->device_reset() callback,
+        * in order to exit DeepSleep state.
+        */
+       UFSHCD_CAP_DEEPSLEEP                            = 1 << 10,
 };
 
 struct ufs_hba_variant_params {