Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1766175a authored by Subhash Jadavani's avatar Subhash Jadavani
Browse files

scsi: ufs: add support for low voltage VCC support



UFS3.0 devices are capable of running at lower level (2.5v) of VCC rail.
If both host and device supports 2.5v level then we do runtime switch
of UFS VCC voltage level.

Change-Id: Ifa7f73f6afdfc382fa018c7403a2da79d08df845
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
parent c8ecc877
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ Optional properties:
- vcc-supply            : phandle to VCC supply regulator node
- vcc-voltage-level     : specifies voltage levels for VCC supply.
                          Should be specified in pairs (min, max), units uV.
- vcc-low-voltage-sup	: If specified, treats min voltage from vcc-voltage-level as
			  low voltage level different from max voltage.
- vccq-supply           : phandle to VCCQ supply regulator node
- vccq2-supply          : phandle to VCCQ2 supply regulator node
- vccq2-voltage-level   : specifies voltage levels for VCCQ2 supply.
@@ -93,6 +95,7 @@ Example:
		vdd-hba-fixed-regulator;
		vcc-supply = <&xxx_reg1>;
		vcc-supply-1p8;
		vcc-low-voltage-sup;
		vccq-supply = <&xxx_reg2>;
		vccq2-supply = <&xxx_reg3>;
		vcc-max-microamp = 500000;
+2 −0
Original line number Diff line number Diff line
@@ -480,6 +480,8 @@ struct ufs_vreg {
	bool unused;
	int min_uV;
	int max_uV;
	bool low_voltage_sup;
	bool low_voltage_active;
	int min_uA;
	int max_uA;
};
+3 −0
Original line number Diff line number Diff line
@@ -197,6 +197,9 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
				vreg->min_uV = be32_to_cpup(&prop[0]);
				vreg->max_uV = be32_to_cpup(&prop[1]);
			}

			if (of_property_read_bool(np, "vcc-low-voltage-sup"))
				vreg->low_voltage_sup = true;
		}
	} else if (!strcmp(name, "vccq")) {
		vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
+48 −0
Original line number Diff line number Diff line
@@ -469,6 +469,13 @@ static int ufshcd_devfreq_target(struct device *dev,
static int ufshcd_devfreq_get_dev_status(struct device *dev,
		struct devfreq_dev_status *stat);
static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba);
static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
				     enum ufs_dev_pwr_mode pwr_mode);
static int ufshcd_config_vreg(struct device *dev,
		struct ufs_vreg *vreg, bool on);
static int ufshcd_enable_vreg(struct device *dev, struct ufs_vreg *vreg);
static int ufshcd_disable_vreg(struct device *dev, struct ufs_vreg *vreg);
static bool ufshcd_is_g4_supported(struct ufs_hba *hba);

#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
@@ -8101,6 +8108,41 @@ static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba)
			__func__, icc_level, ret);
}

static int ufshcd_set_low_vcc_level(struct ufs_hba *hba,
				  struct ufs_dev_desc *dev_desc)
{
	int ret;
	struct ufs_vreg *vreg = hba->vreg_info.vcc;

	/* Check if device supports the low voltage VCC feature */
	if (dev_desc->wspecversion < 0x300 && !ufshcd_is_g4_supported(hba))
		return 0;

	/*
	 * Check if host has support for low VCC voltage?
	 * In addition, also check if we have already set the low VCC level
	 * or not?
	 */
	if (!vreg->low_voltage_sup || vreg->low_voltage_active)
		return 0;

	/* Put the device in sleep before lowering VCC level */
	ret = ufshcd_set_dev_pwr_mode(hba, UFS_SLEEP_PWR_MODE);

	/* Switch off VCC before switching it ON at 2.5v */
	ret = ufshcd_disable_vreg(hba->dev, vreg);
	/* add ~2ms delay before renabling VCC at lower voltage */
	usleep_range(2000, 2100);
	/* Now turn back VCC ON at low voltage */
	vreg->low_voltage_active = true;
	ret = ufshcd_enable_vreg(hba->dev, vreg);

	/* Bring the device in active now */
	ret = ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE);

	return ret;
}

/**
 * ufshcd_scsi_add_wlus - Adds required W-LUs
 * @hba: per-adapter instance
@@ -8794,6 +8836,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
		if (ufshcd_scsi_add_wlus(hba))
			goto out;

		/* lower VCC voltage level */
		ufshcd_set_low_vcc_level(hba, &card);

		/* Initialize devfreq after UFS device is detected */
		if (ufshcd_is_clkscaling_supported(hba)) {
			memcpy(&hba->clk_scaling.saved_pwr_info.info,
@@ -9351,6 +9396,9 @@ static int ufshcd_config_vreg(struct device *dev,
			goto out;

		min_uV = on ? vreg->min_uV : 0;
		if (vreg->low_voltage_sup && !vreg->low_voltage_active)
			min_uV = vreg->max_uV;

		ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
		if (ret) {
			dev_err(dev, "%s: %s set voltage failed, err=%d\n",