/**
 * sr_class1p5_reset_calib() - reset all calibrated voltages
 * @voltdm:	configure for which voltage domain
 * @reset:	reset voltage before we recal?
 * @recal:	should I recalibrate my current opp?
 *
 * if we call this, it means either periodic calibration trigger was
 * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
 * meaning we cant trust the calib voltages anymore, it is better to use
 * nominal in the system
 */
static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
				    bool recal)
{
	struct sr_class1p5_work_data *work_data;

	/* I dont need to go further if sr is not present */
	if (!is_sr_enabled(voltdm))
		return;

	work_data = get_sr1p5_work(voltdm);

	if (work_data->work_active)
		sr_class1p5_disable(voltdm, work_data->vdata, 0);

	omap_voltage_calib_reset(voltdm);

	/*
	 * I should now reset the voltages to my nominal to be safe
	 */
	if (reset)
		omap_voltage_reset(voltdm);

	/*
	 * I should fire a recalibration for current opp if needed
	 * Note: i have just reset my calibrated voltages, and if
	 * i call sr_enable equivalent, I will cause a recalibration
	 * loop, even though the function is called sr_enable.. we
	 * are in class 1.5 ;)
	 */
	if (reset && recal)
		sr_class1p5_enable(voltdm, work_data->vdata);
}
Beispiel #2
0
/**
 * sr_class1p5_voltdm_recal() - Helper routine to reset calibration.
 * @voltdm:	Voltage domain to reset calibration for
 * @user:	unused
 *
 * NOTE: Appropriate locks must be held by calling path to ensure mutual
 * exclusivity
 */
static int sr_class1p5_voltdm_recal(struct voltagedomain *voltdm,
		void *user)
{
	struct omap_volt_data *vdata;

	/*
	 * we need to go no further if sr is not enabled for this domain or
	 * voltage processor is not present for this voltage domain
	 * (example vdd_wakeup). Class 1.5 requires Voltage processor
	 * to function.
	 */
	if (!voltdm->vp || !is_sr_enabled(voltdm))
		return 0;

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

	omap_sr_disable(voltdm);
	omap_voltage_calib_reset(voltdm);
	voltdm_reset(voltdm);
	omap_sr_enable(voltdm, vdata);
	pr_info("%s: %s: calibration reset\n", __func__, voltdm->name);

	return 0;
}
/**
 * do_recalibrate() - work which actually does the calibration
 * @work: pointer to the work
 *
 * on a periodic basis, we come and reset our calibration setup
 * so that a recalibration of the OPPs take place. This takes
 * care of aging factor in the system.
 */
static void do_recalibrate(struct work_struct *work)
{
	struct voltagedomain *voltdm;
	int idx;
	static struct sr_class1p5_work_data *work_data;

	for (idx = 0; idx < MAX_VDDS; idx++) {
		work_data = &class_1p5_data.work_data[idx];
		voltdm = work_data->voltdm;
		if (voltdm) {
			/* if sr is not enabled, we check later */
			if (!is_sr_enabled(voltdm))
				continue;

			/* if we can't pause it, check later */
			if (omap_vscale_pause(voltdm, false))
				continue;

			/* Reset and force a recalibration for current opp */
			sr_class1p5_reset_calib(voltdm, true, true);

			omap_vscale_unpause(voltdm);
		}
	}
	/* We come back again after time the usual delay */
	schedule_delayed_work(&recal_work,
	      msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
}