static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
{
	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
	bool pwm_required;
	int rc = 0;
	int uV;

	rc = spm_regulator_get_voltage(rdev);
	if (IS_ERR_VALUE(rc))
		return rc;

	if (vreg->vlevel == vreg->last_set_vlevel)
		return 0;

	pwm_required = (vreg->regulator_type == QPNP_TYPE_FTS2)
			&& !(vreg->init_mode & QPNP_SMPS_MODE_PWM)
			&& vreg->uV > vreg->last_set_uV;

	if (pwm_required) {
		/* Switch to PWM mode so that voltage ramping is fast. */
		rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_PWM);
		if (rc)
			return rc;
	}

	do {
		uV = vreg->uV > vreg->last_set_uV
		    ? min(vreg->uV, vreg->last_set_uV + (int)vreg->max_step_uV)
		    : max(vreg->uV, vreg->last_set_uV - (int)vreg->max_step_uV);

		rc = spm_regulator_write_voltage(vreg, uV);
		if (rc)
			return rc;
	} while (vreg->last_set_uV != vreg->uV);

	if (pwm_required) {
		/* Wait for mode transition to complete. */
		udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
		/* Switch to AUTO mode so that power consumption is lowered. */
		rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_AUTO);
		if (rc)
			return rc;
	}

	rc = spm_regulator_recalibrate(vreg);

	return rc;
}
static int spm_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
	struct spm_vreg *vreg = rdev_get_drvdata(rdev);

	/*
	 * Map REGULATOR_MODE_NORMAL to PWM mode and REGULATOR_MODE_IDLE to
	 * init_mode.  This ensures that the regulator always stays in PWM mode
	 * in the case that qcom,mode has been specified as "pwm" in device
	 * tree.
	 */
	vreg->mode
	 = mode == REGULATOR_MODE_NORMAL ? QPNP_SMPS_MODE_PWM : vreg->init_mode;

	return qpnp_smps_set_mode(vreg, vreg->mode);
}
Esempio n. 3
0
static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
{
	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
	bool spm_failed = false;
	int rc = 0;
	u8 reg;

	if (vreg->vlevel == vreg->last_set_vlevel)
		return 0;

	if ((vreg->regulator_type == QPNP_TYPE_FTS2)
	    && !(vreg->init_mode & QPNP_SMPS_MODE_PWM)
	    && vreg->uV > vreg->last_set_uV) {
		/* Switch to PWM mode so that voltage ramping is fast. */
		rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_PWM);
		if (rc)
			return rc;
	}

	if (likely(!vreg->bypass_spm)) {
		/* Set voltage control register via SPM. */
		rc = msm_spm_set_vdd(vreg->cpu_num, vreg->vlevel);
		if (rc) {
			pr_debug("%s: msm_spm_set_vdd failed, rc=%d; falling back on SPMI write\n",
				vreg->rdesc.name, rc);
			spm_failed = true;
		}
	}

	if (unlikely(vreg->bypass_spm || spm_failed)) {
		/* Set voltage control register via SPMI. */
		reg = vreg->vlevel;
		rc = spmi_ext_register_writel(vreg->spmi_dev->ctrl,
			vreg->spmi_dev->sid,
			vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
			&reg, 1);
		if (rc) {
			pr_err("%s: spmi_ext_register_writel failed, rc=%d\n",
				vreg->rdesc.name, rc);
			return rc;
		}
	}

	if (vreg->uV > vreg->last_set_uV) {
		/* Wait for voltage stepping to complete. */
		udelay(DIV_ROUND_UP(vreg->uV - vreg->last_set_uV,
					vreg->step_rate));
	}

	if ((vreg->regulator_type == QPNP_TYPE_FTS2)
	    && !(vreg->init_mode & QPNP_SMPS_MODE_PWM)
	    && vreg->uV > vreg->last_set_uV) {
		/* Wait for mode transition to complete. */
		udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
		/* Switch to AUTO mode so that power consumption is lowered. */
		rc = qpnp_smps_set_mode(vreg, QPNP_FTS2_MODE_AUTO);
		if (rc)
			return rc;
	}

	vreg->last_set_uV = vreg->uV;
	vreg->last_set_vlevel = vreg->vlevel;

	return rc;
}