summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c15
-rw-r--r--drivers/scsi/ufs/ufshcd.c62
-rw-r--r--drivers/scsi/ufs/ufshcd.h7
3 files changed, 52 insertions, 32 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3101eca79823..284a7397e558 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1237,7 +1237,18 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
}
}
-static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
+/**
+ * ufs_qcom_setup_clocks - enables/disable clocks
+ * @hba: host controller instance
+ * @on: If true, enable clocks else disable them.
+ * @is_gating_context: If true then it means this function is called from
+ * aggressive clock gating context and we may only need to gate off important
+ * clocks. If false then make sure to gate off all clocks.
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
+ bool is_gating_context)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err;
@@ -1813,7 +1824,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
- ufs_qcom_setup_clocks(hba, true);
+ ufs_qcom_setup_clocks(hba, true, false);
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d1ffa9406baa..b2571ac21f39 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -359,9 +359,11 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
static void ufshcd_hba_exit(struct ufs_hba *hba);
static int ufshcd_probe_hba(struct ufs_hba *hba);
-static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
- bool skip_ref_clk);
-static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_enable_clocks(struct ufs_hba *hba);
+static int ufshcd_disable_clocks(struct ufs_hba *hba,
+ bool is_gating_context);
+static int ufshcd_disable_clocks_skip_ref_clk(struct ufs_hba *hba,
+ bool is_gating_context);
static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused);
static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
@@ -1135,7 +1137,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
spin_unlock_irqrestore(hba->host->host_lock, flags);
ufshcd_hba_vreg_set_hpm(hba);
- ufshcd_setup_clocks(hba, true);
+ ufshcd_enable_clocks(hba);
/* Exit from hibern8 */
if (ufshcd_can_hibern8_during_gating(hba)) {
@@ -1271,10 +1273,10 @@ static void ufshcd_gate_work(struct work_struct *work)
ufshcd_suspend_clkscaling(hba);
if (!ufshcd_is_link_active(hba) && !hba->no_ref_clk_gating)
- ufshcd_setup_clocks(hba, false);
+ ufshcd_disable_clocks(hba, true);
else
/* If link is active, device ref_clk can't be switched off */
- __ufshcd_setup_clocks(hba, false, true);
+ ufshcd_disable_clocks_skip_ref_clk(hba, true);
/* Put the host controller in low power mode if possible */
ufshcd_hba_vreg_set_lpm(hba);
@@ -7030,8 +7032,8 @@ out:
return ret;
}
-static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
- bool skip_ref_clk)
+static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
+ bool skip_ref_clk, bool is_gating_context)
{
int ret = 0;
struct ufs_clk_info *clki;
@@ -7049,7 +7051,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
* before disabling the clocks managed here.
*/
if (!on) {
- ret = ufshcd_vops_setup_clocks(hba, on);
+ ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context);
if (ret)
return ret;
}
@@ -7082,7 +7084,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
* after enabling the clocks managed here.
*/
if (on)
- ret = ufshcd_vops_setup_clocks(hba, on);
+ ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context);
out:
if (ret) {
@@ -7107,9 +7109,21 @@ out:
return ret;
}
-static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
+static int ufshcd_enable_clocks(struct ufs_hba *hba)
{
- return __ufshcd_setup_clocks(hba, on, false);
+ return ufshcd_setup_clocks(hba, true, false, false);
+}
+
+static int ufshcd_disable_clocks(struct ufs_hba *hba,
+ bool is_gating_context)
+{
+ return ufshcd_setup_clocks(hba, false, false, is_gating_context);
+}
+
+static int ufshcd_disable_clocks_skip_ref_clk(struct ufs_hba *hba,
+ bool is_gating_context)
+{
+ return ufshcd_setup_clocks(hba, false, true, is_gating_context);
}
static int ufshcd_init_clocks(struct ufs_hba *hba)
@@ -7182,8 +7196,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->var || !hba->var->vops)
return;
- ufshcd_vops_setup_clocks(hba, false);
-
ufshcd_vops_setup_regulators(hba, false);
ufshcd_vops_exit(hba);
@@ -7212,7 +7224,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
if (err)
goto out_disable_hba_vreg;
- err = ufshcd_setup_clocks(hba, true);
+ err = ufshcd_enable_clocks(hba);
if (err)
goto out_disable_hba_vreg;
@@ -7234,7 +7246,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
out_disable_vreg:
ufshcd_setup_vreg(hba, false);
out_disable_clks:
- ufshcd_setup_clocks(hba, false);
+ ufshcd_disable_clocks(hba, false);
out_disable_hba_vreg:
ufshcd_setup_hba_vreg(hba, false);
out:
@@ -7247,7 +7259,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
ufshcd_variant_hba_exit(hba);
ufshcd_setup_vreg(hba, false);
ufshcd_suspend_clkscaling(hba);
- ufshcd_setup_clocks(hba, false);
+ ufshcd_disable_clocks(hba, false);
ufshcd_setup_hba_vreg(hba, false);
hba->is_powered = false;
}
@@ -7590,15 +7602,13 @@ disable_clks:
if (ret)
goto set_link_active;
- ret = ufshcd_vops_setup_clocks(hba, false);
- if (ret)
- goto vops_resume;
-
if (!ufshcd_is_link_active(hba))
- ufshcd_setup_clocks(hba, false);
+ ret = ufshcd_disable_clocks(hba, false);
else
/* If link is active, device ref_clk can't be switched off */
- __ufshcd_setup_clocks(hba, false, true);
+ ret = ufshcd_disable_clocks_skip_ref_clk(hba, false);
+ if (ret)
+ goto set_link_active;
hba->clk_gating.state = CLKS_OFF;
trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
@@ -7611,8 +7621,6 @@ disable_clks:
ufshcd_hba_vreg_set_lpm(hba);
goto out;
-vops_resume:
- ufshcd_vops_resume(hba, pm_op);
set_link_active:
ufshcd_resume_clkscaling(hba);
ufshcd_vreg_set_hpm(hba);
@@ -7659,7 +7667,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
ufshcd_hba_vreg_set_hpm(hba);
/* Make sure clocks are enabled before accessing controller */
- ret = ufshcd_setup_clocks(hba, true);
+ ret = ufshcd_enable_clocks(hba);
if (ret)
goto out;
@@ -7735,7 +7743,7 @@ disable_vreg:
disable_irq_and_vops_clks:
ufshcd_disable_irq(hba);
ufshcd_suspend_clkscaling(hba);
- ufshcd_setup_clocks(hba, false);
+ ufshcd_disable_clocks(hba, false);
out:
hba->pm_op_in_progress = 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8e2c2f509039..811af66c835c 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -314,7 +314,7 @@ struct ufs_hba_variant_ops {
u32 (*get_ufs_hci_version)(struct ufs_hba *);
int (*clk_scale_notify)(struct ufs_hba *, bool,
enum ufs_notify_change_status);
- int (*setup_clocks)(struct ufs_hba *, bool);
+ int (*setup_clocks)(struct ufs_hba *, bool, bool);
int (*setup_regulators)(struct ufs_hba *, bool);
int (*hce_enable_notify)(struct ufs_hba *,
enum ufs_notify_change_status);
@@ -1074,10 +1074,11 @@ static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
return 0;
}
-static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on)
+static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on,
+ bool is_gating_context)
{
if (hba->var && hba->var->vops && hba->var->vops->setup_clocks)
- return hba->var->vops->setup_clocks(hba, on);
+ return hba->var->vops->setup_clocks(hba, on, is_gating_context);
return 0;
}