From f9d29f1617eb1b2f1fd41622bd1a0fc51658d2f0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 20 Feb 2012 12:26:06 +0200 Subject: [PATCH 1/5] arm: omap3: voltage: fix channel configuration OMAP3 uses the default settings for VDD1 channel, otherwise the settings will overlap with VDD2 and attempting to modify VDD1 voltage will actually change VDD2 voltage. Signed-off-by: Tero Kristo Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/vc3xxx_data.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c index a5ec7f8f2ea8..5d8eaf31569c 100644 --- a/arch/arm/mach-omap2/vc3xxx_data.c +++ b/arch/arm/mach-omap2/vc3xxx_data.c @@ -46,6 +46,7 @@ static struct omap_vc_common omap3_vc_common = { }; struct omap_vc_channel omap3_vc_mpu = { + .flags = OMAP_VC_CHANNEL_DEFAULT, .common = &omap3_vc_common, .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET, .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET, From 23e22a5ed4a5ad26ef89c30decd414024f871664 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 20 Feb 2012 12:26:07 +0200 Subject: [PATCH 2/5] arm: omap3: add common twl configurations for vdd1 and vdd2 VDD1 and VDD2 are the core voltage regulators on OMAP3. VDD1 is used to control MPU/IVA voltage, and VDD2 is used for CORE. These regulators are needed by DVFS. Voltage ranges for VDD1 and VDD2 are taken from twl4030/twl5030 data manuals: - SWCS019L : TWL4030 ES3.1 Data Manual rev L - SWCS030E : TWL5030 ES1.2 Data Manual rev E Signed-off-by: Tero Kristo Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/twl-common.c | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 10b20c652e5d..913d6c3c4cb6 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -126,6 +126,38 @@ static struct regulator_init_data omap3_vpll2_idata = { .consumer_supplies = omap3_vpll2_supplies, }; +static struct regulator_consumer_supply omap3_vdd1_supply[] = { + REGULATOR_SUPPLY("vcc", "mpu.0"), +}; + +static struct regulator_consumer_supply omap3_vdd2_supply[] = { + REGULATOR_SUPPLY("vcc", "l3_main.0"), +}; + +static struct regulator_init_data omap3_vdd1 = { + .constraints = { + .name = "vdd_mpu_iva", + .min_uV = 600000, + .max_uV = 1450000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3_vdd1_supply), + .consumer_supplies = omap3_vdd1_supply, +}; + +static struct regulator_init_data omap3_vdd2 = { + .constraints = { + .name = "vdd_core", + .min_uV = 600000, + .max_uV = 1450000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3_vdd2_supply), + .consumer_supplies = omap3_vdd2_supply, +}; + void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, u32 pdata_flags, u32 regulators_flags) { @@ -133,6 +165,10 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, pmic_data->irq_base = TWL4030_IRQ_BASE; if (!pmic_data->irq_end) pmic_data->irq_end = TWL4030_IRQ_END; + if (!pmic_data->vdd1) + pmic_data->vdd1 = &omap3_vdd1; + if (!pmic_data->vdd2) + pmic_data->vdd2 = &omap3_vdd2; /* Common platform data configurations */ if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb) From 49c008ecce1f9a549c12e8957668d60008ab0d79 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 20 Feb 2012 12:26:08 +0200 Subject: [PATCH 3/5] arm: omap3: twl: add external controllers for core voltage regulators VDD1 and VDD2 now use voltage processor for controlling the regulators. This is done by passing additional voltdm data during the regulator init. Signed-off-by: Tero Kristo Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/twl-common.c | 33 ++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 913d6c3c4cb6..618fefb2b9b9 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -31,12 +31,25 @@ #include "twl-common.h" #include "pm.h" +#include "voltage.h" static struct i2c_board_info __initdata pmic_i2c_board_info = { .addr = 0x48, .flags = I2C_CLIENT_WAKE, }; +static int twl_set_voltage(void *data, int target_uV) +{ + struct voltagedomain *voltdm = (struct voltagedomain *)data; + return voltdm_scale(voltdm, target_uV); +} + +static int twl_get_voltage(void *data) +{ + struct voltagedomain *voltdm = (struct voltagedomain *)data; + return voltdm_get_voltage(voltdm); +} + void __init omap_pmic_init(int bus, u32 clkrate, const char *pmic_type, int pmic_irq, struct twl4030_platform_data *pmic_data) @@ -158,6 +171,16 @@ static struct regulator_init_data omap3_vdd2 = { .consumer_supplies = omap3_vdd2_supply, }; +static struct twl_regulator_driver_data omap3_vdd1_drvdata = { + .get_voltage = twl_get_voltage, + .set_voltage = twl_set_voltage, +}; + +static struct twl_regulator_driver_data omap3_vdd2_drvdata = { + .get_voltage = twl_get_voltage, + .set_voltage = twl_set_voltage, +}; + void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, u32 pdata_flags, u32 regulators_flags) { @@ -165,10 +188,16 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data, pmic_data->irq_base = TWL4030_IRQ_BASE; if (!pmic_data->irq_end) pmic_data->irq_end = TWL4030_IRQ_END; - if (!pmic_data->vdd1) + if (!pmic_data->vdd1) { + omap3_vdd1.driver_data = &omap3_vdd1_drvdata; + omap3_vdd1_drvdata.data = voltdm_lookup("mpu_iva"); pmic_data->vdd1 = &omap3_vdd1; - if (!pmic_data->vdd2) + } + if (!pmic_data->vdd2) { + omap3_vdd2.driver_data = &omap3_vdd2_drvdata; + omap3_vdd2_drvdata.data = voltdm_lookup("core"); pmic_data->vdd2 = &omap3_vdd2; + } /* Common platform data configurations */ if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb) From e160dda0f49f54deddd62e943e449a13430c2e8b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 22 Feb 2012 12:40:40 +0200 Subject: [PATCH 4/5] arm: omap4: add common twl configurations for vdd1, vdd2 and vdd3 VDD1 is used for MPU voltage, VDD2 is for IVA and VDD3 is for CORE. These are needed by DVFS. This patch also adds external controller support for these regulators, the default I2C control channel can't be used to modify the voltages for these regulators on TWL6030. Signed-off-by: Tero Kristo Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/twl-common.c | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 618fefb2b9b9..1ddad222361a 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -349,6 +349,70 @@ static struct regulator_init_data omap4_clk32kg_idata = { }, }; +static struct regulator_consumer_supply omap4_vdd1_supply[] = { + REGULATOR_SUPPLY("vcc", "mpu.0"), +}; + +static struct regulator_consumer_supply omap4_vdd2_supply[] = { + REGULATOR_SUPPLY("vcc", "iva.0"), +}; + +static struct regulator_consumer_supply omap4_vdd3_supply[] = { + REGULATOR_SUPPLY("vcc", "l3_main.0"), +}; + +static struct regulator_init_data omap4_vdd1 = { + .constraints = { + .name = "vdd_mpu", + .min_uV = 500000, + .max_uV = 1500000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(omap4_vdd1_supply), + .consumer_supplies = omap4_vdd1_supply, +}; + +static struct regulator_init_data omap4_vdd2 = { + .constraints = { + .name = "vdd_iva", + .min_uV = 500000, + .max_uV = 1500000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(omap4_vdd2_supply), + .consumer_supplies = omap4_vdd2_supply, +}; + +static struct regulator_init_data omap4_vdd3 = { + .constraints = { + .name = "vdd_core", + .min_uV = 500000, + .max_uV = 1500000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(omap4_vdd3_supply), + .consumer_supplies = omap4_vdd3_supply, +}; + + +static struct twl_regulator_driver_data omap4_vdd1_drvdata = { + .get_voltage = twl_get_voltage, + .set_voltage = twl_set_voltage, +}; + +static struct twl_regulator_driver_data omap4_vdd2_drvdata = { + .get_voltage = twl_get_voltage, + .set_voltage = twl_set_voltage, +}; + +static struct twl_regulator_driver_data omap4_vdd3_drvdata = { + .get_voltage = twl_get_voltage, + .set_voltage = twl_set_voltage, +}; + void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data, u32 pdata_flags, u32 regulators_flags) { @@ -357,6 +421,24 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data, if (!pmic_data->irq_end) pmic_data->irq_end = TWL6030_IRQ_END; + if (!pmic_data->vdd1) { + omap4_vdd1.driver_data = &omap4_vdd1_drvdata; + omap4_vdd1_drvdata.data = voltdm_lookup("mpu"); + pmic_data->vdd1 = &omap4_vdd1; + } + + if (!pmic_data->vdd2) { + omap4_vdd2.driver_data = &omap4_vdd2_drvdata; + omap4_vdd2_drvdata.data = voltdm_lookup("iva"); + pmic_data->vdd2 = &omap4_vdd2; + } + + if (!pmic_data->vdd3) { + omap4_vdd3.driver_data = &omap4_vdd3_drvdata; + omap4_vdd3_drvdata.data = voltdm_lookup("core"); + pmic_data->vdd3 = &omap4_vdd3; + } + /* Common platform data configurations */ if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb) pmic_data->usb = &omap4_usb_pdata; From c15f1d84bb3ddd668593e9bca53221a2f82e9e99 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 2 Mar 2012 14:08:57 -0800 Subject: [PATCH 5/5] ARM: OMAP2+: voltage: ensure voltage used is exact voltage from OPP table When using the SMPS regulators to scale voltages, the regulator framework may pass a minimum voltage that is not an exact OPP voltage. For the VC/VP controlled voltage domains, we must ensure that the voltage requested is the exact voltage from the OPP table. This is especially critical when using SR. To fix, voltdm_scale() uses the target voltage passed to walk through the OPP voltages until it finds a voltage that is >= one of the OPP voltages. Cc: Tero Kristo Cc: Nishanth Menon Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/voltage.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 8a36342e60d2..4dc60e83e00d 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -73,7 +73,8 @@ unsigned long voltdm_get_voltage(struct voltagedomain *voltdm) int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt) { - int ret; + int ret, i; + unsigned long volt = 0; if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); @@ -86,9 +87,23 @@ int voltdm_scale(struct voltagedomain *voltdm, return -ENODATA; } - ret = voltdm->scale(voltdm, target_volt); + /* Adjust voltage to the exact voltage from the OPP table */ + for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) { + if (voltdm->volt_data[i].volt_nominal >= target_volt) { + volt = voltdm->volt_data[i].volt_nominal; + break; + } + } + + if (!volt) { + pr_warning("%s: not scaling. OPP voltage for %lu, not found.\n", + __func__, target_volt); + return -EINVAL; + } + + ret = voltdm->scale(voltdm, volt); if (!ret) - voltdm->nominal_volt = target_volt; + voltdm->nominal_volt = volt; return ret; }