vp.c 10.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/debugfs.h>

#include <plat/common.h>

#include "voltage.h"
#include "vp.h"
#include "prm-regbits-34xx.h"
#include "prm-regbits-44xx.h"
#include "prm44xx.h"

static void __init vp_debugfs_init(struct voltagedomain *voltdm);

static void vp_latch_vsel(struct voltagedomain *voltdm)
{
	struct omap_vp_instance_data *vp = voltdm->vdd->vp_data;
	u32 vpconfig;
	unsigned long uvdc;
	char vsel;
	struct omap_vdd_info *vdd = voltdm->vdd;

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

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

	vsel = vdd->pmic_info->uv_to_vsel(uvdc);

38
	vpconfig = voltdm->read(vp->vpconfig);
39 40 41 42
	vpconfig &= ~(vp->vp_common->vpconfig_initvoltage_mask |
			vp->vp_common->vpconfig_initvdd);
	vpconfig |= vsel << vp->vp_common->vpconfig_initvoltage_shift;

43
	voltdm->write(vpconfig, vp->vpconfig);
44 45

	/* Trigger initVDD value copy to voltage processor */
46 47
	voltdm->write((vpconfig | vp->vp_common->vpconfig_initvdd),
		       vp->vpconfig);
48 49

	/* Clear initVDD copy trigger bit */
50
	voltdm->write(vpconfig, vp->vpconfig);
51 52 53 54 55 56 57 58 59
}

/* Generic voltage init functions */
void __init omap_vp_init(struct voltagedomain *voltdm)
{
	struct omap_vp_instance_data *vp = voltdm->vdd->vp_data;
	struct omap_vdd_info *vdd = voltdm->vdd;
	u32 vp_val;

60
	if (!voltdm->read || !voltdm->write) {
61 62 63 64 65 66 67 68 69
		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
			__func__, voltdm->name);
		return;
	}

	vp_val = vdd->vp_rt_data.vpconfig_erroroffset |
		(vdd->vp_rt_data.vpconfig_errorgain <<
		vp->vp_common->vpconfig_errorgain_shift) |
		vp->vp_common->vpconfig_timeouten;
70
	voltdm->write(vp_val, vp->vpconfig);
71 72 73 74 75

	vp_val = ((vdd->vp_rt_data.vstepmin_smpswaittimemin <<
		vp->vp_common->vstepmin_smpswaittimemin_shift) |
		(vdd->vp_rt_data.vstepmin_stepmin <<
		vp->vp_common->vstepmin_stepmin_shift));
76
	voltdm->write(vp_val, vp->vstepmin);
77 78 79 80 81

	vp_val = ((vdd->vp_rt_data.vstepmax_smpswaittimemax <<
		vp->vp_common->vstepmax_smpswaittimemax_shift) |
		(vdd->vp_rt_data.vstepmax_stepmax <<
		vp->vp_common->vstepmax_stepmax_shift));
82
	voltdm->write(vp_val, vp->vstepmax);
83 84 85 86 87 88 89

	vp_val = ((vdd->vp_rt_data.vlimitto_vddmax <<
		vp->vp_common->vlimitto_vddmax_shift) |
		(vdd->vp_rt_data.vlimitto_vddmin <<
		vp->vp_common->vlimitto_vddmin_shift) |
		(vdd->vp_rt_data.vlimitto_timeout <<
		vp->vp_common->vlimitto_timeout_shift));
90
	voltdm->write(vp_val, vp->vlimitto);
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

	vp_debugfs_init(voltdm);
}

/* VP force update method of voltage scaling */
int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
			      unsigned long target_volt)
{
	struct omap_vp_instance_data *vp = voltdm->vdd->vp_data;
	u32 vpconfig;
	u8 target_vsel, current_vsel;
	int ret, timeout = 0;

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

	/*
	 * Clear all pending TransactionDone interrupt/status. Typical latency
	 * is <3us
	 */
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
113 114
		vp->vp_common->ops->clear_txdone(vp->id);
		if (!vp->vp_common->ops->check_txdone(vp->id))
115 116 117 118 119 120 121 122 123 124
			break;
		udelay(1);
	}
	if (timeout >= VP_TRANXDONE_TIMEOUT) {
		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
			"Voltage change aborted", __func__, voltdm->name);
		return -ETIMEDOUT;
	}

	/* Configure for VP-Force Update */
125
	vpconfig = voltdm->read(vp->vpconfig);
126 127 128 129 130
	vpconfig &= ~(vp->vp_common->vpconfig_initvdd |
			vp->vp_common->vpconfig_forceupdate |
			vp->vp_common->vpconfig_initvoltage_mask);
	vpconfig |= ((target_vsel <<
			vp->vp_common->vpconfig_initvoltage_shift));
131
	voltdm->write(vpconfig, vp->vpconfig);
132 133 134

	/* Trigger initVDD value copy to voltage processor */
	vpconfig |= vp->vp_common->vpconfig_initvdd;
135
	voltdm->write(vpconfig, vp->vpconfig);
136 137 138

	/* Force update of voltage */
	vpconfig |= vp->vp_common->vpconfig_forceupdate;
139
	voltdm->write(vpconfig, vp->vpconfig);
140 141 142 143 144 145

	/*
	 * Wait for TransactionDone. Typical latency is <200us.
	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
	 */
	timeout = 0;
146
	omap_test_timeout(vp->vp_common->ops->check_txdone(vp->id),
147 148 149 150 151 152 153 154 155 156 157 158 159 160
			  VP_TRANXDONE_TIMEOUT, timeout);
	if (timeout >= VP_TRANXDONE_TIMEOUT)
		pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
			"TRANXDONE never got set after the voltage update\n",
			__func__, voltdm->name);

	omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel);

	/*
	 * Disable TransactionDone interrupt , clear all status, clear
	 * control registers
	 */
	timeout = 0;
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
161 162
		vp->vp_common->ops->clear_txdone(vp->id);
		if (!vp->vp_common->ops->check_txdone(vp->id))
163 164 165 166 167 168 169 170 171
			break;
		udelay(1);
	}

	if (timeout >= VP_TRANXDONE_TIMEOUT)
		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying"
			"to clear the TRANXDONE status\n",
			__func__, voltdm->name);

172
	vpconfig = voltdm->read(vp->vpconfig);
173 174
	/* Clear initVDD copy trigger bit */
	vpconfig &= ~vp->vp_common->vpconfig_initvdd;
175
	voltdm->write(vpconfig, vp->vpconfig);
176 177
	/* Clear force bit */
	vpconfig &= ~vp->vp_common->vpconfig_forceupdate;
178
	voltdm->write(vpconfig, vp->vpconfig);
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200

	return 0;
}

/**
 * omap_vp_get_curr_volt() - API to get the current vp voltage.
 * @voltdm:	pointer to the VDD.
 *
 * This API returns the current voltage for the specified voltage processor
 */
unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
{
	struct omap_vp_instance_data *vp = voltdm->vdd->vp_data;
	struct omap_vdd_info *vdd;
	u8 curr_vsel;

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

	vdd = voltdm->vdd;
201
	if (!voltdm->read) {
202 203 204 205 206
		pr_err("%s: No read API for reading vdd_%s regs\n",
			__func__, voltdm->name);
		return 0;
	}

207
	curr_vsel = voltdm->read(vp->voltage);
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237

	if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) {
		pr_warning("%s: PMIC function to convert vsel to voltage"
			"in uV not registerd\n", __func__);
		return 0;
	}

	return vdd->pmic_info->vsel_to_uv(curr_vsel);
}

/**
 * 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_data *vp;
	struct omap_vdd_info *vdd;
	u32 vpconfig;

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

	vdd = voltdm->vdd;
	vp = voltdm->vdd->vp_data;
238
	if (!voltdm->read || !voltdm->write) {
239 240 241 242 243 244 245 246 247 248 249 250
		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 (vdd->vp_enabled)
		return;

	vp_latch_vsel(voltdm);

	/* Enable VP */
251
	vpconfig = voltdm->read(vp->vpconfig);
252
	vpconfig |= vp->vp_common->vpconfig_vpenable;
253
	voltdm->write(vpconfig, vp->vpconfig);
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
	vdd->vp_enabled = true;
}

/**
 * omap_vp_disable() - API to disable a particular VP
 * @voltdm:	pointer to the VDD whose VP is to be disabled.
 *
 * This API disables a particular voltage processor. Needed by the smartreflex
 * class drivers.
 */
void omap_vp_disable(struct voltagedomain *voltdm)
{
	struct omap_vp_instance_data *vp;
	struct omap_vdd_info *vdd;
	u32 vpconfig;
	int timeout;

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

	vdd = voltdm->vdd;
	vp = voltdm->vdd->vp_data;
278
	if (!voltdm->read || !voltdm->write) {
279 280 281 282 283 284 285 286 287 288 289 290 291
		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
			__func__, voltdm->name);
		return;
	}

	/* If VP is already disabled, do nothing. Return */
	if (!vdd->vp_enabled) {
		pr_warning("%s: Trying to disable VP for vdd_%s when"
			"it is already disabled\n", __func__, voltdm->name);
		return;
	}

	/* Disable VP */
292
	vpconfig = voltdm->read(vp->vpconfig);
293
	vpconfig &= ~vp->vp_common->vpconfig_vpenable;
294
	voltdm->write(vpconfig, vp->vpconfig);
295 296 297 298

	/*
	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
	 */
299 300
	omap_test_timeout((voltdm->read(vp->vstatus)),
			  VP_IDLE_TIMEOUT, timeout);
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323

	if (timeout >= VP_IDLE_TIMEOUT)
		pr_warning("%s: vdd_%s idle timedout\n",
			__func__, voltdm->name);

	vdd->vp_enabled = false;

	return;
}

/* Voltage debugfs support */
static int vp_volt_debug_get(void *data, u64 *val)
{
	struct voltagedomain *voltdm = (struct voltagedomain *)data;
	struct omap_vp_instance_data *vp = voltdm->vdd->vp_data;
	struct omap_vdd_info *vdd = voltdm->vdd;
	u8 vsel;

	if (!vdd) {
		pr_warning("Wrong paramater passed\n");
		return -EINVAL;
	}

324
	vsel = voltdm->read(vp->voltage);
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367

	if (!vdd->pmic_info->vsel_to_uv) {
		pr_warning("PMIC function to convert vsel to voltage"
			"in uV not registerd\n");
		return -EINVAL;
	}

	*val = vdd->pmic_info->vsel_to_uv(vsel);
	return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");

static void __init vp_debugfs_init(struct voltagedomain *voltdm)
{
	struct omap_vdd_info *vdd = voltdm->vdd;
	struct dentry *debug_dir;

	debug_dir = debugfs_create_dir("vp", vdd->debug_dir);
	if (IS_ERR(debug_dir))
		pr_err("%s: Unable to create VP debugfs dir dir\n", __func__);

	(void) debugfs_create_x16("errorgain", S_IRUGO, debug_dir,
				&(vdd->vp_rt_data.vpconfig_errorgain));
	(void) debugfs_create_x16("smpswaittimemin", S_IRUGO,
				debug_dir,
				&(vdd->vp_rt_data.vstepmin_smpswaittimemin));
	(void) debugfs_create_x8("stepmin", S_IRUGO, debug_dir,
				&(vdd->vp_rt_data.vstepmin_stepmin));
	(void) debugfs_create_x16("smpswaittimemax", S_IRUGO,
				debug_dir,
				&(vdd->vp_rt_data.vstepmax_smpswaittimemax));
	(void) debugfs_create_x8("stepmax", S_IRUGO, debug_dir,
				&(vdd->vp_rt_data.vstepmax_stepmax));
	(void) debugfs_create_x8("vddmax", S_IRUGO, debug_dir,
				&(vdd->vp_rt_data.vlimitto_vddmax));
	(void) debugfs_create_x8("vddmin", S_IRUGO, debug_dir,
				&(vdd->vp_rt_data.vlimitto_vddmin));
	(void) debugfs_create_x16("timeout", S_IRUGO, debug_dir,
				&(vdd->vp_rt_data.vlimitto_timeout));
	(void) debugfs_create_file("curr_volt", S_IRUGO, debug_dir,
				(void *) voltdm, &vp_volt_debug_fops);
}