scsi: ufs: Introduce device quirk "DELAY_AFTER_LPM"

Some UFS devices require delay after VCC power rail is turned off.
Introduce a device quirk "DELAY_AFTER_LPM" to add 5ms delay after VCC
power-off during suspend flow.

Link: https://lore.kernel.org/r/20200729051840.31318-2-stanley.chu@mediatek.com
Reviewed-by: Andy Teng <andy.teng@mediatek.com>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Reviewed-by: Can Guo <cang@codeaurora.org>
Acked-by: Avri Altman <Avri.Altman@wdc.com>
Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Stanley Chu 2020-07-29 13:18:39 +08:00 committed by Martin K. Petersen
parent bb2e331468
commit c4df6eed97
2 changed files with 18 additions and 0 deletions

View File

@ -109,4 +109,11 @@ struct ufs_dev_fix {
*/ */
#define UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES (1 << 10) #define UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES (1 << 10)
/*
* Some UFS devices require delay after VCC power rail is turned-off.
* Enable this quirk to introduce 5ms delays after VCC power-off during
* suspend flow.
*/
#define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM (1 << 11)
#endif /* UFS_QUIRKS_H_ */ #endif /* UFS_QUIRKS_H_ */

View File

@ -8107,6 +8107,8 @@ out:
static void ufshcd_vreg_set_lpm(struct ufs_hba *hba) static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
{ {
bool vcc_off = false;
/* /*
* It seems some UFS devices may keep drawing more than sleep current * It seems some UFS devices may keep drawing more than sleep current
* (atleast for 500us) from UFS rails (especially from VCCQ rail). * (atleast for 500us) from UFS rails (especially from VCCQ rail).
@ -8135,13 +8137,22 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba) && if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba) &&
!hba->dev_info.is_lu_power_on_wp) { !hba->dev_info.is_lu_power_on_wp) {
ufshcd_setup_vreg(hba, false); ufshcd_setup_vreg(hba, false);
vcc_off = true;
} else if (!ufshcd_is_ufs_dev_active(hba)) { } else if (!ufshcd_is_ufs_dev_active(hba)) {
ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false); ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
vcc_off = true;
if (!ufshcd_is_link_active(hba)) { if (!ufshcd_is_link_active(hba)) {
ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq); ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq);
ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2); ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2);
} }
} }
/*
* Some UFS devices require delay after VCC power rail is turned-off.
*/
if (vcc_off && hba->vreg_info.vcc &&
hba->dev_quirks & UFS_DEVICE_QUIRK_DELAY_AFTER_LPM)
usleep_range(5000, 5100);
} }
static int ufshcd_vreg_set_hpm(struct ufs_hba *hba) static int ufshcd_vreg_set_hpm(struct ufs_hba *hba)