]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/ufs/ufshcd.c
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[karo-tx-linux.git] / drivers / scsi / ufs / ufshcd.c
index 5d60a868830dafe126d7d5bcdf73e959325919be..648a446758801ab6ff338d1dd9e5b5ab052df0da 100644 (file)
@@ -183,6 +183,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
 static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
 static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
 static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
+static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -972,6 +973,8 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
 
        ufshcd_hold(hba, false);
        mutex_lock(&hba->uic_cmd_mutex);
+       ufshcd_add_delay_before_dme_cmd(hba);
+
        spin_lock_irqsave(hba->host->host_lock, flags);
        ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -2058,6 +2061,37 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
        return ret;
 }
 
+static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba)
+{
+       #define MIN_DELAY_BEFORE_DME_CMDS_US    1000
+       unsigned long min_sleep_time_us;
+
+       if (!(hba->quirks & UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS))
+               return;
+
+       /*
+        * last_dme_cmd_tstamp will be 0 only for 1st call to
+        * this function
+        */
+       if (unlikely(!ktime_to_us(hba->last_dme_cmd_tstamp))) {
+               min_sleep_time_us = MIN_DELAY_BEFORE_DME_CMDS_US;
+       } else {
+               unsigned long delta =
+                       (unsigned long) ktime_to_us(
+                               ktime_sub(ktime_get(),
+                               hba->last_dme_cmd_tstamp));
+
+               if (delta < MIN_DELAY_BEFORE_DME_CMDS_US)
+                       min_sleep_time_us =
+                               MIN_DELAY_BEFORE_DME_CMDS_US - delta;
+               else
+                       return; /* no more delay required */
+       }
+
+       /* allow sleep for extra 50us if needed */
+       usleep_range(min_sleep_time_us, min_sleep_time_us + 50);
+}
+
 /**
  * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
  * @hba: per adapter instance
@@ -2157,6 +2191,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
 
        mutex_lock(&hba->uic_cmd_mutex);
        init_completion(&uic_async_done);
+       ufshcd_add_delay_before_dme_cmd(hba);
 
        spin_lock_irqsave(hba->host->host_lock, flags);
        hba->uic_async_done = &uic_async_done;
@@ -4225,22 +4260,15 @@ static struct scsi_host_template ufshcd_driver_template = {
 static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
                                   int ua)
 {
-       int ret = 0;
-       struct regulator *reg = vreg->reg;
-       const char *name = vreg->name;
+       int ret;
 
-       BUG_ON(!vreg);
+       if (!vreg)
+               return 0;
 
-       ret = regulator_set_optimum_mode(reg, ua);
-       if (ret >= 0) {
-               /*
-                * regulator_set_optimum_mode() returns new regulator
-                * mode upon success.
-                */
-               ret = 0;
-       } else {
-               dev_err(dev, "%s: %s set optimum mode(ua=%d) failed, err=%d\n",
-                               __func__, name, ua, ret);
+       ret = regulator_set_load(vreg->reg, ua);
+       if (ret < 0) {
+               dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n",
+                               __func__, vreg->name, ua, ret);
        }
 
        return ret;
@@ -4249,18 +4277,12 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
 static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
-       if (!vreg)
-               return 0;
-
        return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
 }
 
 static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
                                         struct ufs_vreg *vreg)
 {
-       if (!vreg)
-               return 0;
-
        return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
 }