msm: rpm-regulator: merge rpm-regulator and rpm-regulator-8960 drivers
Combine rpm-regulator.c and rpm-regulator-8960.c so that only a
single file named rpm-regulator.c contains the RPM regulator
driver logic. This will initially support both 8660 and 8960.
The data needed to capture the configuration of the RPM regulator
driver on different platforms will be added in platform specific
files.
Change-Id: I57982e73aa7cb30425912b5ff4b90871419e1f8a
Signed-off-by: David Collins <collinsd@codeaurora.org>
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e81bdcd..d0bd6e1 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -158,7 +158,7 @@
obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o
obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
-obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator.o
+obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator.o rpm-regulator-8660.o
obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
ifdef CONFIG_MSM_SUBSYSTEM_RESTART
@@ -209,7 +209,8 @@
obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o
obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
-obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator-8960.o memory_topology.o
+obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
+obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator.o rpm-regulator-8960.o
obj-$(CONFIG_MACH_MSM8960_SIM) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_CDP) += board-msm8960.o devices-8960.o board-msm8960-regulator.o
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-msm8960-regulator.c
index 3b6da9a..e85202d 100644
--- a/arch/arm/mach-msm/board-msm8960-regulator.c
+++ b/arch/arm/mach-msm/board-msm8960-regulator.c
@@ -383,8 +383,8 @@
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
| REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
| REGULATOR_CHANGE_DRMS, 0, _max_uV, _init_peak_uA, 0, _pd, \
- RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_NONE, \
- RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+ RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+ RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
_supply_regulator, _system_uA)
@@ -394,15 +394,15 @@
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE \
| REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE \
| REGULATOR_CHANGE_DRMS, 0, _max_uV, _system_uA, 0, _pd, \
- RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_NONE, \
- RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+ RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+ RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
_supply_regulator, _system_uA)
#define RPM_VS(_id, _always_on, _pd, _sleep_selectable, _supply_regulator) \
RPM_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, 0, 1000, 1000, _pd, \
- RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_NONE, \
- RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+ RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_8960_NONE, \
+ RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
_supply_regulator, 0)
@@ -410,8 +410,8 @@
_supply_regulator, _freq) \
RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
| REGULATOR_CHANGE_STATUS, 0, _max_uV, 1000, 1000, 0, \
- RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_NONE, \
- RPM_VREG_FORCE_MODE_NONE, RPM_VREG_POWER_MODE_PWM, \
+ RPM_VREG_PIN_CTRL_NONE, _freq, RPM_VREG_PIN_FN_8960_NONE, \
+ RPM_VREG_FORCE_MODE_8960_NONE, RPM_VREG_POWER_MODE_8960_PWM, \
RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
_supply_regulator, 0)
@@ -429,7 +429,7 @@
.supply_regulator = _supply_regulator, \
}, \
.id = RPM_VREG_ID_PM8921_##_id##_PC, \
- .pin_fn = RPM_VREG_PIN_FN_##_pin_fn, \
+ .pin_fn = RPM_VREG_PIN_FN_8960_##_pin_fn, \
.pin_ctrl = _pin_ctrl, \
}
@@ -520,6 +520,9 @@
ARRAY_SIZE(msm_pm8921_regulator_pdata);
struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
- .init_data = msm_rpm_regulator_init_data,
- .num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data),
+ .init_data = msm_rpm_regulator_init_data,
+ .num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data),
+ .version = RPM_VREG_VERSION_8960,
+ .vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24,
+ .vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3,
};
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 79bad3f..6804a99 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -3841,35 +3841,73 @@
REGULATOR_SUPPLY("8901_mvs0", NULL),
};
+/* Pin control regulators */
+static struct regulator_consumer_supply vreg_consumers_PM8058_L8_PC[] = {
+ REGULATOR_SUPPLY("8058_l8_pc", NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L20_PC[] = {
+ REGULATOR_SUPPLY("8058_l20_pc", NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_L21_PC[] = {
+ REGULATOR_SUPPLY("8058_l21_pc", NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8058_S2_PC[] = {
+ REGULATOR_SUPPLY("8058_s2_pc", NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_L0_PC[] = {
+ REGULATOR_SUPPLY("8901_l0_pc", NULL),
+};
+static struct regulator_consumer_supply vreg_consumers_PM8901_S4_PC[] = {
+ REGULATOR_SUPPLY("8901_s4_pc", NULL),
+};
+
#define RPM_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
_default_uV, _peak_uA, _avg_uA, _pull_down, _pin_ctrl, \
- _freq, _pin_fn, _rpm_mode, _state, _sleep_selectable, \
+ _freq, _pin_fn, _force_mode, _state, _sleep_selectable, \
_always_on) \
- [RPM_VREG_ID_##_id] = { \
+ { \
.init_data = { \
.constraints = { \
- .valid_modes_mask = _modes, \
- .valid_ops_mask = _ops, \
- .min_uV = _min_uV, \
- .max_uV = _max_uV, \
- .input_uV = _min_uV, \
- .apply_uV = _apply_uV, \
- .always_on = _always_on, \
+ .valid_modes_mask = _modes, \
+ .valid_ops_mask = _ops, \
+ .min_uV = _min_uV, \
+ .max_uV = _max_uV, \
+ .input_uV = _min_uV, \
+ .apply_uV = _apply_uV, \
+ .always_on = _always_on, \
}, \
- .consumer_supplies = vreg_consumers_##_id, \
- .num_consumer_supplies = \
+ .consumer_supplies = vreg_consumers_##_id, \
+ .num_consumer_supplies = \
ARRAY_SIZE(vreg_consumers_##_id), \
}, \
- .default_uV = _default_uV, \
- .peak_uA = _peak_uA, \
- .avg_uA = _avg_uA, \
- .pull_down_enable = _pull_down, \
+ .id = RPM_VREG_ID_##_id, \
+ .default_uV = _default_uV, \
+ .peak_uA = _peak_uA, \
+ .avg_uA = _avg_uA, \
+ .pull_down_enable = _pull_down, \
+ .pin_ctrl = _pin_ctrl, \
+ .freq = RPM_VREG_FREQ_##_freq, \
+ .pin_fn = _pin_fn, \
+ .force_mode = _force_mode, \
+ .state = _state, \
+ .sleep_selectable = _sleep_selectable, \
+ }
+
+/* Pin control initialization */
+#define RPM_PC(_id, _always_on, _pin_fn, _pin_ctrl) \
+ { \
+ .init_data = { \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ .always_on = _always_on, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+ .consumer_supplies = vreg_consumers_##_id##_PC, \
+ }, \
+ .id = RPM_VREG_ID_##_id##_PC, \
+ .pin_fn = RPM_VREG_PIN_FN_8660_##_pin_fn, \
.pin_ctrl = _pin_ctrl, \
- .freq = _freq, \
- .pin_fn = _pin_fn, \
- .mode = _rpm_mode, \
- .state = _state, \
- .sleep_selectable = _sleep_selectable, \
}
/*
@@ -3882,198 +3920,165 @@
* .init_data.constraints.initial_mode.
*/
-#define RPM_VREG_INIT_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
- _max_uV, _init_peak_uA, _pin_ctrl) \
+#define RPM_LDO(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+ _init_peak_uA) \
RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
- _init_peak_uA, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
- RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
- RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
-
-#define RPM_VREG_INIT_LDO_PF(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
- _max_uV, _init_peak_uA, _pin_ctrl, _pin_fn) \
- RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
- REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
- REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
- REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
- REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
- _init_peak_uA, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
- _pin_fn, RPM_VREG_MODE_NONE, RPM_VREG_STATE_OFF, \
+ _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+ RPM_VREG_PIN_FN_8660_ENABLE, \
+ RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
_sleep_selectable, _always_on)
-#define RPM_VREG_INIT_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
- _max_uV, _init_peak_uA, _pin_ctrl, _freq) \
+#define RPM_SMPS(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV, \
+ _init_peak_uA, _freq) \
RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_FAST | \
REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE | \
REGULATOR_MODE_STANDBY, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _min_uV, _init_peak_uA, \
- _init_peak_uA, _pd, _pin_ctrl, _freq, \
- RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
- RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
+ _init_peak_uA, _pd, RPM_VREG_PIN_CTRL_NONE, _freq, \
+ RPM_VREG_PIN_FN_8660_ENABLE, \
+ RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+ _sleep_selectable, _always_on)
-#define RPM_VREG_INIT_VS(_id, _always_on, _pd, _sleep_selectable, _pin_ctrl) \
+#define RPM_VS(_id, _always_on, _pd, _sleep_selectable) \
RPM_VREG_INIT(_id, 0, 0, REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE, \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE, 0, 0, \
- 1000, 1000, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
- RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
- RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
+ 1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+ RPM_VREG_PIN_FN_8660_ENABLE, \
+ RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+ _sleep_selectable, _always_on)
-#define RPM_VREG_INIT_NCP(_id, _always_on, _pd, _sleep_selectable, _min_uV, \
- _max_uV, _pin_ctrl) \
+#define RPM_NCP(_id, _always_on, _pd, _sleep_selectable, _min_uV, _max_uV) \
RPM_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, \
- _min_uV, 1000, 1000, _pd, _pin_ctrl, RPM_VREG_FREQ_NONE, \
- RPM_VREG_PIN_FN_ENABLE, RPM_VREG_MODE_NONE, \
- RPM_VREG_STATE_OFF, _sleep_selectable, _always_on)
+ _min_uV, 1000, 1000, _pd, RPM_VREG_PIN_CTRL_NONE, NONE, \
+ RPM_VREG_PIN_FN_8660_ENABLE, \
+ RPM_VREG_FORCE_MODE_8660_NONE, RPM_VREG_STATE_OFF, \
+ _sleep_selectable, _always_on)
-#define LDO50HMIN RPM_VREG_LDO_50_HPM_MIN_LOAD
-#define LDO150HMIN RPM_VREG_LDO_150_HPM_MIN_LOAD
-#define LDO300HMIN RPM_VREG_LDO_300_HPM_MIN_LOAD
-#define SMPS_HMIN RPM_VREG_SMPS_HPM_MIN_LOAD
-#define FTS_HMIN RPM_VREG_FTSMPS_HPM_MIN_LOAD
+#define LDO50HMIN RPM_VREG_8660_LDO_50_HPM_MIN_LOAD
+#define LDO150HMIN RPM_VREG_8660_LDO_150_HPM_MIN_LOAD
+#define LDO300HMIN RPM_VREG_8660_LDO_300_HPM_MIN_LOAD
+#define SMPS_HMIN RPM_VREG_8660_SMPS_HPM_MIN_LOAD
+#define FTS_HMIN RPM_VREG_8660_FTSMPS_HPM_MIN_LOAD
-static struct rpm_vreg_pdata rpm_vreg_init_pdata[RPM_VREG_ID_MAX] = {
- RPM_VREG_INIT_LDO(PM8058_L0, 0, 1, 0, 1200000, 1200000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L1, 0, 1, 0, 1200000, 1200000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L2, 0, 1, 0, 1800000, 2600000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L3, 0, 1, 0, 1800000, 1800000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L4, 0, 1, 0, 2850000, 2850000, LDO50HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L5, 0, 1, 0, 2850000, 2850000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L6, 0, 1, 0, 3000000, 3600000, LDO50HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L7, 0, 1, 0, 1800000, 1800000, LDO50HMIN, 0),
- RPM_VREG_INIT_LDO_PF(PM8058_L8, 0, 1, 0, 2900000, 3050000, LDO300HMIN,
- RPM_VREG_PIN_CTRL_NONE, RPM_VREG_PIN_FN_SLEEP_B),
- RPM_VREG_INIT_LDO(PM8058_L9, 0, 1, 0, 1800000, 1800000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L10, 0, 1, 0, 2600000, 2600000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L11, 0, 1, 0, 1500000, 1500000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L12, 0, 1, 0, 2900000, 2900000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L13, 0, 1, 0, 2050000, 2050000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L14, 0, 0, 0, 2850000, 2850000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L15, 0, 1, 0, 2850000, 2850000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L16, 1, 1, 0, 1800000, 1800000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L17, 0, 1, 0, 2600000, 2600000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L18, 0, 1, 0, 2200000, 2200000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L19, 0, 1, 0, 2500000, 2500000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO_PF(PM8058_L20, 0, 1, 0, 1800000, 1800000, LDO150HMIN,
- RPM_VREG_PIN_CTRL_NONE, RPM_VREG_PIN_FN_SLEEP_B),
- RPM_VREG_INIT_LDO_PF(PM8058_L21, 1, 1, 0, 1200000, 1200000, LDO150HMIN,
- RPM_VREG_PIN_CTRL_NONE, RPM_VREG_PIN_FN_SLEEP_B),
- RPM_VREG_INIT_LDO(PM8058_L22, 0, 1, 0, 1150000, 1150000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L23, 0, 1, 0, 1200000, 1200000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L24, 0, 1, 0, 1200000, 1200000, LDO150HMIN, 0),
- RPM_VREG_INIT_LDO(PM8058_L25, 0, 1, 0, 1200000, 1200000, LDO150HMIN, 0),
-
- RPM_VREG_INIT_SMPS(PM8058_S0, 0, 1, 1, 500000, 1250000, SMPS_HMIN, 0,
- RPM_VREG_FREQ_1p60),
- RPM_VREG_INIT_SMPS(PM8058_S1, 0, 1, 1, 500000, 1250000, SMPS_HMIN, 0,
- RPM_VREG_FREQ_1p60),
- RPM_VREG_INIT_SMPS(PM8058_S2, 0, 1, 1, 1200000, 1400000, SMPS_HMIN,
- RPM_VREG_PIN_CTRL_A0, RPM_VREG_FREQ_1p60),
- RPM_VREG_INIT_SMPS(PM8058_S3, 1, 1, 0, 1800000, 1800000, SMPS_HMIN, 0,
- RPM_VREG_FREQ_1p60),
- RPM_VREG_INIT_SMPS(PM8058_S4, 1, 1, 0, 2200000, 2200000, SMPS_HMIN, 0,
- RPM_VREG_FREQ_1p60),
-
- RPM_VREG_INIT_VS(PM8058_LVS0, 0, 1, 0, 0),
- RPM_VREG_INIT_VS(PM8058_LVS1, 0, 1, 0, 0),
-
- RPM_VREG_INIT_NCP(PM8058_NCP, 0, 1, 0, 1800000, 1800000, 0),
-
- RPM_VREG_INIT_LDO(PM8901_L0, 0, 1, 0, 1200000, 1200000, LDO300HMIN,
- RPM_VREG_PIN_CTRL_A0),
- RPM_VREG_INIT_LDO(PM8901_L1, 0, 1, 0, 3300000, 3300000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8901_L2, 0, 1, 0, 2850000, 3300000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8901_L3, 0, 1, 0, 3300000, 3300000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8901_L4, 0, 1, 0, 2600000, 2600000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8901_L5, 0, 1, 0, 2850000, 2850000, LDO300HMIN, 0),
- RPM_VREG_INIT_LDO(PM8901_L6, 0, 1, 0, 2200000, 2200000, LDO300HMIN, 0),
-
- RPM_VREG_INIT_SMPS(PM8901_S2, 0, 1, 0, 1300000, 1300000, FTS_HMIN, 0,
- RPM_VREG_FREQ_1p60),
- RPM_VREG_INIT_SMPS(PM8901_S3, 0, 1, 0, 1100000, 1100000, FTS_HMIN, 0,
- RPM_VREG_FREQ_1p60),
- RPM_VREG_INIT_SMPS(PM8901_S4, 0, 1, 0, 1225000, 1225000, FTS_HMIN,
- RPM_VREG_PIN_CTRL_A0, RPM_VREG_FREQ_1p60),
-
- RPM_VREG_INIT_VS(PM8901_LVS0, 1, 1, 0, 0),
- RPM_VREG_INIT_VS(PM8901_LVS1, 0, 1, 0, 0),
- RPM_VREG_INIT_VS(PM8901_LVS2, 0, 1, 0, 0),
- RPM_VREG_INIT_VS(PM8901_LVS3, 0, 1, 0, 0),
- RPM_VREG_INIT_VS(PM8901_MVS0, 0, 1, 0, 0),
+/* RPM early regulator constraints */
+static struct rpm_regulator_init_data rpm_regulator_early_init_data[] = {
+ /* ID a_on pd ss min_uV max_uV init_ip freq */
+ RPM_SMPS(PM8058_S0, 0, 1, 1, 500000, 1250000, SMPS_HMIN, 1p60),
+ RPM_SMPS(PM8058_S1, 0, 1, 1, 500000, 1250000, SMPS_HMIN, 1p60),
};
-#define RPM_VREG(_id) \
- [_id] = { \
- .name = "rpm-regulator", \
- .id = _id, \
- .dev = { \
- .platform_data = &rpm_vreg_init_pdata[_id], \
- }, \
- }
+/* RPM regulator constraints */
+static struct rpm_regulator_init_data rpm_regulator_init_data[] = {
+ /* ID a_on pd ss min_uV max_uV init_ip */
+ RPM_LDO(PM8058_L0, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
+ RPM_LDO(PM8058_L1, 0, 1, 0, 1200000, 1200000, LDO300HMIN),
+ RPM_LDO(PM8058_L2, 0, 1, 0, 1800000, 2600000, LDO300HMIN),
+ RPM_LDO(PM8058_L3, 0, 1, 0, 1800000, 1800000, LDO150HMIN),
+ RPM_LDO(PM8058_L4, 0, 1, 0, 2850000, 2850000, LDO50HMIN),
+ RPM_LDO(PM8058_L5, 0, 1, 0, 2850000, 2850000, LDO300HMIN),
+ RPM_LDO(PM8058_L6, 0, 1, 0, 3000000, 3600000, LDO50HMIN),
+ RPM_LDO(PM8058_L7, 0, 1, 0, 1800000, 1800000, LDO50HMIN),
+ RPM_LDO(PM8058_L8, 0, 1, 0, 2900000, 3050000, LDO300HMIN),
+ RPM_LDO(PM8058_L9, 0, 1, 0, 1800000, 1800000, LDO300HMIN),
+ RPM_LDO(PM8058_L10, 0, 1, 0, 2600000, 2600000, LDO300HMIN),
+ RPM_LDO(PM8058_L11, 0, 1, 0, 1500000, 1500000, LDO150HMIN),
+ RPM_LDO(PM8058_L12, 0, 1, 0, 2900000, 2900000, LDO150HMIN),
+ RPM_LDO(PM8058_L13, 0, 1, 0, 2050000, 2050000, LDO300HMIN),
+ RPM_LDO(PM8058_L14, 0, 0, 0, 2850000, 2850000, LDO300HMIN),
+ RPM_LDO(PM8058_L15, 0, 1, 0, 2850000, 2850000, LDO300HMIN),
+ RPM_LDO(PM8058_L16, 1, 1, 0, 1800000, 1800000, LDO300HMIN),
+ RPM_LDO(PM8058_L17, 0, 1, 0, 2600000, 2600000, LDO150HMIN),
+ RPM_LDO(PM8058_L18, 0, 1, 0, 2200000, 2200000, LDO150HMIN),
+ RPM_LDO(PM8058_L19, 0, 1, 0, 2500000, 2500000, LDO150HMIN),
+ RPM_LDO(PM8058_L20, 0, 1, 0, 1800000, 1800000, LDO150HMIN),
+ RPM_LDO(PM8058_L21, 1, 1, 0, 1200000, 1200000, LDO150HMIN),
+ RPM_LDO(PM8058_L22, 0, 1, 0, 1150000, 1150000, LDO300HMIN),
+ RPM_LDO(PM8058_L23, 0, 1, 0, 1200000, 1200000, LDO300HMIN),
+ RPM_LDO(PM8058_L24, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
+ RPM_LDO(PM8058_L25, 0, 1, 0, 1200000, 1200000, LDO150HMIN),
-static struct platform_device rpm_vreg_device[RPM_VREG_ID_MAX] = {
- RPM_VREG(RPM_VREG_ID_PM8058_L0),
- RPM_VREG(RPM_VREG_ID_PM8058_L1),
- RPM_VREG(RPM_VREG_ID_PM8058_L2),
- RPM_VREG(RPM_VREG_ID_PM8058_L3),
- RPM_VREG(RPM_VREG_ID_PM8058_L4),
- RPM_VREG(RPM_VREG_ID_PM8058_L5),
- RPM_VREG(RPM_VREG_ID_PM8058_L6),
- RPM_VREG(RPM_VREG_ID_PM8058_L7),
- RPM_VREG(RPM_VREG_ID_PM8058_L8),
- RPM_VREG(RPM_VREG_ID_PM8058_L9),
- RPM_VREG(RPM_VREG_ID_PM8058_L10),
- RPM_VREG(RPM_VREG_ID_PM8058_L11),
- RPM_VREG(RPM_VREG_ID_PM8058_L12),
- RPM_VREG(RPM_VREG_ID_PM8058_L13),
- RPM_VREG(RPM_VREG_ID_PM8058_L14),
- RPM_VREG(RPM_VREG_ID_PM8058_L15),
- RPM_VREG(RPM_VREG_ID_PM8058_L16),
- RPM_VREG(RPM_VREG_ID_PM8058_L17),
- RPM_VREG(RPM_VREG_ID_PM8058_L18),
- RPM_VREG(RPM_VREG_ID_PM8058_L19),
- RPM_VREG(RPM_VREG_ID_PM8058_L20),
- RPM_VREG(RPM_VREG_ID_PM8058_L21),
- RPM_VREG(RPM_VREG_ID_PM8058_L22),
- RPM_VREG(RPM_VREG_ID_PM8058_L23),
- RPM_VREG(RPM_VREG_ID_PM8058_L24),
- RPM_VREG(RPM_VREG_ID_PM8058_L25),
- RPM_VREG(RPM_VREG_ID_PM8058_S0),
- RPM_VREG(RPM_VREG_ID_PM8058_S1),
- RPM_VREG(RPM_VREG_ID_PM8058_S2),
- RPM_VREG(RPM_VREG_ID_PM8058_S3),
- RPM_VREG(RPM_VREG_ID_PM8058_S4),
- RPM_VREG(RPM_VREG_ID_PM8058_LVS0),
- RPM_VREG(RPM_VREG_ID_PM8058_LVS1),
- RPM_VREG(RPM_VREG_ID_PM8058_NCP),
- RPM_VREG(RPM_VREG_ID_PM8901_L0),
- RPM_VREG(RPM_VREG_ID_PM8901_L1),
- RPM_VREG(RPM_VREG_ID_PM8901_L2),
- RPM_VREG(RPM_VREG_ID_PM8901_L3),
- RPM_VREG(RPM_VREG_ID_PM8901_L4),
- RPM_VREG(RPM_VREG_ID_PM8901_L5),
- RPM_VREG(RPM_VREG_ID_PM8901_L6),
- RPM_VREG(RPM_VREG_ID_PM8901_S2),
- RPM_VREG(RPM_VREG_ID_PM8901_S3),
- RPM_VREG(RPM_VREG_ID_PM8901_S4),
- RPM_VREG(RPM_VREG_ID_PM8901_LVS0),
- RPM_VREG(RPM_VREG_ID_PM8901_LVS1),
- RPM_VREG(RPM_VREG_ID_PM8901_LVS2),
- RPM_VREG(RPM_VREG_ID_PM8901_LVS3),
- RPM_VREG(RPM_VREG_ID_PM8901_MVS0),
+ /* ID a_on pd ss min_uV max_uV init_ip freq */
+ RPM_SMPS(PM8058_S2, 0, 1, 1, 1200000, 1400000, SMPS_HMIN, 1p60),
+ RPM_SMPS(PM8058_S3, 1, 1, 0, 1800000, 1800000, SMPS_HMIN, 1p60),
+ RPM_SMPS(PM8058_S4, 1, 1, 0, 2200000, 2200000, SMPS_HMIN, 1p60),
+
+ /* ID a_on pd ss */
+ RPM_VS(PM8058_LVS0, 0, 1, 0),
+ RPM_VS(PM8058_LVS1, 0, 1, 0),
+
+ /* ID a_on pd ss min_uV max_uV */
+ RPM_NCP(PM8058_NCP, 0, 1, 0, 1800000, 1800000),
+
+ /* ID a_on pd ss min_uV max_uV init_ip */
+ RPM_LDO(PM8901_L0, 0, 1, 0, 1200000, 1200000, LDO300HMIN),
+ RPM_LDO(PM8901_L1, 0, 1, 0, 3300000, 3300000, LDO300HMIN),
+ RPM_LDO(PM8901_L2, 0, 1, 0, 2850000, 3300000, LDO300HMIN),
+ RPM_LDO(PM8901_L3, 0, 1, 0, 3300000, 3300000, LDO300HMIN),
+ RPM_LDO(PM8901_L4, 0, 1, 0, 2600000, 2600000, LDO300HMIN),
+ RPM_LDO(PM8901_L5, 0, 1, 0, 2850000, 2850000, LDO300HMIN),
+ RPM_LDO(PM8901_L6, 0, 1, 0, 2200000, 2200000, LDO300HMIN),
+
+ /* ID a_on pd ss min_uV max_uV init_ip freq */
+ RPM_SMPS(PM8901_S2, 0, 1, 0, 1300000, 1300000, FTS_HMIN, 1p60),
+ RPM_SMPS(PM8901_S3, 0, 1, 0, 1100000, 1100000, FTS_HMIN, 1p60),
+ RPM_SMPS(PM8901_S4, 0, 1, 0, 1225000, 1225000, FTS_HMIN, 1p60),
+
+ /* ID a_on pd ss */
+ RPM_VS(PM8901_LVS0, 1, 1, 0),
+ RPM_VS(PM8901_LVS1, 0, 1, 0),
+ RPM_VS(PM8901_LVS2, 0, 1, 0),
+ RPM_VS(PM8901_LVS3, 0, 1, 0),
+ RPM_VS(PM8901_MVS0, 0, 1, 0),
+
+ /* ID a_on pin_func pin_ctrl */
+ RPM_PC(PM8058_L8, 0, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+ RPM_PC(PM8058_L20, 0, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+ RPM_PC(PM8058_L21, 1, SLEEP_B, RPM_VREG_PIN_CTRL_NONE),
+ RPM_PC(PM8058_S2, 0, ENABLE, RPM_VREG_PIN_CTRL_PM8058_A0),
+ RPM_PC(PM8901_L0, 0, ENABLE, RPM_VREG_PIN_CTRL_PM8901_A0),
+ RPM_PC(PM8901_S4, 0, ENABLE, RPM_VREG_PIN_CTRL_PM8901_A0),
+};
+
+static struct rpm_regulator_platform_data rpm_regulator_early_pdata = {
+ .init_data = rpm_regulator_early_init_data,
+ .num_regulators = ARRAY_SIZE(rpm_regulator_early_init_data),
+ .version = RPM_VREG_VERSION_8660,
+ .vreg_id_vdd_mem = RPM_VREG_ID_PM8058_S0,
+ .vreg_id_vdd_dig = RPM_VREG_ID_PM8058_S1,
+};
+
+static struct rpm_regulator_platform_data rpm_regulator_pdata = {
+ .init_data = rpm_regulator_init_data,
+ .num_regulators = ARRAY_SIZE(rpm_regulator_init_data),
+ .version = RPM_VREG_VERSION_8660,
+};
+
+static struct platform_device rpm_regulator_early_device = {
+ .name = "rpm-regulator",
+ .id = 0,
+ .dev = {
+ .platform_data = &rpm_regulator_early_pdata,
+ },
+};
+
+static struct platform_device rpm_regulator_device = {
+ .name = "rpm-regulator",
+ .id = 1,
+ .dev = {
+ .platform_data = &rpm_regulator_pdata,
+ },
};
static struct platform_device *early_regulators[] __initdata = {
&msm_device_saw_s0,
&msm_device_saw_s1,
-#ifdef CONFIG_PMIC8058
- &rpm_vreg_device[RPM_VREG_ID_PM8058_S0],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_S1],
-#endif
+ &rpm_regulator_early_device,
};
static struct platform_device *early_devices[] __initdata = {
@@ -5061,57 +5066,7 @@
#ifdef CONFIG_SENSORS_MSM_ADC
&msm_adc_device,
#endif
-#ifdef CONFIG_PMIC8058
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L0],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L1],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L2],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L3],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L4],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L5],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L6],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L7],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L8],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L9],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L10],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L11],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L12],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L13],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L14],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L15],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L16],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L17],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L18],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L19],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L20],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L21],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L22],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L23],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L24],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_L25],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_S2],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_S3],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_S4],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_LVS0],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_LVS1],
- &rpm_vreg_device[RPM_VREG_ID_PM8058_NCP],
-#endif
-#ifdef CONFIG_PMIC8901
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L0],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L1],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L2],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L3],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L4],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L5],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_L6],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_S2],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_S3],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_S4],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_LVS0],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_LVS1],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_LVS2],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_LVS3],
- &rpm_vreg_device[RPM_VREG_ID_PM8901_MVS0],
-#endif
+ &rpm_regulator_device,
#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
@@ -10118,10 +10073,15 @@
* un-reworked SURF cannot resume from.
*/
if (machine_is_msm8x60_surf()) {
- rpm_vreg_init_pdata[RPM_VREG_ID_PM8901_L4]
- .init_data.constraints.always_on = 1;
- rpm_vreg_init_pdata[RPM_VREG_ID_PM8901_L6]
- .init_data.constraints.always_on = 1;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rpm_regulator_init_data); i++)
+ if (rpm_regulator_init_data[i].id
+ == RPM_VREG_ID_PM8901_L4
+ || rpm_regulator_init_data[i].id
+ == RPM_VREG_ID_PM8901_L6)
+ rpm_regulator_init_data[i]
+ .init_data.constraints.always_on = 1;
}
/*
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
index 3bcebd4..85dcd89 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8660.h
@@ -11,67 +11,61 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8660_H
-#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8660_H
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8660_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8660_H
-#define RPM_VREG_PIN_CTRL_NONE 0x00
-#define RPM_VREG_PIN_CTRL_A0 0x01
-#define RPM_VREG_PIN_CTRL_A1 0x02
-#define RPM_VREG_PIN_CTRL_D0 0x04
-#define RPM_VREG_PIN_CTRL_D1 0x08
+#define RPM_VREG_PIN_CTRL_PM8058_A0 0x01
+#define RPM_VREG_PIN_CTRL_PM8058_A1 0x02
+#define RPM_VREG_PIN_CTRL_PM8058_D0 0x04
+#define RPM_VREG_PIN_CTRL_PM8058_D1 0x08
-/*
- * Pin Function
- * ENABLE - pin control switches between disable and enable
- * MODE - pin control switches between LPM and HPM
- * SLEEP_B - regulator is forced into LPM by asserting sleep_b signal
- * NONE - do not use pin control
+#define RPM_VREG_PIN_CTRL_PM8901_A0 0x01
+#define RPM_VREG_PIN_CTRL_PM8901_A1 0x02
+#define RPM_VREG_PIN_CTRL_PM8901_D0 0x04
+#define RPM_VREG_PIN_CTRL_PM8901_D1 0x08
+
+
+/**
+ * enum rpm_vreg_pin_fn_8660 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8660_ENABLE: pin control switches between disable and
+ * enable
+ * %RPM_VREG_PIN_FN_8660_MODE: pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8660_SLEEP_B: regulator is forced into LPM when
+ * sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8660_NONE: do not use pin control for the regulator
+ * and do not allow another master to
+ * request pin control
*
* The pin function specified in platform data corresponds to the active state
* pin function value. Pin function will be NONE until a consumer requests
- * pin control with regulator_set_mode(vreg, REGULATOR_MODE_IDLE).
+ * pin control to be enabled.
*/
-enum rpm_vreg_pin_fn {
- RPM_VREG_PIN_FN_ENABLE = 0,
- RPM_VREG_PIN_FN_MODE,
- RPM_VREG_PIN_FN_SLEEP_B,
- RPM_VREG_PIN_FN_NONE,
+enum rpm_vreg_pin_fn_8660 {
+ RPM_VREG_PIN_FN_8660_ENABLE = 0,
+ RPM_VREG_PIN_FN_8660_MODE,
+ RPM_VREG_PIN_FN_8660_SLEEP_B,
+ RPM_VREG_PIN_FN_8660_NONE,
};
-enum rpm_vreg_mode {
- RPM_VREG_MODE_PIN_CTRL = 0,
- RPM_VREG_MODE_NONE = 0,
- RPM_VREG_MODE_LPM,
- RPM_VREG_MODE_HPM,
+/**
+ * enum rpm_vreg_force_mode_8660 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8660_PIN_CTRL: allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8660_NONE: do not force any mode
+ * %RPM_VREG_FORCE_MODE_8660_LPM: force into low power mode
+ * %RPM_VREG_FORCE_MODE_8660_HPM: force into high power mode
+ *
+ * Force mode is used to override aggregation with other masters and to set
+ * special operating modes.
+ */
+enum rpm_vreg_force_mode_8660 {
+ RPM_VREG_FORCE_MODE_8660_PIN_CTRL = 0,
+ RPM_VREG_FORCE_MODE_8660_NONE = 0,
+ RPM_VREG_FORCE_MODE_8660_LPM,
+ RPM_VREG_FORCE_MODE_8660_HPM,
};
-enum rpm_vreg_state {
- RPM_VREG_STATE_OFF = 0,
- RPM_VREG_STATE_ON,
-};
-
-enum rpm_vreg_freq {
- RPM_VREG_FREQ_NONE,
- RPM_VREG_FREQ_19p20,
- RPM_VREG_FREQ_9p60,
- RPM_VREG_FREQ_6p40,
- RPM_VREG_FREQ_4p80,
- RPM_VREG_FREQ_3p84,
- RPM_VREG_FREQ_3p20,
- RPM_VREG_FREQ_2p74,
- RPM_VREG_FREQ_2p40,
- RPM_VREG_FREQ_2p13,
- RPM_VREG_FREQ_1p92,
- RPM_VREG_FREQ_1p75,
- RPM_VREG_FREQ_1p60,
- RPM_VREG_FREQ_1p48,
- RPM_VREG_FREQ_1p37,
- RPM_VREG_FREQ_1p28,
- RPM_VREG_FREQ_1p20,
-};
-
-enum rpm_vreg_id {
- RPM_VREG_ID_PM8058_L0 = 0,
+enum rpm_vreg_id_8660 {
+ RPM_VREG_ID_PM8058_L0,
RPM_VREG_ID_PM8058_L1,
RPM_VREG_ID_PM8058_L2,
RPM_VREG_ID_PM8058_L3,
@@ -122,55 +116,68 @@
RPM_VREG_ID_PM8901_LVS2,
RPM_VREG_ID_PM8901_LVS3,
RPM_VREG_ID_PM8901_MVS0,
- RPM_VREG_ID_MAX,
+ RPM_VREG_ID_8660_MAX_REAL = RPM_VREG_ID_PM8901_MVS0,
+
+ /* The following are IDs for regulator devices to enable pin control. */
+ RPM_VREG_ID_PM8058_L0_PC,
+ RPM_VREG_ID_PM8058_L1_PC,
+ RPM_VREG_ID_PM8058_L2_PC,
+ RPM_VREG_ID_PM8058_L3_PC,
+ RPM_VREG_ID_PM8058_L4_PC,
+ RPM_VREG_ID_PM8058_L5_PC,
+ RPM_VREG_ID_PM8058_L6_PC,
+ RPM_VREG_ID_PM8058_L7_PC,
+ RPM_VREG_ID_PM8058_L8_PC,
+ RPM_VREG_ID_PM8058_L9_PC,
+ RPM_VREG_ID_PM8058_L10_PC,
+ RPM_VREG_ID_PM8058_L11_PC,
+ RPM_VREG_ID_PM8058_L12_PC,
+ RPM_VREG_ID_PM8058_L13_PC,
+ RPM_VREG_ID_PM8058_L14_PC,
+ RPM_VREG_ID_PM8058_L15_PC,
+ RPM_VREG_ID_PM8058_L16_PC,
+ RPM_VREG_ID_PM8058_L17_PC,
+ RPM_VREG_ID_PM8058_L18_PC,
+ RPM_VREG_ID_PM8058_L19_PC,
+ RPM_VREG_ID_PM8058_L20_PC,
+ RPM_VREG_ID_PM8058_L21_PC,
+ RPM_VREG_ID_PM8058_L22_PC,
+ RPM_VREG_ID_PM8058_L23_PC,
+ RPM_VREG_ID_PM8058_L24_PC,
+ RPM_VREG_ID_PM8058_L25_PC,
+ RPM_VREG_ID_PM8058_S0_PC,
+ RPM_VREG_ID_PM8058_S1_PC,
+ RPM_VREG_ID_PM8058_S2_PC,
+ RPM_VREG_ID_PM8058_S3_PC,
+ RPM_VREG_ID_PM8058_S4_PC,
+ RPM_VREG_ID_PM8058_LVS0_PC,
+ RPM_VREG_ID_PM8058_LVS1_PC,
+
+ RPM_VREG_ID_PM8901_L0_PC,
+ RPM_VREG_ID_PM8901_L1_PC,
+ RPM_VREG_ID_PM8901_L2_PC,
+ RPM_VREG_ID_PM8901_L3_PC,
+ RPM_VREG_ID_PM8901_L4_PC,
+ RPM_VREG_ID_PM8901_L5_PC,
+ RPM_VREG_ID_PM8901_L6_PC,
+ RPM_VREG_ID_PM8901_S0_PC,
+ RPM_VREG_ID_PM8901_S1_PC,
+ RPM_VREG_ID_PM8901_S2_PC,
+ RPM_VREG_ID_PM8901_S3_PC,
+ RPM_VREG_ID_PM8901_S4_PC,
+ RPM_VREG_ID_PM8901_LVS0_PC,
+ RPM_VREG_ID_PM8901_LVS1_PC,
+ RPM_VREG_ID_PM8901_LVS2_PC,
+ RPM_VREG_ID_PM8901_LVS3_PC,
+ RPM_VREG_ID_PM8901_MVS0_PC,
+ RPM_VREG_ID_8660_MAX = RPM_VREG_ID_PM8901_MVS0_PC,
};
/* Minimum high power mode loads in uA. */
-#define RPM_VREG_LDO_50_HPM_MIN_LOAD 5000
-#define RPM_VREG_LDO_150_HPM_MIN_LOAD 10000
-#define RPM_VREG_LDO_300_HPM_MIN_LOAD 10000
-#define RPM_VREG_SMPS_HPM_MIN_LOAD 50000
-#define RPM_VREG_FTSMPS_HPM_MIN_LOAD 100000
-
-/*
- * default_uV = initial voltage to set the regulator to if enable is called
- * before set_voltage (e.g. when boot_on or always_on is set).
- * peak_uA = initial load requirement sent in RPM request; used to determine
- * initial mode.
- * avg_uA = initial avg load requirement sent in RPM request; overwritten
- * along with peak_uA when regulator_set_mode or
- * regulator_set_optimum_mode is called.
- * pin_fn = RPM_VREG_PIN_FN_ENABLE - pin control ON/OFF
- * = RPM_VREG_PIN_FN_MODE - pin control LPM/HPM
- * = RPM_VREG_PIN_FN_SLEEP_B - regulator is forced into LPM by
- * asserting sleep_b signal
- * = RPM_VREG_PIN_FN_NONE - do not use pin control
- * mode = used to specify a force mode which overrides the votes of other
- * RPM masters.
- * state = initial state sent in RPM request.
- * sleep_selectable = flag which indicates that regulator should be accessable
- * by external private API and that spinlocks should be used.
- */
-struct rpm_vreg_pdata {
- struct regulator_init_data init_data;
- int default_uV;
- unsigned peak_uA;
- unsigned avg_uA;
- unsigned pull_down_enable;
- unsigned pin_ctrl;
- enum rpm_vreg_freq freq;
- enum rpm_vreg_pin_fn pin_fn;
- enum rpm_vreg_mode mode;
- enum rpm_vreg_state state;
- int sleep_selectable;
-};
-
-enum rpm_vreg_voter {
- RPM_VREG_VOTER_REG_FRAMEWORK = 0, /* for internal use only */
- RPM_VREG_VOTER1, /* for use by the acpu-clock driver */
- RPM_VREG_VOTER2, /* for use by the acpu-clock driver */
- RPM_VREG_VOTER3, /* for use by other drivers */
- RPM_VREG_VOTER_COUNT,
-};
+#define RPM_VREG_8660_LDO_50_HPM_MIN_LOAD 5000
+#define RPM_VREG_8660_LDO_150_HPM_MIN_LOAD 10000
+#define RPM_VREG_8660_LDO_300_HPM_MIN_LOAD 10000
+#define RPM_VREG_8660_SMPS_HPM_MIN_LOAD 50000
+#define RPM_VREG_8660_FTSMPS_HPM_MIN_LOAD 100000
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
index de7571b..6de47bd 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8960.h
@@ -11,118 +11,83 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8960_H
-#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_8960_H
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8960_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_8960_H
/* Pin control input signals. */
-#define RPM_VREG_PIN_CTRL_NONE 0x00
-#define RPM_VREG_PIN_CTRL_EN0 0x01
-#define RPM_VREG_PIN_CTRL_EN1 0x02
-#define RPM_VREG_PIN_CTRL_EN2 0x04
-#define RPM_VREG_PIN_CTRL_EN3 0x08
-#define RPM_VREG_PIN_CTRL_ALL 0x0F
-
-#define RPM_VREG_PIN_CTRL_PM8921_D1 RPM_VREG_PIN_CTRL_EN0
-#define RPM_VREG_PIN_CTRL_PM8921_A0 RPM_VREG_PIN_CTRL_EN1
-#define RPM_VREG_PIN_CTRL_PM8921_A1 RPM_VREG_PIN_CTRL_EN2
-#define RPM_VREG_PIN_CTRL_PM8921_A2 RPM_VREG_PIN_CTRL_EN3
+#define RPM_VREG_PIN_CTRL_PM8921_D1 0x01
+#define RPM_VREG_PIN_CTRL_PM8921_A0 0x02
+#define RPM_VREG_PIN_CTRL_PM8921_A1 0x04
+#define RPM_VREG_PIN_CTRL_PM8921_A2 0x08
/**
- * enum rpm_vreg_pin_fn - RPM regulator pin function choices
- * %RPM_VREG_PIN_FN_DONT_CARE: do not care about pin control state of the
- * regulator; allow another master processor to
- * specify pin control
- * %RPM_VREG_PIN_FN_ENABLE: pin control switches between disable and enable
- * %RPM_VREG_PIN_FN_MODE: pin control switches between LPM and HPM
- * %RPM_VREG_PIN_FN_SLEEP_B: regulator is forced into LPM when sleep_b signal
- * is asserted
- * %RPM_VREG_PIN_FN_NONE: do not use pin control for the regulator and do
- * not allow another master to request pin control
+ * enum rpm_vreg_pin_fn_8960 - RPM regulator pin function choices
+ * %RPM_VREG_PIN_FN_8960_DONT_CARE: do not care about pin control state of
+ * the regulator; allow another master
+ * processor to specify pin control
+ * %RPM_VREG_PIN_FN_8960_ENABLE: pin control switches between disable and
+ * enable
+ * %RPM_VREG_PIN_FN_8960_MODE: pin control switches between LPM and HPM
+ * %RPM_VREG_PIN_FN_8960_SLEEP_B: regulator is forced into LPM when
+ * sleep_b signal is asserted
+ * %RPM_VREG_PIN_FN_8960_NONE: do not use pin control for the regulator
+ * and do not allow another master to
+ * request pin control
*
* The pin function specified in platform data corresponds to the active state
* pin function value. Pin function will be NONE until a consumer requests
* pin control to be enabled.
*/
-enum rpm_vreg_pin_fn {
- RPM_VREG_PIN_FN_DONT_CARE,
- RPM_VREG_PIN_FN_ENABLE,
- RPM_VREG_PIN_FN_MODE,
- RPM_VREG_PIN_FN_SLEEP_B,
- RPM_VREG_PIN_FN_NONE,
+enum rpm_vreg_pin_fn_8960 {
+ RPM_VREG_PIN_FN_8960_DONT_CARE,
+ RPM_VREG_PIN_FN_8960_ENABLE,
+ RPM_VREG_PIN_FN_8960_MODE,
+ RPM_VREG_PIN_FN_8960_SLEEP_B,
+ RPM_VREG_PIN_FN_8960_NONE,
};
/**
- * enum rpm_vreg_force_mode - RPM regulator force mode choices
- * %RPM_VREG_FORCE_MODE_PIN_CTRL: allow pin control usage
- * %RPM_VREG_FORCE_MODE_NONE: do not force any mode
- * %RPM_VREG_FORCE_MODE_LPM: force into low power mode
- * %RPM_VREG_FORCE_MODE_AUTO: allow regulator to automatically select its
- * own mode based on realtime current draw
- * (only available for SMPS regulators)
- * %RPM_VREG_FORCE_MODE_HPM: force into high power mode
- * %RPM_VREG_FORCE_MODE_BYPASS: set regulator to use bypass mode, i.e. to act
- * as a switch and not regulate (only available
- * for LDO regulators)
+ * enum rpm_vreg_force_mode_8960 - RPM regulator force mode choices
+ * %RPM_VREG_FORCE_MODE_8960_PIN_CTRL: allow pin control usage
+ * %RPM_VREG_FORCE_MODE_8960_NONE: do not force any mode
+ * %RPM_VREG_FORCE_MODE_8960_LPM: force into low power mode
+ * %RPM_VREG_FORCE_MODE_8960_AUTO: allow regulator to automatically select
+ * its own mode based on realtime current
+ * draw (only available for SMPS
+ * regulators)
+ * %RPM_VREG_FORCE_MODE_8960_HPM: force into high power mode
+ * %RPM_VREG_FORCE_MODE_8960_BYPASS: set regulator to use bypass mode, i.e.
+ * to act as a switch and not regulate
+ * (only available for LDO regulators)
*
* Force mode is used to override aggregation with other masters and to set
* special operating modes.
*/
-enum rpm_vreg_force_mode {
- RPM_VREG_FORCE_MODE_PIN_CTRL = 0,
- RPM_VREG_FORCE_MODE_NONE = 0,
- RPM_VREG_FORCE_MODE_LPM,
- RPM_VREG_FORCE_MODE_AUTO, /* SMPS only */
- RPM_VREG_FORCE_MODE_HPM,
- RPM_VREG_FORCE_MODE_BYPASS, /* LDO only */
+enum rpm_vreg_force_mode_8960 {
+ RPM_VREG_FORCE_MODE_8960_PIN_CTRL = 0,
+ RPM_VREG_FORCE_MODE_8960_NONE = 0,
+ RPM_VREG_FORCE_MODE_8960_LPM,
+ RPM_VREG_FORCE_MODE_8960_AUTO, /* SMPS only */
+ RPM_VREG_FORCE_MODE_8960_HPM,
+ RPM_VREG_FORCE_MODE_8960_BYPASS, /* LDO only */
};
/**
- * enum rpm_vreg_power_mode - power mode for SMPS regulators
- * %RPM_VREG_POWER_MODE_HYSTERETIC: Use hysteretic mode for HPM and when
- * usage goes high in AUTO
- * %RPM_VREG_POWER_MODE_PWM: Use PWM mode for HPM and when usage goes
- * high in AUTO
+ * enum rpm_vreg_power_mode_8960 - power mode for SMPS regulators
+ * %RPM_VREG_POWER_MODE_8960_HYSTERETIC: Use hysteretic mode for HPM and when
+ * usage goes high in AUTO
+ * %RPM_VREG_POWER_MODE_8960_PWM: Use PWM mode for HPM and when usage
+ * goes high in AUTO
*/
-enum rpm_vreg_power_mode {
- RPM_VREG_POWER_MODE_HYSTERETIC,
- RPM_VREG_POWER_MODE_PWM,
-};
-
-/**
- * enum rpm_vreg_state - enable state for switch or NCP
- */
-enum rpm_vreg_state {
- RPM_VREG_STATE_OFF,
- RPM_VREG_STATE_ON,
-};
-
-/**
- * enum rpm_vreg_freq - switching frequency for SMPS or NCP
- */
-enum rpm_vreg_freq {
- RPM_VREG_FREQ_NONE,
- RPM_VREG_FREQ_19p20,
- RPM_VREG_FREQ_9p60,
- RPM_VREG_FREQ_6p40,
- RPM_VREG_FREQ_4p80,
- RPM_VREG_FREQ_3p84,
- RPM_VREG_FREQ_3p20,
- RPM_VREG_FREQ_2p74,
- RPM_VREG_FREQ_2p40,
- RPM_VREG_FREQ_2p13,
- RPM_VREG_FREQ_1p92,
- RPM_VREG_FREQ_1p75,
- RPM_VREG_FREQ_1p60,
- RPM_VREG_FREQ_1p48,
- RPM_VREG_FREQ_1p37,
- RPM_VREG_FREQ_1p28,
- RPM_VREG_FREQ_1p20,
+enum rpm_vreg_power_mode_8960 {
+ RPM_VREG_POWER_MODE_8960_HYSTERETIC,
+ RPM_VREG_POWER_MODE_8960_PWM,
};
/**
* enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
*/
-enum rpm_vreg_id {
+enum rpm_vreg_id_8960 {
RPM_VREG_ID_PM8921_L1,
RPM_VREG_ID_PM8921_L2,
RPM_VREG_ID_PM8921_L3,
@@ -211,76 +176,12 @@
};
/* Minimum high power mode loads in uA. */
-#define RPM_VREG_LDO_50_HPM_MIN_LOAD 5000
-#define RPM_VREG_LDO_150_HPM_MIN_LOAD 10000
-#define RPM_VREG_LDO_300_HPM_MIN_LOAD 10000
-#define RPM_VREG_LDO_600_HPM_MIN_LOAD 10000
-#define RPM_VREG_LDO_1200_HPM_MIN_LOAD 10000
-#define RPM_VREG_SMPS_1500_HPM_MIN_LOAD 100000
-#define RPM_VREG_SMPS_2000_HPM_MIN_LOAD 100000
-
-/**
- * struct rpm_regulator_init_data - RPM regulator initialization data
- * @init_data: regulator constraints
- * @id: regulator id; from enum rpm_vreg_id
- * @sleep_selectable: flag which indicates that regulator should be accessable
- * by external private API and that spinlocks should be
- * used instead of mutex locks
- * @system_uA: current drawn from regulator not accounted for by any
- * regulator framework consumer
- * @pull_down_enable: 0 = no pulldown, 1 = pulldown when regulator disabled
- * @freq: enum value representing the switching frequency of an
- * SMPS or NCP
- * @pin_ctrl: pin control inputs to use for the regulator; should be
- * a combination of RPM_VREG_PIN_CTRL_* values
- * @pin_fn: action to perform when pin control pin(s) is/are active
- * @force_mode: used to specify a force mode which overrides the votes
- * of other RPM masters.
- * @default_uV: initial voltage to set the regulator to if enable is
- * called before set_voltage (e.g. when boot_on or
- * always_on is set).
- * @peak_uA: initial peak load requirement sent in RPM request; used
- * to determine initial mode.
- * @avg_uA: average load requirement sent in RPM request
- * @state: initial enable state sent in RPM request for switch or
- * NCP
- */
-struct rpm_regulator_init_data {
- struct regulator_init_data init_data;
- enum rpm_vreg_id id;
- int sleep_selectable;
- int system_uA;
- unsigned pull_down_enable;
- enum rpm_vreg_freq freq;
- unsigned pin_ctrl;
- enum rpm_vreg_pin_fn pin_fn;
- enum rpm_vreg_force_mode force_mode;
- enum rpm_vreg_power_mode power_mode;
- int default_uV;
- unsigned peak_uA;
- unsigned avg_uA;
- enum rpm_vreg_state state;
-};
-
-/**
- * struct rpm_regulator_platform_data - RPM regulator platform data
- */
-struct rpm_regulator_platform_data {
- struct rpm_regulator_init_data *init_data;
- int num_regulators;
-};
-
-/**
- * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
- */
-enum rpm_vreg_voter {
- RPM_VREG_VOTER_REG_FRAMEWORK, /* for internal use only */
- RPM_VREG_VOTER1, /* for use by the acpu-clock driver */
- RPM_VREG_VOTER2, /* for use by the acpu-clock driver */
- RPM_VREG_VOTER3, /* for use by other drivers */
- RPM_VREG_VOTER4, /* for use by the acpu-clock driver */
- RPM_VREG_VOTER5, /* for use by the acpu-clock driver */
- RPM_VREG_VOTER_COUNT,
-};
+#define RPM_VREG_8960_LDO_50_HPM_MIN_LOAD 5000
+#define RPM_VREG_8960_LDO_150_HPM_MIN_LOAD 10000
+#define RPM_VREG_8960_LDO_300_HPM_MIN_LOAD 10000
+#define RPM_VREG_8960_LDO_600_HPM_MIN_LOAD 10000
+#define RPM_VREG_8960_LDO_1200_HPM_MIN_LOAD 10000
+#define RPM_VREG_8960_SMPS_1500_HPM_MIN_LOAD 100000
+#define RPM_VREG_8960_SMPS_2000_HPM_MIN_LOAD 100000
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index 1187efc..9a19194 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -10,18 +10,128 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_H
-#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_H
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_H
#include <linux/regulator/machine.h>
#define RPM_REGULATOR_DEV_NAME "rpm-regulator"
-#if defined(CONFIG_ARCH_MSM8X60)
#include <mach/rpm-regulator-8660.h>
-#elif defined(CONFIG_ARCH_MSM8960)
#include <mach/rpm-regulator-8960.h>
-#endif
+
+/**
+ * enum rpm_vreg_version - supported RPM regulator versions
+ */
+enum rpm_vreg_version {
+ RPM_VREG_VERSION_8660,
+ RPM_VREG_VERSION_8960,
+ RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8960,
+};
+
+#define RPM_VREG_PIN_CTRL_NONE 0x00
+
+/**
+ * enum rpm_vreg_state - enable state for switch or NCP
+ */
+enum rpm_vreg_state {
+ RPM_VREG_STATE_OFF,
+ RPM_VREG_STATE_ON,
+};
+
+/**
+ * enum rpm_vreg_freq - switching frequency for SMPS or NCP
+ */
+enum rpm_vreg_freq {
+ RPM_VREG_FREQ_NONE,
+ RPM_VREG_FREQ_19p20,
+ RPM_VREG_FREQ_9p60,
+ RPM_VREG_FREQ_6p40,
+ RPM_VREG_FREQ_4p80,
+ RPM_VREG_FREQ_3p84,
+ RPM_VREG_FREQ_3p20,
+ RPM_VREG_FREQ_2p74,
+ RPM_VREG_FREQ_2p40,
+ RPM_VREG_FREQ_2p13,
+ RPM_VREG_FREQ_1p92,
+ RPM_VREG_FREQ_1p75,
+ RPM_VREG_FREQ_1p60,
+ RPM_VREG_FREQ_1p48,
+ RPM_VREG_FREQ_1p37,
+ RPM_VREG_FREQ_1p28,
+ RPM_VREG_FREQ_1p20,
+};
+
+/**
+ * struct rpm_regulator_init_data - RPM regulator initialization data
+ * @init_data: regulator constraints
+ * @id: regulator id; from enum rpm_vreg_id
+ * @sleep_selectable: flag which indicates that regulator should be accessable
+ * by external private API and that spinlocks should be
+ * used instead of mutex locks
+ * @system_uA: current drawn from regulator not accounted for by any
+ * regulator framework consumer
+ * @enable_time: time in us taken to enable a regulator to the maximum
+ * allowed voltage for the system. This is dependent upon
+ * the load and capacitance for a regulator on the board.
+ * @pull_down_enable: 0 = no pulldown, 1 = pulldown when regulator disabled
+ * @freq: enum value representing the switching frequency of an
+ * SMPS or NCP
+ * @pin_ctrl: pin control inputs to use for the regulator; should be
+ * a combination of RPM_VREG_PIN_CTRL_* values
+ * @pin_fn: action to perform when pin control pin(s) is/are active
+ * @force_mode: used to specify a force mode which overrides the votes
+ * of other RPM masters.
+ * @default_uV: initial voltage to set the regulator to if enable is
+ * called before set_voltage (e.g. when boot_on or
+ * always_on is set).
+ * @peak_uA: initial peak load requirement sent in RPM request; used
+ * to determine initial mode.
+ * @avg_uA: average load requirement sent in RPM request
+ * @state: initial enable state sent in RPM request for switch or
+ * NCP
+ */
+struct rpm_regulator_init_data {
+ struct regulator_init_data init_data;
+ int id;
+ int sleep_selectable;
+ int system_uA;
+ int enable_time;
+ unsigned pull_down_enable;
+ enum rpm_vreg_freq freq;
+ unsigned pin_ctrl;
+ int pin_fn;
+ int force_mode;
+ int power_mode;
+ int default_uV;
+ unsigned peak_uA;
+ unsigned avg_uA;
+ enum rpm_vreg_state state;
+};
+
+/**
+ * struct rpm_regulator_platform_data - RPM regulator platform data
+ */
+struct rpm_regulator_platform_data {
+ struct rpm_regulator_init_data *init_data;
+ int num_regulators;
+ enum rpm_vreg_version version;
+ int vreg_id_vdd_mem;
+ int vreg_id_vdd_dig;
+};
+
+/**
+ * enum rpm_vreg_voter - RPM regulator voter IDs for private APIs
+ */
+enum rpm_vreg_voter {
+ RPM_VREG_VOTER_REG_FRAMEWORK, /* for internal use only */
+ RPM_VREG_VOTER1, /* for use by the acpu-clock driver */
+ RPM_VREG_VOTER2, /* for use by the acpu-clock driver */
+ RPM_VREG_VOTER3, /* for use by other drivers */
+ RPM_VREG_VOTER4, /* for use by the acpu-clock driver */
+ RPM_VREG_VOTER5, /* for use by the acpu-clock driver */
+ RPM_VREG_VOTER_COUNT,
+};
/**
* rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
@@ -44,8 +154,8 @@
* 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 rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
+ int max_uV, int sleep_also);
/**
* rpm_vreg_set_frequency - sets the frequency of a switching regulator
@@ -54,6 +164,6 @@
*
* Returns 0 on success or errno.
*/
-int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq);
+int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq);
#endif
diff --git a/arch/arm/mach-msm/rpm-regulator-8660.c b/arch/arm/mach-msm/rpm-regulator-8660.c
new file mode 100644
index 0000000..6c4a9ad
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-8660.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "rpm-regulator-private.h"
+
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
+ .request_len = 2,
+ .mV = REQUEST_MEMBER(0, 0x00000FFF, 0),
+ .ip = REQUEST_MEMBER(0, 0x00FFF000, 12),
+ .fm = REQUEST_MEMBER(0, 0x03000000, 24),
+ .pc = REQUEST_MEMBER(0, 0x3C000000, 26),
+ .pf = REQUEST_MEMBER(0, 0xC0000000, 30),
+ .pd = REQUEST_MEMBER(1, 0x00000001, 0),
+ .ia = REQUEST_MEMBER(1, 0x00001FFE, 1),
+};
+
+static struct rpm_vreg_parts smps_parts = {
+ .request_len = 2,
+ .mV = REQUEST_MEMBER(0, 0x00000FFF, 0),
+ .ip = REQUEST_MEMBER(0, 0x00FFF000, 12),
+ .fm = REQUEST_MEMBER(0, 0x03000000, 24),
+ .pc = REQUEST_MEMBER(0, 0x3C000000, 26),
+ .pf = REQUEST_MEMBER(0, 0xC0000000, 30),
+ .pd = REQUEST_MEMBER(1, 0x00000001, 0),
+ .ia = REQUEST_MEMBER(1, 0x00001FFE, 1),
+ .freq = REQUEST_MEMBER(1, 0x001FE000, 13),
+ .freq_clk_src = REQUEST_MEMBER(1, 0x00600000, 21),
+};
+
+static struct rpm_vreg_parts switch_parts = {
+ .request_len = 1,
+ .enable_state = REQUEST_MEMBER(0, 0x00000001, 0),
+ .pd = REQUEST_MEMBER(0, 0x00000002, 1),
+ .pc = REQUEST_MEMBER(0, 0x0000003C, 2),
+ .pf = REQUEST_MEMBER(0, 0x000000C0, 6),
+ .hpm = REQUEST_MEMBER(0, 0x00000300, 8),
+};
+
+static struct rpm_vreg_parts ncp_parts = {
+ .request_len = 1,
+ .mV = REQUEST_MEMBER(0, 0x00000FFF, 0),
+ .enable_state = REQUEST_MEMBER(0, 0x00001000, 12),
+ .comp_mode = REQUEST_MEMBER(0, 0x00002000, 13),
+ .freq = REQUEST_MEMBER(0, 0x003FC000, 14),
+};
+
+/* Physically available PMIC regulator voltage setpoint ranges */
+static struct vreg_range pldo_ranges[] = {
+ VOLTAGE_RANGE( 750000, 1487500, 12500),
+ VOLTAGE_RANGE(1500000, 3075000, 25000),
+ VOLTAGE_RANGE(3100000, 4900000, 50000),
+};
+
+static struct vreg_range nldo_ranges[] = {
+ VOLTAGE_RANGE( 750000, 1537500, 12500),
+};
+
+static struct vreg_range smps_ranges[] = {
+ VOLTAGE_RANGE( 375000, 737500, 12500),
+ VOLTAGE_RANGE( 750000, 1487500, 12500),
+ VOLTAGE_RANGE(1500000, 3075000, 25000),
+};
+
+static struct vreg_range ftsmps_ranges[] = {
+ VOLTAGE_RANGE( 350000, 650000, 50000),
+ VOLTAGE_RANGE( 700000, 1400000, 12500),
+ VOLTAGE_RANGE(1500000, 3300000, 50000),
+};
+
+static struct vreg_range ncp_ranges[] = {
+ VOLTAGE_RANGE(1500000, 3050000, 50000),
+};
+
+static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
+static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
+static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
+
+static struct vreg_set_points *all_set_points[] = {
+ &pldo_set_points,
+ &nldo_set_points,
+ &smps_set_points,
+ &ftsmps_set_points,
+ &ncp_set_points,
+};
+
+#define LDO(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _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_8660_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .type = RPM_REGULATOR_TYPE_LDO, \
+ .set_points = &_ranges##_set_points, \
+ .part = &ldo_parts, \
+ .id = RPM_VREG_ID_##_vreg_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
+ }
+
+#define SMPS(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _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_8660_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .type = RPM_REGULATOR_TYPE_SMPS, \
+ .set_points = &_ranges##_set_points, \
+ .part = &smps_parts, \
+ .id = RPM_VREG_ID_##_vreg_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
+ }
+
+#define LVS(_vreg_id, _rpm_id, _name, _name_pc) \
+ [RPM_VREG_ID_##_vreg_id] = { \
+ .req = { \
+ [0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+ [1] = { .id = -1, }, \
+ }, \
+ .type = RPM_REGULATOR_TYPE_VS, \
+ .part = &switch_parts, \
+ .id = RPM_VREG_ID_##_vreg_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
+ }
+
+#define MVS(_vreg_id, _rpm_id, _name, _name_pc) \
+ LVS(_vreg_id, _rpm_id, _name, _name_pc)
+
+#define NCP(_vreg_id, _rpm_id, _name, _name_pc) \
+ [RPM_VREG_ID_##_vreg_id] = { \
+ .req = { \
+ [0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
+ [1] = { .id = MSM_RPM_ID_##_rpm_id##_1, }, \
+ }, \
+ .type = RPM_REGULATOR_TYPE_NCP, \
+ .set_points = &ncp_set_points, \
+ .part = &ncp_parts, \
+ .id = RPM_VREG_ID_##_vreg_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
+ }
+
+static struct vreg vregs[] = {
+ LDO(PM8058_L0, LDO0, "8058_l0", "8058_l0_pc", nldo, LDO_150),
+ LDO(PM8058_L1, LDO1, "8058_l1", "8058_l1_pc", nldo, LDO_300),
+ LDO(PM8058_L2, LDO2, "8058_l2", "8058_l2_pc", pldo, LDO_300),
+ LDO(PM8058_L3, LDO3, "8058_l3", "8058_l3_pc", pldo, LDO_150),
+ LDO(PM8058_L4, LDO4, "8058_l4", "8058_l4_pc", pldo, LDO_50),
+ LDO(PM8058_L5, LDO5, "8058_l5", "8058_l5_pc", pldo, LDO_300),
+ LDO(PM8058_L6, LDO6, "8058_l6", "8058_l6_pc", pldo, LDO_50),
+ LDO(PM8058_L7, LDO7, "8058_l7", "8058_l7_pc", pldo, LDO_50),
+ LDO(PM8058_L8, LDO8, "8058_l8", "8058_l8_pc", pldo, LDO_300),
+ LDO(PM8058_L9, LDO9, "8058_l9", "8058_l9_pc", pldo, LDO_300),
+ LDO(PM8058_L10, LDO10, "8058_l10", "8058_l10_pc", pldo, LDO_300),
+ LDO(PM8058_L11, LDO11, "8058_l11", "8058_l11_pc", pldo, LDO_150),
+ LDO(PM8058_L12, LDO12, "8058_l12", "8058_l12_pc", pldo, LDO_150),
+ LDO(PM8058_L13, LDO13, "8058_l13", "8058_l13_pc", pldo, LDO_300),
+ LDO(PM8058_L14, LDO14, "8058_l14", "8058_l14_pc", pldo, LDO_300),
+ LDO(PM8058_L15, LDO15, "8058_l15", "8058_l15_pc", pldo, LDO_300),
+ LDO(PM8058_L16, LDO16, "8058_l16", "8058_l16_pc", pldo, LDO_300),
+ LDO(PM8058_L17, LDO17, "8058_l17", "8058_l17_pc", pldo, LDO_150),
+ LDO(PM8058_L18, LDO18, "8058_l18", "8058_l18_pc", pldo, LDO_150),
+ LDO(PM8058_L19, LDO19, "8058_l19", "8058_l19_pc", pldo, LDO_150),
+ LDO(PM8058_L20, LDO20, "8058_l20", "8058_l20_pc", pldo, LDO_150),
+ LDO(PM8058_L21, LDO21, "8058_l21", "8058_l21_pc", nldo, LDO_150),
+ LDO(PM8058_L22, LDO22, "8058_l22", "8058_l22_pc", nldo, LDO_300),
+ LDO(PM8058_L23, LDO23, "8058_l23", "8058_l23_pc", nldo, LDO_300),
+ LDO(PM8058_L24, LDO24, "8058_l24", "8058_l24_pc", nldo, LDO_150),
+ LDO(PM8058_L25, LDO25, "8058_l25", "8058_l25_pc", nldo, LDO_150),
+
+ SMPS(PM8058_S0, SMPS0, "8058_s0", "8058_s0_pc", smps, SMPS),
+ SMPS(PM8058_S1, SMPS1, "8058_s1", "8058_s1_pc", smps, SMPS),
+ SMPS(PM8058_S2, SMPS2, "8058_s2", "8058_s2_pc", smps, SMPS),
+ SMPS(PM8058_S3, SMPS3, "8058_s3", "8058_s3_pc", smps, SMPS),
+ SMPS(PM8058_S4, SMPS4, "8058_s4", "8058_s4_pc", smps, SMPS),
+
+ LVS(PM8058_LVS0, LVS0, "8058_lvs0", "8058_lvs0_pc"),
+ LVS(PM8058_LVS1, LVS1, "8058_lvs1", "8058_lvs1_pc"),
+
+ NCP(PM8058_NCP, NCP, "8058_ncp", NULL),
+
+ LDO(PM8901_L0, LDO0B, "8901_l0", "8901_l0_pc", nldo, LDO_300),
+ LDO(PM8901_L1, LDO1B, "8901_l1", "8901_l1_pc", pldo, LDO_300),
+ LDO(PM8901_L2, LDO2B, "8901_l2", "8901_l2_pc", pldo, LDO_300),
+ LDO(PM8901_L3, LDO3B, "8901_l3", "8901_l3_pc", pldo, LDO_300),
+ LDO(PM8901_L4, LDO4B, "8901_l4", "8901_l4_pc", pldo, LDO_300),
+ LDO(PM8901_L5, LDO5B, "8901_l5", "8901_l5_pc", pldo, LDO_300),
+ LDO(PM8901_L6, LDO6B, "8901_l6", "8901_l6_pc", pldo, LDO_300),
+
+ SMPS(PM8901_S0, SMPS0B, "8901_s0", "8901_s0_pc", ftsmps, FTSMPS),
+ SMPS(PM8901_S1, SMPS1B, "8901_s1", "8901_s1_pc", ftsmps, FTSMPS),
+ SMPS(PM8901_S2, SMPS2B, "8901_s2", "8901_s2_pc", ftsmps, FTSMPS),
+ SMPS(PM8901_S3, SMPS3B, "8901_s3", "8901_s3_pc", ftsmps, FTSMPS),
+ SMPS(PM8901_S4, SMPS4B, "8901_s4", "8901_s4_pc", ftsmps, FTSMPS),
+
+ LVS(PM8901_LVS0, LVS0B, "8901_lvs0", "8901_lvs0_pc"),
+ LVS(PM8901_LVS1, LVS1B, "8901_lvs1", "8901_lvs1_pc"),
+ LVS(PM8901_LVS2, LVS2B, "8901_lvs2", "8901_lvs2_pc"),
+ LVS(PM8901_LVS3, LVS3B, "8901_lvs3", "8901_lvs3_pc"),
+
+ MVS(PM8901_MVS0, MVS, "8901_mvs0", "8901_mvs0_pc"),
+};
+
+static const char *pin_func_label[] = {
+ [RPM_VREG_PIN_FN_8660_ENABLE] = "on/off",
+ [RPM_VREG_PIN_FN_8660_MODE] = "HPM/LPM",
+ [RPM_VREG_PIN_FN_8660_SLEEP_B] = "sleep_b",
+ [RPM_VREG_PIN_FN_8660_NONE] = "none",
+};
+
+static const char *force_mode_label[] = {
+ [RPM_VREG_FORCE_MODE_8660_NONE] = "none",
+ [RPM_VREG_FORCE_MODE_8660_LPM] = "LPM",
+ [RPM_VREG_FORCE_MODE_8660_HPM] = "HPM",
+};
+
+static const char *pin_control_label[] = {
+ " A0",
+ " A1",
+ " D0",
+ " D1",
+};
+
+static int is_real_id(int id)
+{
+ return (id >= 0) && (id <= RPM_VREG_ID_8660_MAX_REAL);
+}
+
+static int pc_id_to_real_id(int id)
+{
+ int real_id;
+
+ if (id >= RPM_VREG_ID_PM8058_L0_PC && id <= RPM_VREG_ID_PM8058_LVS1_PC)
+ real_id = id - RPM_VREG_ID_PM8058_L0_PC + RPM_VREG_ID_PM8058_L0;
+ else
+ real_id = id - RPM_VREG_ID_PM8901_L0_PC + RPM_VREG_ID_PM8901_L0;
+
+ return real_id;
+}
+
+static struct vreg_config config = {
+ .vregs = vregs,
+ .vregs_len = ARRAY_SIZE(vregs),
+
+ .vreg_id_min = RPM_VREG_ID_PM8058_L0,
+ .vreg_id_max = RPM_VREG_ID_8660_MAX,
+
+ .pin_func_none = RPM_VREG_PIN_FN_8660_NONE,
+ .pin_func_sleep_b = RPM_VREG_PIN_FN_8660_SLEEP_B,
+
+ .mode_lpm = REGULATOR_MODE_IDLE,
+ .mode_hpm = REGULATOR_MODE_NORMAL,
+
+ .set_points = all_set_points,
+ .set_points_len = ARRAY_SIZE(all_set_points),
+
+ .label_pin_ctrl = pin_control_label,
+ .label_pin_ctrl_len = ARRAY_SIZE(pin_control_label),
+ .label_pin_func = pin_func_label,
+ .label_pin_func_len = ARRAY_SIZE(pin_func_label),
+ .label_force_mode = force_mode_label,
+ .label_force_mode_len = ARRAY_SIZE(force_mode_label),
+
+ .is_real_id = is_real_id,
+ .pc_id_to_real_id = pc_id_to_real_id,
+
+ .use_legacy_optimum_mode = 1,
+ .ia_follows_ip = 1,
+};
+
+struct vreg_config *get_config_8660(void)
+{
+ return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index 52cc77d..8726ed4 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -13,84 +13,10 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <mach/rpm.h>
-#include <mach/rpm-regulator.h>
-#include <mach/socinfo.h>
+#include "rpm-regulator-private.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_VDD_MEM_DIG = 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 REGULATOR_TYPE_LDO 0
-#define REGULATOR_TYPE_SMPS 1
-#define REGULATOR_TYPE_VS 2
-#define REGULATOR_TYPE_NCP 3
-
-#define MICRO_TO_MILLI(uV) ((uV) / 1000)
-#define MILLI_TO_MICRO(mV) ((mV) * 1000)
-
-#define SET_PART(_vreg, _part, _val) \
- _vreg->req[_vreg->part->_part.word].value \
- = (_vreg->req[_vreg->part->_part.word].value \
- & ~vreg->part->_part.mask) \
- | (((_val) << vreg->part->_part.shift) & vreg->part->_part.mask)
-
-#define GET_PART(_vreg, _part) \
- ((_vreg->req[_vreg->part->_part.word].value & vreg->part->_part.mask) \
- >> vreg->part->_part.shift)
-
-struct request_member {
- int word;
- unsigned int mask;
- int shift;
-};
-
-struct rpm_vreg_parts {
- struct request_member mV; /* voltage: used if voltage is in mV */
- struct request_member uV; /* voltage: used if voltage is in uV */
- struct request_member ip; /* peak current in mA */
- struct request_member pd; /* pull down enable */
- struct request_member ia; /* average current in mA */
- struct request_member fm; /* force mode */
- struct request_member pm; /* power mode */
- struct request_member pc; /* pin control */
- struct request_member pf; /* pin function */
- struct request_member enable_state; /* NCP and switch */
- struct request_member comp_mode; /* NCP */
- struct request_member freq; /* frequency: NCP and SMPS */
- struct request_member freq_clk_src; /* clock source: SMPS */
- struct request_member hpm; /* switch: control OCP ans SS */
- int request_len;
-};
-
-#define REQUEST_MEMBER(_word, _mask, _shift) \
- { \
- .word = _word, \
- .mask = _mask, \
- .shift = _shift, \
- }
-
-struct rpm_vreg_parts ldo_parts = {
+/* RPM regulator request formats */
+static struct rpm_vreg_parts ldo_parts = {
.request_len = 2,
.uV = REQUEST_MEMBER(0, 0x007FFFFF, 0),
.pd = REQUEST_MEMBER(0, 0x00800000, 23),
@@ -101,7 +27,7 @@
.fm = REQUEST_MEMBER(1, 0x00700000, 20),
};
-struct rpm_vreg_parts smps_parts = {
+static struct rpm_vreg_parts smps_parts = {
.request_len = 2,
.uV = REQUEST_MEMBER(0, 0x007FFFFF, 0),
.pd = REQUEST_MEMBER(0, 0x00800000, 23),
@@ -115,7 +41,7 @@
.freq_clk_src = REQUEST_MEMBER(1, 0x60000000, 29),
};
-struct rpm_vreg_parts switch_parts = {
+static struct rpm_vreg_parts switch_parts = {
.request_len = 1,
.enable_state = REQUEST_MEMBER(0, 0x00000001, 0),
.pd = REQUEST_MEMBER(0, 0x00000002, 1),
@@ -124,7 +50,7 @@
.hpm = REQUEST_MEMBER(0, 0x00000C00, 10),
};
-struct rpm_vreg_parts ncp_parts = {
+static struct rpm_vreg_parts ncp_parts = {
.request_len = 1,
.uV = REQUEST_MEMBER(0, 0x007FFFFF, 0),
.enable_state = REQUEST_MEMBER(0, 0x00800000, 23),
@@ -132,26 +58,7 @@
.freq = REQUEST_MEMBER(0, 0x3E000000, 25),
};
-struct vreg_range {
- int min_uV;
- int max_uV;
- int step_uV;
- unsigned n_voltages;
-};
-
-struct vreg_set_points {
- struct vreg_range *range;
- int count;
- unsigned n_voltages;
-};
-
-#define VOLTAGE_RANGE(_min_uV, _max_uV, _step_uV) \
- { \
- .min_uV = _min_uV, \
- .max_uV = _max_uV, \
- .step_uV = _step_uV, \
- }
-
+/* Physically available PMIC regulator voltage setpoint ranges */
static struct vreg_range pldo_ranges[] = {
VOLTAGE_RANGE( 750000, 1487500, 12500),
VOLTAGE_RANGE(1500000, 3075000, 25000),
@@ -183,12 +90,6 @@
VOLTAGE_RANGE(1500000, 3050000, 50000),
};
-#define SET_POINTS(_ranges) \
-{ \
- .range = _ranges, \
- .count = ARRAY_SIZE(_ranges), \
-};
-
static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
@@ -196,1217 +97,164 @@
static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
static struct vreg_set_points ncp_set_points = SET_POINTS(ncp_ranges);
-/*
- * 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))
-
-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_regulator_init_data pdata;
- struct regulator_dev *rdev;
- struct regulator_dev *rdev_pc;
- const char *name;
- struct vreg_set_points *set_points;
- struct rpm_vreg_parts *part;
- int type;
- enum rpm_vreg_id id;
- struct mutex pc_lock;
- int save_uV;
- int mode;
- bool is_enabled;
- bool is_enabled_pc;
- const int hpm_min_load;
- int active_min_uV_vote[RPM_VREG_VOTER_COUNT];
- int sleep_min_uV_vote[RPM_VREG_VOTER_COUNT];
-
+static struct vreg_set_points *all_set_points[] = {
+ &pldo_set_points,
+ &nldo_set_points,
+ &nldo1200_set_points,
+ &smps_set_points,
+ &ftsmps_set_points,
+ &ncp_set_points,
};
-#define LDO(_id, _ranges, _hpm_min_load) \
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
[RPM_VREG_ID_PM8921_##_id] = { \
.req = { \
[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
[1] = { .id = MSM_RPM_ID_PM8921_##_id##_1, }, \
}, \
- .hpm_min_load = RPM_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- .type = REGULATOR_TYPE_LDO, \
+ .hpm_min_load = RPM_VREG_8960_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .type = RPM_REGULATOR_TYPE_LDO, \
.set_points = &_ranges##_set_points, \
.part = &ldo_parts, \
.id = RPM_VREG_ID_PM8921_##_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
}
-#define SMPS(_id, _ranges, _hpm_min_load) \
+#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
[RPM_VREG_ID_PM8921_##_id] = { \
.req = { \
[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
[1] = { .id = MSM_RPM_ID_PM8921_##_id##_1, }, \
}, \
- .hpm_min_load = RPM_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
- .type = REGULATOR_TYPE_SMPS, \
+ .hpm_min_load = RPM_VREG_8960_##_hpm_min_load##_HPM_MIN_LOAD, \
+ .type = RPM_REGULATOR_TYPE_SMPS, \
.set_points = &_ranges##_set_points, \
.part = &smps_parts, \
.id = RPM_VREG_ID_PM8921_##_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
}
-#define LVS(_id) \
+#define LVS(_id, _name, _name_pc) \
[RPM_VREG_ID_PM8921_##_id] = { \
.req = { \
[0] = { .id = MSM_RPM_ID_PM8921_##_id, }, \
[1] = { .id = -1, }, \
}, \
- .type = REGULATOR_TYPE_VS, \
+ .type = RPM_REGULATOR_TYPE_VS, \
.part = &switch_parts, \
.id = RPM_VREG_ID_PM8921_##_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
}
-#define MVS(_vreg_id, _rpm_id) \
+#define MVS(_vreg_id, _name, _name_pc, _rpm_id) \
[RPM_VREG_ID_PM8921_##_vreg_id] = { \
.req = { \
[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
[1] = { .id = -1, }, \
}, \
- .type = REGULATOR_TYPE_VS, \
+ .type = RPM_REGULATOR_TYPE_VS, \
.part = &switch_parts, \
.id = RPM_VREG_ID_PM8921_##_vreg_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
}
-#define NCP(_id) \
+#define NCP(_id, _name, _name_pc) \
[RPM_VREG_ID_PM8921_##_id] = { \
.req = { \
[0] = { .id = MSM_RPM_ID_##_id##_0, }, \
[1] = { .id = MSM_RPM_ID_##_id##_1, }, \
}, \
- .type = REGULATOR_TYPE_NCP, \
+ .type = RPM_REGULATOR_TYPE_NCP, \
.set_points = &ncp_set_points, \
.part = &ncp_parts, \
.id = RPM_VREG_ID_PM8921_##_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
}
static struct vreg vregs[] = {
- LDO(L1, nldo, LDO_150),
- LDO(L2, nldo, LDO_150),
- LDO(L3 , pldo, LDO_150),
- LDO(L4, pldo, LDO_50),
- LDO(L5, pldo, LDO_300),
- LDO(L6, pldo, LDO_600),
- LDO(L7, pldo, LDO_150),
- LDO(L8, pldo, LDO_300),
- LDO(L9, pldo, LDO_300),
- LDO(L10, pldo, LDO_600),
- LDO(L11, pldo, LDO_150),
- LDO(L12, nldo, LDO_150),
- LDO(L14, pldo, LDO_50),
- LDO(L15, pldo, LDO_150),
- LDO(L16, pldo, LDO_300),
- LDO(L17, pldo, LDO_150),
- LDO(L18, nldo, LDO_150),
- LDO(L21, pldo, LDO_150),
- LDO(L22, pldo, LDO_150),
- LDO(L23, pldo, LDO_150),
- LDO(L24, nldo1200, LDO_1200),
- LDO(L25, nldo1200, LDO_1200),
- LDO(L26, nldo1200, LDO_1200),
- LDO(L27, nldo1200, LDO_1200),
- LDO(L28, nldo1200, LDO_1200),
- LDO(L29, pldo, LDO_150),
+ LDO(L1, "8921_l1", "8921_l1_pc", nldo, LDO_150),
+ LDO(L2, "8921_l2", "8921_l2_pc", nldo, LDO_150),
+ LDO(L3, "8921_l3", "8921_l3_pc", pldo, LDO_150),
+ LDO(L4, "8921_l4", "8921_l4_pc", pldo, LDO_50),
+ LDO(L5, "8921_l5", "8921_l5_pc", pldo, LDO_300),
+ LDO(L6, "8921_l6", "8921_l6_pc", pldo, LDO_600),
+ LDO(L7, "8921_l7", "8921_l7_pc", pldo, LDO_150),
+ LDO(L8, "8921_l8", "8921_l8_pc", pldo, LDO_300),
+ LDO(L9, "8921_l9", "8921_l9_pc", pldo, LDO_300),
+ LDO(L10, "8921_l10", "8921_l10_pc", pldo, LDO_600),
+ LDO(L11, "8921_l11", "8921_l11_pc", pldo, LDO_150),
+ LDO(L12, "8921_l12", "8921_l12_pc", nldo, LDO_150),
+ LDO(L14, "8921_l14", "8921_l14_pc", pldo, LDO_50),
+ LDO(L15, "8921_l15", "8921_l15_pc", pldo, LDO_150),
+ LDO(L16, "8921_l16", "8921_l16_pc", pldo, LDO_300),
+ LDO(L17, "8921_l17", "8921_l17_pc", pldo, LDO_150),
+ LDO(L18, "8921_l18", "8921_l18_pc", nldo, LDO_150),
+ LDO(L21, "8921_l21", "8921_l21_pc", pldo, LDO_150),
+ LDO(L22, "8921_l22", "8921_l22_pc", pldo, LDO_150),
+ LDO(L23, "8921_l23", "8921_l23_pc", pldo, LDO_150),
+ LDO(L24, "8921_l24", NULL, nldo1200, LDO_1200),
+ LDO(L25, "8921_l25", NULL, nldo1200, LDO_1200),
+ LDO(L26, "8921_l26", NULL, nldo1200, LDO_1200),
+ LDO(L27, "8921_l27", NULL, nldo1200, LDO_1200),
+ LDO(L28, "8921_l28", NULL, nldo1200, LDO_1200),
+ LDO(L29, "8921_l29", "8921_l29_pc", pldo, LDO_150),
- SMPS(S1, smps, SMPS_1500),
- SMPS(S2, smps, SMPS_1500),
- SMPS(S3, smps, SMPS_1500),
- SMPS(S4, smps, SMPS_1500),
- SMPS(S5, ftsmps, SMPS_2000),
- SMPS(S6, ftsmps, SMPS_2000),
- SMPS(S7, smps, SMPS_1500),
- SMPS(S8, smps, SMPS_1500),
+ SMPS(S1, "8921_s1", "8921_s1_pc", smps, SMPS_1500),
+ SMPS(S2, "8921_s2", "8921_s2_pc", smps, SMPS_1500),
+ SMPS(S3, "8921_s3", "8921_s3_pc", smps, SMPS_1500),
+ SMPS(S4, "8921_s4", "8921_s4_pc", smps, SMPS_1500),
+ SMPS(S5, "8921_s5", NULL, ftsmps, SMPS_2000),
+ SMPS(S6, "8921_s6", NULL, ftsmps, SMPS_2000),
+ SMPS(S7, "8921_s7", "8921_s7_pc", smps, SMPS_1500),
+ SMPS(S8, "8921_s8", "8921_s8_pc", smps, SMPS_1500),
- LVS(LVS1),
- LVS(LVS2),
- LVS(LVS3),
- LVS(LVS4),
- LVS(LVS5),
- LVS(LVS6),
- LVS(LVS7),
- MVS(USB_OTG, USB_OTG_SWITCH),
- MVS(HDMI_MVS, HDMI_SWITCH),
+ LVS(LVS1, "8921_lvs1", "8921_lvs1_pc"),
+ LVS(LVS2, "8921_lvs2", NULL),
+ LVS(LVS3, "8921_lvs3", "8921_lvs3_pc"),
+ LVS(LVS4, "8921_lvs4", "8921_lvs4_pc"),
+ LVS(LVS5, "8921_lvs5", "8921_lvs5_pc"),
+ LVS(LVS6, "8921_lvs6", "8921_lvs6_pc"),
+ LVS(LVS7, "8921_lvs7", "8921_lvs7_pc"),
+ MVS(USB_OTG, "8921_usb_otg", NULL, USB_OTG_SWITCH),
+ MVS(HDMI_MVS, "8921_hdmi_mvs", NULL, HDMI_SWITCH),
- NCP(NCP),
+ NCP(NCP, "8921_ncp", NULL),
};
-#define vreg_err(vreg, fmt, ...) \
- pr_err("%s: " fmt, vreg->name, ##__VA_ARGS__)
-
-#define VREG_ID_IS_VDD_MEM_OR_DIG(id) \
- ((id == RPM_VREG_ID_PM8921_L24) || (id == RPM_VREG_ID_PM8921_S3))
-
-const char *pin_func_label[] = {
- [RPM_VREG_PIN_FN_DONT_CARE] = "don't care",
- [RPM_VREG_PIN_FN_ENABLE] = "on/off",
- [RPM_VREG_PIN_FN_MODE] = "HPM/LPM",
- [RPM_VREG_PIN_FN_SLEEP_B] = "sleep_b",
- [RPM_VREG_PIN_FN_NONE] = "none",
+static const char *pin_func_label[] = {
+ [RPM_VREG_PIN_FN_8960_DONT_CARE] = "don't care",
+ [RPM_VREG_PIN_FN_8960_ENABLE] = "on/off",
+ [RPM_VREG_PIN_FN_8960_MODE] = "HPM/LPM",
+ [RPM_VREG_PIN_FN_8960_SLEEP_B] = "sleep_b",
+ [RPM_VREG_PIN_FN_8960_NONE] = "none",
};
-const char *force_mode_label[] = {
- [RPM_VREG_FORCE_MODE_NONE] = "none",
- [RPM_VREG_FORCE_MODE_LPM] = "LPM",
- [RPM_VREG_FORCE_MODE_AUTO] = "auto",
- [RPM_VREG_FORCE_MODE_HPM] = "HPM",
- [RPM_VREG_FORCE_MODE_BYPASS] = "BYP",
+static const char *force_mode_label[] = {
+ [RPM_VREG_FORCE_MODE_8960_NONE] = "none",
+ [RPM_VREG_FORCE_MODE_8960_LPM] = "LPM",
+ [RPM_VREG_FORCE_MODE_8960_AUTO] = "auto",
+ [RPM_VREG_FORCE_MODE_8960_HPM] = "HPM",
+ [RPM_VREG_FORCE_MODE_8960_BYPASS] = "BYP",
};
-const char *power_mode_label[] = {
- [RPM_VREG_POWER_MODE_HYSTERETIC] = "HYS",
- [RPM_VREG_POWER_MODE_PWM] = "PWM",
+static const char *power_mode_label[] = {
+ [RPM_VREG_POWER_MODE_8960_HYSTERETIC] = "HYS",
+ [RPM_VREG_POWER_MODE_8960_PWM] = "PWM",
};
-static void rpm_regulator_req(struct vreg *vreg, int set)
-{
- int uV, ip, fm, pm, pc, pf, pd, ia, freq, clk, state, hpm, comp_mode;
- const char *pf_label = "", *fm_label = "", *pc_total = "";
- const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
- const char *pm_label = "";
-
- /* Suppress VDD_MEM and VDD_DIG printing. */
- if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
- && VREG_ID_IS_VDD_MEM_OR_DIG(vreg->id))
- return;
-
- if (vreg->part->uV.mask)
- uV = GET_PART(vreg, uV);
- else
- uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
-
- ip = GET_PART(vreg, ip);
- fm = GET_PART(vreg, fm);
- pm = GET_PART(vreg, pm);
- pc = GET_PART(vreg, pc);
- pf = GET_PART(vreg, pf);
- pd = GET_PART(vreg, pd);
- ia = GET_PART(vreg, ia);
- freq = GET_PART(vreg, freq);
- clk = GET_PART(vreg, freq_clk_src);
- state = GET_PART(vreg, enable_state);
- hpm = GET_PART(vreg, hpm);
- comp_mode = GET_PART(vreg, comp_mode);
-
- if (pf >= 0 && pf < ARRAY_SIZE(pin_func_label))
- pf_label = pin_func_label[pf];
-
- if (fm >= 0 && fm < ARRAY_SIZE(force_mode_label))
- fm_label = force_mode_label[fm];
-
- if (pm >= 0 && pm < ARRAY_SIZE(power_mode_label))
- pm_label = power_mode_label[pm];
-
- if (pc & RPM_VREG_PIN_CTRL_EN0)
- pc_en0 = " D1";
- if (pc & RPM_VREG_PIN_CTRL_EN1)
- pc_en1 = " A0";
- if (pc & RPM_VREG_PIN_CTRL_EN2)
- pc_en2 = " A1";
- if (pc & RPM_VREG_PIN_CTRL_EN3)
- pc_en3 = " A2";
- if (pc == RPM_VREG_PIN_CTRL_NONE)
- pc_total = " none";
-
- switch (vreg->type) {
- case REGULATOR_TYPE_LDO:
- pr_info("%s %-9s: s=%c, v=%7d uV, 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->name,
- (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), uV, ip,
- fm_label, fm, pc_en0, pc_en1, pc_en2, pc_en3, pc_total,
- pc, pf_label, pf, (pd == 1 ? "Y" : "N"), pd, ia,
- vreg->req[0].id, vreg->req[0].value,
- vreg->req[1].id, vreg->req[1].value);
- break;
- case REGULATOR_TYPE_SMPS:
- pr_info("%s %-9s: s=%c, v=%7d uV, ip=%4d mA, fm=%s (%d), "
- "pc=%s%s%s%s%s (%d), pf=%s (%d), pd=%s (%d), "
- "ia=%4d mA, freq=%2d, pm=%s (%d), clk_src=%d; "
- "req[0]={%d, 0x%08X}, req[1]={%d, 0x%08X}\n",
- (set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
- vreg->name,
- (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'), uV, ip,
- fm_label, fm, pc_en0, pc_en1, pc_en2, pc_en3, pc_total,
- pc, pf_label, pf, (pd == 1 ? "Y" : "N"), pd, ia, freq,
- pm_label, pm, clk, vreg->req[0].id, vreg->req[0].value,
- vreg->req[1].id, vreg->req[1].value);
- break;
- case REGULATOR_TYPE_VS:
- pr_info("%s %-9s: s=%c, state=%s (%d), pd=%s (%d), "
- "pc =%s%s%s%s%s (%d), pf=%s (%d), hpm=%d; "
- "req[0]={%d, 0x%08X}\n",
- (set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
- vreg->name, (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
- (state == 1 ? "on" : "off"), state,
- (pd == 1 ? "Y" : "N"), pd, pc_en0, pc_en1, pc_en2,
- pc_en3, pc_total, pc, pf_label, pf, hpm,
- vreg->req[0].id, vreg->req[0].value);
- break;
- case REGULATOR_TYPE_NCP:
- pr_info("%s %-9s: s=%c, v=-%7d uV, state=%s (%d), freq=%2d, "
- "comp=%d; req[0]={%d, 0x%08X}\n",
- (set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
- vreg->name, (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'),
- uV, (state == 1 ? "on" : "off"), state, freq, comp_mode,
- vreg->req[0].id, vreg->req[0].value);
- break;
- }
-}
-
-static void rpm_regulator_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
- int set, int voter_uV, int aggregate_uV)
-{
- /* Suppress VDD_MEM and VDD_DIG printing. */
- if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
- && VREG_ID_IS_VDD_MEM_OR_DIG(vreg->id))
- return;
-
- pr_info("vote received %-9s: voter=%d, set=%c, v_voter=%7d uV, "
- "v_aggregate=%7d uV\n", vreg->name, voter,
- (set == 0 ? 'A' : 'S'), voter_uV, aggregate_uV);
-}
-
-static void rpm_regulator_duplicate(struct vreg *vreg, int set, int cnt)
-{
- /* Suppress VDD_MEM and VDD_DIG printing. */
- if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
- && VREG_ID_IS_VDD_MEM_OR_DIG(vreg->id))
- return;
-
- if (cnt == 2)
- pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}, "
- "req[1]={%d, 0x%08X}\n", vreg->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("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}\n",
- vreg->name, (set == 0 ? 'A' : 'S'),
- vreg->req[0].id, vreg->req[0].value);
-}
-
-/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(pm8921_noirq_lock);
-
-static int voltage_from_req(struct vreg *vreg)
-{
- int uV = 0;
-
- if (vreg->part->uV.mask)
- uV = GET_PART(vreg, uV);
- else
- uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
-
- return uV;
-}
-
-static void voltage_to_req(int uV, struct vreg *vreg)
-{
- if (vreg->part->uV.mask)
- SET_PART(vreg, uV, uV);
- else
- SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
-}
-
-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_uV_vote = 0;
- unsigned prev0, prev1;
- int *min_uV_vote;
- int i;
-
- if (set == MSM_RPM_CTX_SET_0) {
- min_uV_vote = vreg->active_min_uV_vote;
- prev_req = vreg->prev_active_req;
- } else {
- min_uV_vote = vreg->sleep_min_uV_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_uV_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_uV_vote = max(max_uV_vote, min_uV_vote[i]);
- voltage_to_req(max_uV_vote, vreg);
-
- if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_VOTE)
- rpm_regulator_vote(vreg, voter, set, min_uV_vote[voter],
- max_uV_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;
-
- vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
- "set=%s, id=%d, rc=%d\n",
- (set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
- vreg->req[0].id, rc);
- } else {
- /* Only save if nonzero and active set. */
- if (max_uV_vote && (set == MSM_RPM_CTX_SET_0))
- vreg->save_uV = max_uV_vote;
- if (msm_rpm_vreg_debug_mask
- & MSM_RPM_VREG_DEBUG_REQUEST)
- rpm_regulator_req(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) {
- rpm_regulator_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 int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
- unsigned long flags;
- int rc;
-
- if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
- return -EINVAL;
-
- spin_lock_irqsave(&pm8921_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.
- */
- if (vreg->part->uV.mask) {
- s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
- s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
- } else {
- s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
- s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
- }
-
- rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
- s_mask[0], s_val[0], s_mask[1], s_val[1],
- cnt, update_voltage);
- }
-
- rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
- mask1, val1, cnt, update_voltage);
-
- spin_unlock_irqrestore(&pm8921_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)
-{
- unsigned int mask[2] = {0}, val[2] = {0};
- struct vreg_range *range;
- struct vreg *vreg;
- int uV = min_uV;
- int lim_min_uV, lim_max_uV, i, rc;
-
- if (vreg_id < 0 || vreg_id > RPM_VREG_ID_PM8921_MAX_REAL) {
- pr_err("invalid regulator id=%d\n", vreg_id);
- return -EINVAL;
- }
-
- /*
- * TODO: make this function a no-op for 8064 so that it can be called by
- * consumers on 8064 before RPM capabilities are present. (needed for
- * acpuclock driver)
- */
- if (cpu_is_apq8064())
- return 0;
-
- vreg = &vregs[vreg_id];
- range = &vreg->set_points->range[0];
-
- if (!vreg->pdata.sleep_selectable) {
- vreg_err(vreg, "regulator is not marked sleep selectable\n");
- return -EINVAL;
- }
-
- /*
- * Check if request voltage is outside of allowed range. The regulator
- * core has already checked that constraint range is inside of the
- * physically allowed range.
- */
- lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
- lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
-
- if (uV < lim_min_uV && max_uV >= lim_min_uV)
- uV = lim_min_uV;
-
- if (uV < lim_min_uV || uV > lim_max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside allowed v=[%d, %d]\n",
- min_uV, max_uV, lim_min_uV, lim_max_uV);
- return -EINVAL;
- }
-
- /* Find the range which uV is inside of. */
- for (i = vreg->set_points->count - 1; i > 0; i--) {
- if (uV > vreg->set_points->range[i - 1].max_uV) {
- range = &vreg->set_points->range[i];
- break;
- }
- }
-
- /*
- * Force uV to be an allowed set point and apply a ceiling function
- * to non-set point values.
- */
- uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
- uV = uV * range->step_uV + range->min_uV;
-
- if (vreg->part->uV.mask) {
- val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
- mask[vreg->part->uV.word] = vreg->part->uV.mask;
- } else {
- val[vreg->part->mV.word]
- = MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
- mask[vreg->part->mV.word] = vreg->part->mV.mask;
- }
-
- rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
- val[1], vreg->part->request_len, 1);
- if (rc)
- vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(rpm_vreg_set_voltage);
-
-/**
- * rpm_vreg_set_frequency - sets the frequency of a switching regulator
- * @vreg: ID for regulator
- * @freq: enum corresponding to desired frequency
- *
- * Returns 0 on success or errno.
- */
-int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq)
-{
- unsigned int mask[2] = {0}, val[2] = {0};
- struct vreg *vreg;
- int rc;
-
- if (vreg_id < 0 || vreg_id > RPM_VREG_ID_PM8921_MAX_REAL) {
- pr_err("invalid regulator id=%d\n", vreg_id);
- return -EINVAL;
- }
-
- /*
- * TODO: make this function a no-op for 8064 so that it can be called by
- * consumers on 8064 before RPM capabilities are present.
- */
- if (cpu_is_apq8064())
- return 0;
-
- vreg = &vregs[vreg_id];
-
- if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
- vreg_err(vreg, "invalid frequency=%d\n", freq);
- return -EINVAL;
- }
- if (!vreg->pdata.sleep_selectable) {
- vreg_err(vreg, "regulator is not marked sleep selectable\n");
- return -EINVAL;
- }
- if (!vreg->part->freq.mask) {
- vreg_err(vreg, "frequency not supported\n");
- return -EINVAL;
- }
-
- val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
- mask[vreg->part->freq.word] = vreg->part->freq.mask;
-
- rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
- val[0], mask[1], val[1], vreg->part->request_len, 0);
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
-
-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_peak_load(struct vreg *vreg, unsigned load_uA)
-{
- unsigned load_max
- = MILLI_TO_MICRO(vreg->part->ip.mask >> vreg->part->ip.shift);
-
- return (load_uA > load_max ? load_max : load_uA);
-}
-
-static inline unsigned saturate_avg_load(struct vreg *vreg, unsigned load_uA)
-{
- unsigned load_max
- = MILLI_TO_MICRO(vreg->part->ia.mask >> vreg->part->ia.shift);
- return (load_uA > load_max ? load_max : 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(&pm8921_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(&pm8921_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)
- rpm_regulator_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;
-
- vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n",
- vreg->req[0].id, rc);
- } else {
- if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST)
- rpm_regulator_req(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 vreg_is_enabled(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- int enabled;
-
- mutex_lock(&vreg->pc_lock);
- enabled = vreg->is_enabled;
- mutex_unlock(&vreg->pc_lock);
-
- return enabled;
-}
-
-static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
-{
- switch (vreg->type) {
- case REGULATOR_TYPE_LDO:
- case REGULATOR_TYPE_SMPS:
- /* Enable by setting a voltage. */
- if (vreg->part->uV.mask) {
- val[vreg->part->uV.word]
- |= vreg->save_uV << vreg->part->uV.shift;
- mask[vreg->part->uV.word] |= vreg->part->uV.mask;
- } else {
- val[vreg->part->mV.word]
- |= MICRO_TO_MILLI(vreg->save_uV)
- << vreg->part->mV.shift;
- mask[vreg->part->mV.word] |= vreg->part->mV.mask;
- }
- break;
- case REGULATOR_TYPE_VS:
- case REGULATOR_TYPE_NCP:
- /* Enable by setting enable_state. */
- val[vreg->part->enable_state.word]
- |= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
- mask[vreg->part->enable_state.word]
- |= vreg->part->enable_state.mask;
- }
-}
-
-static int vreg_enable(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mask[2] = {0}, val[2] = {0};
- int rc = 0;
-
- set_enable(vreg, mask, val);
-
- mutex_lock(&vreg->pc_lock);
-
- rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
- vreg->part->request_len);
- if (!rc)
- vreg->is_enabled = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static void set_disable(struct vreg *vreg, unsigned int *mask,
- unsigned int *val)
-{
- switch (vreg->type) {
- case REGULATOR_TYPE_LDO:
- case REGULATOR_TYPE_SMPS:
- /* Disable by setting a voltage of 0 uV. */
- if (vreg->part->uV.mask) {
- val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
- mask[vreg->part->uV.word] |= vreg->part->uV.mask;
- } else {
- val[vreg->part->mV.word] |= 0 << vreg->part->mV.shift;
- mask[vreg->part->mV.word] |= vreg->part->mV.mask;
- }
- break;
- case REGULATOR_TYPE_VS:
- case REGULATOR_TYPE_NCP:
- /* Disable by setting enable_state. */
- val[vreg->part->enable_state.word]
- |= RPM_VREG_STATE_OFF << vreg->part->enable_state.shift;
- mask[vreg->part->enable_state.word]
- |= vreg->part->enable_state.mask;
- }
-}
-
-static int vreg_disable(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mask[2] = {0}, val[2] = {0};
- int rc = 0;
-
- set_disable(vreg, mask, val);
-
- mutex_lock(&vreg->pc_lock);
-
- /* Only disable if pin control is not in use. */
- if (!vreg->is_enabled_pc)
- rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
- vreg->part->request_len);
-
- if (!rc)
- vreg->is_enabled = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
- unsigned *selector)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- struct vreg_range *range = &vreg->set_points->range[0];
- unsigned int mask[2] = {0}, val[2] = {0};
- int rc = 0, uV = min_uV;
- int lim_min_uV, lim_max_uV, i;
-
- /* Check if request voltage is outside of physically settable range. */
- lim_min_uV = vreg->set_points->range[0].min_uV;
- lim_max_uV =
- vreg->set_points->range[vreg->set_points->count - 1].max_uV;
-
- if (uV < lim_min_uV && max_uV >= lim_min_uV)
- uV = lim_min_uV;
-
- if (uV < lim_min_uV || uV > lim_max_uV) {
- vreg_err(vreg,
- "request v=[%d, %d] is outside possible v=[%d, %d]\n",
- min_uV, max_uV, lim_min_uV, lim_max_uV);
- return -EINVAL;
- }
-
- /* Find the range which uV is inside of. */
- for (i = vreg->set_points->count - 1; i > 0; i--) {
- if (uV > vreg->set_points->range[i - 1].max_uV) {
- range = &vreg->set_points->range[i];
- break;
- }
- }
-
- /*
- * Force uV to be an allowed set point and apply a ceiling function
- * to non-set point values.
- */
- uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
- uV = uV * range->step_uV + range->min_uV;
-
- if (vreg->part->uV.mask) {
- val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
- mask[vreg->part->uV.word] = vreg->part->uV.mask;
- } else {
- val[vreg->part->mV.word]
- = MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
- mask[vreg->part->mV.word] = vreg->part->mV.mask;
- }
-
- mutex_lock(&vreg->pc_lock);
-
- /*
- * Only send a request for a new voltage if the regulator is currently
- * enabled. This will ensure that LDO and SMPS regulators are not
- * inadvertently turned on because voltage > 0 is equivalent to
- * enabling. For NCP, this just removes unnecessary RPM requests.
- */
- if (vreg->is_enabled) {
- rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
- vreg->part->request_len);
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
- } else if (vreg->type == REGULATOR_TYPE_NCP) {
- /* Regulator is disabled; store but don't send new request. */
- rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
- }
-
- if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
- vreg->save_uV = uV;
-
- mutex_unlock(&vreg->pc_lock);
-
- return rc;
-}
-
-static int vreg_get_voltage(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
-
- return vreg->save_uV;
-}
-
-static int vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- int uV = 0;
- int i;
-
- if (!vreg->set_points) {
- vreg_err(vreg, "no voltages available\n");
- return -EINVAL;
- }
-
- if (selector >= vreg->set_points->n_voltages)
- return 0;
-
- for (i = 0; i < vreg->set_points->count; i++) {
- if (selector < vreg->set_points->range[i].n_voltages) {
- uV = selector * vreg->set_points->range[i].step_uV
- + vreg->set_points->range[i].min_uV;
- break;
- } else {
- selector -= vreg->set_points->range[i].n_voltages;
- }
- }
-
- return uV;
-}
-
-static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mask[2] = {0}, val[2] = {0};
- int rc = 0;
- int peak_uA;
-
- mutex_lock(&vreg->pc_lock);
-
- peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
- & vreg->part->ip.mask) >> vreg->part->ip.shift);
-
- switch (mode) {
- case REGULATOR_MODE_NORMAL:
- /* Make sure that request currents are in HPM range. */
- if (peak_uA < vreg_hpm_min_uA(vreg)) {
- val[vreg->part->ip.word]
- = MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
- << vreg->part->ip.shift;
- mask[vreg->part->ip.word] = vreg->part->ip.mask;
- }
- break;
- case REGULATOR_MODE_IDLE:
- /* Make sure that request currents are in LPM range. */
- if (peak_uA > vreg_lpm_max_uA(vreg)) {
- val[vreg->part->ip.word]
- = MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
- << vreg->part->ip.shift;
- mask[vreg->part->ip.word] = vreg->part->ip.mask;
- }
- break;
- default:
- vreg_err(vreg, "invalid mode: %u\n", mode);
- mutex_unlock(&vreg->pc_lock);
- return -EINVAL;
- }
-
- if (vreg->is_enabled) {
- rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
- vreg->part->request_len);
- } else {
- /* Regulator is disabled; store but don't send new request. */
- rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
- }
-
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
- else
- vreg->mode = mode;
-
- mutex_unlock(&vreg->pc_lock);
-
- return rc;
-}
-
-static unsigned int vreg_get_mode(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
-
- return vreg->mode;
-}
-
-static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
- int input_uV, int output_uV, int load_uA)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mode;
-
- load_uA += vreg->pdata.system_uA;
-
- mutex_lock(&vreg->pc_lock);
- SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
- mutex_unlock(&vreg->pc_lock);
-
- if (load_uA >= vreg->hpm_min_load)
- mode = REGULATOR_MODE_NORMAL;
- else
- mode = REGULATOR_MODE_IDLE;
-
- return mode;
-}
-
-/*
- * Returns the logical pin control enable state because the pin control options
- * present in the hardware out of restart could be different from those desired
- * by the consumer.
- */
-static int vreg_pin_control_is_enabled(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
-
- return vreg->is_enabled_pc;
-}
-
-static int vreg_pin_control_enable(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mask[2] = {0}, val[2] = {0};
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- val[vreg->part->pc.word]
- |= vreg->pdata.pin_ctrl << vreg->part->pc.shift;
- mask[vreg->part->pc.word] |= vreg->part->pc.mask;
-
- val[vreg->part->pf.word] |= vreg->pdata.pin_fn << vreg->part->pf.shift;
- mask[vreg->part->pf.word] |= vreg->part->pf.mask;
-
- if (!vreg->is_enabled)
- set_enable(vreg, mask, val);
-
- rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
- vreg->part->request_len);
-
- if (!rc)
- vreg->is_enabled_pc = true;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
- return rc;
-}
-
-static int vreg_pin_control_disable(struct regulator_dev *rdev)
-{
- struct vreg *vreg = rdev_get_drvdata(rdev);
- unsigned int mask[2] = {0}, val[2] = {0};
- enum rpm_vreg_pin_fn pin_fn;
- int rc;
-
- mutex_lock(&vreg->pc_lock);
-
- val[vreg->part->pc.word]
- |= RPM_VREG_PIN_CTRL_NONE << vreg->part->pc.shift;
- mask[vreg->part->pc.word] |= vreg->part->pc.mask;
-
- pin_fn = RPM_VREG_PIN_FN_NONE;
- if (vreg->pdata.pin_fn == RPM_VREG_PIN_FN_SLEEP_B)
- pin_fn = RPM_VREG_PIN_FN_SLEEP_B;
- val[vreg->part->pf.word] |= pin_fn << vreg->part->pf.shift;
- mask[vreg->part->pf.word] |= vreg->part->pf.mask;
-
- if (!vreg->is_enabled)
- set_disable(vreg, mask, val);
-
- rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
- vreg->part->request_len);
-
- if (!rc)
- vreg->is_enabled_pc = false;
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-
- return rc;
-}
-
-/* Real regulator operations. */
-static struct regulator_ops ldo_ops = {
- .enable = vreg_enable,
- .disable = vreg_disable,
- .is_enabled = vreg_is_enabled,
- .set_voltage = vreg_set_voltage,
- .get_voltage = vreg_get_voltage,
- .list_voltage = vreg_list_voltage,
- .set_mode = vreg_set_mode,
- .get_mode = vreg_get_mode,
- .get_optimum_mode = vreg_get_optimum_mode,
+static const char *pin_control_label[] = {
+ " D1",
+ " A0",
+ " A1",
+ " A2",
};
-static struct regulator_ops smps_ops = {
- .enable = vreg_enable,
- .disable = vreg_disable,
- .is_enabled = vreg_is_enabled,
- .set_voltage = vreg_set_voltage,
- .get_voltage = vreg_get_voltage,
- .list_voltage = vreg_list_voltage,
- .set_mode = vreg_set_mode,
- .get_mode = vreg_get_mode,
- .get_optimum_mode = vreg_get_optimum_mode,
-};
-
-static struct regulator_ops switch_ops = {
- .enable = vreg_enable,
- .disable = vreg_disable,
- .is_enabled = vreg_is_enabled,
-};
-
-static struct regulator_ops ncp_ops = {
- .enable = vreg_enable,
- .disable = vreg_disable,
- .is_enabled = vreg_is_enabled,
- .set_voltage = vreg_set_voltage,
- .get_voltage = vreg_get_voltage,
- .list_voltage = vreg_list_voltage,
-};
-
-/* Pin control regulator operations. */
-static struct regulator_ops pin_control_ops = {
- .enable = vreg_pin_control_enable,
- .disable = vreg_pin_control_disable,
- .is_enabled = vreg_pin_control_is_enabled,
-};
-
-#define VREG_DESC(_id, _name, _ops) \
- [RPM_VREG_ID_PM8921_##_id] = { \
- .id = RPM_VREG_ID_PM8921_##_id, \
- .name = _name, \
- .ops = _ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- }
-
-static struct regulator_desc vreg_description[] = {
- VREG_DESC(L1, "8921_l1", &ldo_ops),
- VREG_DESC(L2, "8921_l2", &ldo_ops),
- VREG_DESC(L3, "8921_l3", &ldo_ops),
- VREG_DESC(L4, "8921_l4", &ldo_ops),
- VREG_DESC(L5, "8921_l5", &ldo_ops),
- VREG_DESC(L6, "8921_l6", &ldo_ops),
- VREG_DESC(L7, "8921_l7", &ldo_ops),
- VREG_DESC(L8, "8921_l8", &ldo_ops),
- VREG_DESC(L9, "8921_l9", &ldo_ops),
- VREG_DESC(L10, "8921_l10", &ldo_ops),
- VREG_DESC(L11, "8921_l11", &ldo_ops),
- VREG_DESC(L12, "8921_l12", &ldo_ops),
- VREG_DESC(L14, "8921_l14", &ldo_ops),
- VREG_DESC(L15, "8921_l15", &ldo_ops),
- VREG_DESC(L16, "8921_l16", &ldo_ops),
- VREG_DESC(L17, "8921_l17", &ldo_ops),
- VREG_DESC(L18, "8921_l18", &ldo_ops),
- VREG_DESC(L21, "8921_l21", &ldo_ops),
- VREG_DESC(L22, "8921_l22", &ldo_ops),
- VREG_DESC(L23, "8921_l23", &ldo_ops),
- VREG_DESC(L24, "8921_l24", &ldo_ops),
- VREG_DESC(L25, "8921_l25", &ldo_ops),
- VREG_DESC(L26, "8921_l26", &ldo_ops),
- VREG_DESC(L27, "8921_l27", &ldo_ops),
- VREG_DESC(L28, "8921_l28", &ldo_ops),
- VREG_DESC(L29, "8921_l29", &ldo_ops),
-
- VREG_DESC(S1, "8921_s1", &smps_ops),
- VREG_DESC(S2, "8921_s2", &smps_ops),
- VREG_DESC(S3, "8921_s3", &smps_ops),
- VREG_DESC(S4, "8921_s4", &smps_ops),
- VREG_DESC(S5, "8921_s5", &smps_ops),
- VREG_DESC(S6, "8921_s6", &smps_ops),
- VREG_DESC(S7, "8921_s7", &smps_ops),
- VREG_DESC(S8, "8921_s8", &smps_ops),
-
- VREG_DESC(LVS1, "8921_lvs1", &switch_ops),
- VREG_DESC(LVS2, "8921_lvs2", &switch_ops),
- VREG_DESC(LVS3, "8921_lvs3", &switch_ops),
- VREG_DESC(LVS4, "8921_lvs4", &switch_ops),
- VREG_DESC(LVS5, "8921_lvs5", &switch_ops),
- VREG_DESC(LVS6, "8921_lvs6", &switch_ops),
- VREG_DESC(LVS7, "8921_lvs7", &switch_ops),
-
- VREG_DESC(USB_OTG, "8921_usb_otg", &switch_ops),
- VREG_DESC(HDMI_MVS, "8921_hdmi_mvs", &switch_ops),
- VREG_DESC(NCP, "8921_ncp", &ncp_ops),
-
- VREG_DESC(L1_PC, "8921_l1_pc", &pin_control_ops),
- VREG_DESC(L2_PC, "8921_l2_pc", &pin_control_ops),
- VREG_DESC(L3_PC, "8921_l3_pc", &pin_control_ops),
- VREG_DESC(L4_PC, "8921_l4_pc", &pin_control_ops),
- VREG_DESC(L5_PC, "8921_l5_pc", &pin_control_ops),
- VREG_DESC(L6_PC, "8921_l6_pc", &pin_control_ops),
- VREG_DESC(L7_PC, "8921_l7_pc", &pin_control_ops),
- VREG_DESC(L8_PC, "8921_l8_pc", &pin_control_ops),
- VREG_DESC(L9_PC, "8921_l9_pc", &pin_control_ops),
- VREG_DESC(L10_PC, "8921_l10_pc", &pin_control_ops),
- VREG_DESC(L11_PC, "8921_l11_pc", &pin_control_ops),
- VREG_DESC(L12_PC, "8921_l12_pc", &pin_control_ops),
- VREG_DESC(L14_PC, "8921_l14_pc", &pin_control_ops),
- VREG_DESC(L15_PC, "8921_l15_pc", &pin_control_ops),
- VREG_DESC(L16_PC, "8921_l16_pc", &pin_control_ops),
- VREG_DESC(L17_PC, "8921_l17_pc", &pin_control_ops),
- VREG_DESC(L18_PC, "8921_l18_pc", &pin_control_ops),
- VREG_DESC(L21_PC, "8921_l21_pc", &pin_control_ops),
- VREG_DESC(L22_PC, "8921_l22_pc", &pin_control_ops),
- VREG_DESC(L23_PC, "8921_l23_pc", &pin_control_ops),
- VREG_DESC(L29_PC, "8921_l29_pc", &pin_control_ops),
-
- VREG_DESC(S1_PC, "8921_s1_pc", &pin_control_ops),
- VREG_DESC(S2_PC, "8921_s2_pc", &pin_control_ops),
- VREG_DESC(S3_PC, "8921_s3_pc", &pin_control_ops),
- VREG_DESC(S4_PC, "8921_s4_pc", &pin_control_ops),
- VREG_DESC(S7_PC, "8921_s7_pc", &pin_control_ops),
- VREG_DESC(S8_PC, "8921_s8_pc", &pin_control_ops),
-
- VREG_DESC(LVS1_PC, "8921_lvs1_pc", &pin_control_ops),
- VREG_DESC(LVS3_PC, "8921_lvs3_pc", &pin_control_ops),
- VREG_DESC(LVS4_PC, "8921_lvs4_pc", &pin_control_ops),
- VREG_DESC(LVS5_PC, "8921_lvs5_pc", &pin_control_ops),
- VREG_DESC(LVS6_PC, "8921_lvs6_pc", &pin_control_ops),
- VREG_DESC(LVS7_PC, "8921_lvs7_pc", &pin_control_ops),
-};
-
-static inline int is_real_regulator(int id)
+static int is_real_id(int id)
{
return (id >= 0) && (id <= RPM_VREG_ID_PM8921_MAX_REAL);
}
@@ -1431,237 +279,36 @@
return real_id;
}
-static int __devinit
-rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
- struct device *dev)
-{
- enum rpm_vreg_pin_fn pin_fn;
- struct regulator_desc *rdesc;
- struct regulator_dev *rdev;
- struct vreg *vreg;
- const char *reg_name = "";
- unsigned pin_ctrl;
- int rc = 0, id = pdata->id;
+static struct vreg_config config = {
+ .vregs = vregs,
+ .vregs_len = ARRAY_SIZE(vregs),
- if (id < 0 || id > RPM_VREG_ID_PM8921_MAX) {
- pr_err("invalid regulator id: %d\n", id);
- return -ENODEV;
- }
+ .vreg_id_min = RPM_VREG_ID_PM8921_L1,
+ .vreg_id_max = RPM_VREG_ID_PM8921_MAX,
- rdesc = &vreg_description[pdata->id];
- if (!is_real_regulator(pdata->id))
- id = pc_id_to_real_id(pdata->id);
- vreg = &vregs[id];
- reg_name = vreg_description[pdata->id].name;
- if (!pdata) {
- pr_err("%s: requires platform data\n", reg_name);
- return -EINVAL;
- }
- if (vreg->set_points)
- rdesc->n_voltages = vreg->set_points->n_voltages;
- else
- rdesc->n_voltages = 0;
+ .pin_func_none = RPM_VREG_PIN_FN_8960_NONE,
+ .pin_func_sleep_b = RPM_VREG_PIN_FN_8960_SLEEP_B,
- mutex_lock(&vreg->pc_lock);
+ .mode_lpm = REGULATOR_MODE_IDLE,
+ .mode_hpm = REGULATOR_MODE_NORMAL,
- if (is_real_regulator(pdata->id)) {
- /* Do not modify pin control and pin function values. */
- pin_ctrl = vreg->pdata.pin_ctrl;
- pin_fn = vreg->pdata.pin_fn;
- memcpy(&(vreg->pdata), pdata,
- sizeof(struct rpm_regulator_init_data));
- vreg->pdata.pin_ctrl = pin_ctrl;
- vreg->pdata.pin_fn = pin_fn;
- vreg->name = reg_name;
+ .set_points = all_set_points,
+ .set_points_len = ARRAY_SIZE(all_set_points),
- vreg->save_uV = vreg->pdata.default_uV;
- if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
- vreg->mode = REGULATOR_MODE_NORMAL;
- else
- vreg->mode = REGULATOR_MODE_IDLE;
+ .label_pin_ctrl = pin_control_label,
+ .label_pin_ctrl_len = ARRAY_SIZE(pin_control_label),
+ .label_pin_func = pin_func_label,
+ .label_pin_func_len = ARRAY_SIZE(pin_func_label),
+ .label_force_mode = force_mode_label,
+ .label_force_mode_len = ARRAY_SIZE(force_mode_label),
+ .label_power_mode = power_mode_label,
+ .label_power_mode_len = ARRAY_SIZE(power_mode_label),
- /* Initialize the RPM request. */
- SET_PART(vreg, ip,
- MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
- SET_PART(vreg, fm, vreg->pdata.force_mode);
- SET_PART(vreg, pm, vreg->pdata.power_mode);
- SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
- SET_PART(vreg, ia,
- MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
- SET_PART(vreg, freq, vreg->pdata.freq);
- SET_PART(vreg, freq_clk_src, 0);
- SET_PART(vreg, comp_mode, 0);
- SET_PART(vreg, hpm, 0);
- if (!vreg->is_enabled_pc) {
- SET_PART(vreg, pf, RPM_VREG_PIN_FN_NONE);
- SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
- }
- } else {
- /* Pin control regulator */
- if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
- == RPM_VREG_PIN_CTRL_NONE
- && pdata->pin_fn != RPM_VREG_PIN_FN_SLEEP_B) {
- pr_err("%s: no pin control input specified\n",
- reg_name);
- mutex_unlock(&vreg->pc_lock);
- return -EINVAL;
- }
- vreg->pdata.pin_ctrl = pdata->pin_ctrl;
- vreg->pdata.pin_fn = pdata->pin_fn;
- if (!vreg->name)
- vreg->name = reg_name;
-
- /* Initialize the RPM request. */
- pin_fn = 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)
- pin_fn = RPM_VREG_PIN_FN_SLEEP_B;
- SET_PART(vreg, pf, pin_fn);
- SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
- }
-
- mutex_unlock(&vreg->pc_lock);
-
- if (rc)
- goto bail;
-
- rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
- if (IS_ERR(rdev)) {
- rc = PTR_ERR(rdev);
- pr_err("regulator_register failed: %s, rc=%d\n", reg_name, rc);
- return rc;
- } else {
- if (is_real_regulator(pdata->id))
- vreg->rdev = rdev;
- else
- vreg->rdev_pc = rdev;
- }
-
-bail:
- if (rc)
- pr_err("error for %s, rc=%d\n", reg_name, rc);
-
- return rc;
-}
-
-static int __devinit rpm_vreg_probe(struct platform_device *pdev)
-{
- struct rpm_regulator_platform_data *platform_data;
- int rc = 0;
- int i;
-
- platform_data = pdev->dev.platform_data;
- if (!platform_data) {
- pr_err("rpm-regulator requires platform data\n");
- return -EINVAL;
- }
-
- /* Initialize all of the regulators listed in the platform data. */
- for (i = 0; i < platform_data->num_regulators; i++) {
- rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
- &pdev->dev);
- if (rc) {
- pr_err("rpm_vreg_init_regulator failed, rc=%d\n", rc);
- goto remove_regulators;
- }
- }
-
- platform_set_drvdata(pdev, platform_data);
-
- return rc;
-
-remove_regulators:
- /* Unregister all regulators added before the erroring one. */
- for (; i >= 0; i--) {
- if (is_real_regulator(platform_data->init_data[i].id))
- regulator_unregister(vregs[i].rdev);
- else
- regulator_unregister(
- vregs[pc_id_to_real_id(i)].rdev_pc);
- }
-
- return rc;
-}
-
-static int __devexit rpm_vreg_remove(struct platform_device *pdev)
-{
- struct rpm_regulator_platform_data *platform_data;
- int i, id;
-
- platform_data = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
- if (platform_data) {
- for (i = 0; i < platform_data->num_regulators; i++) {
- id = platform_data->init_data[i].id;
- if (is_real_regulator(id)) {
- regulator_unregister(vregs[id].rdev);
- vregs[id].rdev = NULL;
- } else {
- regulator_unregister(
- vregs[pc_id_to_real_id(id)].rdev_pc);
- vregs[id].rdev_pc = NULL;
- }
- }
- }
-
- return 0;
-}
-
-static struct platform_driver rpm_vreg_driver = {
- .probe = rpm_vreg_probe,
- .remove = __devexit_p(rpm_vreg_remove),
- .driver = {
- .name = RPM_REGULATOR_DEV_NAME,
- .owner = THIS_MODULE,
- },
+ .is_real_id = is_real_id,
+ .pc_id_to_real_id = pc_id_to_real_id,
};
-static int __init rpm_vreg_init(void)
+struct vreg_config *get_config_8960(void)
{
- struct vreg_set_points *set_points[] = {
- &pldo_set_points,
- &nldo_set_points,
- &nldo1200_set_points,
- &smps_set_points,
- &ftsmps_set_points,
- &ncp_set_points,
- };
- int i, j;
-
- /* Calculate the number of set points available for each regualtor. */
- for (i = 0; i < ARRAY_SIZE(set_points); i++) {
- for (j = 0; j < set_points[i]->count; j++) {
- set_points[i]->range[j].n_voltages
- = (set_points[i]->range[j].max_uV
- - set_points[i]->range[j].min_uV)
- / set_points[i]->range[j].step_uV + 1;
- set_points[i]->n_voltages
- += set_points[i]->range[j].n_voltages;
- }
- }
-
- /* Initialize pin control mutexes */
- for (i = 0; i < ARRAY_SIZE(vregs); i++)
- mutex_init(&vregs[i].pc_lock);
-
- return platform_driver_register(&rpm_vreg_driver);
+ return &config;
}
-
-static void __exit rpm_vreg_exit(void)
-{
- int i;
-
- platform_driver_unregister(&rpm_vreg_driver);
-
- for (i = 0; i < ARRAY_SIZE(vregs); i++)
- mutex_destroy(&vregs[i].pc_lock);
-}
-
-postcore_initcall(rpm_vreg_init);
-module_exit(rpm_vreg_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MSM8960 rpm regulator driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:" RPM_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
new file mode 100644
index 0000000..7e5a528
--- /dev/null
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_RPM_REGULATOR_INT_H
+#define __ARCH_ARM_MACH_MSM_RPM_REGULATOR_INT_H
+
+#include <linux/regulator/driver.h>
+#include <mach/rpm.h>
+#include <mach/rpm-regulator.h>
+
+/* Possible RPM regulator request types */
+enum rpm_regulator_type {
+ RPM_REGULATOR_TYPE_LDO,
+ RPM_REGULATOR_TYPE_SMPS,
+ RPM_REGULATOR_TYPE_VS,
+ RPM_REGULATOR_TYPE_NCP,
+ RPM_REGULATOR_TYPE_MAX = RPM_REGULATOR_TYPE_NCP,
+};
+
+struct request_member {
+ int word;
+ unsigned int mask;
+ int shift;
+};
+
+/* Possible RPM regulator request members */
+struct rpm_vreg_parts {
+ struct request_member mV; /* voltage: used if voltage is in mV */
+ struct request_member uV; /* voltage: used if voltage is in uV */
+ struct request_member ip; /* peak current in mA */
+ struct request_member pd; /* pull down enable */
+ struct request_member ia; /* average current in mA */
+ struct request_member fm; /* force mode */
+ struct request_member pm; /* power mode */
+ struct request_member pc; /* pin control */
+ struct request_member pf; /* pin function */
+ struct request_member enable_state; /* NCP and switch */
+ struct request_member comp_mode; /* NCP */
+ struct request_member freq; /* frequency: NCP and SMPS */
+ struct request_member freq_clk_src; /* clock source: SMPS */
+ struct request_member hpm; /* switch: control OCP and SS */
+ int request_len;
+};
+
+struct vreg_range {
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ unsigned n_voltages;
+};
+
+struct vreg_set_points {
+ struct vreg_range *range;
+ int count;
+ unsigned n_voltages;
+};
+
+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_regulator_init_data pdata;
+ struct regulator_desc rdesc;
+ struct regulator_desc rdesc_pc;
+ struct regulator_dev *rdev;
+ struct regulator_dev *rdev_pc;
+ struct vreg_set_points *set_points;
+ struct rpm_vreg_parts *part;
+ int type;
+ int id;
+ struct mutex pc_lock;
+ int save_uV;
+ int mode;
+ bool is_enabled;
+ bool is_enabled_pc;
+ const int hpm_min_load;
+ int active_min_uV_vote[RPM_VREG_VOTER_COUNT];
+ int sleep_min_uV_vote[RPM_VREG_VOTER_COUNT];
+};
+
+struct vreg_config {
+ struct vreg *vregs;
+ int vregs_len;
+
+ int vreg_id_min;
+ int vreg_id_max;
+
+ int pin_func_none;
+ int pin_func_sleep_b;
+
+ unsigned int mode_lpm;
+ unsigned int mode_hpm;
+
+ struct vreg_set_points **set_points;
+ int set_points_len;
+
+ const char **label_pin_ctrl;
+ int label_pin_ctrl_len;
+ const char **label_pin_func;
+ int label_pin_func_len;
+ const char **label_force_mode;
+ int label_force_mode_len;
+ const char **label_power_mode;
+ int label_power_mode_len;
+
+ int (*is_real_id) (int vreg_id);
+ int (*pc_id_to_real_id) (int vreg_id);
+
+ /* Legacy options to be used with MSM8660 */
+ int use_legacy_optimum_mode;
+ int ia_follows_ip;
+};
+
+#define REQUEST_MEMBER(_word, _mask, _shift) \
+ { \
+ .word = _word, \
+ .mask = _mask, \
+ .shift = _shift, \
+ }
+
+#define VOLTAGE_RANGE(_min_uV, _max_uV, _step_uV) \
+ { \
+ .min_uV = _min_uV, \
+ .max_uV = _max_uV, \
+ .step_uV = _step_uV, \
+ }
+
+#define SET_POINTS(_ranges) \
+{ \
+ .range = _ranges, \
+ .count = ARRAY_SIZE(_ranges), \
+};
+
+#define MICRO_TO_MILLI(uV) ((uV) / 1000)
+#define MILLI_TO_MICRO(mV) ((mV) * 1000)
+
+#if defined(CONFIG_ARCH_MSM8X60)
+struct vreg_config *get_config_8660(void);
+#else
+static inline struct vreg_config *get_config_8660(void)
+{
+ return NULL;
+}
+#endif
+
+#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064)
+struct vreg_config *get_config_8960(void);
+#else
+static inline struct vreg_config *get_config_8960(void)
+{
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index b9e577a..3de0179 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/*
+ * 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
@@ -10,18 +11,22 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/module.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/slab.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 <mach/socinfo.h>
#include "rpm_resources.h"
+#include "rpm-regulator-private.h"
/* Debug Definitions */
@@ -29,7 +34,7 @@
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),
+ MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG = BIT(3),
};
static int msm_rpm_vreg_debug_mask;
@@ -37,241 +42,241 @@
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)
+struct vreg_config *(*get_config[])(void) = {
+ [RPM_VREG_VERSION_8660] = get_config_8660,
+ [RPM_VREG_VERSION_8960] = get_config_8960,
+};
-/* 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
+#define SET_PART(_vreg, _part, _val) \
+ _vreg->req[_vreg->part->_part.word].value \
+ = (_vreg->req[_vreg->part->_part.word].value \
+ & ~vreg->part->_part.mask) \
+ | (((_val) << vreg->part->_part.shift) & vreg->part->_part.mask)
-/* 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
+#define GET_PART(_vreg, _part) \
+ ((_vreg->req[_vreg->part->_part.word].value & vreg->part->_part.mask) \
+ >> vreg->part->_part.shift)
-/* 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
+#define USES_PART(_vreg, _part) (vreg->part->_part.mask)
-/* 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
+#define vreg_err(vreg, fmt, ...) \
+ pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
-/* 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
+#define RPM_VREG_PIN_CTRL_EN0 0x01
+#define RPM_VREG_PIN_CTRL_EN1 0x02
+#define RPM_VREG_PIN_CTRL_EN2 0x04
+#define RPM_VREG_PIN_CTRL_EN3 0x08
+#define RPM_VREG_PIN_CTRL_ALL 0x0F
-/* NCP register word 1 */
-#define NCP_VOLTAGE 0x0FFF
-#define NCP_VOLTAGE_SHIFT 0
-#define NCP_STATE 0x1000
-#define NCP_STATE_SHIFT 12
-
+static const char *label_freq[] = {
+ [RPM_VREG_FREQ_NONE] = " N/A",
+ [RPM_VREG_FREQ_19p20] = "19.2",
+ [RPM_VREG_FREQ_9p60] = "9.60",
+ [RPM_VREG_FREQ_6p40] = "6.40",
+ [RPM_VREG_FREQ_4p80] = "4.80",
+ [RPM_VREG_FREQ_3p84] = "3.84",
+ [RPM_VREG_FREQ_3p20] = "3.20",
+ [RPM_VREG_FREQ_2p74] = "2.74",
+ [RPM_VREG_FREQ_2p40] = "2.40",
+ [RPM_VREG_FREQ_2p13] = "2.13",
+ [RPM_VREG_FREQ_1p92] = "1.92",
+ [RPM_VREG_FREQ_1p75] = "1.75",
+ [RPM_VREG_FREQ_1p60] = "1.60",
+ [RPM_VREG_FREQ_1p48] = "1.48",
+ [RPM_VREG_FREQ_1p37] = "1.37",
+ [RPM_VREG_FREQ_1p28] = "1.28",
+ [RPM_VREG_FREQ_1p20] = "1.20",
+};
/*
* 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
+#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))
+/* rpm_version keeps track of the version for the currently running driver. */
+enum rpm_vreg_version rpm_version = -1;
-/* 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)
+/* config holds all configuration data of the currently running driver. */
+static struct vreg_config *config;
-#define IS_8901_SMPS(id) ((id >= RPM_VREG_ID_PM8901_S0 && \
- id <= RPM_VREG_ID_PM8901_S4))
+/* These regulator ID values are specified in the board file. */
+static int vreg_id_vdd_mem, vreg_id_vdd_dig;
-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;
-};
+static inline int vreg_id_is_vdd_mem_or_dig(int id)
+{
+ return id == vreg_id_vdd_mem || id == vreg_id_vdd_dig;
+}
-#define RPM_VREG_NCP_HPM_MIN_LOAD 0
+#define DEBUG_PRINT_BUFFER_SIZE 512
-#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, \
+static void rpm_regulator_req(struct vreg *vreg, int set)
+{
+ int uV, mV, fm, pm, pc, pf, pd, freq, state, i;
+ const char *pf_label = "", *fm_label = "", *pc_total = "";
+ const char *pc_en[4] = {"", "", "", ""};
+ const char *pm_label = "", *freq_label = "";
+ char buf[DEBUG_PRINT_BUFFER_SIZE];
+ size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+ int pos = 0;
+
+ /* Suppress VDD_MEM and VDD_DIG printing. */
+ if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+ && vreg_id_is_vdd_mem_or_dig(vreg->id))
+ return;
+
+ uV = GET_PART(vreg, uV);
+ mV = GET_PART(vreg, mV);
+ if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
+ uV = -uV;
+ mV = -mV;
}
-#define VREG_1(_vreg_id, _rpm_id) \
- [RPM_VREG_ID_##_vreg_id] = { \
- .req = { \
- [0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
- [1] = { .id = -1, }, \
- }, \
+ fm = GET_PART(vreg, fm);
+ pm = GET_PART(vreg, pm);
+ pc = GET_PART(vreg, pc);
+ pf = GET_PART(vreg, pf);
+ pd = GET_PART(vreg, pd);
+ freq = GET_PART(vreg, freq);
+ state = GET_PART(vreg, enable_state);
+
+ if (pf >= 0 && pf < config->label_pin_func_len)
+ pf_label = config->label_pin_func[pf];
+
+ if (fm >= 0 && fm < config->label_force_mode_len)
+ fm_label = config->label_force_mode[fm];
+
+ if (pm >= 0 && pm < config->label_power_mode_len)
+ pm_label = config->label_power_mode[pm];
+
+ if (freq >= 0 && freq < ARRAY_SIZE(label_freq))
+ freq_label = label_freq[freq];
+
+ for (i = 0; i < config->label_pin_ctrl_len; i++)
+ if (pc & (1 << i))
+ pc_en[i] = config->label_pin_ctrl[i];
+
+ if (pc == RPM_VREG_PIN_CTRL_NONE)
+ pc_total = " none";
+
+ pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+ KERN_INFO, __func__);
+
+ pos += scnprintf(buf + pos, buflen - pos, "%s %-9s: s=%c",
+ (set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
+ vreg->rdesc.name,
+ (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'));
+
+ if (USES_PART(vreg, uV))
+ pos += scnprintf(buf + pos, buflen - pos, ", v=%7d uV", uV);
+ if (USES_PART(vreg, mV))
+ pos += scnprintf(buf + pos, buflen - pos, ", v=%4d mV", mV);
+ if (USES_PART(vreg, enable_state))
+ pos += scnprintf(buf + pos, buflen - pos, ", state=%s (%d)",
+ (state == 1 ? "on" : "off"), state);
+ if (USES_PART(vreg, ip))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", ip=%4d mA", GET_PART(vreg, ip));
+ if (USES_PART(vreg, fm))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", fm=%s (%d)", fm_label, fm);
+ if (USES_PART(vreg, pc))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", pc=%s%s%s%s%s (%X)", pc_en[0], pc_en[1],
+ pc_en[2], pc_en[3], pc_total, pc);
+ if (USES_PART(vreg, pf))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", pf=%s (%d)", pf_label, pf);
+ if (USES_PART(vreg, pd))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", pd=%s (%d)", (pd == 1 ? "Y" : "N"), pd);
+ if (USES_PART(vreg, ia))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", ia=%4d mA", GET_PART(vreg, ia));
+ if (USES_PART(vreg, freq)) {
+ if (vreg->type == RPM_REGULATOR_TYPE_NCP)
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", freq=%2d", freq);
+ else
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", freq=%s MHz (%2d)", freq_label, freq);
}
+ if (USES_PART(vreg, pm))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", pm=%s (%d)", pm_label, pm);
+ if (USES_PART(vreg, freq_clk_src))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", clk_src=%d", GET_PART(vreg, freq_clk_src));
+ if (USES_PART(vreg, comp_mode))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", comp=%d", GET_PART(vreg, comp_mode));
+ if (USES_PART(vreg, hpm))
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", hpm=%d", GET_PART(vreg, hpm));
-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),
+ pos += scnprintf(buf + pos, buflen - pos, "; req[0]={%d, 0x%08X}",
+ vreg->req[0].id, vreg->req[0].value);
+ if (vreg->part->request_len > 1)
+ pos += scnprintf(buf + pos, buflen - pos,
+ ", req[1]={%d, 0x%08X}", vreg->req[1].id,
+ vreg->req[1].value);
- 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),
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+ printk(buf);
+}
- VREG_1(PM8058_LVS0, LVS0),
- VREG_1(PM8058_LVS1, LVS1),
+static void rpm_regulator_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
+ int set, int voter_uV, int aggregate_uV)
+{
+ /* Suppress VDD_MEM and VDD_DIG printing. */
+ if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+ && vreg_id_is_vdd_mem_or_dig(vreg->id))
+ return;
- VREG_2(PM8058_NCP, NCP, NCP_HPM_MIN_LOAD),
+ pr_info("vote received %-9s: voter=%d, set=%c, v_voter=%7d uV, "
+ "v_aggregate=%7d uV\n", vreg->rdesc.name, voter,
+ (set == 0 ? 'A' : 'S'), voter_uV, aggregate_uV);
+}
- 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),
+static void rpm_regulator_duplicate(struct vreg *vreg, int set, int cnt)
+{
+ /* Suppress VDD_MEM and VDD_DIG printing. */
+ if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
+ && vreg_id_is_vdd_mem_or_dig(vreg->id))
+ return;
- 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);
+ if (cnt == 2)
+ pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}, "
+ "req[1]={%d, 0x%08X}\n", vreg->rdesc.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("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}\n",
+ vreg->rdesc.name, (set == 0 ? 'A' : 'S'),
+ vreg->req[0].id, vreg->req[0].value);
+}
/* Spin lock needed for sleep-selectable regulators. */
-static DEFINE_SPINLOCK(pm8058_noirq_lock);
+static DEFINE_SPINLOCK(rpm_noirq_lock);
static int voltage_from_req(struct vreg *vreg)
{
- int shift = 0;
- uint32_t value = 0, mask = 0;
+ int uV = 0;
- value = vreg->req[0].value;
+ if (vreg->part->uV.mask)
+ uV = GET_PART(vreg, uV);
+ else
+ uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
- 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;
+ return uV;
}
-static void voltage_to_req(int voltage, struct vreg *vreg)
+static void voltage_to_req(int uV, 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;
+ if (vreg->part->uV.mask)
+ SET_PART(vreg, uV, uV);
+ else
+ SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
}
static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
@@ -280,15 +285,16 @@
int update_voltage)
{
struct msm_rpm_iv_pair *prev_req;
- int rc = 0, max_mV_vote = 0, i;
+ int rc = 0, max_uV_vote = 0;
unsigned prev0, prev1;
- int *min_mV_vote;
+ int *min_uV_vote;
+ int i;
if (set == MSM_RPM_CTX_SET_0) {
- min_mV_vote = vreg->active_min_mV_vote;
+ min_uV_vote = vreg->active_min_uV_vote;
prev_req = vreg->prev_active_req;
} else {
- min_mV_vote = vreg->sleep_min_mV_vote;
+ min_uV_vote = vreg->sleep_min_uV_vote;
prev_req = vreg->prev_sleep_req;
}
@@ -301,42 +307,41 @@
vreg->req[1].value |= val1 & mask1;
if (update_voltage)
- min_mV_vote[voter] = voltage_from_req(vreg);
+ min_uV_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);
+ max_uV_vote = max(max_uV_vote, min_uV_vote[i]);
+ voltage_to_req(max_uV_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);
+ rpm_regulator_vote(vreg, voter, set, min_uV_vote[voter],
+ max_uV_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__,
+ vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
+ "set=%s, id=%d, rc=%d\n",
(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 (max_uV_vote && (set == MSM_RPM_CTX_SET_0))
+ vreg->save_uV = max_uV_vote;
if (msm_rpm_vreg_debug_mask
& MSM_RPM_VREG_DEBUG_REQUEST)
- print_rpm_request(vreg, set);
+ rpm_regulator_req(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);
+ rpm_regulator_duplicate(vreg, set, cnt);
}
return rc;
@@ -347,14 +352,14 @@
unsigned mask1, unsigned val1, unsigned cnt,
int update_voltage)
{
+ unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
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);
+ spin_lock_irqsave(&rpm_noirq_lock, flags);
/*
* Send sleep set request first so that subsequent set_mode, etc calls
@@ -369,28 +374,23 @@
* 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;
+ if (vreg->part->uV.mask) {
+ s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
+ s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
+ } else {
+ s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
+ s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
}
rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
- mask0_sleep, val0_sleep,
- mask1, val1, cnt, update_voltage);
+ s_mask[0], s_val[0], s_mask[1], s_val[1],
+ 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);
+ spin_unlock_irqrestore(&rpm_noirq_lock, flags);
return rc;
}
@@ -416,38 +416,87 @@
* 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 rpm_vreg_set_voltage(int 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;
+ unsigned int mask[2] = {0}, val[2] = {0};
+ struct vreg_range *range;
+ struct vreg *vreg;
+ int uV = min_uV;
+ int lim_min_uV, lim_max_uV, i, rc;
- if (vreg_id < 0 || vreg_id >= RPM_VREG_ID_MAX)
- return -EINVAL;
+ /*
+ * HACK: make this function a no-op for 8064 so that it can be called by
+ * consumers on 8064 before RPM capabilities are present. (needed for
+ * acpuclock driver)
+ */
+ if (cpu_is_apq8064())
+ return 0;
- 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;
+ if (!config) {
+ pr_err("rpm-regulator driver has not probed yet.\n");
+ return -ENODEV;
}
- rc = vreg_set_noirq(&vregs[vreg_id], voter, sleep_also, mask0, val0,
- mask1, val1, cnt, 1);
+ if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
+ pr_err("invalid regulator id=%d\n", vreg_id);
+ return -EINVAL;
+ }
+
+ vreg = &config->vregs[vreg_id];
+ range = &vreg->set_points->range[0];
+
+ if (!vreg->pdata.sleep_selectable) {
+ vreg_err(vreg, "regulator is not marked sleep selectable\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Check if request voltage is outside of allowed range. The regulator
+ * core has already checked that constraint range is inside of the
+ * physically allowed range.
+ */
+ lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
+ lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
+
+ if (uV < lim_min_uV && max_uV >= lim_min_uV)
+ uV = lim_min_uV;
+
+ if (uV < lim_min_uV || uV > lim_max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside allowed v=[%d, %d]\n",
+ min_uV, max_uV, lim_min_uV, lim_max_uV);
+ return -EINVAL;
+ }
+
+ /* Find the range which uV is inside of. */
+ for (i = vreg->set_points->count - 1; i > 0; i--) {
+ if (uV > vreg->set_points->range[i - 1].max_uV) {
+ range = &vreg->set_points->range[i];
+ break;
+ }
+ }
+
+ /*
+ * Force uV to be an allowed set point and apply a ceiling function
+ * to non-set point values.
+ */
+ uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+ uV = uV * range->step_uV + range->min_uV;
+
+ if (vreg->part->uV.mask) {
+ val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
+ mask[vreg->part->uV.word] = vreg->part->uV.mask;
+ } else {
+ val[vreg->part->mV.word]
+ = MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
+ mask[vreg->part->mV.word] = vreg->part->mV.mask;
+ }
+
+ rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
+ val[1], vreg->part->request_len, 1);
+ if (rc)
+ vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
return rc;
}
@@ -456,52 +505,60 @@
/**
* rpm_vreg_set_frequency - sets the frequency of a switching regulator
* @vreg: ID for regulator
- * @min_uV: minimum acceptable frequency of operation
+ * @freq: enum corresponding to desired frequency
*
* Returns 0 on success or errno.
*/
-int rpm_vreg_set_frequency(enum rpm_vreg_id vreg_id, enum rpm_vreg_freq freq)
+int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
{
- unsigned val0 = 0, val1 = 0, mask0 = 0, mask1 = 0, cnt = 2;
+ unsigned int mask[2] = {0}, val[2] = {0};
+ struct vreg *vreg;
int rc;
- if (vreg_id < 0 || vreg_id >= RPM_VREG_ID_MAX) {
- pr_err("%s: invalid regulator id=%d\n", __func__, vreg_id);
+ /*
+ * HACK: make this function a no-op for 8064 so that it can be called by
+ * consumers on 8064 before RPM capabilities are present.
+ */
+ if (cpu_is_apq8064())
+ return 0;
+
+ if (!config) {
+ pr_err("rpm-regulator driver has not probed yet.\n");
+ return -ENODEV;
+ }
+
+ if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
+ pr_err("invalid regulator id=%d\n", vreg_id);
return -EINVAL;
}
+ vreg = &config->vregs[vreg_id];
+
if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
- pr_err("%s: invalid frequency=%d\n", __func__, freq);
+ vreg_err(vreg, "invalid frequency=%d\n", freq);
+ return -EINVAL;
+ }
+ if (!vreg->pdata.sleep_selectable) {
+ vreg_err(vreg, "regulator is not marked sleep selectable\n");
+ return -EINVAL;
+ }
+ if (!vreg->part->freq.mask) {
+ vreg_err(vreg, "frequency not supported\n");
return -EINVAL;
}
- if (!IS_SMPS(vreg_id)) {
- pr_err("%s: regulator id=%d does not support frequency\n",
- __func__, vreg_id);
- return -EINVAL;
- }
+ val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
+ mask[vreg->part->freq.word] = vreg->part->freq.mask;
- 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);
+ rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
+ val[0], mask[1], val[1], vreg->part->request_len, 0);
+ if (rc)
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
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;
@@ -512,9 +569,19 @@
return vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
}
-static inline unsigned saturate_load(unsigned load_uA)
+static inline unsigned saturate_peak_load(struct vreg *vreg, unsigned load_uA)
{
- return (load_uA > MAX_POSSIBLE_LOAD ? MAX_POSSIBLE_LOAD : load_uA);
+ unsigned load_max
+ = MILLI_TO_MICRO(vreg->part->ip.mask >> vreg->part->ip.shift);
+
+ return (load_uA > load_max ? load_max : load_uA);
+}
+
+static inline unsigned saturate_avg_load(struct vreg *vreg, unsigned load_uA)
+{
+ unsigned load_max
+ = MILLI_TO_MICRO(vreg->part->ia.mask >> vreg->part->ia.shift);
+ return (load_uA > load_max ? load_max : load_uA);
}
/* Change vreg->req, but do not send it to the RPM. */
@@ -523,8 +590,8 @@
{
unsigned long flags = 0;
- if (vreg->pdata->sleep_selectable)
- spin_lock_irqsave(&pm8058_noirq_lock, flags);
+ if (vreg->pdata.sleep_selectable)
+ spin_lock_irqsave(&rpm_noirq_lock, flags);
vreg->req[0].value &= ~mask0;
vreg->req[0].value |= val0 & mask0;
@@ -532,8 +599,8 @@
vreg->req[1].value &= ~mask1;
vreg->req[1].value |= val1 & mask1;
- if (vreg->pdata->sleep_selectable)
- spin_unlock_irqrestore(&pm8058_noirq_lock, flags);
+ if (vreg->pdata.sleep_selectable)
+ spin_unlock_irqrestore(&rpm_noirq_lock, flags);
return 0;
}
@@ -548,7 +615,7 @@
* Bypass the normal route for regulators that can be called to change
* just the active set values.
*/
- if (vreg->pdata->sleep_selectable)
+ if (vreg->pdata.sleep_selectable)
return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
mask0, val0, mask1, val1, cnt, 1);
@@ -564,7 +631,7 @@
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);
+ rpm_regulator_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
return 0;
}
@@ -573,11 +640,11 @@
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);
+ vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n",
+ 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);
+ rpm_regulator_req(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;
}
@@ -585,880 +652,736 @@
return rc;
}
-static int smps_is_enabled(struct regulator_dev *dev)
+static int vreg_is_enabled(struct regulator_dev *rdev)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
- return ((vreg->req[0].value & SMPS_VOLTAGE) >> SMPS_VOLTAGE_SHIFT) != 0;
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ int enabled;
+
+ mutex_lock(&vreg->pc_lock);
+ enabled = vreg->is_enabled;
+ mutex_unlock(&vreg->pc_lock);
+
+ return enabled;
}
-static int _smps_set_voltage(struct regulator_dev *dev, int min_uV)
+static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
{
- 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);
+ switch (vreg->type) {
+ case RPM_REGULATOR_TYPE_LDO:
+ case RPM_REGULATOR_TYPE_SMPS:
+ /* Enable by setting a voltage. */
+ if (vreg->part->uV.mask) {
+ val[vreg->part->uV.word]
+ |= vreg->save_uV << vreg->part->uV.shift;
+ mask[vreg->part->uV.word] |= vreg->part->uV.mask;
+ } else {
+ val[vreg->part->mV.word]
+ |= MICRO_TO_MILLI(vreg->save_uV)
+ << vreg->part->mV.shift;
+ mask[vreg->part->mV.word] |= vreg->part->mV.mask;
+ }
+ break;
+ case RPM_REGULATOR_TYPE_VS:
+ case RPM_REGULATOR_TYPE_NCP:
+ /* Enable by setting enable_state. */
+ val[vreg->part->enable_state.word]
+ |= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
+ mask[vreg->part->enable_state.word]
+ |= vreg->part->enable_state.mask;
}
-
- 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,
+static int vreg_enable(struct regulator_dev *rdev)
+{
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mask[2] = {0}, val[2] = {0};
+ int rc = 0;
+
+ set_enable(vreg, mask, val);
+
+ mutex_lock(&vreg->pc_lock);
+
+ rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+ vreg->part->request_len);
+ if (!rc)
+ vreg->is_enabled = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static void set_disable(struct vreg *vreg, unsigned int *mask,
+ unsigned int *val)
+{
+ switch (vreg->type) {
+ case RPM_REGULATOR_TYPE_LDO:
+ case RPM_REGULATOR_TYPE_SMPS:
+ /* Disable by setting a voltage of 0 uV. */
+ if (vreg->part->uV.mask) {
+ val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
+ mask[vreg->part->uV.word] |= vreg->part->uV.mask;
+ } else {
+ val[vreg->part->mV.word] |= 0 << vreg->part->mV.shift;
+ mask[vreg->part->mV.word] |= vreg->part->mV.mask;
+ }
+ break;
+ case RPM_REGULATOR_TYPE_VS:
+ case RPM_REGULATOR_TYPE_NCP:
+ /* Disable by setting enable_state. */
+ val[vreg->part->enable_state.word]
+ |= RPM_VREG_STATE_OFF << vreg->part->enable_state.shift;
+ mask[vreg->part->enable_state.word]
+ |= vreg->part->enable_state.mask;
+ }
+}
+
+static int vreg_disable(struct regulator_dev *rdev)
+{
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mask[2] = {0}, val[2] = {0};
+ int rc = 0;
+
+ set_disable(vreg, mask, val);
+
+ mutex_lock(&vreg->pc_lock);
+
+ /* Only disable if pin control is not in use. */
+ if (!vreg->is_enabled_pc)
+ rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+ vreg->part->request_len);
+
+ if (!rc)
+ vreg->is_enabled = false;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
unsigned *selector)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
- int rc = 0;
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ struct vreg_range *range = &vreg->set_points->range[0];
+ unsigned int mask[2] = {0}, val[2] = {0};
+ int rc = 0, uV = min_uV;
+ int lim_min_uV, lim_max_uV, i;
- if (smps_is_enabled(dev))
- rc = _smps_set_voltage(dev, min_uV);
- if (rc)
- return rc;
+ /* Check if request voltage is outside of physically settable range. */
+ lim_min_uV = vreg->set_points->range[0].min_uV;
+ lim_max_uV =
+ vreg->set_points->range[vreg->set_points->count - 1].max_uV;
- /* only save if nonzero (or not disabling) */
- if (min_uV && (!vreg->pdata->sleep_selectable || !smps_is_enabled(dev)))
- vreg->save_uV = min_uV;
+ if (uV < lim_min_uV && max_uV >= lim_min_uV)
+ uV = lim_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:
+ if (uV < lim_min_uV || uV > lim_max_uV) {
+ vreg_err(vreg,
+ "request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ min_uV, max_uV, lim_min_uV, lim_max_uV);
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;
+ /* Find the range which uV is inside of. */
+ for (i = vreg->set_points->count - 1; i > 0; i--) {
+ if (uV > vreg->set_points->range[i - 1].max_uV) {
+ range = &vreg->set_points->range[i];
+ break;
}
}
- 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;
- }
+ /*
+ * Force uV to be an allowed set point and apply a ceiling function
+ * to non-set point values.
+ */
+ uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+ uV = uV * range->step_uV + range->min_uV;
- if (smps_is_enabled(dev)) {
- rc = vreg_set(vreg, mask0, val0, mask1, val1, 2);
+ if (vreg->part->uV.mask) {
+ val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
+ mask[vreg->part->uV.word] = vreg->part->uV.mask;
} else {
+ val[vreg->part->mV.word]
+ = MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
+ mask[vreg->part->mV.word] = vreg->part->mV.mask;
+ }
+
+ mutex_lock(&vreg->pc_lock);
+
+ /*
+ * Only send a request for a new voltage if the regulator is currently
+ * enabled. This will ensure that LDO and SMPS regulators are not
+ * inadvertently turned on because voltage > 0 is equivalent to
+ * enabling. For NCP, this just removes unnecessary RPM requests.
+ */
+ if (vreg->is_enabled) {
+ rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+ vreg->part->request_len);
+ if (rc)
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+ } else if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
/* 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);
+ rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
}
- if (load_uA >= vreg->hpm_min_load)
- return REGULATOR_MODE_FAST;
- return REGULATOR_MODE_STANDBY;
-}
+ if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
+ vreg->save_uV = uV;
-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;
+ mutex_unlock(&vreg->pc_lock);
return rc;
}
-static int ldo_get_voltage(struct regulator_dev *dev)
+static int vreg_get_voltage(struct regulator_dev *rdev)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+
return vreg->save_uV;
}
-static int ldo_enable(struct regulator_dev *dev)
+static int vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
- int rc = 0;
- unsigned mask, val;
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ int uV = 0;
+ int i;
- /* 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:
+ if (!vreg->set_points) {
+ vreg_err(vreg, "no voltages available\n");
return -EINVAL;
}
- if (set_hpm == 1) {
- /* Make sure that request currents are at HPM level. */
+ if (selector >= vreg->set_points->n_voltages)
+ return 0;
+
+ for (i = 0; i < vreg->set_points->count; i++) {
+ if (selector < vreg->set_points->range[i].n_voltages) {
+ uV = selector * vreg->set_points->range[i].step_uV
+ + vreg->set_points->range[i].min_uV;
+ break;
+ } else {
+ selector -= vreg->set_points->range[i].n_voltages;
+ }
+ }
+
+ return uV;
+}
+
+static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mask[2] = {0}, val[2] = {0};
+ int rc = 0;
+ int peak_uA;
+
+ mutex_lock(&vreg->pc_lock);
+
+ peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
+ & vreg->part->ip.mask) >> vreg->part->ip.shift);
+
+ if (mode == config->mode_hpm) {
+ /* Make sure that request currents are in HPM range. */
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;
+ val[vreg->part->ip.word]
+ = MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
+ << vreg->part->ip.shift;
+ mask[vreg->part->ip.word] = vreg->part->ip.mask;
+
+ if (config->ia_follows_ip) {
+ val[vreg->part->ia.word]
+ |= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
+ << vreg->part->ia.shift;
+ mask[vreg->part->ia.word]
+ |= vreg->part->ia.mask;
+ }
}
- } else if (set_hpm == 0) {
- /* Make sure that request currents are at LPM level. */
+ } else if (mode == config->mode_lpm) {
+ /* Make sure that request currents are in LPM range. */
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;
+ val[vreg->part->ip.word]
+ = MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
+ << vreg->part->ip.shift;
+ mask[vreg->part->ip.word] = vreg->part->ip.mask;
+
+ if (config->ia_follows_ip) {
+ val[vreg->part->ia.word]
+ |= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
+ << vreg->part->ia.shift;
+ mask[vreg->part->ia.word]
+ |= vreg->part->ia.mask;
+ }
}
+ } else {
+ vreg_err(vreg, "invalid mode: %u\n", mode);
+ mutex_unlock(&vreg->pc_lock);
+ return -EINVAL;
}
- 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);
+ if (vreg->is_enabled) {
+ rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+ vreg->part->request_len);
} else {
/* Regulator is disabled; store but don't send new request. */
- rc = vreg_store(vreg, mask0, val0, mask1, val1);
+ rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
}
+
if (rc)
- return rc;
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+ else
+ vreg->mode = mode;
-done:
- vreg->mode_initialized = mode_initialized;
- vreg->optimum = optimum;
- vreg->pc_vote = pc_vote;
+ mutex_unlock(&vreg->pc_lock);
- return 0;
+ return rc;
}
-static unsigned int ldo_get_mode(struct regulator_dev *dev)
+static unsigned int vreg_get_mode(struct regulator_dev *rdev)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
+ struct vreg *vreg = rdev_get_drvdata(rdev);
- 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;
+ return vreg->mode;
}
-unsigned int ldo_get_optimum_mode(struct regulator_dev *dev, int input_uV,
- int output_uV, int load_uA)
+static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode;
- 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);
- }
+ load_uA += vreg->pdata.system_uA;
+
+ mutex_lock(&vreg->pc_lock);
+ SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
+ if (config->ia_follows_ip)
+ SET_PART(vreg, ia,
+ MICRO_TO_MILLI(saturate_avg_load(vreg, load_uA)));
+ mutex_unlock(&vreg->pc_lock);
if (load_uA >= vreg->hpm_min_load)
- return REGULATOR_MODE_FAST;
- return REGULATOR_MODE_STANDBY;
+ mode = config->mode_hpm;
+ else
+ mode = config->mode_lpm;
+
+ return mode;
}
-static int switch_enable(struct regulator_dev *dev)
+static unsigned int vreg_legacy_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
- unsigned mask = 0, val = 0;
+ struct vreg *vreg = rdev_get_drvdata(rdev);
- /* 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;
+ if (MICRO_TO_MILLI(load_uA) <= 0) {
+ /*
+ * vreg_legacy_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 vreg->mode;
}
- 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;
+ return vreg_get_optimum_mode(rdev, input_uV, output_uV, load_uA);
}
/*
- * 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
+ * Returns the logical pin control enable state because the pin control options
+ * present in the hardware out of restart could be different from those desired
+ * by the consumer.
*/
-static int switch_set_mode(struct regulator_dev *dev, unsigned int mode)
+static int vreg_pin_control_is_enabled(struct regulator_dev *rdev)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
- unsigned pc_vote = vreg->pc_vote;
- unsigned mask, val;
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->is_enabled_pc;
+}
+
+static int vreg_pin_control_enable(struct regulator_dev *rdev)
+{
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mask[2] = {0}, val[2] = {0};
int rc;
- switch (mode) {
- case REGULATOR_MODE_IDLE:
- if (pc_vote++)
- goto done; /* already taken care of */
+ mutex_lock(&vreg->pc_lock);
- 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;
+ val[vreg->part->pc.word]
+ |= vreg->pdata.pin_ctrl << vreg->part->pc.shift;
+ mask[vreg->part->pc.word] |= vreg->part->pc.mask;
- case REGULATOR_MODE_NORMAL:
- if (--pc_vote)
- goto done; /* already taken care of */
+ val[vreg->part->pf.word] |= vreg->pdata.pin_fn << vreg->part->pf.shift;
+ mask[vreg->part->pf.word] |= vreg->part->pf.mask;
- 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;
+ if (!vreg->is_enabled)
+ set_enable(vreg, mask, val);
- default:
- return -EINVAL;
- }
+ rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+ vreg->part->request_len);
- 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)
+ vreg->is_enabled_pc = true;
+
+ mutex_unlock(&vreg->pc_lock);
+
if (rc)
- return rc;
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
-done:
- vreg->pc_vote = pc_vote;
- return 0;
+ return rc;
}
-static unsigned int switch_get_mode(struct regulator_dev *dev)
+static int vreg_pin_control_disable(struct regulator_dev *rdev)
{
- struct vreg *vreg = rdev_get_drvdata(dev);
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mask[2] = {0}, val[2] = {0};
+ int pin_fn, rc;
- if (vreg->pc_vote)
- return REGULATOR_MODE_IDLE;
- return REGULATOR_MODE_NORMAL;
+ mutex_lock(&vreg->pc_lock);
+
+ val[vreg->part->pc.word]
+ |= RPM_VREG_PIN_CTRL_NONE << vreg->part->pc.shift;
+ mask[vreg->part->pc.word] |= vreg->part->pc.mask;
+
+ pin_fn = config->pin_func_none;
+ if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
+ pin_fn = config->pin_func_sleep_b;
+ val[vreg->part->pf.word] |= pin_fn << vreg->part->pf.shift;
+ mask[vreg->part->pf.word] |= vreg->part->pf.mask;
+
+ if (!vreg->is_enabled)
+ set_disable(vreg, mask, val);
+
+ rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
+ vreg->part->request_len);
+
+ if (!rc)
+ vreg->is_enabled_pc = false;
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
+
+ return rc;
}
-static int ncp_enable(struct regulator_dev *dev)
+static int vreg_enable_time(struct regulator_dev *rdev)
{
- return vreg_set(rdev_get_drvdata(dev), NCP_STATE,
- RPM_VREG_STATE_ON << NCP_STATE_SHIFT, 0, 0, 2);
+ struct vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->pdata.enable_time;
}
-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);
-}
-
+/* Real regulator operations. */
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,
+ .enable = vreg_enable,
+ .disable = vreg_disable,
+ .is_enabled = vreg_is_enabled,
+ .set_voltage = vreg_set_voltage,
+ .get_voltage = vreg_get_voltage,
+ .list_voltage = vreg_list_voltage,
+ .set_mode = vreg_set_mode,
+ .get_mode = vreg_get_mode,
+ .get_optimum_mode = vreg_get_optimum_mode,
+ .enable_time = vreg_enable_time,
};
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,
+ .enable = vreg_enable,
+ .disable = vreg_disable,
+ .is_enabled = vreg_is_enabled,
+ .set_voltage = vreg_set_voltage,
+ .get_voltage = vreg_get_voltage,
+ .list_voltage = vreg_list_voltage,
+ .set_mode = vreg_set_mode,
+ .get_mode = vreg_get_mode,
+ .get_optimum_mode = vreg_get_optimum_mode,
+ .enable_time = vreg_enable_time,
};
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,
+ .enable = vreg_enable,
+ .disable = vreg_disable,
+ .is_enabled = vreg_is_enabled,
+ .enable_time = vreg_enable_time,
};
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,
+ .enable = vreg_enable,
+ .disable = vreg_disable,
+ .is_enabled = vreg_is_enabled,
+ .set_voltage = vreg_set_voltage,
+ .get_voltage = vreg_get_voltage,
+ .list_voltage = vreg_list_voltage,
+ .enable_time = vreg_enable_time,
};
-#define DESC(_id, _name, _ops) \
- [_id] = { \
- .id = _id, \
- .name = _name, \
- .ops = _ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
+/* Pin control regulator operations. */
+static struct regulator_ops pin_control_ops = {
+ .enable = vreg_pin_control_enable,
+ .disable = vreg_pin_control_disable,
+ .is_enabled = vreg_pin_control_is_enabled,
+};
+
+struct regulator_ops *vreg_ops[] = {
+ [RPM_REGULATOR_TYPE_LDO] = &ldo_ops,
+ [RPM_REGULATOR_TYPE_SMPS] = &smps_ops,
+ [RPM_REGULATOR_TYPE_VS] = &switch_ops,
+ [RPM_REGULATOR_TYPE_NCP] = &ncp_ops,
+};
+
+static int __devinit
+rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
+ struct device *dev)
+{
+ struct regulator_desc *rdesc = NULL;
+ struct regulator_dev *rdev;
+ struct vreg *vreg;
+ unsigned pin_ctrl;
+ int id, pin_fn;
+ int rc = 0;
+
+ if (!pdata) {
+ pr_err("platform data missing\n");
+ return -EINVAL;
}
-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),
+ id = pdata->id;
- 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),
+ if (id < config->vreg_id_min || id > config->vreg_id_max) {
+ pr_err("invalid regulator id: %d\n", id);
+ return -ENODEV;
+ }
- DESC(RPM_VREG_ID_PM8058_LVS0, "8058_lvs0", &switch_ops),
- DESC(RPM_VREG_ID_PM8058_LVS1, "8058_lvs1", &switch_ops),
+ if (!config->is_real_id(pdata->id))
+ id = config->pc_id_to_real_id(pdata->id);
+ vreg = &config->vregs[id];
- 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;
+ if (config->is_real_id(pdata->id))
+ rdesc = &vreg->rdesc;
else
- vreg->optimum = REGULATOR_MODE_STANDBY;
+ rdesc = &vreg->rdesc_pc;
- 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
+ if (vreg->type < 0 || vreg->type > RPM_REGULATOR_TYPE_MAX) {
+ pr_err("%s: invalid regulator type: %d\n",
+ vreg->rdesc.name, vreg->type);
return -EINVAL;
+ }
- return 0;
+ mutex_lock(&vreg->pc_lock);
+
+ if (vreg->set_points)
+ rdesc->n_voltages = vreg->set_points->n_voltages;
+ else
+ rdesc->n_voltages = 0;
+
+ rdesc->id = pdata->id;
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+
+ if (config->is_real_id(pdata->id)) {
+ /*
+ * Real regulator; do not modify pin control and pin function
+ * values.
+ */
+ rdesc->ops = vreg_ops[vreg->type];
+ pin_ctrl = vreg->pdata.pin_ctrl;
+ pin_fn = vreg->pdata.pin_fn;
+ memcpy(&(vreg->pdata), pdata,
+ sizeof(struct rpm_regulator_init_data));
+ vreg->pdata.pin_ctrl = pin_ctrl;
+ vreg->pdata.pin_fn = pin_fn;
+
+ vreg->save_uV = vreg->pdata.default_uV;
+ if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
+ vreg->mode = config->mode_hpm;
+ else
+ vreg->mode = config->mode_lpm;
+
+ /* Initialize the RPM request. */
+ SET_PART(vreg, ip,
+ MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
+ SET_PART(vreg, fm, vreg->pdata.force_mode);
+ SET_PART(vreg, pm, vreg->pdata.power_mode);
+ SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
+ SET_PART(vreg, ia,
+ MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
+ SET_PART(vreg, freq, vreg->pdata.freq);
+ SET_PART(vreg, freq_clk_src, 0);
+ SET_PART(vreg, comp_mode, 0);
+ SET_PART(vreg, hpm, 0);
+ if (!vreg->is_enabled_pc) {
+ SET_PART(vreg, pf, config->pin_func_none);
+ SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
+ }
+ } else {
+ if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
+ == RPM_VREG_PIN_CTRL_NONE
+ && pdata->pin_fn != config->pin_func_sleep_b) {
+ pr_err("%s: no pin control input specified\n",
+ vreg->rdesc.name);
+ mutex_unlock(&vreg->pc_lock);
+ return -EINVAL;
+ }
+ rdesc->ops = &pin_control_ops;
+ vreg->pdata.pin_ctrl = pdata->pin_ctrl;
+ vreg->pdata.pin_fn = pdata->pin_fn;
+
+ /* Initialize the RPM request. */
+ pin_fn = config->pin_func_none;
+ /* Allow pf=sleep_b to be specified by platform data. */
+ if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
+ pin_fn = config->pin_func_sleep_b;
+ SET_PART(vreg, pf, pin_fn);
+ SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
+ }
+
+ mutex_unlock(&vreg->pc_lock);
+
+ if (rc)
+ goto bail;
+
+ rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
+ if (IS_ERR(rdev)) {
+ rc = PTR_ERR(rdev);
+ pr_err("regulator_register failed: %s, rc=%d\n",
+ vreg->rdesc.name, rc);
+ return rc;
+ } else {
+ if (config->is_real_id(pdata->id))
+ vreg->rdev = rdev;
+ else
+ vreg->rdev_pc = rdev;
+ }
+
+bail:
+ if (rc)
+ pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);
+
+ return rc;
+}
+
+static void rpm_vreg_set_point_init(void)
+{
+ struct vreg_set_points **set_points;
+ int i, j, temp;
+
+ set_points = config->set_points;
+
+ /* Calculate the number of set points available for each regulator. */
+ for (i = 0; i < config->set_points_len; i++) {
+ temp = 0;
+ for (j = 0; j < set_points[i]->count; j++) {
+ set_points[i]->range[j].n_voltages
+ = (set_points[i]->range[j].max_uV
+ - set_points[i]->range[j].min_uV)
+ / set_points[i]->range[j].step_uV + 1;
+ temp += set_points[i]->range[j].n_voltages;
+ }
+ set_points[i]->n_voltages = temp;
+ }
}
static int __devinit rpm_vreg_probe(struct platform_device *pdev)
{
- struct regulator_desc *rdesc;
- struct regulator_dev *rdev;
- struct vreg *vreg;
- int rc;
+ struct rpm_regulator_platform_data *platform_data;
+ int rc = 0;
+ int i, id;
- if (pdev == NULL)
+ platform_data = pdev->dev.platform_data;
+ if (!platform_data) {
+ pr_err("rpm-regulator requires platform data\n");
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;
+ if (rpm_version >= 0 && rpm_version <= RPM_VREG_VERSION_MAX
+ && platform_data->version != rpm_version) {
+ pr_err("rpm version %d does not match previous version %d\n",
+ platform_data->version, rpm_version);
+ return -EINVAL;
}
- platform_set_drvdata(pdev, rdev);
+ if (platform_data->version < 0
+ || platform_data->version > RPM_VREG_VERSION_MAX) {
+ pr_err("rpm version %d is invalid\n", platform_data->version);
+ return -EINVAL;
+ }
+
+ if (rpm_version < 0 || rpm_version > RPM_VREG_VERSION_MAX) {
+ rpm_version = platform_data->version;
+ config = get_config[platform_data->version]();
+ vreg_id_vdd_mem = platform_data->vreg_id_vdd_mem;
+ vreg_id_vdd_dig = platform_data->vreg_id_vdd_dig;
+ if (!config) {
+ pr_err("rpm version %d is not available\n",
+ platform_data->version);
+ return -ENODEV;
+ }
+ if (config->use_legacy_optimum_mode)
+ for (i = 0; i < ARRAY_SIZE(vreg_ops); i++)
+ vreg_ops[i]->get_optimum_mode
+ = vreg_legacy_get_optimum_mode;
+ rpm_vreg_set_point_init();
+ /* First time probed; initialize pin control mutexes. */
+ for (i = 0; i < config->vregs_len; i++)
+ mutex_init(&config->vregs[i].pc_lock);
+ }
+
+ /* Initialize all of the regulators listed in the platform data. */
+ for (i = 0; i < platform_data->num_regulators; i++) {
+ rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
+ &pdev->dev);
+ if (rc) {
+ pr_err("rpm_vreg_init_regulator failed, rc=%d\n", rc);
+ goto remove_regulators;
+ }
+ }
+
+ platform_set_drvdata(pdev, platform_data);
+
+ return rc;
+
+remove_regulators:
+ /* Unregister all regulators added before the erroring one. */
+ for (; i >= 0; i--) {
+ id = platform_data->init_data[i].id;
+ if (config->is_real_id(id)) {
+ regulator_unregister(config->vregs[id].rdev);
+ config->vregs[id].rdev = NULL;
+ } else {
+ regulator_unregister(config->vregs[
+ config->pc_id_to_real_id(id)].rdev_pc);
+ config->vregs[id].rdev_pc = NULL;
+ }
+ }
return rc;
}
static int __devexit rpm_vreg_remove(struct platform_device *pdev)
{
- struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct rpm_regulator_platform_data *platform_data;
+ int i, id;
+ platform_data = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
- regulator_unregister(rdev);
+
+ if (platform_data) {
+ for (i = 0; i < platform_data->num_regulators; i++) {
+ id = platform_data->init_data[i].id;
+ if (config->is_real_id(id)) {
+ regulator_unregister(config->vregs[id].rdev);
+ config->vregs[id].rdev = NULL;
+ } else {
+ regulator_unregister(config->vregs[
+ config->pc_id_to_real_id(id)].rdev_pc);
+ config->vregs[id].rdev_pc = NULL;
+ }
+ }
+ }
return 0;
}
@@ -1467,7 +1390,7 @@
.probe = rpm_vreg_probe,
.remove = __devexit_p(rpm_vreg_remove),
.driver = {
- .name = "rpm-regulator",
+ .name = RPM_REGULATOR_DEV_NAME,
.owner = THIS_MODULE,
},
};
@@ -1479,189 +1402,18 @@
static void __exit rpm_vreg_exit(void)
{
+ int i;
+
platform_driver_unregister(&rpm_vreg_driver);
+
+ for (i = 0; i < config->vregs_len; i++)
+ mutex_destroy(&config->vregs[i].pc_lock);
}
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_DESCRIPTION("MSM RPM regulator driver");
MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:rpm-regulator");
+MODULE_ALIAS("platform:" RPM_REGULATOR_DEV_NAME);
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
index 721e9c3..de8b918 100644
--- a/drivers/net/wireless/libra/qcomwlan_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -42,6 +42,15 @@
"8058_s2",
"8058_s1",
};
+ static const char *vregs_qwlan_pc_name[] = {
+ "8058_l20_pc",
+ "8058_l8_pc",
+ NULL,
+ NULL,
+ "8901_l0_pc",
+ "8058_s2_pc",
+ NULL,
+ };
static const int vregs_qwlan_val_min[] = {
1800000,
3050000,
@@ -80,6 +89,7 @@
};
bool const *vregs_is_pin_controlled;
static struct regulator *vregs_qwlan[ARRAY_SIZE(vregs_qwlan_name)];
+ static struct regulator *vregs_pc_qwlan[ARRAY_SIZE(vregs_qwlan_name)];
static struct msm_xo_voter *wlan_clock;
int ret, i, rc = 0;
unsigned wlan_gpio_deep_sleep = GPIO_WLAN_DEEP_SLEEP_N;
@@ -157,11 +167,14 @@
}
/* vote for pin control (if needed) */
if (vregs_is_pin_controlled[i]) {
- rc = regulator_set_mode(vregs_qwlan[i],
- REGULATOR_MODE_IDLE);
- if (rc) {
- pr_err("regulator_set_mode(%s) failed\n",
- vregs_qwlan_name[i]);
+ vregs_pc_qwlan[i] = regulator_get(NULL,
+ vregs_qwlan_pc_name[i]);
+ if (IS_ERR(vregs_pc_qwlan[i])) {
+ pr_err("regulator get of %s failed "
+ "(%ld)\n",
+ vregs_qwlan_pc_name[i],
+ PTR_ERR(vregs_pc_qwlan[i]));
+ rc = PTR_ERR(vregs_pc_qwlan[i]);
goto vreg_fail;
}
}
@@ -173,7 +186,23 @@
vregs_qwlan_name[i], rc);
goto vreg_fail;
}
+ if (vregs_is_pin_controlled[i]) {
+ rc = regulator_enable(vregs_pc_qwlan[i]);
+ if (rc < 0) {
+ pr_err("vreg %s enable failed (%d)\n",
+ vregs_qwlan_pc_name[i], rc);
+ goto vreg_fail;
+ }
+ }
} else if (!on && wlan_on) {
+ if (vregs_is_pin_controlled[i]) {
+ rc = regulator_disable(vregs_pc_qwlan[i]);
+ if (rc < 0) {
+ pr_err("vreg %s disable failed (%d)\n",
+ vregs_qwlan_pc_name[i], rc);
+ goto vreg_fail;
+ }
+ }
rc = regulator_disable(vregs_qwlan[i]);
if (rc < 0) {
pr_err("vreg %s disable failed (%d)\n",
@@ -192,6 +221,8 @@
vreg_fail:
regulator_put(vregs_qwlan[i]);
+ if (vregs_is_pin_controlled[i])
+ regulator_put(vregs_pc_qwlan[i]);
vreg_get_fail:
i--;
while (i >= 0) {
@@ -202,7 +233,18 @@
vregs_qwlan_name[i],
!on ? "enable" : "disable", ret);
}
+ if (vregs_is_pin_controlled[i]) {
+ ret = !on ? regulator_enable(vregs_pc_qwlan[i]) :
+ regulator_disable(vregs_pc_qwlan[i]);
+ if (ret < 0) {
+ pr_err("vreg %s %s failed (%d) in err path\n",
+ vregs_qwlan_pc_name[i],
+ !on ? "enable" : "disable", ret);
+ }
+ }
regulator_put(vregs_qwlan[i]);
+ if (vregs_is_pin_controlled[i])
+ regulator_put(vregs_pc_qwlan[i]);
i--;
}
if (!on)