Commit 60f01870 authored by Yaniv Gardi's avatar Yaniv Gardi Committed by Martin K. Petersen

scsi: ufs: disable vccq if it's not needed by UFS device

Some UFS devices don't require VCCQ rail for device operations hence
this change adds support to recognize such devices and remove vote for
the unused VCCQ rail.
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: default avatarYaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c58ab7aa
...@@ -501,6 +501,7 @@ struct ufs_vreg { ...@@ -501,6 +501,7 @@ struct ufs_vreg {
struct regulator *reg; struct regulator *reg;
const char *name; const char *name;
bool enabled; bool enabled;
bool unused;
int min_uV; int min_uV;
int max_uV; int max_uV;
int min_uA; int min_uA;
......
...@@ -195,6 +195,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba); ...@@ -195,6 +195,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba);
static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
bool skip_ref_clk); bool skip_ref_clk);
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_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_exit(struct ufs_hba *hba);
static int ufshcd_uic_hibern8_enter(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 inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
...@@ -4662,6 +4663,12 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) ...@@ -4662,6 +4663,12 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
goto out; goto out;
ufs_advertise_fixup_device(hba); ufs_advertise_fixup_device(hba);
ret = ufshcd_set_vccq_rail_unused(hba,
(hba->dev_quirks & UFS_DEVICE_NO_VCCQ) ? true : false);
if (ret)
goto out;
/* UFS device is also active now */ /* UFS device is also active now */
ufshcd_set_ufs_dev_active(hba); ufshcd_set_ufs_dev_active(hba);
ufshcd_force_reset_auto_bkops(hba); ufshcd_force_reset_auto_bkops(hba);
...@@ -4812,12 +4819,23 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, ...@@ -4812,12 +4819,23 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba, static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
struct ufs_vreg *vreg) struct ufs_vreg *vreg)
{ {
return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA); if (!vreg)
return 0;
else if (vreg->unused)
return 0;
else
return ufshcd_config_vreg_load(hba->dev, vreg,
UFS_VREG_LPM_LOAD_UA);
} }
static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
struct ufs_vreg *vreg) struct ufs_vreg *vreg)
{ {
if (!vreg)
return 0;
else if (vreg->unused)
return 0;
else
return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA); return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
} }
...@@ -4853,7 +4871,9 @@ static int ufshcd_enable_vreg(struct device *dev, struct ufs_vreg *vreg) ...@@ -4853,7 +4871,9 @@ static int ufshcd_enable_vreg(struct device *dev, struct ufs_vreg *vreg)
{ {
int ret = 0; int ret = 0;
if (!vreg || vreg->enabled) if (!vreg)
goto out;
else if (vreg->enabled || vreg->unused)
goto out; goto out;
ret = ufshcd_config_vreg(dev, vreg, true); ret = ufshcd_config_vreg(dev, vreg, true);
...@@ -4873,7 +4893,9 @@ static int ufshcd_disable_vreg(struct device *dev, struct ufs_vreg *vreg) ...@@ -4873,7 +4893,9 @@ static int ufshcd_disable_vreg(struct device *dev, struct ufs_vreg *vreg)
{ {
int ret = 0; int ret = 0;
if (!vreg || !vreg->enabled) if (!vreg)
goto out;
else if (!vreg->enabled || vreg->unused)
goto out; goto out;
ret = regulator_disable(vreg->reg); ret = regulator_disable(vreg->reg);
...@@ -4979,6 +5001,36 @@ static int ufshcd_init_hba_vreg(struct ufs_hba *hba) ...@@ -4979,6 +5001,36 @@ static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
return 0; return 0;
} }
static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused)
{
int ret = 0;
struct ufs_vreg_info *info = &hba->vreg_info;
if (!info)
goto out;
else if (!info->vccq)
goto out;
if (unused) {
/* shut off the rail here */
ret = ufshcd_toggle_vreg(hba->dev, info->vccq, false);
/*
* Mark this rail as no longer used, so it doesn't get enabled
* later by mistake
*/
if (!ret)
info->vccq->unused = true;
} else {
/*
* rail should have been already enabled hence just make sure
* that unused flag is cleared.
*/
info->vccq->unused = false;
}
out:
return ret;
}
static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
bool skip_ref_clk) bool skip_ref_clk)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment