Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
new file mode 100644
index 0000000..b9e577a
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -0,0 +1,1667 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/pmic8901.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+
+#include "rpm_resources.h"
+
+/* Debug Definitions */
+
+enum {
+	MSM_RPM_VREG_DEBUG_REQUEST = BIT(0),
+	MSM_RPM_VREG_DEBUG_VOTE = BIT(1),
+	MSM_RPM_VREG_DEBUG_DUPLICATE = BIT(2),
+	MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1 = BIT(3),
+};
+
+static int msm_rpm_vreg_debug_mask;
+module_param_named(
+	debug_mask, msm_rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+#define MICRO_TO_MILLI(uV)			((uV) / 1000)
+#define MILLI_TO_MICRO(mV)			((mV) * 1000)
+
+/* LDO register word 1 */
+#define LDO_VOLTAGE				0x00000FFF
+#define LDO_VOLTAGE_SHIFT			0
+#define LDO_PEAK_CURRENT			0x00FFF000
+#define LDO_PEAK_CURRENT_SHIFT			12
+#define LDO_MODE				0x03000000
+#define LDO_MODE_SHIFT				24
+#define LDO_PIN_CTRL				0x3C000000
+#define LDO_PIN_CTRL_SHIFT			26
+#define LDO_PIN_FN				0xC0000000
+#define LDO_PIN_FN_SHIFT			30
+
+/* LDO register word 2 */
+#define LDO_PULL_DOWN_ENABLE			0x00000001
+#define LDO_PULL_DOWN_ENABLE_SHIFT		0
+#define LDO_AVG_CURRENT				0x00001FFE
+#define LDO_AVG_CURRENT_SHIFT			1
+
+/* SMPS register word 1 */
+#define SMPS_VOLTAGE				0x00000FFF
+#define SMPS_VOLTAGE_SHIFT			0
+#define SMPS_PEAK_CURRENT			0x00FFF000
+#define SMPS_PEAK_CURRENT_SHIFT			12
+#define SMPS_MODE				0x03000000
+#define SMPS_MODE_SHIFT				24
+#define SMPS_PIN_CTRL				0x3C000000
+#define SMPS_PIN_CTRL_SHIFT			26
+#define SMPS_PIN_FN				0xC0000000
+#define SMPS_PIN_FN_SHIFT			30
+
+/* SMPS register word 2 */
+#define SMPS_PULL_DOWN_ENABLE			0x00000001
+#define SMPS_PULL_DOWN_ENABLE_SHIFT		0
+#define SMPS_AVG_CURRENT			0x00001FFE
+#define SMPS_AVG_CURRENT_SHIFT			1
+#define SMPS_FREQ				0x001FE000
+#define SMPS_FREQ_SHIFT				13
+#define SMPS_CLK_SRC				0x00600000
+#define SMPS_CLK_SRC_SHIFT			21
+
+/* SWITCH register word 1 */
+#define SWITCH_STATE				0x0001
+#define SWITCH_STATE_SHIFT			0
+#define SWITCH_PULL_DOWN_ENABLE			0x0002
+#define SWITCH_PULL_DOWN_ENABLE_SHIFT		1
+#define SWITCH_PIN_CTRL				0x003C
+#define SWITCH_PIN_CTRL_SHIFT			2
+#define SWITCH_PIN_FN				0x00C0
+#define SWITCH_PIN_FN_SHIFT			6
+
+/* NCP register word 1 */
+#define NCP_VOLTAGE				0x0FFF
+#define NCP_VOLTAGE_SHIFT			0
+#define NCP_STATE				0x1000
+#define NCP_STATE_SHIFT				12
+
+/*
+ * This is used when voting for LPM or HPM by subtracting or adding to the
+ * hpm_min_load of a regulator.  It has units of uA.
+ */
+#define LOAD_THRESHOLD_STEP			1000
+
+/* This is the maximum uA load that can be passed to the RPM. */
+#define MAX_POSSIBLE_LOAD			(MILLI_TO_MICRO(0xFFF))
+
+/* Voltage regulator types */
+#define IS_LDO(id)	((id >= RPM_VREG_ID_PM8058_L0 && \
+			  id <= RPM_VREG_ID_PM8058_L25) || \
+			 (id >= RPM_VREG_ID_PM8901_L0 && \
+			  id <= RPM_VREG_ID_PM8901_L6))
+#define IS_SMPS(id)	((id >= RPM_VREG_ID_PM8058_S0 && \
+			  id <= RPM_VREG_ID_PM8058_S4) || \
+			 (id >= RPM_VREG_ID_PM8901_S0 && \
+			  id <= RPM_VREG_ID_PM8901_S4))
+#define IS_SWITCH(id)	((id >= RPM_VREG_ID_PM8058_LVS0 && \
+			  id <= RPM_VREG_ID_PM8058_LVS1) || \
+			 (id >= RPM_VREG_ID_PM8901_LVS0 && \
+			  id <= RPM_VREG_ID_PM8901_LVS3) || \
+			 (id == RPM_VREG_ID_PM8901_MVS0))
+#define IS_NCP(id)	(id == RPM_VREG_ID_PM8058_NCP)
+
+#define IS_8901_SMPS(id) ((id >= RPM_VREG_ID_PM8901_S0 && \
+			  id <= RPM_VREG_ID_PM8901_S4))
+
+struct vreg {
+	struct msm_rpm_iv_pair	req[2];
+	struct msm_rpm_iv_pair	prev_active_req[2];
+	struct msm_rpm_iv_pair	prev_sleep_req[2];
+	struct rpm_vreg_pdata	*pdata;
+	int			save_uV;
+	const int		hpm_min_load;
+	unsigned		pc_vote;
+	unsigned		optimum;
+	unsigned		mode_initialized;
+	int			active_min_mV_vote[RPM_VREG_VOTER_COUNT];
+	int			sleep_min_mV_vote[RPM_VREG_VOTER_COUNT];
+	enum rpm_vreg_id	id;
+};
+
+#define RPM_VREG_NCP_HPM_MIN_LOAD	0
+
+#define VREG_2(_vreg_id, _rpm_id, _hpm_min_load) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+			[1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+		}, \
+		.hpm_min_load = RPM_VREG_##_hpm_min_load, \
+	}
+
+#define VREG_1(_vreg_id, _rpm_id) \
+	[RPM_VREG_ID_##_vreg_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+	}
+
+static struct vreg vregs[RPM_VREG_ID_MAX] = {
+	VREG_2(PM8058_L0, LDO0, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L1, LDO1, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L2, LDO2, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L3, LDO3, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L4, LDO4, LDO_50_HPM_MIN_LOAD),
+	VREG_2(PM8058_L5, LDO5, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L6, LDO6, LDO_50_HPM_MIN_LOAD),
+	VREG_2(PM8058_L7, LDO7, LDO_50_HPM_MIN_LOAD),
+	VREG_2(PM8058_L8, LDO8, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L9, LDO9, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L10, LDO10, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L11, LDO11, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L12, LDO12, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L13, LDO13, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L14, LDO14, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L15, LDO15, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L16, LDO16, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L17, LDO17, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L18, LDO18, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L19, LDO19, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L20, LDO20, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L21, LDO21, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L22, LDO22, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L23, LDO23, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8058_L24, LDO24, LDO_150_HPM_MIN_LOAD),
+	VREG_2(PM8058_L25, LDO25, LDO_150_HPM_MIN_LOAD),
+
+	VREG_2(PM8058_S0, SMPS0, SMPS_HPM_MIN_LOAD),
+	VREG_2(PM8058_S1, SMPS1, SMPS_HPM_MIN_LOAD),
+	VREG_2(PM8058_S2, SMPS2, SMPS_HPM_MIN_LOAD),
+	VREG_2(PM8058_S3, SMPS3, SMPS_HPM_MIN_LOAD),
+	VREG_2(PM8058_S4, SMPS4, SMPS_HPM_MIN_LOAD),
+
+	VREG_1(PM8058_LVS0, LVS0),
+	VREG_1(PM8058_LVS1, LVS1),
+
+	VREG_2(PM8058_NCP, NCP, NCP_HPM_MIN_LOAD),
+
+	VREG_2(PM8901_L0, LDO0B, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8901_L1, LDO1B, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8901_L2, LDO2B, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8901_L3, LDO3B, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8901_L4, LDO4B, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8901_L5, LDO5B, LDO_300_HPM_MIN_LOAD),
+	VREG_2(PM8901_L6, LDO6B, LDO_300_HPM_MIN_LOAD),
+
+	VREG_2(PM8901_S0, SMPS0B, FTSMPS_HPM_MIN_LOAD),
+	VREG_2(PM8901_S1, SMPS1B, FTSMPS_HPM_MIN_LOAD),
+	VREG_2(PM8901_S2, SMPS2B, FTSMPS_HPM_MIN_LOAD),
+	VREG_2(PM8901_S3, SMPS3B, FTSMPS_HPM_MIN_LOAD),
+	VREG_2(PM8901_S4, SMPS4B, FTSMPS_HPM_MIN_LOAD),
+
+	VREG_1(PM8901_LVS0, LVS0B),
+	VREG_1(PM8901_LVS1, LVS1B),
+	VREG_1(PM8901_LVS2, LVS2B),
+	VREG_1(PM8901_LVS3, LVS3B),
+
+	VREG_1(PM8901_MVS0, MVS),
+};
+
+static void print_rpm_request(struct vreg *vreg, int set);
+static void print_rpm_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
+			int set, int voter_mV, int aggregate_mV);
+static void print_rpm_duplicate(struct vreg *vreg, int set, int cnt);
+
+static unsigned int smps_get_mode(struct regulator_dev *dev);
+static unsigned int ldo_get_mode(struct regulator_dev *dev);
+static unsigned int switch_get_mode(struct regulator_dev *dev);
+
+/* Spin lock needed for sleep-selectable regulators. */
+static DEFINE_SPINLOCK(pm8058_noirq_lock);
+
+static int voltage_from_req(struct vreg *vreg)
+{
+	int shift = 0;
+	uint32_t value = 0, mask = 0;
+
+	value = vreg->req[0].value;
+
+	if (IS_SMPS(vreg->id)) {
+		mask = SMPS_VOLTAGE;
+		shift = SMPS_VOLTAGE_SHIFT;
+	} else if (IS_LDO(vreg->id)) {
+		mask = LDO_VOLTAGE;
+		shift = LDO_VOLTAGE_SHIFT;
+	} else if (IS_NCP(vreg->id)) {
+		mask = NCP_VOLTAGE;
+		shift = NCP_VOLTAGE_SHIFT;
+	}
+
+	return (value & mask) >> shift;
+}
+
+static void voltage_to_req(int voltage, struct vreg *vreg)
+{
+	int shift = 0;
+	uint32_t *value = NULL, mask = 0;
+
+	value = &(vreg->req[0].value);
+
+	if (IS_SMPS(vreg->id)) {
+		mask = SMPS_VOLTAGE;
+		shift = SMPS_VOLTAGE_SHIFT;
+	} else if (IS_LDO(vreg->id)) {
+		mask = LDO_VOLTAGE;
+		shift = LDO_VOLTAGE_SHIFT;
+	} else if (IS_NCP(vreg->id)) {
+		mask = NCP_VOLTAGE;
+		shift = NCP_VOLTAGE_SHIFT;
+	}
+
+	*value &= ~mask;
+	*value |= (voltage << shift) & mask;
+}
+
+static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
+			  int set, unsigned mask0, unsigned val0,
+			  unsigned mask1, unsigned val1, unsigned cnt,
+			  int update_voltage)
+{
+	struct msm_rpm_iv_pair *prev_req;
+	int rc = 0, max_mV_vote = 0, i;
+	unsigned prev0, prev1;
+	int *min_mV_vote;
+
+	if (set == MSM_RPM_CTX_SET_0) {
+		min_mV_vote = vreg->active_min_mV_vote;
+		prev_req = vreg->prev_active_req;
+	} else {
+		min_mV_vote = vreg->sleep_min_mV_vote;
+		prev_req = vreg->prev_sleep_req;
+	}
+
+	prev0 = vreg->req[0].value;
+	vreg->req[0].value &= ~mask0;
+	vreg->req[0].value |= val0 & mask0;
+
+	prev1 = vreg->req[1].value;
+	vreg->req[1].value &= ~mask1;
+	vreg->req[1].value |= val1 & mask1;
+
+	if (update_voltage)
+		min_mV_vote[voter] = voltage_from_req(vreg);
+
+	/* Find the highest voltage voted for and use it. */
+	for (i = 0; i < RPM_VREG_VOTER_COUNT; i++)
+		max_mV_vote = max(max_mV_vote, min_mV_vote[i]);
+	voltage_to_req(max_mV_vote, vreg);
+
+	if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_VOTE)
+		print_rpm_vote(vreg, voter, set, min_mV_vote[voter],
+				max_mV_vote);
+
+	/* Ignore duplicate requests */
+	if (vreg->req[0].value != prev_req[0].value ||
+	    vreg->req[1].value != prev_req[1].value) {
+
+		rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
+		if (rc) {
+			vreg->req[0].value = prev0;
+			vreg->req[1].value = prev1;
+
+			pr_err("%s: msm_rpmrs_set_noirq failed - "
+				"set=%s, id=%d, rc=%d\n", __func__,
+				(set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
+				vreg->req[0].id, rc);
+		} else {
+			/* Only save if nonzero and active set. */
+			if (max_mV_vote && (set == MSM_RPM_CTX_SET_0))
+				vreg->save_uV = MILLI_TO_MICRO(max_mV_vote);
+			if (msm_rpm_vreg_debug_mask
+			    & MSM_RPM_VREG_DEBUG_REQUEST)
+				print_rpm_request(vreg, set);
+			prev_req[0].value = vreg->req[0].value;
+			prev_req[1].value = vreg->req[1].value;
+		}
+	} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
+		print_rpm_duplicate(vreg, set, cnt);
+	}
+
+	return rc;
+}
+
+static int vreg_set_noirq(struct vreg *vreg, enum rpm_vreg_voter voter,
+			  int sleep, unsigned mask0, unsigned val0,
+			  unsigned mask1, unsigned val1, unsigned cnt,
+			  int update_voltage)
+{
+	unsigned long flags;
+	int rc;
+	unsigned val0_sleep, mask0_sleep;
+
+	if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pm8058_noirq_lock, flags);
+
+	/*
+	 * Send sleep set request first so that subsequent set_mode, etc calls
+	 * use the voltage from the active set.
+	 */
+	if (sleep)
+		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
+				mask0, val0, mask1, val1, cnt, update_voltage);
+	else {
+		/*
+		 * Vote for 0 V in the sleep set when active set-only is
+		 * specified.  This ensures that a disable vote will be issued
+		 * at some point for the sleep set of the regulator.
+		 */
+		val0_sleep = val0;
+		mask0_sleep = mask0;
+		if (IS_SMPS(vreg->id)) {
+			val0_sleep &= ~SMPS_VOLTAGE;
+			mask0_sleep |= SMPS_VOLTAGE;
+		} else if (IS_LDO(vreg->id)) {
+			val0_sleep &= ~LDO_VOLTAGE;
+			mask0_sleep |= LDO_VOLTAGE;
+		} else if (IS_NCP(vreg->id)) {
+			val0_sleep &= ~NCP_VOLTAGE;
+			mask0_sleep |= NCP_VOLTAGE;
+		}
+
+		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
+					mask0_sleep, val0_sleep,
+					mask1, val1, cnt, update_voltage);
+	}
+
+	rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
+					mask1, val1, cnt, update_voltage);
+
+	spin_unlock_irqrestore(&pm8058_noirq_lock, flags);
+
+	return rc;
+}
+
+/**
+ * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
+ * @vreg: ID for regulator
+ * @voter: ID for the voter
+ * @min_uV: minimum acceptable voltage (in uV) that is voted for
+ * @max_uV: maximum acceptable voltage (in uV) that is voted for
+ * @sleep_also: 0 for active set only, non-0 for active set and sleep set
+ *
+ * Returns 0 on success or errno.
+ *
+ * This function is used to vote for the voltage of a regulator without
+ * using the regulator framework.  It is needed by consumers which hold spin
+ * locks or have interrupts disabled because the regulator framework can sleep.
+ * It is also needed by consumers which wish to only vote for active set
+ * regulator voltage.
+ *
+ * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
+ *
+ * This function may only be called for regulators which have the sleep flag
+ * specified in their private data.
+ */
+int rpm_vreg_set_voltage(enum rpm_vreg_id vreg_id, enum rpm_vreg_voter voter,
+			 int min_uV, int max_uV, int sleep_also)
+{
+	int rc;
+	unsigned val0 = 0, val1 = 0, mask0 = 0, mask1 = 0, cnt = 2;
+
+	if (vreg_id < 0 || vreg_id >= RPM_VREG_ID_MAX)
+		return -EINVAL;
+
+	if (!vregs[vreg_id].pdata->sleep_selectable)
+		return -EINVAL;
+
+	if (min_uV < vregs[vreg_id].pdata->init_data.constraints.min_uV ||
+	    min_uV > vregs[vreg_id].pdata->init_data.constraints.max_uV)
+		return -EINVAL;
+
+	if (IS_SMPS(vreg_id)) {
+		mask0 = SMPS_VOLTAGE;
+		val0 = MICRO_TO_MILLI(min_uV) << SMPS_VOLTAGE_SHIFT;
+	} else if (IS_LDO(vreg_id)) {
+		mask0 = LDO_VOLTAGE;
+		val0 = MICRO_TO_MILLI(min_uV) << LDO_VOLTAGE_SHIFT;
+	} else if (IS_NCP(vreg_id)) {
+		mask0 = NCP_VOLTAGE;
+		val0 = MICRO_TO_MILLI(min_uV) << NCP_VOLTAGE_SHIFT;
+		cnt = 1;
+	} else {
+		cnt = 1;
+	}
+
+	rc = vreg_set_noirq(&vregs[vreg_id], voter, sleep_also, mask0, val0,
+			    mask1, val1, cnt, 1);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_vreg_set_voltage);
+
+/**
+ * rpm_vreg_set_frequency - sets the frequency of a switching regulator
+ * @vreg: ID for regulator
+ * @min_uV: minimum acceptable frequency of operation
+ *
+ * Returns 0 on success or errno.
+ */
+int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq)
+{
+	unsigned val0 = 0, val1 = 0, mask0 = 0, mask1 = 0, cnt = 2;
+	int rc;
+
+	if (vreg_id < 0 || vreg_id >= RPM_VREG_ID_MAX) {
+		pr_err("%s: invalid regulator id=%d\n", __func__, vreg_id);
+		return -EINVAL;
+	}
+
+	if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
+		pr_err("%s: invalid frequency=%d\n", __func__, freq);
+		return -EINVAL;
+	}
+
+	if (!IS_SMPS(vreg_id)) {
+		pr_err("%s: regulator id=%d does not support frequency\n",
+			__func__, vreg_id);
+		return -EINVAL;
+	}
+
+	if (!vregs[vreg_id].pdata->sleep_selectable) {
+		pr_err("%s: regulator id=%d is not marked sleep selectable\n",
+			__func__, vreg_id);
+		return -EINVAL;
+	}
+
+	mask1 = SMPS_FREQ;
+	val1 = freq << SMPS_FREQ_SHIFT;
+
+	rc = vreg_set_noirq(&vregs[vreg_id], RPM_VREG_VOTER_REG_FRAMEWORK,
+			    1, mask0, val0, mask1, val1, cnt, 0);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
+
+#define IS_PMIC_8901_V1(rev)		((rev) == PM_8901_REV_1p0 || \
+					 (rev) == PM_8901_REV_1p1)
+
+#define PMIC_8901_V1_SCALE(uV)		((((uV) - 62100) * 23) / 25)
+
+static inline int vreg_hpm_min_uA(struct vreg *vreg)
+{
+	return vreg->hpm_min_load;
+}
+
+static inline int vreg_lpm_max_uA(struct vreg *vreg)
+{
+	return vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
+}
+
+static inline unsigned saturate_load(unsigned load_uA)
+{
+	return (load_uA > MAX_POSSIBLE_LOAD ? MAX_POSSIBLE_LOAD : load_uA);
+}
+
+/* Change vreg->req, but do not send it to the RPM. */
+static int vreg_store(struct vreg *vreg, unsigned mask0, unsigned val0,
+		unsigned mask1, unsigned val1)
+{
+	unsigned long flags = 0;
+
+	if (vreg->pdata->sleep_selectable)
+		spin_lock_irqsave(&pm8058_noirq_lock, flags);
+
+	vreg->req[0].value &= ~mask0;
+	vreg->req[0].value |= val0 & mask0;
+
+	vreg->req[1].value &= ~mask1;
+	vreg->req[1].value |= val1 & mask1;
+
+	if (vreg->pdata->sleep_selectable)
+		spin_unlock_irqrestore(&pm8058_noirq_lock, flags);
+
+	return 0;
+}
+
+static int vreg_set(struct vreg *vreg, unsigned mask0, unsigned val0,
+		unsigned mask1, unsigned val1, unsigned cnt)
+{
+	unsigned prev0 = 0, prev1 = 0;
+	int rc;
+
+	/*
+	 * Bypass the normal route for regulators that can be called to change
+	 * just the active set values.
+	 */
+	if (vreg->pdata->sleep_selectable)
+		return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
+					mask0, val0, mask1, val1, cnt, 1);
+
+	prev0 = vreg->req[0].value;
+	vreg->req[0].value &= ~mask0;
+	vreg->req[0].value |= val0 & mask0;
+
+	prev1 = vreg->req[1].value;
+	vreg->req[1].value &= ~mask1;
+	vreg->req[1].value |= val1 & mask1;
+
+	/* Ignore duplicate requests */
+	if (vreg->req[0].value == vreg->prev_active_req[0].value &&
+	    vreg->req[1].value == vreg->prev_active_req[1].value) {
+		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE)
+			print_rpm_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
+		return 0;
+	}
+
+	rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+	if (rc) {
+		vreg->req[0].value = prev0;
+		vreg->req[1].value = prev1;
+
+		pr_err("%s: msm_rpm_set fail id=%d, rc=%d\n",
+				__func__, vreg->req[0].id, rc);
+	} else {
+		if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST)
+			print_rpm_request(vreg, MSM_RPM_CTX_SET_0);
+		vreg->prev_active_req[0].value = vreg->req[0].value;
+		vreg->prev_active_req[1].value = vreg->req[1].value;
+	}
+
+	return rc;
+}
+
+static int smps_is_enabled(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	return ((vreg->req[0].value & SMPS_VOLTAGE) >> SMPS_VOLTAGE_SHIFT) != 0;
+}
+
+static int _smps_set_voltage(struct regulator_dev *dev, int min_uV)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	int scaled_min_uV = min_uV;
+	static int pmic8901_rev;
+
+	/* Scale input request voltage down if using v1 PMIC 8901. */
+	if (IS_8901_SMPS(vreg->id) && min_uV) {
+		if (pmic8901_rev <= 0)
+			pmic8901_rev = pm8901_rev(NULL);
+
+		if (pmic8901_rev < 0)
+			pr_err("%s: setting %s to %d uV; PMIC 8901 revision "
+				"unavailable, no scaling can be performed.\n",
+				__func__, dev->desc->name, min_uV);
+		else if (IS_PMIC_8901_V1(pmic8901_rev))
+			scaled_min_uV = PMIC_8901_V1_SCALE(min_uV);
+	}
+
+	return vreg_set(vreg, SMPS_VOLTAGE,
+			MICRO_TO_MILLI(scaled_min_uV) << SMPS_VOLTAGE_SHIFT,
+			0, 0, 2);
+}
+
+static int smps_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV,
+			    unsigned *selector)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	int rc = 0;
+
+	if (smps_is_enabled(dev))
+		rc = _smps_set_voltage(dev, min_uV);
+	if (rc)
+		return rc;
+
+	/* only save if nonzero (or not disabling) */
+	if (min_uV && (!vreg->pdata->sleep_selectable || !smps_is_enabled(dev)))
+		vreg->save_uV = min_uV;
+
+	return rc;
+}
+
+static int smps_get_voltage(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	return vreg->save_uV;
+}
+
+static int smps_enable(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	int rc = 0;
+	unsigned mask, val;
+
+	/* enable by setting voltage */
+	if (MICRO_TO_MILLI(vreg->save_uV) > 0) {
+		/* reenable pin control if it is in use */
+		if (smps_get_mode(dev) == REGULATOR_MODE_IDLE) {
+			mask = SMPS_PIN_CTRL | SMPS_PIN_FN;
+			val = vreg->pdata->pin_ctrl << SMPS_PIN_CTRL_SHIFT
+				| vreg->pdata->pin_fn << SMPS_PIN_FN_SHIFT;
+			vreg_store(vreg, mask, val, 0, 0);
+		}
+
+		rc = _smps_set_voltage(dev, vreg->save_uV);
+	}
+	return rc;
+}
+
+static int smps_disable(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	unsigned mask, val;
+
+	/* turn off pin control */
+	mask = SMPS_PIN_CTRL | SMPS_PIN_FN;
+	val = RPM_VREG_PIN_CTRL_NONE << SMPS_PIN_CTRL_SHIFT
+		| RPM_VREG_PIN_FN_NONE << SMPS_PIN_FN_SHIFT;
+	vreg_store(vreg, mask, val, 0, 0);
+
+	/* disable by setting voltage to zero */
+	return _smps_set_voltage(dev, 0);
+}
+
+/*
+ * Optimum mode programming:
+ * REGULATOR_MODE_FAST: Go to HPM (highest priority)
+ * REGULATOR_MODE_STANDBY: Go to pin ctrl mode if there are any pin ctrl
+ * votes, else go to LPM
+ *
+ * Pin ctrl mode voting via regulator set_mode:
+ * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
+ * go to HPM
+ * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
+ *
+ * Pin ctrl mode takes priority on the RPM when force mode is not set;
+ * therefore, pin ctrl bits must be cleared if LPM or HPM is being voted for.
+ */
+static int smps_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	unsigned optimum = vreg->optimum;
+	unsigned pc_vote = vreg->pc_vote;
+	unsigned mode_initialized = vreg->mode_initialized;
+	unsigned mask0 = 0, val0 = 0, mask1 = 0, val1 = 0;
+	int set_hpm = -1, set_pin_control = -1;
+	int peak_uA;
+	int rc = 0;
+
+	peak_uA = MILLI_TO_MICRO((vreg->req[0].value & SMPS_PEAK_CURRENT) >>
+		  SMPS_PEAK_CURRENT_SHIFT);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		set_hpm = 1;
+		set_pin_control = 0;
+		optimum = REGULATOR_MODE_FAST;
+		mode_initialized = 1;
+		break;
+
+	case REGULATOR_MODE_STANDBY:
+		set_hpm = 0;
+		if (pc_vote)
+			set_pin_control = 1;
+		else
+			set_pin_control = 0;
+		optimum = REGULATOR_MODE_STANDBY;
+		mode_initialized = 1;
+		break;
+
+	case REGULATOR_MODE_IDLE:
+		if (pc_vote++)
+			goto done; /* already taken care of */
+
+		if (mode_initialized && optimum == REGULATOR_MODE_FAST) {
+			set_hpm = 1;
+			set_pin_control = 0;
+		} else {
+			set_pin_control = 1;
+		}
+		break;
+
+	case REGULATOR_MODE_NORMAL:
+		if (pc_vote && --pc_vote)
+			goto done; /* already taken care of */
+
+		if (optimum == REGULATOR_MODE_STANDBY)
+			set_hpm = 0;
+		else
+			set_hpm = 1;
+		set_pin_control = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (set_hpm == 1) {
+		/* Make sure that request currents are at HPM level. */
+		if (peak_uA < vreg_hpm_min_uA(vreg)) {
+			mask0 = SMPS_PEAK_CURRENT;
+			mask1 = SMPS_AVG_CURRENT;
+			val0 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
+			   SMPS_PEAK_CURRENT_SHIFT) & SMPS_PEAK_CURRENT;
+			val1 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
+			     SMPS_AVG_CURRENT_SHIFT) & SMPS_AVG_CURRENT;
+		}
+	} else if (set_hpm == 0) {
+		/* Make sure that request currents are at LPM level. */
+		if (peak_uA > vreg_lpm_max_uA(vreg)) {
+			mask0 = SMPS_PEAK_CURRENT;
+			mask1 = SMPS_AVG_CURRENT;
+			val0 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
+			   SMPS_PEAK_CURRENT_SHIFT) & SMPS_PEAK_CURRENT;
+			val1 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
+			     SMPS_AVG_CURRENT_SHIFT) & SMPS_AVG_CURRENT;
+		}
+	}
+
+	if (set_pin_control == 1) {
+		/* Enable pin control and pin function. */
+		mask0 |= SMPS_PIN_CTRL | SMPS_PIN_FN;
+		val0 |= vreg->pdata->pin_ctrl << SMPS_PIN_CTRL_SHIFT
+			| vreg->pdata->pin_fn << SMPS_PIN_FN_SHIFT;
+	} else if (set_pin_control == 0) {
+		/* Clear pin control and pin function*/
+		mask0 |= SMPS_PIN_CTRL | SMPS_PIN_FN;
+		val0 |= RPM_VREG_PIN_CTRL_NONE << SMPS_PIN_CTRL_SHIFT
+			| RPM_VREG_PIN_FN_NONE << SMPS_PIN_FN_SHIFT;
+	}
+
+	if (smps_is_enabled(dev)) {
+		rc = vreg_set(vreg, mask0, val0, mask1, val1, 2);
+	} else {
+		/* Regulator is disabled; store but don't send new request. */
+		rc = vreg_store(vreg, mask0, val0, mask1, val1);
+	}
+	if (rc)
+		return rc;
+
+done:
+	vreg->mode_initialized = mode_initialized;
+	vreg->optimum = optimum;
+	vreg->pc_vote = pc_vote;
+
+	return 0;
+}
+
+static unsigned int smps_get_mode(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	if ((vreg->optimum == REGULATOR_MODE_FAST) && vreg->mode_initialized)
+		return REGULATOR_MODE_FAST;
+	else if (vreg->pc_vote)
+		return REGULATOR_MODE_IDLE;
+	else if (vreg->optimum == REGULATOR_MODE_STANDBY)
+		return REGULATOR_MODE_STANDBY;
+	return REGULATOR_MODE_FAST;
+}
+
+unsigned int smps_get_optimum_mode(struct regulator_dev *dev, int input_uV,
+		int output_uV, int load_uA)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	if (MICRO_TO_MILLI(load_uA) > 0) {
+		vreg->req[0].value &= ~SMPS_PEAK_CURRENT;
+		vreg->req[0].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
+				   SMPS_PEAK_CURRENT_SHIFT) & SMPS_PEAK_CURRENT;
+		vreg->req[1].value &= ~SMPS_AVG_CURRENT;
+		vreg->req[1].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
+				     SMPS_AVG_CURRENT_SHIFT) & SMPS_AVG_CURRENT;
+	} else {
+		/*
+		 * smps_get_optimum_mode is being called before consumers have
+		 * specified their load currents via regulator_set_optimum_mode.
+		 * Return whatever the existing mode is.
+		 */
+		return smps_get_mode(dev);
+	}
+
+	if (load_uA >= vreg->hpm_min_load)
+		return REGULATOR_MODE_FAST;
+	return REGULATOR_MODE_STANDBY;
+}
+
+static int ldo_is_enabled(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	return ((vreg->req[0].value & LDO_VOLTAGE) >> LDO_VOLTAGE_SHIFT) != 0;
+}
+
+static int _ldo_set_voltage(struct regulator_dev *dev, int min_uV)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	return vreg_set(vreg, LDO_VOLTAGE,
+			MICRO_TO_MILLI(min_uV) << LDO_VOLTAGE_SHIFT,
+			0, 0, 2);
+}
+
+static int ldo_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV,
+			   unsigned *selector)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	int rc = 0;
+
+	if (ldo_is_enabled(dev))
+		rc = _ldo_set_voltage(dev, min_uV);
+	if (rc)
+		return rc;
+
+	/* only save if nonzero (or not disabling) */
+	if (min_uV && (!vreg->pdata->sleep_selectable || !ldo_is_enabled(dev)))
+		vreg->save_uV = min_uV;
+
+	return rc;
+}
+
+static int ldo_get_voltage(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	return vreg->save_uV;
+}
+
+static int ldo_enable(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	int rc = 0;
+	unsigned mask, val;
+
+	/* enable by setting voltage */
+	if (MICRO_TO_MILLI(vreg->save_uV) > 0) {
+		/* reenable pin control if it is in use */
+		if (ldo_get_mode(dev) == REGULATOR_MODE_IDLE) {
+			mask = LDO_PIN_CTRL | LDO_PIN_FN;
+			val = vreg->pdata->pin_ctrl << LDO_PIN_CTRL_SHIFT
+				| vreg->pdata->pin_fn << LDO_PIN_FN_SHIFT;
+			vreg_store(vreg, mask, val, 0, 0);
+		}
+
+		rc = _ldo_set_voltage(dev, vreg->save_uV);
+	}
+	return rc;
+}
+
+static int ldo_disable(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	unsigned mask, val;
+
+	/* turn off pin control */
+	mask = LDO_PIN_CTRL | LDO_PIN_FN;
+	val = RPM_VREG_PIN_CTRL_NONE << LDO_PIN_CTRL_SHIFT
+		| RPM_VREG_PIN_FN_NONE << LDO_PIN_FN_SHIFT;
+	vreg_store(vreg, mask, val, 0, 0);
+
+	/* disable by setting voltage to zero */
+	return _ldo_set_voltage(dev, 0);
+}
+
+/*
+ * Optimum mode programming:
+ * REGULATOR_MODE_FAST: Go to HPM (highest priority)
+ * REGULATOR_MODE_STANDBY: Go to pin ctrl mode if there are any pin ctrl
+ * votes, else go to LPM
+ *
+ * Pin ctrl mode voting via regulator set_mode:
+ * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
+ * go to HPM
+ * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
+ *
+ * Pin ctrl mode takes priority on the RPM when force mode is not set;
+ * therefore, pin ctrl bits must be cleared if LPM or HPM is being voted for.
+ */
+static int ldo_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	unsigned optimum = vreg->optimum;
+	unsigned pc_vote = vreg->pc_vote;
+	unsigned mode_initialized = vreg->mode_initialized;
+	unsigned mask0 = 0, val0 = 0, mask1 = 0, val1 = 0;
+	int set_hpm = -1, set_pin_control = -1;
+	int peak_uA;
+	int rc = 0;
+
+	peak_uA = MILLI_TO_MICRO((vreg->req[0].value & LDO_PEAK_CURRENT) >>
+		  LDO_PEAK_CURRENT_SHIFT);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		set_hpm = 1;
+		set_pin_control = 0;
+		optimum = REGULATOR_MODE_FAST;
+		mode_initialized = 1;
+		break;
+
+	case REGULATOR_MODE_STANDBY:
+		set_hpm = 0;
+		if (pc_vote)
+			set_pin_control = 1;
+		else
+			set_pin_control = 0;
+		optimum = REGULATOR_MODE_STANDBY;
+		mode_initialized = 1;
+		break;
+
+	case REGULATOR_MODE_IDLE:
+		if (pc_vote++)
+			goto done; /* already taken care of */
+
+		if (mode_initialized && optimum == REGULATOR_MODE_FAST) {
+			set_hpm = 1;
+			set_pin_control = 0;
+		} else {
+			set_pin_control = 1;
+		}
+		break;
+
+	case REGULATOR_MODE_NORMAL:
+		if (pc_vote && --pc_vote)
+			goto done; /* already taken care of */
+
+		if (optimum == REGULATOR_MODE_STANDBY)
+			set_hpm = 0;
+		else
+			set_hpm = 1;
+		set_pin_control = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (set_hpm == 1) {
+		/* Make sure that request currents are at HPM level. */
+		if (peak_uA < vreg_hpm_min_uA(vreg)) {
+			mask0 = LDO_PEAK_CURRENT;
+			mask1 = LDO_AVG_CURRENT;
+			val0 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
+				LDO_PEAK_CURRENT_SHIFT) & LDO_PEAK_CURRENT;
+			val1 = (MICRO_TO_MILLI(vreg_hpm_min_uA(vreg)) <<
+				LDO_AVG_CURRENT_SHIFT) & LDO_AVG_CURRENT;
+		}
+	} else if (set_hpm == 0) {
+		/* Make sure that request currents are at LPM level. */
+		if (peak_uA > vreg_lpm_max_uA(vreg)) {
+			mask0 = LDO_PEAK_CURRENT;
+			mask1 = LDO_AVG_CURRENT;
+			val0 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
+				LDO_PEAK_CURRENT_SHIFT) & LDO_PEAK_CURRENT;
+			val1 = (MICRO_TO_MILLI(vreg_lpm_max_uA(vreg)) <<
+				LDO_AVG_CURRENT_SHIFT) & LDO_AVG_CURRENT;
+		}
+	}
+
+	if (set_pin_control == 1) {
+		/* Enable pin control and pin function. */
+		mask0 |= LDO_PIN_CTRL | LDO_PIN_FN;
+		val0 |= vreg->pdata->pin_ctrl << LDO_PIN_CTRL_SHIFT
+			| vreg->pdata->pin_fn << LDO_PIN_FN_SHIFT;
+	} else if (set_pin_control == 0) {
+		/* Clear pin control and pin function*/
+		mask0 |= LDO_PIN_CTRL | LDO_PIN_FN;
+		val0 |= RPM_VREG_PIN_CTRL_NONE << LDO_PIN_CTRL_SHIFT
+			| RPM_VREG_PIN_FN_NONE << LDO_PIN_FN_SHIFT;
+	}
+
+	if (ldo_is_enabled(dev)) {
+		rc = vreg_set(vreg, mask0, val0, mask1, val1, 2);
+	} else {
+		/* Regulator is disabled; store but don't send new request. */
+		rc = vreg_store(vreg, mask0, val0, mask1, val1);
+	}
+	if (rc)
+		return rc;
+
+done:
+	vreg->mode_initialized = mode_initialized;
+	vreg->optimum = optimum;
+	vreg->pc_vote = pc_vote;
+
+	return 0;
+}
+
+static unsigned int ldo_get_mode(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	if ((vreg->optimum == REGULATOR_MODE_FAST) && vreg->mode_initialized)
+		return REGULATOR_MODE_FAST;
+	else if (vreg->pc_vote)
+		return REGULATOR_MODE_IDLE;
+	else if (vreg->optimum == REGULATOR_MODE_STANDBY)
+		return REGULATOR_MODE_STANDBY;
+	return REGULATOR_MODE_FAST;
+}
+
+unsigned int ldo_get_optimum_mode(struct regulator_dev *dev, int input_uV,
+		int output_uV, int load_uA)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	if (MICRO_TO_MILLI(load_uA) > 0) {
+		vreg->req[0].value &= ~LDO_PEAK_CURRENT;
+		vreg->req[0].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
+				     LDO_PEAK_CURRENT_SHIFT) & LDO_PEAK_CURRENT;
+		vreg->req[1].value &= ~LDO_AVG_CURRENT;
+		vreg->req[1].value |= (MICRO_TO_MILLI(saturate_load(load_uA)) <<
+				       LDO_AVG_CURRENT_SHIFT) & LDO_AVG_CURRENT;
+	} else {
+		/*
+		 * ldo_get_optimum_mode is being called before consumers have
+		 * specified their load currents via regulator_set_optimum_mode.
+		 * Return whatever the existing mode is.
+		 */
+		return ldo_get_mode(dev);
+	}
+
+	if (load_uA >= vreg->hpm_min_load)
+		return REGULATOR_MODE_FAST;
+	return REGULATOR_MODE_STANDBY;
+}
+
+static int switch_enable(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	unsigned mask = 0, val = 0;
+
+	/* reenable pin control if it is in use */
+	if (switch_get_mode(dev) == REGULATOR_MODE_IDLE) {
+		mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
+		val = vreg->pdata->pin_ctrl << SWITCH_PIN_CTRL_SHIFT
+			| vreg->pdata->pin_fn << SWITCH_PIN_FN_SHIFT;
+	}
+
+	return vreg_set(rdev_get_drvdata(dev), SWITCH_STATE | mask,
+		(RPM_VREG_STATE_ON << SWITCH_STATE_SHIFT) | val, 0, 0, 1);
+}
+
+static int switch_disable(struct regulator_dev *dev)
+{
+	unsigned mask, val;
+
+	/* turn off pin control */
+	mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
+	val = RPM_VREG_PIN_CTRL_NONE << SWITCH_PIN_CTRL_SHIFT
+		| RPM_VREG_PIN_FN_NONE << SWITCH_PIN_FN_SHIFT;
+
+	return vreg_set(rdev_get_drvdata(dev), SWITCH_STATE | mask,
+		(RPM_VREG_STATE_OFF << SWITCH_STATE_SHIFT) | val, 0, 0, 1);
+}
+
+static int switch_is_enabled(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	enum rpm_vreg_state state;
+
+	state = (vreg->req[0].value & SWITCH_STATE) >> SWITCH_STATE_SHIFT;
+
+	return state == RPM_VREG_STATE_ON;
+}
+
+/*
+ * Pin ctrl mode voting via regulator set_mode:
+ * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
+ * go to HPM
+ * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
+ */
+static int switch_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	unsigned pc_vote = vreg->pc_vote;
+	unsigned mask, val;
+	int rc;
+
+	switch (mode) {
+	case REGULATOR_MODE_IDLE:
+		if (pc_vote++)
+			goto done; /* already taken care of */
+
+		mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
+		val = vreg->pdata->pin_ctrl << SWITCH_PIN_CTRL_SHIFT
+			| vreg->pdata->pin_fn << SWITCH_PIN_FN_SHIFT;
+		break;
+
+	case REGULATOR_MODE_NORMAL:
+		if (--pc_vote)
+			goto done; /* already taken care of */
+
+		mask = SWITCH_PIN_CTRL | SWITCH_PIN_FN;
+		val = RPM_VREG_PIN_CTRL_NONE << SWITCH_PIN_CTRL_SHIFT
+			| RPM_VREG_PIN_FN_NONE << SWITCH_PIN_FN_SHIFT;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (switch_is_enabled(dev)) {
+		rc = vreg_set(vreg, mask, val, 0, 0, 2);
+	} else {
+		/* Regulator is disabled; store but don't send new request. */
+		rc = vreg_store(vreg, mask, val, 0, 0);
+	}
+	if (rc)
+		return rc;
+
+done:
+	vreg->pc_vote = pc_vote;
+	return 0;
+}
+
+static unsigned int switch_get_mode(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	if (vreg->pc_vote)
+		return REGULATOR_MODE_IDLE;
+	return REGULATOR_MODE_NORMAL;
+}
+
+static int ncp_enable(struct regulator_dev *dev)
+{
+	return vreg_set(rdev_get_drvdata(dev), NCP_STATE,
+			RPM_VREG_STATE_ON << NCP_STATE_SHIFT, 0, 0, 2);
+}
+
+static int ncp_disable(struct regulator_dev *dev)
+{
+	return vreg_set(rdev_get_drvdata(dev), NCP_STATE,
+			RPM_VREG_STATE_OFF << NCP_STATE_SHIFT, 0, 0, 2);
+}
+
+static int ncp_is_enabled(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+	enum rpm_vreg_state state;
+
+	state = (vreg->req[0].value & NCP_STATE) >> NCP_STATE_SHIFT;
+
+	return state == RPM_VREG_STATE_ON;
+}
+
+static int ncp_set_voltage(struct regulator_dev *dev, int min_uV, int max_uV,
+			   unsigned *selector)
+{
+	return vreg_set(rdev_get_drvdata(dev), NCP_VOLTAGE,
+			MICRO_TO_MILLI(min_uV) << NCP_VOLTAGE_SHIFT, 0, 0, 2);
+}
+
+static int ncp_get_voltage(struct regulator_dev *dev)
+{
+	struct vreg *vreg = rdev_get_drvdata(dev);
+
+	return MILLI_TO_MICRO((vreg->req[0].value & NCP_VOLTAGE) >>
+			NCP_VOLTAGE_SHIFT);
+}
+
+static struct regulator_ops ldo_ops = {
+	.enable = ldo_enable,
+	.disable = ldo_disable,
+	.is_enabled = ldo_is_enabled,
+	.set_voltage = ldo_set_voltage,
+	.get_voltage = ldo_get_voltage,
+	.set_mode = ldo_set_mode,
+	.get_optimum_mode = ldo_get_optimum_mode,
+	.get_mode = ldo_get_mode,
+};
+
+static struct regulator_ops smps_ops = {
+	.enable = smps_enable,
+	.disable = smps_disable,
+	.is_enabled = smps_is_enabled,
+	.set_voltage = smps_set_voltage,
+	.get_voltage = smps_get_voltage,
+	.set_mode = smps_set_mode,
+	.get_optimum_mode = smps_get_optimum_mode,
+	.get_mode = smps_get_mode,
+};
+
+static struct regulator_ops switch_ops = {
+	.enable = switch_enable,
+	.disable = switch_disable,
+	.is_enabled = switch_is_enabled,
+	.set_mode = switch_set_mode,
+	.get_mode = switch_get_mode,
+};
+
+static struct regulator_ops ncp_ops = {
+	.enable = ncp_enable,
+	.disable = ncp_disable,
+	.is_enabled = ncp_is_enabled,
+	.set_voltage = ncp_set_voltage,
+	.get_voltage = ncp_get_voltage,
+};
+
+#define DESC(_id, _name, _ops) \
+	[_id] = { \
+		.id = _id, \
+		.name = _name, \
+		.ops = _ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+	}
+
+static struct regulator_desc vreg_descrip[RPM_VREG_ID_MAX] = {
+	DESC(RPM_VREG_ID_PM8058_L0, "8058_l0", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L1, "8058_l1", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L2, "8058_l2", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L3, "8058_l3", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L4, "8058_l4", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L5, "8058_l5", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L6, "8058_l6", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L7, "8058_l7", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L8, "8058_l8", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L9, "8058_l9", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L10, "8058_l10", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L11, "8058_l11", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L12, "8058_l12", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L13, "8058_l13", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L14, "8058_l14", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L15, "8058_l15", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L16, "8058_l16", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L17, "8058_l17", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L18, "8058_l18", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L19, "8058_l19", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L20, "8058_l20", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L21, "8058_l21", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L22, "8058_l22", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L23, "8058_l23", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L24, "8058_l24", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8058_L25, "8058_l25", &ldo_ops),
+
+	DESC(RPM_VREG_ID_PM8058_S0, "8058_s0", &smps_ops),
+	DESC(RPM_VREG_ID_PM8058_S1, "8058_s1", &smps_ops),
+	DESC(RPM_VREG_ID_PM8058_S2, "8058_s2", &smps_ops),
+	DESC(RPM_VREG_ID_PM8058_S3, "8058_s3", &smps_ops),
+	DESC(RPM_VREG_ID_PM8058_S4, "8058_s4", &smps_ops),
+
+	DESC(RPM_VREG_ID_PM8058_LVS0, "8058_lvs0", &switch_ops),
+	DESC(RPM_VREG_ID_PM8058_LVS1, "8058_lvs1", &switch_ops),
+
+	DESC(RPM_VREG_ID_PM8058_NCP, "8058_ncp", &ncp_ops),
+
+	DESC(RPM_VREG_ID_PM8901_L0, "8901_l0", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8901_L1, "8901_l1", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8901_L2, "8901_l2", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8901_L3, "8901_l3", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8901_L4, "8901_l4", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8901_L5, "8901_l5", &ldo_ops),
+	DESC(RPM_VREG_ID_PM8901_L6, "8901_l6", &ldo_ops),
+
+	DESC(RPM_VREG_ID_PM8901_S0, "8901_s0", &smps_ops),
+	DESC(RPM_VREG_ID_PM8901_S1, "8901_s1", &smps_ops),
+	DESC(RPM_VREG_ID_PM8901_S2, "8901_s2", &smps_ops),
+	DESC(RPM_VREG_ID_PM8901_S3, "8901_s3", &smps_ops),
+	DESC(RPM_VREG_ID_PM8901_S4, "8901_s4", &smps_ops),
+
+	DESC(RPM_VREG_ID_PM8901_LVS0, "8901_lvs0", &switch_ops),
+	DESC(RPM_VREG_ID_PM8901_LVS1, "8901_lvs1", &switch_ops),
+	DESC(RPM_VREG_ID_PM8901_LVS2, "8901_lvs2", &switch_ops),
+	DESC(RPM_VREG_ID_PM8901_LVS3, "8901_lvs3", &switch_ops),
+
+	DESC(RPM_VREG_ID_PM8901_MVS0, "8901_mvs0", &switch_ops),
+};
+
+static void ldo_init(struct vreg *vreg)
+{
+	enum rpm_vreg_pin_fn pf = RPM_VREG_PIN_FN_NONE;
+
+	/* Allow pf=sleep_b to be specified by platform data. */
+	if (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
+		pf = RPM_VREG_PIN_FN_SLEEP_B;
+
+	vreg->req[0].value =
+		MICRO_TO_MILLI(saturate_load(vreg->pdata->peak_uA)) <<
+			LDO_PEAK_CURRENT_SHIFT |
+		vreg->pdata->mode << LDO_MODE_SHIFT | pf << LDO_PIN_FN_SHIFT |
+		RPM_VREG_PIN_CTRL_NONE << LDO_PIN_CTRL_SHIFT;
+
+	vreg->req[1].value =
+		vreg->pdata->pull_down_enable << LDO_PULL_DOWN_ENABLE_SHIFT |
+		MICRO_TO_MILLI(saturate_load(vreg->pdata->avg_uA)) <<
+			LDO_AVG_CURRENT_SHIFT;
+}
+
+static void smps_init(struct vreg *vreg)
+{
+	enum rpm_vreg_pin_fn pf = RPM_VREG_PIN_FN_NONE;
+
+	/* Allow pf=sleep_b to be specified by platform data. */
+	if (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
+		pf = RPM_VREG_PIN_FN_SLEEP_B;
+
+	vreg->req[0].value =
+		MICRO_TO_MILLI(saturate_load(vreg->pdata->peak_uA)) <<
+			SMPS_PEAK_CURRENT_SHIFT |
+		vreg->pdata->mode << SMPS_MODE_SHIFT | pf << SMPS_PIN_FN_SHIFT |
+		RPM_VREG_PIN_CTRL_NONE << SMPS_PIN_CTRL_SHIFT;
+
+
+	vreg->req[1].value =
+		vreg->pdata->pull_down_enable << SMPS_PULL_DOWN_ENABLE_SHIFT |
+		MICRO_TO_MILLI(saturate_load(vreg->pdata->avg_uA)) <<
+			SMPS_AVG_CURRENT_SHIFT |
+		vreg->pdata->freq << SMPS_FREQ_SHIFT |
+		0 << SMPS_CLK_SRC_SHIFT;
+}
+
+static void ncp_init(struct vreg *vreg)
+{
+	vreg->req[0].value = vreg->pdata->state << NCP_STATE_SHIFT;
+}
+
+static void switch_init(struct vreg *vreg)
+{
+	enum rpm_vreg_pin_fn pf = RPM_VREG_PIN_FN_NONE;
+
+	/* Allow pf=sleep_b to be specified by platform data. */
+	if (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
+		pf = RPM_VREG_PIN_FN_SLEEP_B;
+
+	vreg->req[0].value =
+		vreg->pdata->state << SWITCH_STATE_SHIFT |
+		vreg->pdata->pull_down_enable <<
+			SWITCH_PULL_DOWN_ENABLE_SHIFT |
+		pf << SWITCH_PIN_FN_SHIFT |
+		RPM_VREG_PIN_CTRL_NONE << SWITCH_PIN_CTRL_SHIFT;
+}
+
+static int vreg_init(enum rpm_vreg_id id, struct vreg *vreg)
+{
+	vreg->save_uV = vreg->pdata->default_uV;
+
+	if (vreg->pdata->peak_uA >= vreg->hpm_min_load)
+		vreg->optimum = REGULATOR_MODE_FAST;
+	else
+		vreg->optimum = REGULATOR_MODE_STANDBY;
+
+	vreg->mode_initialized = 0;
+
+	if (IS_LDO(id))
+		ldo_init(vreg);
+	else if (IS_SMPS(id))
+		smps_init(vreg);
+	else if (IS_NCP(id))
+		ncp_init(vreg);
+	else if (IS_SWITCH(id))
+		switch_init(vreg);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int __devinit rpm_vreg_probe(struct platform_device *pdev)
+{
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	struct vreg *vreg;
+	int rc;
+
+	if (pdev == NULL)
+		return -EINVAL;
+
+	if (pdev->id < 0 || pdev->id >= RPM_VREG_ID_MAX)
+		return -ENODEV;
+
+	vreg = &vregs[pdev->id];
+	vreg->pdata = pdev->dev.platform_data;
+	vreg->id = pdev->id;
+	rdesc = &vreg_descrip[pdev->id];
+
+	rc = vreg_init(pdev->id, vreg);
+	if (rc) {
+		pr_err("%s: vreg_init failed, rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	/* Disallow idle and normal modes if pin control isn't set. */
+	if ((vreg->pdata->pin_ctrl == RPM_VREG_PIN_CTRL_NONE)
+	    && ((vreg->pdata->pin_fn == RPM_VREG_PIN_FN_ENABLE)
+		    || (vreg->pdata->pin_fn == RPM_VREG_PIN_FN_MODE)))
+		vreg->pdata->init_data.constraints.valid_modes_mask
+			&= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
+
+	rdev = regulator_register(rdesc, &pdev->dev,
+			&vreg->pdata->init_data, vreg);
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		pr_err("%s: id=%d, rc=%d\n", __func__,
+				pdev->id, rc);
+		return rc;
+	}
+
+	platform_set_drvdata(pdev, rdev);
+
+	return rc;
+}
+
+static int __devexit rpm_vreg_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver rpm_vreg_driver = {
+	.probe = rpm_vreg_probe,
+	.remove = __devexit_p(rpm_vreg_remove),
+	.driver = {
+		.name = "rpm-regulator",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init rpm_vreg_init(void)
+{
+	return platform_driver_register(&rpm_vreg_driver);
+}
+
+static void __exit rpm_vreg_exit(void)
+{
+	platform_driver_unregister(&rpm_vreg_driver);
+}
+
+postcore_initcall(rpm_vreg_init);
+module_exit(rpm_vreg_exit);
+
+#define VREG_ID_IS_8058_S0_OR_S1(id) \
+	((id == RPM_VREG_ID_PM8058_S0) || (id == RPM_VREG_ID_PM8058_S1))
+
+static void print_rpm_request(struct vreg *vreg, int set)
+{
+	int v, ip, fm, pc, pf, pd, ia, freq, clk, state;
+
+	/* Suppress 8058_s0 and 8058_s1 printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1)
+	    && VREG_ID_IS_8058_S0_OR_S1(vreg->id))
+		return;
+
+	if (IS_LDO(vreg->id)) {
+		v = (vreg->req[0].value & LDO_VOLTAGE) >> LDO_VOLTAGE_SHIFT;
+		ip = (vreg->req[0].value & LDO_PEAK_CURRENT)
+			>> LDO_PEAK_CURRENT_SHIFT;
+		fm = (vreg->req[0].value & LDO_MODE) >> LDO_MODE_SHIFT;
+		pc = (vreg->req[0].value & LDO_PIN_CTRL) >> LDO_PIN_CTRL_SHIFT;
+		pf = (vreg->req[0].value & LDO_PIN_FN) >> LDO_PIN_FN_SHIFT;
+		pd = (vreg->req[1].value & LDO_PULL_DOWN_ENABLE)
+			>> LDO_PULL_DOWN_ENABLE_SHIFT;
+		ia = (vreg->req[1].value & LDO_AVG_CURRENT)
+				>> LDO_AVG_CURRENT_SHIFT;
+
+		pr_info("rpm-regulator: %s %-9s: s=%c, v=%4d mV, ip=%4d "
+			"mA, fm=%s (%d), pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s "
+			"(%d), ia=%4d mA; req[0]={%d, 0x%08X}, "
+			"req[1]={%d, 0x%08X}\n",
+			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+			vreg_descrip[vreg->id].name,
+			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), v, ip,
+			(fm == RPM_VREG_MODE_NONE ? "none" :
+				(fm == RPM_VREG_MODE_LPM ? "LPM" :
+				       (fm == RPM_VREG_MODE_HPM ? "HPM" : ""))),
+			fm,
+			(pc & RPM_VREG_PIN_CTRL_A0 ? " A0" : ""),
+			(pc & RPM_VREG_PIN_CTRL_A1 ? " A1" : ""),
+			(pc & RPM_VREG_PIN_CTRL_D0 ? " D0" : ""),
+			(pc & RPM_VREG_PIN_CTRL_D1 ? " D1" : ""),
+			(pc == RPM_VREG_PIN_CTRL_NONE ? " none" : ""), pc,
+			(pf == RPM_VREG_PIN_FN_NONE ?
+				"none" :
+				(pf == RPM_VREG_PIN_FN_ENABLE ?
+					"on/off" :
+					(pf == RPM_VREG_PIN_FN_MODE ?
+						"HPM/LPM" :
+						(pf == RPM_VREG_PIN_FN_SLEEP_B ?
+							"sleep_b" : "")))),
+			pf, (pd == 1 ? "Y" : "N"), pd, ia,
+			vreg->req[0].id, vreg->req[0].value,
+			vreg->req[1].id, vreg->req[1].value);
+
+	} else if (IS_SMPS(vreg->id)) {
+		v = (vreg->req[0].value & SMPS_VOLTAGE) >> SMPS_VOLTAGE_SHIFT;
+		ip = (vreg->req[0].value & SMPS_PEAK_CURRENT)
+			>> SMPS_PEAK_CURRENT_SHIFT;
+		fm = (vreg->req[0].value & SMPS_MODE) >> SMPS_MODE_SHIFT;
+		pc = (vreg->req[0].value & SMPS_PIN_CTRL)
+			>> SMPS_PIN_CTRL_SHIFT;
+		pf = (vreg->req[0].value & SMPS_PIN_FN) >> SMPS_PIN_FN_SHIFT;
+		pd = (vreg->req[1].value & SMPS_PULL_DOWN_ENABLE)
+			>> SMPS_PULL_DOWN_ENABLE_SHIFT;
+		ia = (vreg->req[1].value & SMPS_AVG_CURRENT)
+			>> SMPS_AVG_CURRENT_SHIFT;
+		freq = (vreg->req[1].value & SMPS_FREQ) >> SMPS_FREQ_SHIFT;
+		clk = (vreg->req[1].value & SMPS_CLK_SRC) >> SMPS_CLK_SRC_SHIFT;
+
+		pr_info("rpm-regulator: %s %-9s: s=%c, v=%4d mV, ip=%4d "
+			"mA, fm=%s (%d), pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s "
+			"(%d), ia=%4d mA, freq=%2d, clk=%d; "
+			"req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
+			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+			vreg_descrip[vreg->id].name,
+			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), v, ip,
+			(fm == RPM_VREG_MODE_NONE ? "none" :
+				(fm == RPM_VREG_MODE_LPM ? "LPM" :
+				       (fm == RPM_VREG_MODE_HPM ? "HPM" : ""))),
+			fm,
+			(pc & RPM_VREG_PIN_CTRL_A0 ? " A0" : ""),
+			(pc & RPM_VREG_PIN_CTRL_A1 ? " A1" : ""),
+			(pc & RPM_VREG_PIN_CTRL_D0 ? " D0" : ""),
+			(pc & RPM_VREG_PIN_CTRL_D1 ? " D1" : ""),
+			(pc == RPM_VREG_PIN_CTRL_NONE ? " none" : ""), pc,
+			(pf == RPM_VREG_PIN_FN_NONE ?
+				"none" :
+				(pf == RPM_VREG_PIN_FN_ENABLE ?
+					"on/off" :
+					(pf == RPM_VREG_PIN_FN_MODE ?
+						"HPM/LPM" :
+						(pf == RPM_VREG_PIN_FN_SLEEP_B ?
+							"sleep_b" : "")))),
+			pf, (pd == 1 ? "Y" : "N"), pd, ia, freq, clk,
+			vreg->req[0].id, vreg->req[0].value,
+			vreg->req[1].id, vreg->req[1].value);
+
+	} else if (IS_SWITCH(vreg->id)) {
+		state = (vreg->req[0].value & SWITCH_STATE)
+			>> SWITCH_STATE_SHIFT;
+		pd = (vreg->req[0].value & SWITCH_PULL_DOWN_ENABLE)
+			>> SWITCH_PULL_DOWN_ENABLE_SHIFT;
+		pc = (vreg->req[0].value & SWITCH_PIN_CTRL)
+			>> SWITCH_PIN_CTRL_SHIFT;
+		pf = (vreg->req[0].value & SWITCH_PIN_FN)
+			>> SWITCH_PIN_FN_SHIFT;
+
+		pr_info("rpm-regulator: %s %-9s: s=%c, state=%s (%d), "
+			"pd=%s (%d), pc =%s%s%s%s%s (%d), pf=%s (%d); "
+			"req[0]={%d, 0x%08X}\n",
+			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+			vreg_descrip[vreg->id].name,
+			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
+			(state == 1 ? "on" : "off"), state,
+			(pd == 1 ? "Y" : "N"), pd,
+			(pc & RPM_VREG_PIN_CTRL_A0 ? " A0" : ""),
+			(pc & RPM_VREG_PIN_CTRL_A1 ? " A1" : ""),
+			(pc & RPM_VREG_PIN_CTRL_D0 ? " D0" : ""),
+			(pc & RPM_VREG_PIN_CTRL_D1 ? " D1" : ""),
+			(pc == RPM_VREG_PIN_CTRL_NONE ? " none" : ""), pc,
+			(pf == RPM_VREG_PIN_FN_NONE ?
+				"none" :
+				(pf == RPM_VREG_PIN_FN_ENABLE ?
+					"on/off" :
+					(pf == RPM_VREG_PIN_FN_MODE ?
+						"HPM/LPM" :
+						(pf == RPM_VREG_PIN_FN_SLEEP_B ?
+							"sleep_b" : "")))),
+			pf, vreg->req[0].id, vreg->req[0].value);
+
+	} else if (IS_NCP(vreg->id)) {
+		v = (vreg->req[0].value & NCP_VOLTAGE) >> NCP_VOLTAGE_SHIFT;
+		state = (vreg->req[0].value & NCP_STATE) >> NCP_STATE_SHIFT;
+
+		pr_info("rpm-regulator: %s %-9s: s=%c, v=-%4d mV, "
+			"state=%s (%d); req[0]={%d, 0x%08X}\n",
+			(set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+			vreg_descrip[vreg->id].name,
+			(set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
+			v, (state == 1 ? "on" : "off"), state,
+			vreg->req[0].id, vreg->req[0].value);
+	}
+}
+
+static void print_rpm_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
+			int set, int voter_mV, int aggregate_mV)
+{
+	/* Suppress 8058_s0 and 8058_s1 printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1)
+	    && VREG_ID_IS_8058_S0_OR_S1(vreg->id))
+		return;
+
+	pr_info("rpm-regulator: vote received %-9s: voter=%d, set=%c, "
+		"v_voter=%4d mV, v_aggregate=%4d mV\n",
+		vreg_descrip[vreg->id].name, voter, (set == 0 ? 'A' : 'S'),
+		voter_mV, aggregate_mV);
+}
+
+static void print_rpm_duplicate(struct vreg *vreg, int set, int cnt)
+{
+	/* Suppress 8058_s0 and 8058_s1 printing. */
+	if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_8058_S0_S1)
+	    && VREG_ID_IS_8058_S0_OR_S1(vreg->id))
+		return;
+
+	if (cnt == 2)
+		pr_info("rpm-regulator: ignored duplicate request %-9s: set=%c;"
+			" req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
+			vreg_descrip[vreg->id].name, (set == 0 ? 'A' : 'S'),
+			vreg->req[0].id, vreg->req[0].value,
+			vreg->req[1].id, vreg->req[1].value);
+	else if (cnt == 1)
+		pr_info("rpm-regulator: ignored duplicate request %-9s: set=%c;"
+			" req[0]={%d, 0x%08X}\n",
+			vreg_descrip[vreg->id].name, (set == 0 ? 'A' : 'S'),
+			vreg->req[0].id, vreg->req[0].value);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("rpm regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:rpm-regulator");