コード例 #1
0
ファイル: pm.c プロジェクト: IngenicC/linux-linaro-natty
/*
 * This API is to be called during init to put the various voltage
 * domains to the voltage as per the opp table. Typically we boot up
 * at the nominal voltage. So this function finds out the rate of
 * the clock associated with the voltage domain, finds out the correct
 * opp entry and puts the voltage domain to the voltage specifies
 * in the opp entry
 */
static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
						struct device *dev)
{
	struct voltagedomain *voltdm;
	struct clk *clk;
	struct opp *opp;
	unsigned long freq, bootup_volt;

	if (!vdd_name || !clk_name || !dev) {
		printk(KERN_ERR "%s: Invalid parameters!\n", __func__);
		goto exit;
	}

	voltdm = omap_voltage_domain_lookup(vdd_name);
	if (IS_ERR(voltdm)) {
		printk(KERN_ERR "%s: Unable to get vdd pointer for vdd_%s\n",
			__func__, vdd_name);
		goto exit;
	}

	clk =  clk_get(NULL, clk_name);
	if (IS_ERR(clk)) {
		printk(KERN_ERR "%s: unable to get clk %s\n",
			__func__, clk_name);
		goto exit;
	}

	freq = clk->rate;
	clk_put(clk);

	opp = opp_find_freq_ceil(dev, &freq);
	if (IS_ERR(opp)) {
		printk(KERN_ERR "%s: unable to find boot up OPP for vdd_%s\n",
			__func__, vdd_name);
		goto exit;
	}

	bootup_volt = opp_get_voltage(opp);
	if (!bootup_volt) {
		printk(KERN_ERR "%s: unable to find voltage corresponding"
			"to the bootup OPP for vdd_%s\n", __func__, vdd_name);
		goto exit;
	}

	omap_voltage_scale_vdd(voltdm, bootup_volt);
	return 0;

exit:
	printk(KERN_ERR "%s: Unable to put vdd_%s to its init voltage\n\n",
		__func__, vdd_name);
	return -EINVAL;
}
コード例 #2
0
/**
 * omap_voltage_reset() - Resets the voltage of a particular voltage domain
 *			to that of the current OPP.
 * @voltdm:	pointer to the VDD whose voltage is to be reset.
 *
 * This API finds out the correct voltage the voltage domain is supposed
 * to be at and resets the voltage to that level. Should be used expecially
 * while disabling any voltage compensation modules.
 */
void omap_voltage_reset(struct voltagedomain *voltdm)
{
	unsigned long target_uvdc;

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

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

	omap_voltage_scale_vdd(voltdm, target_uvdc);
}
コード例 #3
0
/**
 * do_calibrate() - work which actually does the calibration
 * @work: pointer to the work
 *
 * calibration routine uses the following logic:
 * on the first trigger, we start the isr to collect sr voltages
 * wait for stabilization delay (reschdule self instead of sleeping)
 * after the delay, see if we collected any isr events
 * if none, we have calibrated voltage.
 * if there are any, we retry untill we giveup.
 * on retry timeout, select a voltage to use as safe voltage.
 */
static void do_calibrate(struct work_struct *work)
{
	struct sr_class1p5_work_data *work_data =
	    container_of(work, struct sr_class1p5_work_data, work.work);
	unsigned long u_volt_safe = 0, u_volt_current = 0;
	struct omap_volt_data *volt_data;
	struct voltagedomain *voltdm;

	if (unlikely(!work_data)) {
		pr_err("%s: ooops.. null work_data?\n", __func__);
		return;
	}

	/*
	 * Handle the case where we might have just been scheduled AND
	 * 1.5 disable was called.
	 */
	if (omap_vscale_pause(work_data->voltdm, true)) {
		schedule_delayed_work(&work_data->work,
				      msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
						       SR1P5_STABLE_SAMPLES));
		return;
	}

	voltdm = work_data->voltdm;
	/*
	 * In the unlikely case that we did get through when unplanned,
	 * flag and return.
	 */
	if (unlikely(!work_data->work_active)) {
		pr_err("%s:%s unplanned work invocation!\n", __func__,
		       voltdm->name);
		omap_vscale_unpause(work_data->voltdm);
		return;
	}

	work_data->num_calib_triggers++;
	/* if we are triggered first time, we need to start isr to sample */
	if (work_data->num_calib_triggers == 1)
		goto start_sampling;

	/* Stop isr from interrupting our measurements :) */
	sr_notifier_control(voltdm, false);

	volt_data = work_data->vdata;

	/* if there are no samples captured.. SR is silent, aka stability! */
	if (!work_data->num_osc_samples) {
		u_volt_safe = omap_vp_get_curr_volt(voltdm);
		u_volt_current = u_volt_safe;
		goto done_calib;
	}
	if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) {
		pr_warning("%s: %s recalib timeout!\n", __func__,
			   work_data->voltdm->name);
		goto oscillating_calib;
	}

	/* we have potential oscillations/first sample */
start_sampling:
	work_data->num_osc_samples = 0;
	/* Clear pending events */
	sr_notifier_control(voltdm, false);
	/* Clear all transdones */
	while (omap_vp_is_transdone(voltdm))
		omap_vp_clear_transdone(voltdm);
	/* trigger sampling */
	sr_notifier_control(voltdm, true);
	schedule_delayed_work(&work_data->work,
			      msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
					       SR1P5_STABLE_SAMPLES));
	omap_vscale_unpause(work_data->voltdm);

	return;

oscillating_calib:
	/* Use the nominal voltage as the safe voltage */
	u_volt_safe = volt_data->volt_nominal;
	/* pick up current voltage to switch if needed */
	u_volt_current = omap_vp_get_curr_volt(voltdm);

	/* Fall through to close up common stuff */
done_calib:
	omap_vp_disable(voltdm);
	sr_disable(voltdm);

	volt_data->volt_calibrated = u_volt_safe;
	/* Setup my dynamic voltage for the next calibration for this opp */
	volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data);

	/*
	 * if the voltage we decided as safe is not the current voltage,
	 * switch
	 */

	if (cpu_is_omap3630()) {
		pr_debug("%s:%s - sr opp margin %d\n", __func__, voltdm->name, volt_data->sr_oppmargin);

		volt_data->volt_calibrated += volt_data->sr_oppmargin;
		if (volt_data->volt_calibrated > volt_data->volt_nominal) {
			volt_data->volt_calibrated = volt_data->volt_nominal;
		}
	}

	if (volt_data->volt_calibrated != u_volt_current) {
		pr_debug("%s:%s reconfiguring to voltage %d\n",
			 __func__, voltdm->name, volt_data->volt_calibrated);
		omap_voltage_scale_vdd(voltdm, volt_data);
	}

	/*
	 * TODO: Setup my wakeup voltage to allow immediate going to OFF and
	 * on - Pending twl and voltage layer cleanups.
	 * This is necessary, as this is not done as part of regular
	 * Dvfs flow.
	 * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated);
	 */
	work_data->work_active = false;
	omap_vscale_unpause(work_data->voltdm);

	/* Release c-state constraint */
	omap_pm_set_max_mpu_wakeup_lat(&work_data->qos_request, -1);
	pr_debug("%s - %s: release c-state\n", __func__, voltdm->name);
}