Exemplo n.º 1
0
/**
 * omap_vp_enable() - API to enable a particular VP
 * @voltdm:	pointer to the VDD whose VP is to be enabled.
 *
 * This API enables a particular voltage processor. Needed by the smartreflex
 * class drivers.
 */
void omap_vp_enable(struct voltagedomain *voltdm)
{
	struct omap_vp_instance *vp;
	u32 vpconfig;
	struct omap_volt_data *volt;

	if (IS_ERR_OR_NULL(voltdm)) {
		pr_err("%s: VDD specified does not exist!\n", __func__);
		return;
	}

	vp = voltdm->vp;
	if (IS_ERR_OR_NULL(vp)) {
		pr_err("%s: No VP info for vdd_%s\n", __func__, voltdm->name);
		return;
	}

	if (!voltdm->read || !voltdm->write) {
		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
			__func__, voltdm->name);
		return;
	}

	/* If VP is already enabled, do nothing. Return */
	if (vp->enabled)
		return;

	volt = omap_voltage_get_curr_vdata(voltdm);
	if (!volt) {
		pr_warning("%s: unable to find current voltage for %s\n",
			   __func__, voltdm->name);
		return;
	}

	vpconfig = _vp_set_init_voltage(voltdm,
					omap_get_operation_voltage(volt));

	/* Enable VP */
	vpconfig |= vp->common->vpconfig_vpenable;
	voltdm->write(vpconfig, vp->vpconfig);

	vp->enabled = true;
}
Exemplo n.º 2
0
static void vp_latch_vsel(struct voltagedomain *voltdm)
{
	struct omap_vp_instance *vp = voltdm->vp;
	struct omap_volt_data *v = omap_voltage_get_curr_vdata(voltdm);
	u32 vpconfig;
	unsigned long uvdc;
	char vsel;

	if (IS_ERR_OR_NULL(v)) {
		pr_warning("%s: unable to get voltage for vdd_%s\n",
			__func__, voltdm->name);
		return;
	}
	uvdc = omap_get_operation_voltage(v);
	if (!uvdc) {
		pr_warning("%s: unable to find current voltage for vdd_%s\n",
			__func__, voltdm->name);
		return;
	}

	if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) {
		pr_warning("%s: PMIC function to convert voltage in uV to"
			" vsel not registered\n", __func__);
		return;
	}

	vsel = voltdm->pmic->uv_to_vsel(uvdc);

	vpconfig = voltdm->read(vp->vpconfig);
	vpconfig &= ~(vp->common->vpconfig_initvoltage_mask |
			vp->common->vpconfig_initvdd);
	vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask);
	voltdm->write(vpconfig, vp->vpconfig);

	/* Trigger initVDD value copy to voltage processor */
	voltdm->write((vpconfig | vp->common->vpconfig_initvdd),
		       vp->vpconfig);

	/* Clear initVDD copy trigger bit */
	voltdm->write(vpconfig, vp->vpconfig);
}
Exemplo n.º 3
0
/* VP force update method of voltage scaling */
int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
			      struct omap_volt_data *target_v)
{
	struct omap_vp_instance *vp = voltdm->vp;
	u32 vpconfig;
	u8 target_vsel, current_vsel;
	int ret, timeout = 0;
	unsigned long target_volt = omap_get_operation_voltage(target_v);

	/*
	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
	 * This is an additional allowance to ensure we are in proper state
	 * to enter into forceupdate state transition.
	 */
	omap_test_timeout((voltdm->read(vp->vstatus) & vp->common->vstatus_vpidle),
			VP_IDLE_TIMEOUT, timeout);

	if (timeout >= VP_IDLE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s:vdd_%s idletimdout forceupdate(v=%ld)\n",
			__func__, voltdm->name, target_volt);

	ret = omap_vc_pre_scale(voltdm, target_volt, target_v,
				&target_vsel, &current_vsel);
	if (ret)
		return ret;

	/*
	 * Clear all pending TransactionDone interrupt/status. Typical latency
	 * is <3us
	 */
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}
	if (timeout >= VP_TRANXDONE_TIMEOUT) {
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded."
			"Voltage change aborted target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);
		return -ETIMEDOUT;
	}

	/* Configure for VP-Force Update */
	vpconfig = voltdm->read(vp->vpconfig);
	vpconfig &= ~(vp->common->vpconfig_initvdd |
			vp->common->vpconfig_forceupdate |
			vp->common->vpconfig_initvoltage_mask);
	vpconfig |= ((target_vsel <<
		      __ffs(vp->common->vpconfig_initvoltage_mask)));
	voltdm->write(vpconfig, vp->vpconfig);

	/* Trigger initVDD value copy to voltage processor */
	vpconfig |= vp->common->vpconfig_initvdd;
	voltdm->write(vpconfig, vp->vpconfig);

	/* Force update of voltage */
	vpconfig |= vp->common->vpconfig_forceupdate;
	voltdm->write(vpconfig, vp->vpconfig);

	/*
	 * Wait for TransactionDone. Typical latency is <200us.
	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
	 */
	timeout = 0;
	omap_test_timeout(vp->common->ops->check_txdone(vp->id),
			  VP_TRANXDONE_TIMEOUT, timeout);
	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded. "
			"TRANXDONE never got set after the voltage update. "
			"target volt=%ld, target vsel=0x%02x, "
			"current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	omap_vc_post_scale(voltdm, target_volt, target_v,
			   target_vsel, current_vsel);

	/*
	 * Disable TransactionDone interrupt , clear all status, clear
	 * control registers
	 */
	timeout = 0;
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}

	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded while"
			"trying to clear the TRANXDONE status. target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	vpconfig = voltdm->read(vp->vpconfig);
	/* Clear initVDD copy trigger bit */
	vpconfig &= ~vp->common->vpconfig_initvdd;
	voltdm->write(vpconfig, vp->vpconfig);
	/* Clear force bit */
	vpconfig &= ~vp->common->vpconfig_forceupdate;
	voltdm->write(vpconfig, vp->vpconfig);

	return 0;
}
Exemplo n.º 4
0
/* VP force update method of voltage scaling */
int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
			      struct omap_volt_data *target_v)
{
	struct omap_vp_instance *vp;
	u32 vpconfig;
	u8 target_vsel, current_vsel;
	int ret, timeout = 0;
	unsigned long target_volt;

	if (IS_ERR_OR_NULL(voltdm)) {
		pr_err("%s: VDD specified does not exist!\n", __func__);
		return -EINVAL;
	}

	if (IS_ERR_OR_NULL(voltdm->write)) {
		pr_err("%s: No write API for writing vdd_%s regs\n",
		       __func__, voltdm->name);
		return -EINVAL;
	}

	if (IS_ERR_OR_NULL(target_v)) {
		pr_err("%s: No target_v info to scale vdd_%s\n",
		       __func__, voltdm->name);
		return -EINVAL;
	}

	vp = voltdm->vp;
	if (IS_ERR_OR_NULL(vp)) {
		pr_err("%s: No VP info for vdd_%s\n", __func__, voltdm->name);
		return -EINVAL;
	}

	target_volt = omap_get_operation_voltage(target_v);

	ret = _vp_wait_for_idle(voltdm, vp);
	if (ret) {
		_vp_controlled_err(vp, voltdm,
				   "%s: vdd_%s idle timedout (v=%ld)\n",
				   __func__, voltdm->name, target_volt);
		return ret;
	}

	ret = omap_vc_pre_scale(voltdm, target_volt, target_v,
				&target_vsel, &current_vsel);
	if (ret)
		return ret;

	/*
	 * Clear all pending TransactionDone interrupt/status. Typical latency
	 * is <3us
	 */
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}
	if (timeout >= VP_TRANXDONE_TIMEOUT) {
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded."
			"Voltage change aborted target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);
		return -ETIMEDOUT;
	}

	vpconfig = _vp_set_init_voltage(voltdm, target_volt);

	/* Force update of voltage */
	voltdm->write(vpconfig | vp->common->vpconfig_forceupdate,
		      voltdm->vp->vpconfig);

	/*
	 * Wait for TransactionDone. Typical latency is <200us.
	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
	 */
	timeout = 0;
	omap_test_timeout(vp->common->ops->check_txdone(vp->id),
			  VP_TRANXDONE_TIMEOUT, timeout);
	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded. "
			"TRANXDONE never got set after the voltage update. "
			"target volt=%ld, target vsel=0x%02x, "
			"current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	omap_vc_post_scale(voltdm, target_volt, target_v,
			   target_vsel, current_vsel);

	/*
	 * Disable TransactionDone interrupt , clear all status, clear
	 * control registers
	 */
	timeout = 0;
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}

	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded while"
			"trying to clear the TRANXDONE status. target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	/* Clear force bit */
	voltdm->write(vpconfig, vp->vpconfig);

	return 0;
}