diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index d0bd6e16be4..0d36b0ae41f 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -220,6 +220,7 @@ obj-$(CONFIG_ARCH_MSM8960) += bms-batterydata.o obj-$(CONFIG_ARCH_APQ8064) += board-apq8064.o devices-8064.o board-apq8064-regulator.o obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o +obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator.o rpm-regulator-9615.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h new file mode 100644 index 00000000000..f5fa8caa70e --- /dev/null +++ b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h @@ -0,0 +1,138 @@ +/* + * 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_INCLUDE_MACH_RPM_REGULATOR_9615_H +#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_9615_H + +/* Pin control input signals. */ +#define RPM_VREG_PIN_CTRL_PM8018_D1 0x01 +#define RPM_VREG_PIN_CTRL_PM8018_A0 0x02 +#define RPM_VREG_PIN_CTRL_PM8018_A1 0x04 +#define RPM_VREG_PIN_CTRL_PM8018_A2 0x08 + +/** + * enum rpm_vreg_pin_fn_9615 - RPM regulator pin function choices + * %RPM_VREG_PIN_FN_9615_DONT_CARE: do not care about pin control state of + * the regulator; allow another master + * processor to specify pin control + * %RPM_VREG_PIN_FN_9615_ENABLE: pin control switches between disable and + * enable + * %RPM_VREG_PIN_FN_9615_MODE: pin control switches between LPM and HPM + * %RPM_VREG_PIN_FN_9615_SLEEP_B: regulator is forced into LPM when + * sleep_b signal is asserted + * %RPM_VREG_PIN_FN_9615_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_9615 { + RPM_VREG_PIN_FN_9615_DONT_CARE, + RPM_VREG_PIN_FN_9615_ENABLE, + RPM_VREG_PIN_FN_9615_MODE, + RPM_VREG_PIN_FN_9615_SLEEP_B, + RPM_VREG_PIN_FN_9615_NONE, +}; + +/** + * enum rpm_vreg_force_mode_9615 - RPM regulator force mode choices + * %RPM_VREG_FORCE_MODE_9615_PIN_CTRL: allow pin control usage + * %RPM_VREG_FORCE_MODE_9615_NONE: do not force any mode + * %RPM_VREG_FORCE_MODE_9615_LPM: force into low power mode + * %RPM_VREG_FORCE_MODE_9615_AUTO: allow regulator to automatically select + * its own mode based on realtime current + * draw (only available for SMPS + * regulators) + * %RPM_VREG_FORCE_MODE_9615_HPM: force into high power mode + * %RPM_VREG_FORCE_MODE_9615_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_9615 { + RPM_VREG_FORCE_MODE_9615_PIN_CTRL = 0, + RPM_VREG_FORCE_MODE_9615_NONE = 0, + RPM_VREG_FORCE_MODE_9615_LPM, + RPM_VREG_FORCE_MODE_9615_AUTO, /* SMPS only */ + RPM_VREG_FORCE_MODE_9615_HPM, + RPM_VREG_FORCE_MODE_9615_BYPASS, /* LDO only */ +}; + +/** + * enum rpm_vreg_power_mode_9615 - power mode for SMPS regulators + * %RPM_VREG_POWER_MODE_9615_HYSTERETIC: Use hysteretic mode for HPM and when + * usage goes high in AUTO + * %RPM_VREG_POWER_MODE_9615_PWM: Use PWM mode for HPM and when usage + * goes high in AUTO + */ +enum rpm_vreg_power_mode_9615 { + RPM_VREG_POWER_MODE_9615_HYSTERETIC, + RPM_VREG_POWER_MODE_9615_PWM, +}; + +/** + * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control) + */ +enum rpm_vreg_id_9615 { + RPM_VREG_ID_PM8018_L2, + RPM_VREG_ID_PM8018_L3, + RPM_VREG_ID_PM8018_L4, + RPM_VREG_ID_PM8018_L5, + RPM_VREG_ID_PM8018_L6, + RPM_VREG_ID_PM8018_L7, + RPM_VREG_ID_PM8018_L8, + RPM_VREG_ID_PM8018_L9, + RPM_VREG_ID_PM8018_L10, + RPM_VREG_ID_PM8018_L11, + RPM_VREG_ID_PM8018_L12, + RPM_VREG_ID_PM8018_L13, + RPM_VREG_ID_PM8018_L14, + RPM_VREG_ID_PM8018_S1, + RPM_VREG_ID_PM8018_S2, + RPM_VREG_ID_PM8018_S3, + RPM_VREG_ID_PM8018_S4, + RPM_VREG_ID_PM8018_S5, + RPM_VREG_ID_PM8018_LVS1, + RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_LVS1, + + /* The following are IDs for regulator devices to enable pin control. */ + RPM_VREG_ID_PM8018_L2_PC, + RPM_VREG_ID_PM8018_L3_PC, + RPM_VREG_ID_PM8018_L4_PC, + RPM_VREG_ID_PM8018_L5_PC, + RPM_VREG_ID_PM8018_L6_PC, + RPM_VREG_ID_PM8018_L7_PC, + RPM_VREG_ID_PM8018_L8_PC, + RPM_VREG_ID_PM8018_L13_PC, + RPM_VREG_ID_PM8018_L14_PC, + RPM_VREG_ID_PM8018_S1_PC, + RPM_VREG_ID_PM8018_S2_PC, + RPM_VREG_ID_PM8018_S3_PC, + RPM_VREG_ID_PM8018_S4_PC, + RPM_VREG_ID_PM8018_S5_PC, + RPM_VREG_ID_PM8018_LVS1_PC, + RPM_VREG_ID_PM8018_MAX = RPM_VREG_ID_PM8018_LVS1_PC, +}; + +/* Minimum high power mode loads in uA. */ +#define RPM_VREG_9615_LDO_50_HPM_MIN_LOAD 5000 +#define RPM_VREG_9615_LDO_150_HPM_MIN_LOAD 10000 +#define RPM_VREG_9615_LDO_300_HPM_MIN_LOAD 10000 +#define RPM_VREG_9615_LDO_1200_HPM_MIN_LOAD 10000 +#define RPM_VREG_9615_SMPS_1500_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 9a19194ce4c..8b5a1e7ff2c 100644 --- a/arch/arm/mach-msm/include/mach/rpm-regulator.h +++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h @@ -19,6 +19,7 @@ #include #include +#include /** * enum rpm_vreg_version - supported RPM regulator versions @@ -26,7 +27,8 @@ enum rpm_vreg_version { RPM_VREG_VERSION_8660, RPM_VREG_VERSION_8960, - RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8960, + RPM_VREG_VERSION_9615, + RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_9615, }; #define RPM_VREG_PIN_CTRL_NONE 0x00 diff --git a/arch/arm/mach-msm/rpm-regulator-9615.c b/arch/arm/mach-msm/rpm-regulator-9615.c new file mode 100644 index 00000000000..23c0ee33ae2 --- /dev/null +++ b/arch/arm/mach-msm/rpm-regulator-9615.c @@ -0,0 +1,232 @@ +/* + * 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, + .uV = REQUEST_MEMBER(0, 0x007FFFFF, 0), + .pd = REQUEST_MEMBER(0, 0x00800000, 23), + .pc = REQUEST_MEMBER(0, 0x0F000000, 24), + .pf = REQUEST_MEMBER(0, 0xF0000000, 28), + .ip = REQUEST_MEMBER(1, 0x000003FF, 0), + .ia = REQUEST_MEMBER(1, 0x000FFC00, 10), + .fm = REQUEST_MEMBER(1, 0x00700000, 20), +}; + +static struct rpm_vreg_parts smps_parts = { + .request_len = 2, + .uV = REQUEST_MEMBER(0, 0x007FFFFF, 0), + .pd = REQUEST_MEMBER(0, 0x00800000, 23), + .pc = REQUEST_MEMBER(0, 0x0F000000, 24), + .pf = REQUEST_MEMBER(0, 0xF0000000, 28), + .ip = REQUEST_MEMBER(1, 0x000003FF, 0), + .ia = REQUEST_MEMBER(1, 0x000FFC00, 10), + .fm = REQUEST_MEMBER(1, 0x00700000, 20), + .pm = REQUEST_MEMBER(1, 0x00800000, 23), + .freq = REQUEST_MEMBER(1, 0x1F000000, 24), + .freq_clk_src = REQUEST_MEMBER(1, 0x60000000, 29), +}; + +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, 0x000003C0, 6), + .hpm = REQUEST_MEMBER(0, 0x00000C00, 10), +}; + +/* 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 nldo1200_ranges[] = { + VOLTAGE_RANGE( 375000, 743750, 6250), + 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_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); +static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges); + +static struct vreg_set_points *all_set_points[] = { + &pldo_set_points, + &nldo_set_points, + &nldo1200_set_points, + &smps_set_points, +}; + +#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \ + [RPM_VREG_ID_PM8018_##_id] = { \ + .req = { \ + [0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \ + [1] = { .id = MSM_RPM_ID_PM8018_##_id##_1, }, \ + }, \ + .hpm_min_load = RPM_VREG_9615_##_hpm_min_load##_HPM_MIN_LOAD, \ + .type = RPM_REGULATOR_TYPE_LDO, \ + .set_points = &_ranges##_set_points, \ + .part = &ldo_parts, \ + .id = RPM_VREG_ID_PM8018_##_id, \ + .rdesc.name = _name, \ + .rdesc_pc.name = _name_pc, \ + } + +#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \ + [RPM_VREG_ID_PM8018_##_id] = { \ + .req = { \ + [0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \ + [1] = { .id = MSM_RPM_ID_PM8018_##_id##_1, }, \ + }, \ + .hpm_min_load = RPM_VREG_9615_##_hpm_min_load##_HPM_MIN_LOAD, \ + .type = RPM_REGULATOR_TYPE_SMPS, \ + .set_points = &_ranges##_set_points, \ + .part = &smps_parts, \ + .id = RPM_VREG_ID_PM8018_##_id, \ + .rdesc.name = _name, \ + .rdesc_pc.name = _name_pc, \ + } + +#define LVS(_id, _name, _name_pc) \ + [RPM_VREG_ID_PM8018_##_id] = { \ + .req = { \ + [0] = { .id = MSM_RPM_ID_PM8018_##_id, }, \ + [1] = { .id = -1, }, \ + }, \ + .type = RPM_REGULATOR_TYPE_VS, \ + .part = &switch_parts, \ + .id = RPM_VREG_ID_PM8018_##_id, \ + .rdesc.name = _name, \ + .rdesc_pc.name = _name_pc, \ + } + +static struct vreg vregs[] = { + LDO(L2, "8018_l2", "8018_l2_pc", pldo, LDO_50), + LDO(L3, "8018_l3", "8018_l3_pc", pldo, LDO_50), + LDO(L4, "8018_l4", "8018_l4_pc", pldo, LDO_300), + LDO(L5, "8018_l5", "8018_l5_pc", pldo, LDO_150), + LDO(L6, "8018_l6", "8018_l6_pc", pldo, LDO_150), + LDO(L7, "8018_l7", "8018_l7_pc", pldo, LDO_300), + LDO(L8, "8018_l8", "8018_l8_pc", nldo, LDO_150), + LDO(L9, "8018_l9", NULL, nldo1200, LDO_1200), + LDO(L10, "8018_l10", NULL, nldo1200, LDO_1200), + LDO(L11, "8018_l11", NULL, nldo1200, LDO_1200), + LDO(L12, "8018_l12", NULL, nldo1200, LDO_1200), + LDO(L13, "8018_l13", "8018_l13_pc", pldo, LDO_50), + LDO(L14, "8018_l14", "8018_l14_pc", pldo, LDO_50), + + SMPS(S1, "8018_s1", "8018_s1_pc", smps, SMPS_1500), + SMPS(S2, "8018_s2", "8018_s2_pc", smps, SMPS_1500), + SMPS(S3, "8018_s3", "8018_s3_pc", smps, SMPS_1500), + SMPS(S4, "8018_s4", "8018_s4_pc", smps, SMPS_1500), + SMPS(S5, "8018_s5", "8018_s5_pc", smps, SMPS_1500), + + LVS(LVS1, "8018_lvs1", "8018_lvs1_pc"), +}; + +static const char *pin_control_label[] = { + " D1", + " A0", + " A1", + " A2", +}; + +static const char *pin_func_label[] = { + [RPM_VREG_PIN_FN_9615_DONT_CARE] = "don't care", + [RPM_VREG_PIN_FN_9615_ENABLE] = "on/off", + [RPM_VREG_PIN_FN_9615_MODE] = "HPM/LPM", + [RPM_VREG_PIN_FN_9615_SLEEP_B] = "sleep_b", + [RPM_VREG_PIN_FN_9615_NONE] = "none", +}; + +static const char *force_mode_label[] = { + [RPM_VREG_FORCE_MODE_9615_NONE] = "none", + [RPM_VREG_FORCE_MODE_9615_LPM] = "LPM", + [RPM_VREG_FORCE_MODE_9615_AUTO] = "auto", + [RPM_VREG_FORCE_MODE_9615_HPM] = "HPM", + [RPM_VREG_FORCE_MODE_9615_BYPASS] = "BYP", +}; + +static const char *power_mode_label[] = { + [RPM_VREG_POWER_MODE_9615_HYSTERETIC] = "HYS", + [RPM_VREG_POWER_MODE_9615_PWM] = "PWM", +}; + +static int is_real_id(int id) +{ + return (id >= 0) && (id <= RPM_VREG_ID_PM8018_MAX_REAL); +} + +static int pc_id_to_real_id(int id) +{ + int real_id; + + if (id >= RPM_VREG_ID_PM8018_L2_PC && id <= RPM_VREG_ID_PM8018_L8_PC) + real_id = id - RPM_VREG_ID_PM8018_L2_PC + RPM_VREG_ID_PM8018_L2; + else + real_id = id - RPM_VREG_ID_PM8018_L13_PC + + RPM_VREG_ID_PM8018_L13; + + return real_id; +} + +static struct vreg_config config = { + .vregs = vregs, + .vregs_len = ARRAY_SIZE(vregs), + + .vreg_id_min = RPM_VREG_ID_PM8018_L2, + .vreg_id_max = RPM_VREG_ID_PM8018_MAX, + + .pin_func_none = RPM_VREG_PIN_FN_9615_NONE, + .pin_func_sleep_b = RPM_VREG_PIN_FN_9615_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), + .label_power_mode = power_mode_label, + .label_power_mode_len = ARRAY_SIZE(power_mode_label), + + .is_real_id = is_real_id, + .pc_id_to_real_id = pc_id_to_real_id, +}; + +struct vreg_config *get_config_9615(void) +{ + return &config; +} diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h index 7e5a52835d6..ff127d9b150 100644 --- a/arch/arm/mach-msm/rpm-regulator-private.h +++ b/arch/arm/mach-msm/rpm-regulator-private.h @@ -162,4 +162,13 @@ static inline struct vreg_config *get_config_8960(void) } #endif +#if defined(CONFIG_ARCH_MSM9615) +struct vreg_config *get_config_9615(void); +#else +static inline struct vreg_config *get_config_9615(void) +{ + return NULL; +} +#endif + #endif diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c index 3de01794797..249496924ce 100644 --- a/arch/arm/mach-msm/rpm-regulator.c +++ b/arch/arm/mach-msm/rpm-regulator.c @@ -45,6 +45,7 @@ module_param_named( struct vreg_config *(*get_config[])(void) = { [RPM_VREG_VERSION_8660] = get_config_8660, [RPM_VREG_VERSION_8960] = get_config_8960, + [RPM_VREG_VERSION_9615] = get_config_9615, }; #define SET_PART(_vreg, _part, _val) \