public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] OMAP3+: introduce SR class 1.5
@ 2011-02-19 12:01 Nishanth Menon
  2011-02-19 12:01 ` [PATCH 01/19] omap3: hwmod: add smartreflex irqs Nishanth Menon
                   ` (19 more replies)
  0 siblings, 20 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Hi,
This series intends to introduce SmartReflex AVS Class 1.5 support which
is now the recommended AVS class for usage in OMAP3630, OMAP4 an potentially
in later generation of silicon as well. Smartreflex class 1.5 is a software
controlled hardware calibration mechanism designed to improve dvfs latencies
and system performance as well as helping bring in additional benefits to the
system from h/w perspective. The corresponding patch has details on this class
and the implementation as well.

The series eventually results in OMAP343x based platforms using class3 and
OMAP3630, OMAP4 platforms using class1.5 automatically without modifications
or additions to board files.

This series is Based on:
a) k.org 2.6.38-rc5 (b2.6.38-rc5)
b) The following branches Kevin Hilman's tree: (pm-base)
 'pm/for_2.6.38/pm-fixes', 'pm/for_2.6.39/pm-misc' and 'pm/pm-wip/cpufreq'
 http://git.kernel.org/?p=linux/kernel/git/khilman/linux-omap-pm.git;a=summary
c) sr-fixes: (sr-baseline)
	http://marc.info/?l=linux-omap&m=129783708019505&w=2
	http://marc.info/?l=linux-omap&m=129679846322563&w=2

This series is also available at:
	git://gitorious.org/linux-omap-nm-sr/linux-omap-sr.git
	Branch: sr-1.5-v1

Note: There is also a branch sr-dvfs-1.5 in my tree which contains the test
version of code which is based off Vishwa's DVFS series which is currently
being revamped. it may need few handtweaking for testing (esp selecting class
at menuconfig level or by commenting out appropriate late_init).

The series contains a bunch of bugfixes and improvements needed to introduce
Smartreflex class 1.5.

Nishanth Menon (19):
  omap3: hwmod: add smartreflex irqs
  omap3630: hwmod: sr: enable for higher ES
  omap3+: voltage: remove initial voltage
  omap3+: voltage: remove spurious pr_notice for debugfs
  omap3+: voltage: use IS_ERR_OR_NULL
  omap3+: voltage: use volt_data pointer instead values
  omap3+: voltage: add transdone apis
  omap3+: sr: make notify independent of class
  omap3+: sr: introduce class init,deinit and priv data
  omap3+: sr: fix cosmetic indentation
  omap3+: sr: call handler with interrupt disabled
  omap3+: sr: disable interrupt by default
  omap3+: sr: enable/disable SR only on need
  omap3+: sr: introduce notifiers flags
  omap3+: sr: introduce notifier_control
  omap3+: sr: disable spamming interrupts
  omap3+: sr: make enable path use volt_data pointer
  omap3630+: sr: add support for class 1.5
  omap3430: sr: class3: restrict cpu to run on

 arch/arm/mach-omap2/Makefile                  |    1 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c    |   25 +-
 arch/arm/mach-omap2/pm.c                      |    3 +-
 arch/arm/mach-omap2/smartreflex-class1p5.c    |  556 +++++++++++++++++++++++++
 arch/arm/mach-omap2/smartreflex-class3.c      |   21 +-
 arch/arm/mach-omap2/smartreflex.c             |  249 ++++++++++--
 arch/arm/mach-omap2/voltage.c                 |  236 ++++++++---
 arch/arm/plat-omap/Kconfig                    |   17 +
 arch/arm/plat-omap/include/plat/smartreflex.h |   42 ++-
 arch/arm/plat-omap/include/plat/voltage.h     |   36 ++-
 10 files changed, 1062 insertions(+), 124 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c

Testing performed:
- basic boot tests on SDP3630 and SDP3430 - with bare series
- Detailed dvfs tests with Viswha's series on SDP3430 and SDP3630
- OMAP4 was'nt supported yet by dvfs series, so very restricted tests.
- Build tests with and without each of SR classes, SMARTREFLEX enabled.

Test Script: http://pastebin.mozilla.org/1080985

I request any additional tests on Panda, BeagleXM, EVM platforms that folks
may have. please feel free to comment and provide tested-by/Acked-by feedback
before I take this ahead including l-a.

Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 01/19] omap3: hwmod: add smartreflex irqs
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-02 23:48   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES Nishanth Menon
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

OMAP3 smartreflex irqs in hwmod structures with the same naming as
present in OMAP4. Without these IRQs being registered, SmartReflex
driver will be unable to get the irq numbers to handle notifications

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 8d81813..ea1f49a 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -265,6 +265,15 @@ static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+
+static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
+	{.name = "sr1_irq", .irq = 18},
+};
+
+static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
+	{.name = "sr2_irq", .irq = 19},
+};
+
 /* L4 CORE -> SR1 interface */
 static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
 	{
@@ -1289,6 +1298,8 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
 					CHIP_IS_OMAP3430ES3_0 |
 					CHIP_IS_OMAP3430ES3_1),
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_mpu_irqs),
 };
 
 static struct omap_hwmod omap36xx_sr1_hwmod = {
@@ -1308,6 +1319,8 @@ static struct omap_hwmod omap36xx_sr1_hwmod = {
 	.slaves		= omap3_sr1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_mpu_irqs),
 };
 
 /* SR2 */
@@ -1335,6 +1348,8 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
 					CHIP_IS_OMAP3430ES3_0 |
 					CHIP_IS_OMAP3430ES3_1),
 	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+	.mpu_irqs	= omap3_smartreflex_core_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_core_irqs),
 };
 
 static struct omap_hwmod omap36xx_sr2_hwmod = {
@@ -1354,6 +1369,8 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
 	.slaves		= omap3_sr2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+	.mpu_irqs	= omap3_smartreflex_core_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_core_irqs),
 };
 
 static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
  2011-02-19 12:01 ` [PATCH 01/19] omap3: hwmod: add smartreflex irqs Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 13:22   ` Vishwanath Sripathy
  2011-02-19 12:01 ` [PATCH 03/19] omap3+: voltage: remove initial voltage Nishanth Menon
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Enable hwmod entries for OMAP3630 for higher ES revisions as
well. This is to ensure that SR can be used in all revisions of
OMAP3630 as of this posting.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ea1f49a..bbcbea6 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -1318,7 +1318,9 @@ static struct omap_hwmod omap36xx_sr1_hwmod = {
 	},
 	.slaves		= omap3_sr1_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
-	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1	|
+					CHIP_IS_OMAP3630ES1_1	|
+					CHIP_IS_OMAP3630ES1_2),
 	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
 	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_mpu_irqs),
 };
@@ -1368,7 +1370,9 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
 	},
 	.slaves		= omap3_sr2_slaves,
 	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
-	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1	|
+					CHIP_IS_OMAP3630ES1_1	|
+					CHIP_IS_OMAP3630ES1_2),
 	.mpu_irqs	= omap3_smartreflex_core_irqs,
 	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_core_irqs),
 };
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
  2011-02-19 12:01 ` [PATCH 01/19] omap3: hwmod: add smartreflex irqs Nishanth Menon
  2011-02-19 12:01 ` [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 13:24   ` Vishwanath Sripathy
  2011-02-19 12:01 ` [PATCH 04/19] omap3+: voltage: remove spurious pr_notice for debugfs Nishanth Menon
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

omap2_set_init_voltage should setup the curr_volt based on which OPP
the system is functioning at. Blindly setting a 1.2v setting in the
initial structure may not even match the default voltages stored in
the voltage table which are supported for the domain.

For example, OMAP3430 core domain does not use 1.2v and ends up
generating a warning on the first transition.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/voltage.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 12be525..280ee12 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -863,7 +863,6 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
 	sys_clk_speed /= 1000;
 
 	/* Generic voltage parameters */
-	vdd->curr_volt = 1200000;
 	vdd->ocp_mod = OCP_MOD;
 	vdd->prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
 	vdd->read_reg = omap3_voltage_read_reg;
@@ -1054,7 +1053,6 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
 	sys_clk_speed /= 1000;
 
 	/* Generic voltage parameters */
-	vdd->curr_volt = 1200000;
 	vdd->ocp_mod = OMAP4430_PRM_OCP_SOCKET_INST;
 	vdd->read_reg = omap4_voltage_read_reg;
 	vdd->write_reg = omap4_voltage_write_reg;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 04/19] omap3+: voltage: remove spurious pr_notice for debugfs
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (2 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 03/19] omap3+: voltage: remove initial voltage Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 12:01 ` [PATCH 05/19] omap3+: voltage: use IS_ERR_OR_NULL Nishanth Menon
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

cat of debugfs entry for vp_volt provides voltage. The additional pr_notice
is just spam on console and provides no additional information.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/voltage.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 280ee12..992b383 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -347,7 +347,6 @@ static int vp_volt_debug_get(void *data, u64 *val)
 	}
 
 	vsel = vdd->read_reg(vdd->vp_reg.prm_mod, vdd->vp_offs.voltage);
-	pr_notice("curr_vsel = %x\n", vsel);
 
 	if (!vdd->pmic_info->vsel_to_uv) {
 		pr_warning("PMIC function to convert vsel to voltage"
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 05/19] omap3+: voltage: use IS_ERR_OR_NULL
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (3 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 04/19] omap3+: voltage: remove spurious pr_notice for debugfs Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 12:01 ` [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values Nishanth Menon
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Use IS_ERR_OR_NULL macro instead of just IS_ERR or !xyz || IS_ERR(xyz)
style usage.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/voltage.c |   28 ++++++++++++++--------------
 1 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 992b383..3ee8a80 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -471,7 +471,7 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
 
 	vdd->debug_dir = debugfs_create_dir(name, voltage_dir);
 	kfree(name);
-	if (IS_ERR(vdd->debug_dir)) {
+	if (IS_ERR_OR_NULL(vdd->debug_dir)) {
 		pr_warning("%s: Unable to create debugfs directory for"
 			" vdd_%s\n", __func__, vdd->voltdm.name);
 		vdd->debug_dir = NULL;
@@ -851,7 +851,7 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
 	 * smpswaittimemin and smpswaittimemax.
 	 */
 	sys_ck = clk_get(NULL, "sys_ck");
-	if (IS_ERR(sys_ck)) {
+	if (IS_ERR_OR_NULL(sys_ck)) {
 		pr_warning("%s: Could not get the sys clk to calculate"
 			"various vdd_%s params\n", __func__, vdd->voltdm.name);
 		return -EINVAL;
@@ -1041,7 +1041,7 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
 	 * smpswaittimemin and smpswaittimemax.
 	 */
 	sys_ck = clk_get(NULL, "sys_clkin_ck");
-	if (IS_ERR(sys_ck)) {
+	if (IS_ERR_OR_NULL(sys_ck)) {
 		pr_warning("%s: Could not get the sys clk to calculate"
 			"various vdd_%s params\n", __func__, vdd->voltdm.name);
 		return -EINVAL;
@@ -1125,7 +1125,7 @@ unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
 {
 	struct omap_vdd_info *vdd;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return 0;
 	}
@@ -1146,7 +1146,7 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
 	struct omap_vdd_info *vdd;
 	u8 curr_vsel;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return 0;
 	}
@@ -1183,7 +1183,7 @@ void omap_vp_enable(struct voltagedomain *voltdm)
 	u32 vpconfig;
 	u16 mod;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return;
 	}
@@ -1224,7 +1224,7 @@ void omap_vp_disable(struct voltagedomain *voltdm)
 	u16 mod;
 	int timeout;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return;
 	}
@@ -1308,7 +1308,7 @@ void omap_voltage_reset(struct voltagedomain *voltdm)
 {
 	unsigned long target_uvdc;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return;
 	}
@@ -1340,7 +1340,7 @@ void omap_voltage_get_volttable(struct voltagedomain *voltdm,
 {
 	struct omap_vdd_info *vdd;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return;
 	}
@@ -1371,7 +1371,7 @@ struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
 	struct omap_vdd_info *vdd;
 	int i;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return ERR_PTR(-EINVAL);
 	}
@@ -1409,7 +1409,7 @@ int omap_voltage_register_pmic(struct voltagedomain *voltdm,
 {
 	struct omap_vdd_info *vdd;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return -EINVAL;
 	}
@@ -1436,7 +1436,7 @@ struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm)
 {
 	struct omap_vdd_info *vdd;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return NULL;
 	}
@@ -1461,7 +1461,7 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm,
 {
 	struct omap_vdd_info *vdd;
 
-	if (!voltdm || IS_ERR(voltdm)) {
+	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
 		return;
 	}
@@ -1531,7 +1531,7 @@ int __init omap_voltage_late_init(void)
 	}
 
 	voltage_dir = debugfs_create_dir("voltage", NULL);
-	if (IS_ERR(voltage_dir))
+	if (IS_ERR_OR_NULL(voltage_dir))
 		pr_err("%s: Unable to create voltage debugfs main dir\n",
 			__func__);
 	for (i = 0; i < nr_scalable_vdd; i++) {
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (4 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 05/19] omap3+: voltage: use IS_ERR_OR_NULL Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-24  5:28   ` Gulati, Shweta
  2011-02-19 12:01 ` [PATCH 07/19] omap3+: voltage: add transdone apis Nishanth Menon
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Voltage values can get confusing in meaning with various Smartreflex
classes being active. Depending on the class used, the actual voltage
selected might be a variant. Hence pass the volt_data pointers through
the structure. Each voltage domain contains a set of volt_data structs.
Each of those volt_data struct represents a voltage point that is supported
for that domain. Hence, this is a more accurate representation of the
voltage point we are interested in going to, and the actual translation
of this voltage point to the voltage value is done inside the voltage layer
which allows the users of the voltage layer to be blissfully ignorant
of any complexity of the underneath layers.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/pm.c                  |    3 +-
 arch/arm/mach-omap2/smartreflex-class3.c  |    3 +-
 arch/arm/mach-omap2/voltage.c             |   72 +++++++++++++++--------------
 arch/arm/plat-omap/include/plat/voltage.h |   13 ++++-
 4 files changed, 53 insertions(+), 38 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d5a102c..669998b 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -209,7 +209,8 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
 		goto exit;
 	}
 
-	omap_voltage_scale_vdd(voltdm, bootup_volt);
+	omap_voltage_scale_vdd(voltdm,
+			omap_voltage_get_voltdata(voltdm, bootup_volt));
 	return 0;
 
 exit:
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 60e7055..2195668 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -15,7 +15,8 @@
 
 static int sr_class3_enable(struct voltagedomain *voltdm)
 {
-	unsigned long volt = omap_voltage_get_nom_volt(voltdm);
+	unsigned long volt = omap_get_operation_voltage(
+		omap_voltage_get_nom_volt(voltdm));
 
 	if (!volt) {
 		pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n",
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 3ee8a80..08f0abf 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -146,14 +146,14 @@ struct omap_vdd_info {
 	struct vc_reg_info vc_reg;
 	struct voltagedomain voltdm;
 	struct dentry *debug_dir;
-	u32 curr_volt;
+	struct omap_volt_data *curr_volt;
 	u16 ocp_mod;
 	u8 prm_irqst_reg;
 	bool vp_enabled;
 	u32 (*read_reg) (u16 mod, u8 offset);
 	void (*write_reg) (u32 val, u16 mod, u8 offset);
 	int (*volt_scale) (struct omap_vdd_info *vdd,
-		unsigned long target_volt);
+		struct omap_volt_data *target_volt);
 };
 
 static struct omap_vdd_info *vdd_info;
@@ -361,13 +361,15 @@ static int vp_volt_debug_get(void *data, u64 *val)
 static int nom_volt_debug_get(void *data, u64 *val)
 {
 	struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
+	struct omap_volt_data *volt_data;
 
 	if (!vdd) {
 		pr_warning("Wrong paramater passed\n");
 		return -EINVAL;
 	}
+	volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
 
-	*val = omap_voltage_get_nom_volt(&vdd->voltdm);
+	*val = volt_data->volt_nominal;
 
 	return 0;
 }
@@ -382,7 +384,8 @@ static void vp_latch_vsel(struct omap_vdd_info *vdd)
 	unsigned long uvdc;
 	char vsel;
 
-	uvdc = omap_voltage_get_nom_volt(&vdd->voltdm);
+	uvdc = omap_get_operation_voltage(
+			omap_voltage_get_nom_volt(&vdd->voltdm));
 	if (!uvdc) {
 		pr_warning("%s: unable to find current voltage for vdd_%s\n",
 			__func__, vdd->voltdm.name);
@@ -505,12 +508,18 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
 
 /* Voltage scale and accessory APIs */
 static int _pre_volt_scale(struct omap_vdd_info *vdd,
-		unsigned long target_volt, u8 *target_vsel, u8 *current_vsel)
+		struct omap_volt_data *target_volt, u8 *target_vsel,
+		u8 *current_vsel)
 {
-	struct omap_volt_data *volt_data;
 	u32 vc_cmdval, vp_errgain_val;
 	u16 vp_mod, vc_mod;
 
+	if (IS_ERR_OR_NULL(target_volt) || IS_ERR_OR_NULL(vdd) ||
+			!target_vsel || !current_vsel) {
+		pr_err("%s: invalid parms!\n", __func__);
+		return -EINVAL;
+	}
+
 	/* Check if suffiecient pmic info is available for this vdd */
 	if (!vdd->pmic_info) {
 		pr_err("%s: Insufficient pmic info to scale the vdd_%s\n",
@@ -534,12 +543,8 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
 	vp_mod = vdd->vp_reg.prm_mod;
 	vc_mod = vdd->vc_reg.prm_mod;
 
-	/* Get volt_data corresponding to target_volt */
-	volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
-	if (IS_ERR(volt_data))
-		volt_data = NULL;
-
-	*target_vsel = vdd->pmic_info->uv_to_vsel(target_volt);
+	*target_vsel = vdd->pmic_info->uv_to_vsel(
+			omap_get_operation_voltage(target_volt));
 	*current_vsel = vdd->read_reg(vp_mod, vdd->vp_offs.voltage);
 
 	/* Setting the ON voltage to the new target voltage */
@@ -549,22 +554,21 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
 	vdd->write_reg(vc_cmdval, vc_mod, vdd->vc_reg.cmdval_reg);
 
 	/* Setting vp errorgain based on the voltage */
-	if (volt_data) {
-		vp_errgain_val = vdd->read_reg(vp_mod,
-				vdd->vp_offs.vpconfig);
-		vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
-		vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
-		vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
-				vdd->vp_reg.vpconfig_errorgain_shift;
-		vdd->write_reg(vp_errgain_val, vp_mod,
-				vdd->vp_offs.vpconfig);
-	}
+	vp_errgain_val = vdd->read_reg(vp_mod,
+			vdd->vp_offs.vpconfig);
+	vdd->vp_reg.vpconfig_errorgain = target_volt->vp_errgain;
+	vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
+	vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
+			vdd->vp_reg.vpconfig_errorgain_shift;
+	vdd->write_reg(vp_errgain_val, vp_mod,
+			vdd->vp_offs.vpconfig);
 
 	return 0;
 }
 
 static void _post_volt_scale(struct omap_vdd_info *vdd,
-		unsigned long target_volt, u8 target_vsel, u8 current_vsel)
+		struct omap_volt_data *target_volt, u8 target_vsel,
+		u8 current_vsel)
 {
 	u32 smps_steps = 0, smps_delay = 0;
 
@@ -579,7 +583,7 @@ static void _post_volt_scale(struct omap_vdd_info *vdd,
 
 /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
 static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
-		unsigned long target_volt)
+		struct omap_volt_data *target_volt)
 {
 	u32 loop_cnt = 0, retries_cnt = 0;
 	u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
@@ -632,7 +636,7 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
 
 /* VP force update method of voltage scaling */
 static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
-		unsigned long target_volt)
+		struct omap_volt_data *target_volt)
 {
 	u32 vpconfig;
 	u16 mod, ocp_mod;
@@ -1118,16 +1122,15 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
  * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
  * @voltdm:	pointer to the VDD for which current voltage info is needed
  *
- * API to get the current non-auto-compensated voltage for a VDD.
- * Returns 0 in case of error else returns the current voltage for the VDD.
+ * API to get the current non-auto-compensated voltage data pointer for a VDD.
  */
-unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
+struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
 {
 	struct omap_vdd_info *vdd;
 
 	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
-		return 0;
+		return ERR_PTR(-ENODATA);
 	}
 
 	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
@@ -1269,18 +1272,19 @@ void omap_vp_disable(struct voltagedomain *voltdm)
  * omap_voltage_scale_vdd() - API to scale voltage of a particular
  *				voltage domain.
  * @voltdm:	pointer to the VDD which is to be scaled.
- * @target_volt:	The target voltage of the voltage domain
+ * @target_volt:	The target voltage data for the voltage domain
  *
  * This API should be called by the kernel to do the voltage scaling
  * for a particular voltage domain during dvfs or any other situation.
  */
 int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
-		unsigned long target_volt)
+		struct omap_volt_data *target_volt)
 {
 	struct omap_vdd_info *vdd;
 
-	if (!voltdm || IS_ERR(voltdm)) {
-		pr_warning("%s: VDD specified does not exist!\n", __func__);
+	if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(target_volt)) {
+		pr_warning("%s: Bad Params vdm=%p tv=%p!\n", __func__,
+				voltdm, target_volt);
 		return -EINVAL;
 	}
 
@@ -1306,7 +1310,7 @@ int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
  */
 void omap_voltage_reset(struct voltagedomain *voltdm)
 {
-	unsigned long target_uvdc;
+	struct omap_volt_data *target_uvdc;
 
 	if (IS_ERR_OR_NULL(voltdm)) {
 		pr_warning("%s: VDD specified does not exist!\n", __func__);
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index 5bd204e..52df49f 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -117,13 +117,13 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm);
 void omap_vp_enable(struct voltagedomain *voltdm);
 void omap_vp_disable(struct voltagedomain *voltdm);
 int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
-		unsigned long target_volt);
+		struct omap_volt_data *target_volt);
 void omap_voltage_reset(struct voltagedomain *voltdm);
 void omap_voltage_get_volttable(struct voltagedomain *voltdm,
 		struct omap_volt_data **volt_data);
 struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
 		unsigned long volt);
-unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
+struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
 struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
 #ifdef CONFIG_PM
 int omap_voltage_register_pmic(struct voltagedomain *voltdm,
@@ -152,4 +152,13 @@ static inline struct voltagedomain *omap_voltage_domain_lookup(char *name)
 }
 #endif
 
+/* convert volt data to the voltage for the voltage data */
+static inline unsigned long omap_get_operation_voltage(
+		struct omap_volt_data *vdata)
+{
+	if (IS_ERR_OR_NULL(vdata))
+		return 0;
+	return vdata->volt_nominal;
+}
+
 #endif
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 07/19] omap3+: voltage: add transdone apis
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (5 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 12:01 ` [PATCH 08/19] omap3+: sr: make notify independent of class Nishanth Menon
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Transdone event in Voltage processor gives us fine grained status on
the current status of the voltage communication with the PMIC.
Unfortunately, irq generation by VP is based on the start of the
transmission to VC from VP, not at the end (or the completion of
the voltage setting). Hence any users of voltage layer who need
to know fine grained information such as confirmation if the voltage
is actually send to PMIC, needs to depend on this status.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/voltage.c             |   64 ++++++++++++++++++++++-------
 arch/arm/plat-omap/include/plat/voltage.h |    2 +
 2 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 08f0abf..77cb0cd 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -639,8 +639,8 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
 		struct omap_volt_data *target_volt)
 {
 	u32 vpconfig;
-	u16 mod, ocp_mod;
-	u8 target_vsel, current_vsel, prm_irqst_reg;
+	u16 mod;
+	u8 target_vsel, current_vsel;
 	int ret, timeout = 0;
 
 	ret = _pre_volt_scale(vdd, target_volt, &target_vsel, &current_vsel);
@@ -648,18 +648,13 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
 		return ret;
 
 	mod = vdd->vp_reg.prm_mod;
-	ocp_mod = vdd->ocp_mod;
-	prm_irqst_reg = vdd->prm_irqst_reg;
-
 	/*
 	 * Clear all pending TransactionDone interrupt/status. Typical latency
 	 * is <3us
 	 */
 	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
-		vdd->write_reg(vdd->vp_reg.tranxdone_status,
-				ocp_mod, prm_irqst_reg);
-		if (!(vdd->read_reg(ocp_mod, prm_irqst_reg) &
-				vdd->vp_reg.tranxdone_status))
+		omap_vp_clear_transdone(&vdd->voltdm);
+		if (!omap_vp_is_transdone(&vdd->voltdm))
 				break;
 		udelay(1);
 	}
@@ -691,7 +686,7 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
 	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
 	 */
 	timeout = 0;
-	omap_test_timeout((vdd->read_reg(ocp_mod, prm_irqst_reg) &
+	omap_test_timeout((vdd->read_reg(vdd->ocp_mod, vdd->prm_irqst_reg) &
 			vdd->vp_reg.tranxdone_status),
 			VP_TRANXDONE_TIMEOUT, timeout);
 	if (timeout >= VP_TRANXDONE_TIMEOUT)
@@ -707,11 +702,9 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
 	 */
 	timeout = 0;
 	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
-		vdd->write_reg(vdd->vp_reg.tranxdone_status,
-				ocp_mod, prm_irqst_reg);
-		if (!(vdd->read_reg(ocp_mod, prm_irqst_reg) &
-				vdd->vp_reg.tranxdone_status))
-				break;
+		omap_vp_clear_transdone(&vdd->voltdm);
+		if (!omap_vp_is_transdone(&vdd->voltdm))
+			break;
 		udelay(1);
 	}
 
@@ -1269,6 +1262,47 @@ void omap_vp_disable(struct voltagedomain *voltdm)
 }
 
 /**
+ * omap_vp_is_transdone() - is voltage transfer done on vp?
+ * @voltdm:	pointer to the VDD which is to be scaled.
+ *
+ * VP's transdone bit is the only way to ensure that the transfer
+ * of the voltage value has actually been send over to the PMIC
+ * This is hence useful for all users of voltage domain to precisely
+ * identify once the PMIC voltage has been set by the voltage processor
+ */
+bool omap_vp_is_transdone(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+
+	if (IS_ERR_OR_NULL(voltdm)) {
+		pr_warning("%s: Bad Params vdm=%p\n", __func__, voltdm);
+		return false;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	return (vdd->read_reg(vdd->ocp_mod, vdd->prm_irqst_reg) &
+			vdd->vp_reg.tranxdone_status) ? true : false;
+}
+
+/**
+ * omap_vp_clear_transdone() - clear voltage transfer done status on vp
+ * @voltdm:	pointer to the VDD which is to be scaled.
+ */
+bool omap_vp_clear_transdone(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+
+	if (IS_ERR_OR_NULL(voltdm)) {
+		pr_warning("%s: Bad Params vdm=%p\n", __func__, voltdm);
+		return false;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	vdd->write_reg(vdd->vp_reg.tranxdone_status,
+			vdd->ocp_mod, vdd->prm_irqst_reg);
+	return true;
+}
+/**
  * omap_voltage_scale_vdd() - API to scale voltage of a particular
  *				voltage domain.
  * @voltdm:	pointer to the VDD which is to be scaled.
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index 52df49f..332c581 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -124,6 +124,8 @@ void omap_voltage_get_volttable(struct voltagedomain *voltdm,
 struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
 		unsigned long volt);
 struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
+bool omap_vp_is_transdone(struct voltagedomain *voltdm);
+bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
 struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
 #ifdef CONFIG_PM
 int omap_voltage_register_pmic(struct voltagedomain *voltdm,
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 08/19] omap3+: sr: make notify independent of class
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (6 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 07/19] omap3+: voltage: add transdone apis Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:05   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data Nishanth Menon
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Interrupt notification mechanism of SmartReflex can be used by the
choice of implementation of the class driver. For example, Class 2 and
Class 1.5 of SmartReflex can both use the interrupt notification to
identify the transition of voltage or other events.

Hence, the actual class does not matter for notifier. Let the class
driver's handling decide how it should be used. smartreflex driver
should provide just the primitives.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index eba90a4..6f0c7d0 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -142,7 +142,7 @@ static irqreturn_t sr_interrupt(int irq, void *data)
 		sr_write_reg(sr_info, IRQSTATUS, status);
 	}
 
-	if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
+	if (sr_class->notify)
 		sr_class->notify(sr_info->voltdm, status);
 
 	return IRQ_HANDLED;
@@ -257,9 +257,7 @@ static int sr_late_init(struct omap_sr *sr_info)
 	struct resource *mem;
 	int ret = 0;
 
-	if (sr_class->class_type == SR_CLASS2 &&
-		sr_class->notify_flags && sr_info->irq) {
-
+	if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
 		name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
 		if (name == NULL) {
 			ret = -ENOMEM;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (7 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 08/19] omap3+: sr: make notify independent of class Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:08   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 10/19] omap3+: sr: fix cosmetic indentation Nishanth Menon
                   ` (10 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Certain class drivers such as class 1.5 drivers, will need specific
notification that they have to be started up or stopped independent
of smart reflex operation. They also may need private data to be
used for operations of their own, provide the same.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c             |   14 ++++++++++++++
 arch/arm/plat-omap/include/plat/smartreflex.h |    7 +++++++
 2 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 6f0c7d0..fb675c0 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -220,6 +220,13 @@ static void sr_start_vddautocomp(struct omap_sr *sr)
 		return;
 	}
 
+	if (sr_class->class_init &&
+	    sr_class->class_init(sr->voltdm, sr_class->class_priv_data)) {
+		dev_err(&sr->pdev->dev,
+			"%s: SRClass initialization failed\n", __func__);
+		return;
+	}
+
 	if (!sr_class->enable(sr->voltdm))
 		sr->autocomp_active = true;
 }
@@ -235,6 +242,13 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
 
 	if (sr->autocomp_active) {
 		sr_class->disable(sr->voltdm, 1);
+		if (sr_class->class_deinit &&
+		    sr_class->class_deinit(sr->voltdm,
+			    sr_class->class_priv_data)) {
+			dev_err(&sr->pdev->dev,
+				"%s: SR[%d]Class deinitialization failed\n",
+				__func__, sr->srid);
+		}
 		sr->autocomp_active = false;
 	}
 }
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
index 6568c88..8b6ecd9 100644
--- a/arch/arm/plat-omap/include/plat/smartreflex.h
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -167,6 +167,8 @@ struct omap_sr_pmic_data {
  *
  * @enable:		API to enable a particular class smaartreflex.
  * @disable:		API to disable a particular class smartreflex.
+ * @class_init:		API to do class specific initialization (optional)
+ * @class_deinit:	API to do class specific initialization (optional)
  * @configure:		API to configure a particular class smartreflex.
  * @notify:		API to notify the class driver about an event in SR.
  *			Not needed for class3.
@@ -174,14 +176,19 @@ struct omap_sr_pmic_data {
  * @class_type:		specify which smartreflex class.
  *			Can be used by the SR driver to take any class
  *			based decisions.
+ * @class_priv_data:	Class specific private data (optional)
  */
 struct omap_sr_class_data {
 	int (*enable)(struct voltagedomain *voltdm);
 	int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
+	int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
+	int (*class_deinit)(struct voltagedomain *voltdm,
+			void *class_priv_data);
 	int (*configure)(struct voltagedomain *voltdm);
 	int (*notify)(struct voltagedomain *voltdm, u32 status);
 	u8 notify_flags;
 	u8 class_type;
+	void *class_priv_data;
 };
 
 /**
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 10/19] omap3+: sr: fix cosmetic indentation
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (8 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:09   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 11/19] omap3+: sr: call handler with interrupt disabled Nishanth Menon
                   ` (9 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Error label case seems to have a 2 tab indentation when just 1 is
necessary.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index fb675c0..1fe8b95 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -289,15 +289,15 @@ static int sr_late_init(struct omap_sr *sr_info)
 	return ret;
 
 error:
-		iounmap(sr_info->base);
-		mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
-		release_mem_region(mem->start, resource_size(mem));
-		list_del(&sr_info->node);
-		dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
-			"interrupt handler. Smartreflex will"
-			"not function as desired\n", __func__);
-		kfree(sr_info);
-		return ret;
+	iounmap(sr_info->base);
+	mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+	list_del(&sr_info->node);
+	dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
+		"interrupt handler. Smartreflex will"
+		"not function as desired\n", __func__);
+	kfree(sr_info);
+	return ret;
 }
 
 static void sr_v1_disable(struct omap_sr *sr)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 11/19] omap3+: sr: call handler with interrupt disabled
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (9 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 10/19] omap3+: sr: fix cosmetic indentation Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:11   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 12/19] omap3+: sr: disable interrupt by default Nishanth Menon
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Request the handler irq such that there is no nesting for calls.
the notifiers are not expected to be nested, further the interrupt
events for status change should be handled prior to the next event
else there is a risk of loosing events.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 1fe8b95..7931fcd 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -278,7 +278,7 @@ static int sr_late_init(struct omap_sr *sr_info)
 			goto error;
 		}
 		ret = request_irq(sr_info->irq, sr_interrupt,
-				0, name, (void *)sr_info);
+				IRQF_DISABLED, name, (void *)sr_info);
 		if (ret)
 			goto error;
 	}
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 12/19] omap3+: sr: disable interrupt by default
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (10 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 11/19] omap3+: sr: call handler with interrupt disabled Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:15   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 13/19] omap3+: sr: enable/disable SR only on need Nishanth Menon
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

We will enable and disable interrupt on a need basis in the class
driver. we need to keep the irq disabled by default else the
forceupdate or vcbypass events could trigger events that we dont
need/expect to handle.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 7931fcd..9c61ab0 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -281,6 +281,7 @@ static int sr_late_init(struct omap_sr *sr_info)
 				IRQF_DISABLED, name, (void *)sr_info);
 		if (ret)
 			goto error;
+		disable_irq(sr_info->irq);
 	}
 
 	if (pdata && pdata->enable_on_init)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 13/19] omap3+: sr: enable/disable SR only on need
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (11 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 12/19] omap3+: sr: disable interrupt by default Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 12:01 ` [PATCH 14/19] omap3+: sr: introduce notifiers flags Nishanth Menon
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Since we already know the state of the autocomp enablement, we can
see if the requested state is different from the current state and
enable/disable SR only on the need basis.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 9c61ab0..65431df 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -819,10 +819,13 @@ static int omap_sr_autocomp_store(void *data, u64 val)
 		return -EINVAL;
 	}
 
-	if (!val)
-		sr_stop_vddautocomp(sr_info);
-	else
-		sr_start_vddautocomp(sr_info);
+	/* control enable/disable only if there is a delta in value */
+	if (sr_info->autocomp_active ^ val) {
+		if (!val)
+			sr_stop_vddautocomp(sr_info);
+		else
+			sr_start_vddautocomp(sr_info);
+	}
 
 	return 0;
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 14/19] omap3+: sr: introduce notifiers flags
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (12 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 13/19] omap3+: sr: enable/disable SR only on need Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:17   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 15/19] omap3+: sr: introduce notifier_control Nishanth Menon
                   ` (5 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

SmartReflex IP v1 and v2 have different registers and offsets.
Currently, we pass the status as is to the class driver. However,
since we dont pass the version of the underlying SR hardware
to the Class driver, it will not be unable to make consistent
sense of the status bits coming over to it.

A class driver should be able to function without dependency
on the exact IP version it is actually running on. We hence
introduce our own translation in s/w level for a generic
notification flag.

As part of this change, we will now call the notifier iff we get
a match with the notifier flags that the class driver requested.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c             |   73 ++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/smartreflex.h |    6 ++
 2 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 65431df..165f6f3 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -123,27 +123,94 @@ static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
 	return ERR_PTR(-ENODATA);
 }
 
+static inline u32 notifier_to_irqen_v1(u8 notify_flags)
+{
+	u32 val;
+	val = (notify_flags & SR_NOTIFY_MCUACCUM) ?
+		ERRCONFIG_MCUACCUMINTEN : 0;
+	val |= (notify_flags & SR_NOTIFY_MCUVALID) ?
+		ERRCONFIG_MCUVALIDINTEN : 0;
+	val |= (notify_flags & SR_NOTIFY_MCUBOUND) ?
+		ERRCONFIG_MCUBOUNDINTEN : 0;
+	val |= (notify_flags & SR_NOTIFY_MCUDISACK) ?
+		ERRCONFIG_MCUDISACKINTEN : 0;
+	return val;
+}
+
+static inline u32 notifier_to_irqen_v2(u8 notify_flags)
+{
+	u32 val;
+	val = (notify_flags & SR_NOTIFY_MCUACCUM) ?
+		IRQENABLE_MCUACCUMINT : 0;
+	val |= (notify_flags & SR_NOTIFY_MCUVALID) ?
+		IRQENABLE_MCUVALIDINT : 0;
+	val |= (notify_flags & SR_NOTIFY_MCUBOUND) ?
+		IRQENABLE_MCUBOUNDSINT : 0;
+	val |= (notify_flags & SR_NOTIFY_MCUDISACK) ?
+		IRQENABLE_MCUDISABLEACKINT : 0;
+	return val;
+}
+
+static inline u8 irqstat_to_notifier_v1(u32 status)
+{
+	u8 val;
+	val = (status & ERRCONFIG_MCUACCUMINTST) ?
+		SR_NOTIFY_MCUACCUM : 0;
+	val |= (status & ERRCONFIG_MCUVALIDINTEN) ?
+		SR_NOTIFY_MCUVALID : 0;
+	val |= (status & ERRCONFIG_MCUBOUNDINTEN) ?
+		SR_NOTIFY_MCUBOUND : 0;
+	val |= (status & ERRCONFIG_MCUDISACKINTEN) ?
+		SR_NOTIFY_MCUDISACK : 0;
+	return val;
+}
+
+static inline u8 irqstat_to_notifier_v2(u32 status)
+{
+	u8 val;
+	val = (status & IRQENABLE_MCUACCUMINT) ?
+		SR_NOTIFY_MCUACCUM : 0;
+	val |= (status & IRQENABLE_MCUVALIDINT) ?
+		SR_NOTIFY_MCUVALID : 0;
+	val |= (status & IRQENABLE_MCUBOUNDSINT) ?
+		SR_NOTIFY_MCUBOUND : 0;
+	val |= (status & IRQENABLE_MCUDISABLEACKINT) ?
+		SR_NOTIFY_MCUDISACK : 0;
+	return val;
+}
+
+
 static irqreturn_t sr_interrupt(int irq, void *data)
 {
 	struct omap_sr *sr_info = (struct omap_sr *)data;
 	u32 status = 0;
+	u32 value = 0;
 
 	if (sr_info->ip_type == SR_TYPE_V1) {
+		/* Status bits are one bit before enable bits in v1 */
+		value = notifier_to_irqen_v1(sr_class->notify_flags) >> 1;
+
 		/* Read the status bits */
 		status = sr_read_reg(sr_info, ERRCONFIG_V1);
+		status &= value;
 
 		/* Clear them by writing back */
-		sr_write_reg(sr_info, ERRCONFIG_V1, status);
+		sr_modify_reg(sr_info, ERRCONFIG_V1, value, status);
+
+		value = irqstat_to_notifier_v1(status);
 	} else if (sr_info->ip_type == SR_TYPE_V2) {
+		value = notifier_to_irqen_v2(sr_class->notify_flags);
 		/* Read the status bits */
-		sr_read_reg(sr_info, IRQSTATUS);
+		status = sr_read_reg(sr_info, IRQSTATUS);
+		status &= value;
 
 		/* Clear them by writing back */
 		sr_write_reg(sr_info, IRQSTATUS, status);
+		value = irqstat_to_notifier_v2(status);
 	}
 
 	if (sr_class->notify)
-		sr_class->notify(sr_info->voltdm, status);
+		sr_class->notify(sr_info->voltdm, value);
 
 	return IRQ_HANDLED;
 }
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
index 8b6ecd9..ff07d1e 100644
--- a/arch/arm/plat-omap/include/plat/smartreflex.h
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -141,6 +141,12 @@
 #define OMAP3430_SR_ERRWEIGHT		0x04
 #define OMAP3430_SR_ERRMAXLIMIT		0x02
 
+/* Smart reflex notifiers for class drivers to use */
+#define SR_NOTIFY_MCUACCUM     (0x1 << 0)
+#define SR_NOTIFY_MCUVALID     (0x1 << 1)
+#define SR_NOTIFY_MCUBOUND     (0x1 << 2)
+#define SR_NOTIFY_MCUDISACK    (0x1 << 3)
+
 /**
  * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass
  *				pmic specific info to smartreflex driver
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 15/19] omap3+: sr: introduce notifier_control
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (13 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 14/19] omap3+: sr: introduce notifiers flags Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 13:40   ` Vishwanath Sripathy
  2011-02-19 12:01 ` [PATCH 16/19] omap3+: sr: disable spamming interrupts Nishanth Menon
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

We need some mechanism from class drivers to control when notifiers
should be triggered and when not, currently we have none, which makes
Class driver usage of the interrupt events almost impossible.
Introduce an smartreflex driver api for doing the same.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c             |   57 +++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/smartreflex.h |    8 ++++
 2 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 165f6f3..ad23b8d 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -704,6 +704,63 @@ void sr_disable(struct voltagedomain *voltdm)
 }
 
 /**
+ * sr_notifier_control() - control the notifier mechanism
+ * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ * @enable:	true to enable notifiers and false to disable the same
+ *
+ * SR modules allow an MCU interrupt mechanism that vary based on the IP
+ * revision, we allow the system to generate interrupt if the class driver
+ * has capability to handle the same. it is upto the class driver to ensure
+ * the proper sequencing and handling for a clean implementation. returns
+ * 0 if all goes fine, else returns failure results
+ */
+int sr_notifier_control(struct voltagedomain *voltdm, bool enable)
+{
+	struct omap_sr *sr = _sr_lookup(voltdm);
+	u32 value = 0;
+	if (IS_ERR_OR_NULL(sr)) {
+		pr_warning("%s: sr corresponding to domain not found\n",
+				__func__);
+		return -EINVAL;
+	}
+	if (!sr->autocomp_active)
+		return -EINVAL;
+
+	/* if I could never register an isr, why bother?? */
+	if (!(sr_class && sr_class->notify && sr_class->notify_flags &&
+			sr->irq)) {
+		dev_warn(&sr->pdev->dev,
+			"%s: unable to setup irq without handling mechanism\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (sr->ip_type) {
+	case SR_TYPE_V1:
+		value = notifier_to_irqen_v1(sr_class->notify_flags);
+		sr_modify_reg(sr, ERRCONFIG_V1, value,
+				(enable) ? value : 0);
+		break;
+	case SR_TYPE_V2:
+		value = notifier_to_irqen_v2(sr_class->notify_flags);
+		sr_write_reg(sr, (enable) ? IRQENABLE_SET : IRQENABLE_CLR,
+				value);
+		break;
+	default:
+		 dev_warn(&sr->pdev->dev, "%s: unknown type of sr??\n",
+				 __func__);
+		return -EINVAL;
+	}
+
+	if (enable)
+		enable_irq(sr->irq);
+	else
+		disable_irq_nosync(sr->irq);
+
+	return 0;
+}
+
+/**
  * sr_register_class() - API to register a smartreflex class parameters.
  * @class_data:	The structure containing various sr class specific data.
  *
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
index ff07d1e..d420f44 100644
--- a/arch/arm/plat-omap/include/plat/smartreflex.h
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -242,6 +242,7 @@ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
 /* Smartreflex driver hooks to be called from Smartreflex class driver */
 int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
 void sr_disable(struct voltagedomain *voltdm);
+int sr_notifier_control(struct voltagedomain *voltdm, bool enable);
 int sr_configure_errgen(struct voltagedomain *voltdm);
 int sr_configure_minmax(struct voltagedomain *voltdm);
 
@@ -250,6 +251,13 @@ int sr_register_class(struct omap_sr_class_data *class_data);
 #else
 static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
 static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
+
+static inline int sr_notifier_control(struct voltagedomain *voltdm,
+		bool enable)
+{
+	return -EINVAL;
+}
+
 static inline void omap_sr_disable_reset_volt(
 		struct voltagedomain *voltdm) {}
 static inline void omap_sr_register_pmic(
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 16/19] omap3+: sr: disable spamming interrupts
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (14 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 15/19] omap3+: sr: introduce notifier_control Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:21   ` Kevin Hilman
  2011-02-19 12:01 ` [PATCH 17/19] omap3+: sr: make enable path use volt_data pointer Nishanth Menon
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

At times with bad SR configurations especially during silicon bringups,
we could get continuous spurious interrupts which end up hanging the
platform in the form of an ISR call for status bits that are
automatically enabled by the h/w without any s/w clearing option.

If we detect scenarios where isr was called without the corresponding
notification bit being set, instead of hanging up the system,
we will disable interrupt after noting the event in the system log
to try and keep system sanity and allow developer to debug and fix
the condition.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index ad23b8d..0301186 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -209,8 +209,16 @@ static irqreturn_t sr_interrupt(int irq, void *data)
 		value = irqstat_to_notifier_v2(status);
 	}
 
-	if (sr_class->notify)
-		sr_class->notify(sr_info->voltdm, value);
+	/* Attempt some resemblence of recovery! */
+	if (!value) {
+		dev_err(&sr_info->pdev->dev, "%s: Spurious interrupt!"
+			"status = 0x%08x. Disabling to prevent spamming!!\n",
+			__func__, status);
+		disable_irq_nosync(sr_info->irq);
+	} else {
+		if (sr_class->notify)
+			sr_class->notify(sr_info->voltdm, value);
+	}
 
 	return IRQ_HANDLED;
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 17/19] omap3+: sr: make enable path use volt_data pointer
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (15 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 16/19] omap3+: sr: disable spamming interrupts Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-02-19 12:01 ` [PATCH 18/19] omap3630+: sr: add support for class 1.5 Nishanth Menon
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Passing the volt_data pointers accross allows us to save us the effort
of looking up the voltage data pointer from the voltage value at
multiple layers, we need to look at the voltage data in dvfs layer
for further processing, so modify the APIs to pass the voltage data
pointer all the way through to lower layers to the smartreflex class
drivers.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex-class3.c      |   13 +++----------
 arch/arm/mach-omap2/smartreflex.c             |   25 ++++++++++++-------------
 arch/arm/plat-omap/include/plat/smartreflex.h |    8 +++++---
 3 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 2195668..7ac88da 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -13,19 +13,12 @@
 
 #include <plat/smartreflex.h>
 
-static int sr_class3_enable(struct voltagedomain *voltdm)
+static int sr_class3_enable(struct voltagedomain *voltdm,
+		struct omap_volt_data *volt_data)
 {
-	unsigned long volt = omap_get_operation_voltage(
-		omap_voltage_get_nom_volt(voltdm));
-
-	if (!volt) {
-		pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n",
-				__func__, voltdm->name);
-		return -ENODATA;
-	}
 
 	omap_vp_enable(voltdm);
-	return sr_enable(voltdm, volt);
+	return sr_enable(voltdm, volt_data);
 }
 
 static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 0301186..3a5f2f6 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -302,7 +302,8 @@ static void sr_start_vddautocomp(struct omap_sr *sr)
 		return;
 	}
 
-	if (!sr_class->enable(sr->voltdm))
+	if (!sr_class->enable(sr->voltdm,
+			omap_voltage_get_nom_volt(sr->voltdm)))
 		sr->autocomp_active = true;
 }
 
@@ -618,7 +619,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
 /**
  * sr_enable() - Enables the smartreflex module.
  * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
- * @volt:	The voltage at which the Voltage domain associated with
+ * @volt_data:	The voltage at which the Voltage domain associated with
  *		the smartreflex module is operating at.
  *		This is required only to program the correct Ntarget value.
  *
@@ -626,10 +627,9 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
  * enable a smartreflex module. Returns 0 on success. Returns error
  * value if the voltage passed is wrong or if ntarget value is wrong.
  */
-int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
+int sr_enable(struct voltagedomain *voltdm, struct omap_volt_data *volt_data)
 {
 	u32 nvalue_reciprocal;
-	struct omap_volt_data *volt_data;
 	struct omap_sr *sr = _sr_lookup(voltdm);
 	int ret;
 
@@ -639,19 +639,16 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
 		return -EINVAL;
 	}
 
-	volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
-
-	if (IS_ERR(volt_data)) {
-		dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
-			"for nominal voltage %ld\n", __func__, volt);
-		return -ENODATA;
+	if (IS_ERR_OR_NULL(volt_data)) {
+		dev_warn(&sr->pdev->dev, "%s: bad voltage data\n", __func__);
+		return -EINVAL;
 	}
 
 	nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
 
 	if (!nvalue_reciprocal) {
 		dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n",
-			__func__, volt);
+			__func__, omap_get_operation_voltage(volt_data));
 		return -ENODATA;
 	}
 
@@ -808,13 +805,15 @@ int sr_register_class(struct omap_sr_class_data *class_data)
  * omap_sr_enable() -  API to enable SR clocks and to call into the
  *			registered smartreflex class enable API.
  * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ * @volt_data:	Voltage data to go to
  *
  * This API is to be called from the kernel in order to enable
  * a particular smartreflex module. This API will do the initial
  * configurations to turn on the smartreflex module and in turn call
  * into the registered smartreflex class enable API.
  */
-void omap_sr_enable(struct voltagedomain *voltdm)
+void omap_sr_enable(struct voltagedomain *voltdm,
+			struct omap_volt_data *volt_data)
 {
 	struct omap_sr *sr = _sr_lookup(voltdm);
 
@@ -833,7 +832,7 @@ void omap_sr_enable(struct voltagedomain *voltdm)
 		return;
 	}
 
-	sr_class->enable(voltdm);
+	sr_class->enable(voltdm, volt_data);
 }
 
 /**
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
index d420f44..07f35b2 100644
--- a/arch/arm/plat-omap/include/plat/smartreflex.h
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -185,7 +185,8 @@ struct omap_sr_pmic_data {
  * @class_priv_data:	Class specific private data (optional)
  */
 struct omap_sr_class_data {
-	int (*enable)(struct voltagedomain *voltdm);
+	int (*enable)(struct voltagedomain *voltdm,
+			struct omap_volt_data *volt_data);
 	int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
 	int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
 	int (*class_deinit)(struct voltagedomain *voltdm,
@@ -232,7 +233,8 @@ struct omap_sr_data {
 };
 
 /* Smartreflex module enable/disable interface */
-void omap_sr_enable(struct voltagedomain *voltdm);
+void omap_sr_enable(struct voltagedomain *voltdm,
+			struct omap_volt_data *volt_data);
 void omap_sr_disable(struct voltagedomain *voltdm);
 void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
 
@@ -240,7 +242,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
 void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
 
 /* Smartreflex driver hooks to be called from Smartreflex class driver */
-int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
+int sr_enable(struct voltagedomain *voltdm, struct omap_volt_data *volt_data);
 void sr_disable(struct voltagedomain *voltdm);
 int sr_notifier_control(struct voltagedomain *voltdm, bool enable);
 int sr_configure_errgen(struct voltagedomain *voltdm);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 18/19] omap3630+: sr: add support for class 1.5
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (16 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 17/19] omap3+: sr: make enable path use volt_data pointer Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-01  9:53   ` Gulati, Shweta
  2011-02-19 12:01 ` [PATCH 19/19] omap3430: sr: class3: restrict cpu to run on Nishanth Menon
  2011-03-03  0:33 ` [PATCH 00/19] OMAP3+: introduce SR class 1.5 Kevin Hilman
  19 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap
  Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon, Ambresh K,
	Eduardo Valentin, Igor Dmitriev, Paul,
	Peter 'p2' De Schrijver

Traditional SmartReflex AVS(Automatic Voltage Scaling) classes are:
* Class 0 - Product test calibration
	Silicon is calibration at production floor and fused with voltages
	for each OPP
* Class 1 - Boot time calibration
	Silicon is calibrated once at boot time and voltages are stored for
	the lifetime of operation.
* Class 2 - continuous s/w calibration
	SR module notifies s/w for any change in the system which is desired
	and the s/w makes runtime decisions in terms of setting the voltage,
	this mechanism could be used in the system which does not have PMIC
	capable of SR without using the voltage controller and voltage
	processor blocks.
* Class 3 - continuous h/w calibration
	SR module is switch on after reaching a voltage level and SR
	continuously monitors the system and makes runtime adjustments without
	s/w involvement.

OMAP3430 has used SmartReflex AVS and with a a PMIC which understands the SR
protocol, Class 3 has been used. With OMAP3630 onwards, a new SmartReflex AVS
class of operation Class 1.5 was introduced.
* Class 1.5 - periodic s/w calibration
	This uses the h/w calibration loop and at the end of calibration
	stores the voltages to be used run time, periodic recalibration is
	performed as well.

The operational mode is describes as the following:
* SmartReflex AVS h/w calibration loop is essential to identify the optimal
	voltage for a given OPP.
* Once this optimal voltage is detected, SmartReflex AVS loop is disabled in
	class 1.5 mode of operation.
* Until there is a need for a recalibration, any further transition to an OPP
	voltage which is calibrated can use the calibrated voltage and does not
	require enabling the SR AVS h/w loop.
* On a periodic basis (recommendation being once approximately every 24 hours),
	software is expected to perform a recalibration to find a new optimal
	voltage which is compensated for device aging.
	- For performing this recalibration, the start voltage does not need to
	be the nominal voltage anymore. instead, the system can start with a
	voltage which is 50mV higher than the previously calibrated voltage to
	identify the new optimal voltage as the aging factor within a period of
	1 day is not going to be anywhere close to 50mV.
	- This "new starting point" for recalibration is called a dynamic
	nominal voltage for that voltage point.
In short, with the introduction of SmartReflex class 1.5, there are three new
voltages possible in a system's dvfs transition:
* Nominal Voltage - The maximum voltage needed for a worst possible device
	in the worst possible conditions. This is the voltage we choose as
	the starting point for the h/w loop to optimize for the first time
	calibration on system bootup.
* Dynamic Nominal Voltage - Worst case voltage for a specific device in
	considering the system aging on the worst process device.
* Calibrated Voltage - Best voltage for the current device at a given point
	of time.

In terms of the implementation, doing calibration involves waiting for the
smartreflex h/w loop to settle down, and doing this as part of the dvfs flow
itself is to increase the latency of dvfs transition when there is a need to
calibrate that opp. instead, the calibration is performed "out of path" using
a workqueue statemachine. The workqueue waits for the system stabilization,
then enables VP interrupts to monitor for system instability interms of voltage
oscillations that are reported back to the system as interrupts, in case of
prolonged system oscillations, nominal voltage is chosen as a safe voltage and
this event is logged in the system log for developer debug and fixing.

For the recalibration, a common workqueue for all domains is started at the
start of the class initialization and it resets the calibrated voltages
on a periodic basis. For distros that may choose not to do the recommended
periodic recalibration, instead choose to perform boot time calibration,
kconfig configuration option is provided to do so.

TODO:
a) Cpuidle and suspend paths are not integrated with SmartReflex driver at
   this point.
b) Since the SR registers are accessed and controlled in parallel to DVFS
   some sort of mechanism is necessary to be introduced along with OMAP
   dvfs layer to ensure mutual exclusivity
c) Additional debug interfaces for vmin analysis for platform characterization
   and addition of system margin needs to be introduced from smartreflex
   perspective.

This implementation also includes the following contributors:
Tony Lindgren for suggestion on using interrupt based mechanism instead of
polling to detect voltage oscillations.
Peter 'p2' De Schrijver for debating alternatives on recalibration mechanisms
Paul Walmsey, Eduardo Valentin, Ambresh K, Igor Dmitriev and quiet a few others
for patient review, testing and reporting of issues of a previous incarnation
of this implemenation. Last, but not the least, the TI H/w team in introducing
this new SR AVS class and patiently debating it's various facets.

Cc: Ambresh K <ambresh@ti.com>
Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
Cc: Igor Dmitriev <ext-dmitriev.igor@nokia.com>
Cc: Paul <paul@pwsan.com>
Cc: Peter 'p2' De Schrijver <Peter.De-Schrijver@nokia.com>
Cc: Tony Lindgren <tony@atomide.com>

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/Makefile                  |    1 +
 arch/arm/mach-omap2/smartreflex-class1p5.c    |  556 +++++++++++++++++++++++++
 arch/arm/mach-omap2/smartreflex-class3.c      |    4 +-
 arch/arm/mach-omap2/smartreflex.c             |   34 ++-
 arch/arm/mach-omap2/voltage.c                 |   69 +++
 arch/arm/plat-omap/Kconfig                    |   17 +
 arch/arm/plat-omap/include/plat/smartreflex.h |   13 +-
 arch/arm/plat-omap/include/plat/voltage.h     |   23 +-
 8 files changed, 709 insertions(+), 8 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 1c0c2b0..1a82e6d 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o voltage.o pm_bus.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
 obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)	+= smartreflex-class3.o
+obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS1P5)	+= smartreflex-class1p5.o
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
diff --git a/arch/arm/mach-omap2/smartreflex-class1p5.c b/arch/arm/mach-omap2/smartreflex-class1p5.c
new file mode 100644
index 0000000..832f10b
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex-class1p5.c
@@ -0,0 +1,556 @@
+/*
+ * Smart reflex Class 1.5 specific implementations
+ *
+ * Copyright (C) 2010-2011 Texas Instruments, Inc.
+ * Nishanth Menon <nm@ti.com>
+ *
+ * Smart reflex class 1.5 is also called periodic SW Calibration
+ * Some of the highlights are as follows:
+ * – Host CPU triggers OPP calibration when transitioning to non calibrated
+ *   OPP
+ * – SR-AVS + VP modules are used to perform calibration
+ * – Once completed, the SmartReflex-AVS module can be disabled
+ * – Enables savings based on process, supply DC accuracy and aging
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+#include <linux/opp.h>
+
+#include <plat/smartreflex.h>
+#include <plat/voltage.h>
+
+#define MAX_VDDS 3
+#define SR1P5_SAMPLING_DELAY_MS	1
+#define SR1P5_STABLE_SAMPLES	5
+#define SR1P5_MAX_TRIGGERS	5
+
+/*
+ * we expect events in 10uS, if we dont get 2wice times as much,
+ * we could kind of ignore this as a missed event.
+ */
+#define MAX_CHECK_VPTRANS_US	20
+
+/**
+ * struct sr_class1p5_work_data - data meant to be used by calibration work
+ * @work:	calibration work
+ * @voltdm:		voltage domain for which we are triggering
+ * @vdata:	voltage data we are calibrating
+ * @num_calib_triggers:	number of triggers from calibration loop
+ * @num_osc_samples:	number of samples collected by isr
+ * @work_active:	have we scheduled a work item?
+ */
+struct sr_class1p5_work_data {
+	struct delayed_work work;
+	struct voltagedomain *voltdm;
+	struct omap_volt_data *vdata;
+	u8 num_calib_triggers;
+	u8 num_osc_samples;
+	bool work_active;
+};
+
+#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
+/* recal_work:	recalibration calibration work */
+static struct delayed_work recal_work;
+#endif
+
+/**
+ * struct sr_class1p5_data - private data for class 1p5
+ * @work_data:		work item data per voltage domain
+ */
+struct sr_class1p5_data {
+	struct sr_class1p5_work_data work_data[MAX_VDDS];
+};
+
+static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
+				    bool recal);
+
+/* our instance of class 1p5 private data */
+static struct sr_class1p5_data class_1p5_data;
+
+static struct sr_class1p5_work_data *get_sr1p5_work(struct voltagedomain
+						    *voltdm)
+{
+	int idx;
+	for (idx = 0; idx < MAX_VDDS; idx++) {
+		if (class_1p5_data.work_data[idx].voltdm && !strcmp
+		    (class_1p5_data.work_data[idx].voltdm->name, voltdm->name))
+			return &class_1p5_data.work_data[idx];
+	}
+	return ERR_PTR(-ENODATA);
+}
+
+/**
+ * sr_class1p5_notify() - isr notifier for status events
+ * @voltdm:	voltage domain for which we were triggered
+ * @status:	notifier event to use
+ *
+ * This basically collects data for the work to use.
+ */
+static int sr_class1p5_notify(struct voltagedomain *voltdm, u32 status)
+{
+	struct sr_class1p5_work_data *work_data;
+	int idx = 0;
+	work_data = get_sr1p5_work(voltdm);
+
+	if (unlikely(!work_data)) {
+		pr_err("%s:%s no work data!!\n", __func__, voltdm->name);
+		return -EINVAL;
+	}
+
+	/* Wait for transdone so that we know the voltage to read */
+	do {
+		if (omap_vp_is_transdone(voltdm))
+			break;
+		idx++;
+		/* get some constant delay */
+		udelay(1);
+	} while (idx < MAX_CHECK_VPTRANS_US);
+
+	/*
+	 * If we timeout, we still read the data,
+	 * if we are oscillating+irq latencies are too high, we could
+	 * have scenarios where we miss transdone event. since
+	 * we waited long enough, it is still safe to read the voltage
+	 * as we would have waited long enough - still flag it..
+	 */
+	if (idx >= MAX_CHECK_VPTRANS_US)
+		pr_warning("%s: timed out waiting for transdone!!\n", __func__);
+
+	omap_vp_clear_transdone(voltdm);
+
+	idx = (work_data->num_osc_samples) % SR1P5_STABLE_SAMPLES;
+	work_data->num_osc_samples++;
+
+	return 0;
+}
+
+/**
+ * do_calibrate() - work which actually does the calibration
+ * @work: pointer to the work
+ *
+ * calibration routine uses the following logic:
+ * on the first trigger, we start the isr to collect sr voltages
+ * wait for stabilization delay (reschdule self instead of sleeping)
+ * after the delay, see if we collected any isr events
+ * if none, we have calibrated voltage.
+ * if there are any, we retry untill we giveup.
+ * on retry timeout, select a voltage to use as safe voltage.
+ */
+static void do_calibrate(struct work_struct *work)
+{
+	struct sr_class1p5_work_data *work_data =
+	    container_of(work, struct sr_class1p5_work_data, work.work);
+	unsigned long u_volt_safe = 0, u_volt_current = 0;
+	struct omap_volt_data *volt_data;
+	struct voltagedomain *voltdm;
+
+	if (unlikely(!work_data)) {
+		pr_err("%s: ooops.. null work_data?\n", __func__);
+		return;
+	}
+
+	/*
+	 * TODO:Handle the case where we might have just been scheduled AND
+	 * 1.5 disable was called. check and HOLD dvfs
+	 */
+
+	voltdm = work_data->voltdm;
+	/*
+	 * In the unlikely case that we did get through when unplanned,
+	 * flag and return.
+	 */
+	if (unlikely(!work_data->work_active)) {
+		pr_err("%s:%s unplanned work invocation!\n", __func__,
+		       voltdm->name);
+		/* TODO release the dvfs */
+		return;
+	}
+
+	work_data->num_calib_triggers++;
+	/* if we are triggered first time, we need to start isr to sample */
+	if (work_data->num_calib_triggers == 1)
+		goto start_sampling;
+
+	/* Stop isr from interrupting our measurements :) */
+	sr_notifier_control(voltdm, false);
+
+	volt_data = work_data->vdata;
+
+	/* if there are no samples captured.. SR is silent, aka stability! */
+	if (!work_data->num_osc_samples) {
+		u_volt_safe = omap_vp_get_curr_volt(voltdm);
+		u_volt_current = u_volt_safe;
+		goto done_calib;
+	}
+	if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) {
+		pr_warning("%s: %s recalib timeout!\n", __func__,
+			   work_data->voltdm->name);
+		goto oscillating_calib;
+	}
+
+	/* we have potential oscillations/first sample */
+start_sampling:
+	work_data->num_osc_samples = 0;
+	/* Clear pending events */
+	sr_notifier_control(voltdm, false);
+	/* Clear all transdones */
+	while (omap_vp_is_transdone(voltdm))
+		omap_vp_clear_transdone(voltdm);
+	/* trigger sampling */
+	sr_notifier_control(voltdm, true);
+	schedule_delayed_work(&work_data->work,
+			      msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
+					       SR1P5_STABLE_SAMPLES));
+	/* TODO: release dvfs */
+	return;
+
+oscillating_calib:
+	/* Use the nominal voltage as the safe voltage */
+	u_volt_safe = volt_data->volt_nominal;
+	/* pick up current voltage to switch if needed */
+	u_volt_current = omap_vp_get_curr_volt(voltdm);
+
+	/* Fall through to close up common stuff */
+done_calib:
+	omap_vp_disable(voltdm);
+	sr_disable(voltdm);
+
+	volt_data->volt_calibrated = u_volt_safe;
+	/* Setup my dynamic voltage for the next calibration for this opp */
+	volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data);
+
+	/*
+	 * if the voltage we decided as safe is not the current voltage,
+	 * switch
+	 */
+	if (volt_data->volt_calibrated != u_volt_current) {
+		pr_debug("%s:%s reconfiguring to voltage %d\n",
+			 __func__, voltdm->name, volt_data->volt_calibrated);
+		omap_voltage_scale_vdd(voltdm, volt_data);
+	}
+
+	/*
+	 * TODO: Setup my wakeup voltage to allow immediate going to OFF and
+	 * on - Pending twl and voltage layer cleanups.
+	 * This is necessary, as this is not done as part of regular
+	 * Dvfs flow.
+	 * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated);
+	 */
+	work_data->work_active = false;
+	/* TODO: release dvfs */
+}
+
+#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
+/**
+ * do_recalibrate() - work which actually does the calibration
+ * @work: pointer to the work
+ *
+ * on a periodic basis, we come and reset our calibration setup
+ * so that a recalibration of the OPPs take place. This takes
+ * care of aging factor in the system.
+ */
+static void do_recalibrate(struct work_struct *work)
+{
+	struct voltagedomain *voltdm;
+	int idx;
+	static struct sr_class1p5_work_data *work_data;
+
+	for (idx = 0; idx < MAX_VDDS; idx++) {
+		work_data = &class_1p5_data.work_data[idx];
+		voltdm = work_data->voltdm;
+		if (voltdm) {
+			/* if sr is not enabled, we check later */
+			if (!is_sr_enabled(voltdm))
+				continue;
+			/* TODO: Pause the dvfs transitions */
+			/* if sr is not enabled, we check later */
+
+			/* Reset and force a recalibration for current opp */
+			sr_class1p5_reset_calib(voltdm, true, true);
+
+			/* TODO: unpause DVFS transitions */
+		}
+	}
+	/* We come back again after time the usual delay */
+	schedule_delayed_work(&recal_work,
+	      msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
+}
+#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */
+
+/**
+ * sr_class1p5_enable() - class 1.5 mode of enable
+ * @voltdm:		voltage domain to enable SR for
+ * @volt_data:	voltdata to the voltage transition taking place
+ *
+ * when this gets called, we use the h/w loop to setup our voltages
+ * to an calibrated voltage, detect any oscillations, recover from the same
+ * and finally store the optimized voltage as the calibrated voltage in the
+ * system
+ */
+static int sr_class1p5_enable(struct voltagedomain *voltdm,
+			      struct omap_volt_data *volt_data)
+{
+	int r;
+	struct sr_class1p5_work_data *work_data;
+	/* if already calibrated, nothing to do here.. */
+	if (volt_data->volt_calibrated)
+		return 0;
+
+	work_data = get_sr1p5_work(voltdm);
+	if (unlikely(!work_data)) {
+		pr_err("%s: aieeee.. bad work data??\n", __func__);
+		return -EINVAL;
+	}
+
+	if (work_data->work_active)
+		return 0;
+
+	omap_vp_enable(voltdm);
+	r = sr_enable(voltdm, volt_data);
+	if (r) {
+		pr_err("%s: sr[%s] failed\n", __func__, voltdm->name);
+		omap_vp_disable(voltdm);
+		return r;
+	}
+	work_data->vdata = volt_data;
+	work_data->work_active = true;
+	work_data->num_calib_triggers = 0;
+	/* program the workqueue and leave it to calibrate offline.. */
+	schedule_delayed_work(&work_data->work,
+			      msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
+					       SR1P5_STABLE_SAMPLES));
+
+	return 0;
+}
+
+/**
+ * sr_class1p5_disable() - disable for class 1p5
+ * @voltdm: voltage domain for the sr which needs disabling
+ * @volt_data:	voltagedata to disable
+ * @is_volt_reset: reset the voltage?
+ *
+ * we dont do anything if the class 1p5 is being used. this is because we
+ * already disable sr at the end of calibration and no h/w loop is actually
+ * active when this is called.
+ */
+static int sr_class1p5_disable(struct voltagedomain *voltdm,
+			       struct omap_volt_data *volt_data,
+			       int is_volt_reset)
+{
+	struct sr_class1p5_work_data *work_data;
+
+	work_data = get_sr1p5_work(voltdm);
+	if (work_data->work_active) {
+		/* if volt reset and work is active, we dont allow this */
+		if (is_volt_reset)
+			return -EBUSY;
+		/* flag work is dead and remove the old work */
+		work_data->work_active = false;
+		cancel_delayed_work_sync(&work_data->work);
+		sr_notifier_control(voltdm, false);
+		omap_vp_disable(voltdm);
+		sr_disable(voltdm);
+	}
+
+	/* if already calibrated, nothin special to do here.. */
+	if (volt_data->volt_calibrated)
+		return 0;
+
+	if (is_volt_reset)
+		omap_voltage_reset(voltdm);
+	return 0;
+}
+
+/**
+ * sr_class1p5_configure() - configuration function
+ * @voldm:	configure for which voltage domain
+ *
+ * we dont do much here other than setup some registers for
+ * the sr module involved.
+ */
+static int sr_class1p5_configure(struct voltagedomain *voltdm)
+{
+	return sr_configure_errgen(voltdm);
+}
+
+/**
+ * sr_class1p5_reset_calib() - reset all calibrated voltages
+ * @srid:	srid to reset the calibration for
+ * @reset:	reset voltage before we recal?
+ * @recal:	should I recalibrate my current opp?
+ *
+ * if we call this, it means either periodic calibration trigger was
+ * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
+ * meaning we cant trust the calib voltages anymore, it is better to use
+ * nominal in the system
+ */
+static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
+				    bool recal)
+{
+	struct sr_class1p5_work_data *work_data;
+
+	/* I dont need to go further if sr is not present */
+	if (!is_sr_enabled(voltdm))
+		return;
+
+	work_data = get_sr1p5_work(voltdm);
+
+	if (work_data->work_active)
+		sr_class1p5_disable(voltdm, work_data->vdata, 0);
+
+	omap_voltage_calib_reset(voltdm);
+
+	/*
+	 * I should now reset the voltages to my nominal to be safe
+	 */
+	if (reset)
+		omap_voltage_reset(voltdm);
+
+	/*
+	 * I should fire a recalibration for current opp if needed
+	 * Note: i have just reset my calibrated voltages, and if
+	 * i call sr_enable equivalent, I will cause a recalibration
+	 * loop, even though the function is called sr_enable.. we
+	 * are in class 1.5 ;)
+	 */
+	if (reset && recal)
+		sr_class1p5_enable(voltdm, work_data->vdata);
+}
+
+/**
+ * sr_class1p5_cinit() - class 1p5 init
+ * @voltdm:		sr voltage domain
+ * @class_priv_data:	private data for the class
+ *
+ * we do class specific initialization like creating sysfs/debugfs entries
+ * needed, spawning of a kthread if needed etc.
+ */
+static int sr_class1p5_cinit(struct voltagedomain *voltdm,
+			     void *class_priv_data)
+{
+	struct sr_class1p5_work_data *work_data;
+	int idx;
+
+	if (!class_priv_data) {
+		pr_err("%s: bad param? no priv data!\n", __func__);
+		return -EINVAL;
+	}
+
+	/* setup our work params */
+	work_data = get_sr1p5_work(voltdm);
+	if (!IS_ERR_OR_NULL(work_data)) {
+		pr_err("%s: ooopps.. class already initialized for %s! bug??\n",
+		       __func__, voltdm->name);
+		return -EINVAL;
+	}
+	work_data = NULL;
+	/* get the next spare work_data */
+	for (idx = 0; idx < MAX_VDDS; idx++) {
+		if (!class_1p5_data.work_data[idx].voltdm) {
+			work_data = &class_1p5_data.work_data[idx];
+			break;
+		}
+	}
+	if (!work_data) {
+		pr_err("%s: no more space for work data for domains!\n",
+			__func__);
+		return -ENOMEM;
+	}
+	work_data->voltdm = voltdm;
+	INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, do_calibrate);
+	return 0;
+}
+
+/**
+ * sr_class1p5_cdeinit() - class 1p5 deinitialization
+ * @voltdm:	voltage domain for which to do this.
+ * @class_priv_data: class private data for deinitialiation
+ *
+ * currently only resets the calibrated voltage forcing dvfs voltages
+ * to be used in the system
+ */
+static int sr_class1p5_cdeinit(struct voltagedomain *voltdm,
+			       void *class_priv_data)
+{
+	struct sr_class1p5_work_data *work_data;
+
+	/* setup our work params */
+	work_data = get_sr1p5_work(voltdm);
+	if (IS_ERR_OR_NULL(work_data)) {
+		pr_err("%s: ooopps.. class not initialized for %s! bug??\n",
+		       __func__, voltdm->name);
+		return -EINVAL;
+	}
+
+	/*
+	 * we dont have SR periodic calib anymore.. so reset calibs
+	 * we are already protected by sr debugfs lock, so no lock needed
+	 * here.
+	 */
+	sr_class1p5_reset_calib(voltdm, true, false);
+
+	/* reset all data for this work data */
+	memset(work_data, 0, sizeof(*work_data));
+
+	return 0;
+}
+
+/* SR class1p5 structure */
+static struct omap_sr_class_data class1p5_data = {
+	.enable = sr_class1p5_enable,
+	.disable = sr_class1p5_disable,
+	.configure = sr_class1p5_configure,
+	.class_type = SR_CLASS1P5,
+	.class_init = sr_class1p5_cinit,
+	.class_deinit = sr_class1p5_cdeinit,
+	.notify = sr_class1p5_notify,
+	/*
+	 * trigger for bound - this tells VP that SR has a voltage
+	 * change. we should ensure transdone is set before reading
+	 * vp voltage.
+	 */
+	.notify_flags = SR_NOTIFY_MCUBOUND,
+	.class_priv_data = (void *)&class_1p5_data,
+};
+
+/**
+ * sr_class1p5_init() - register class 1p5 as default
+ *
+ * board files call this function to use class 1p5, we register with the
+ * smartreflex subsystem
+ */
+static int __init sr_class1p5_init(void)
+{
+	int r;
+
+	/* Enable this class only for OMAP3630 and OMAP4 */
+	if (!(cpu_is_omap3630() || cpu_is_omap44xx()))
+		return -EINVAL;
+
+	r = sr_register_class(&class1p5_data);
+	if (r) {
+		pr_err("SmartReflex class 1.5 driver: "
+		       "failed to register with %d\n", r);
+	} else {
+#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
+		INIT_DELAYED_WORK_DEFERRABLE(&recal_work, do_recalibrate);
+		schedule_delayed_work(&recal_work, msecs_to_jiffies(
+				CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
+#endif
+		pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n",
+			CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY);
+	}
+	return r;
+}
+late_initcall(sr_class1p5_init);
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 7ac88da..5f7a33e 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -21,7 +21,9 @@ static int sr_class3_enable(struct voltagedomain *voltdm,
 	return sr_enable(voltdm, volt_data);
 }
 
-static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
+static int sr_class3_disable(struct voltagedomain *voltdm,
+				struct omap_volt_data *vdata,
+				int is_volt_reset)
 {
 	omap_vp_disable(voltdm);
 	sr_disable(voltdm);
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 3a5f2f6..bb55b65 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -317,7 +317,9 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
 	}
 
 	if (sr->autocomp_active) {
-		sr_class->disable(sr->voltdm, 1);
+		sr_class->disable(sr->voltdm,
+				omap_voltage_get_nom_volt(sr->voltdm),
+				1);
 		if (sr_class->class_deinit &&
 		    sr_class->class_deinit(sr->voltdm,
 			    sr_class->class_priv_data)) {
@@ -471,6 +473,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
 /* Public Functions */
 
 /**
+ * is_sr_enabled() - is Smart reflex enabled for this domain?
+ * @voltdm: voltage domain to check
+ *
+ * Returns 0 if SR is enabled for this domain, else returns err
+ */
+bool is_sr_enabled(struct voltagedomain *voltdm)
+{
+	struct omap_sr *sr;
+	if (IS_ERR_OR_NULL(voltdm)) {
+		pr_warning("%s: invalid param voltdm\n", __func__);
+		return false;
+	}
+	sr = _sr_lookup(voltdm);
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return false;
+	}
+	return sr->autocomp_active;
+}
+
+/**
  * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
  *			 error generator module.
  * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
@@ -839,6 +863,7 @@ void omap_sr_enable(struct voltagedomain *voltdm,
  * omap_sr_disable() - API to disable SR without resetting the voltage
  *			processor voltage
  * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ * @volt_data:	Voltage data to go to
  *
  * This API is to be called from the kernel in order to disable
  * a particular smartreflex module. This API will in turn call
@@ -846,7 +871,8 @@ void omap_sr_enable(struct voltagedomain *voltdm,
  * the smartreflex class disable not to reset the VP voltage after
  * disabling smartreflex.
  */
-void omap_sr_disable(struct voltagedomain *voltdm)
+void omap_sr_disable(struct voltagedomain *voltdm,
+		struct omap_volt_data *vdata)
 {
 	struct omap_sr *sr = _sr_lookup(voltdm);
 
@@ -865,7 +891,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
 		return;
 	}
 
-	sr_class->disable(voltdm, 0);
+	sr_class->disable(voltdm, vdata, 0);
 }
 
 /**
@@ -898,7 +924,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
 		return;
 	}
 
-	sr_class->disable(voltdm, 1);
+	sr_class->disable(voltdm, omap_voltage_get_nom_volt(voltdm), 1);
 }
 
 /**
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 77cb0cd..c451835 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -374,9 +374,45 @@ static int nom_volt_debug_get(void *data, u64 *val)
 	return 0;
 }
 
+static int dyn_volt_debug_get(void *data, u64 *val)
+{
+	struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
+	struct omap_volt_data *volt_data;
+
+	if (!vdd) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+	volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
+
+	*val = volt_data->volt_dynamic_nominal;
+
+	return 0;
+}
+
+static int calib_volt_debug_get(void *data, u64 *val)
+{
+	struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
+	struct omap_volt_data *volt_data;
+
+	if (!vdd) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+	volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
+
+	*val = volt_data->volt_calibrated;
+
+	return 0;
+}
+
 DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");
 DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
 								"%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL,
+								"%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL,
+								"%llu\n");
 static void vp_latch_vsel(struct omap_vdd_info *vdd)
 {
 	u32 vpconfig;
@@ -504,6 +540,12 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
 	(void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
 				vdd->debug_dir, (void *) vdd,
 				&nom_volt_debug_fops);
+	(void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO,
+				vdd->debug_dir, (void *) vdd,
+				&dyn_volt_debug_fops);
+	(void) debugfs_create_file("curr_calibrated_volt", S_IRUGO,
+				vdd->debug_dir, (void *) vdd,
+				&calib_volt_debug_fops);
 }
 
 /* Voltage scale and accessory APIs */
@@ -1132,6 +1174,33 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
 }
 
 /**
+ * omap_voltage_calib_reset() - reset the calibrated voltage entries
+ * @voltdm: voltage domain to reset the entries for
+ *
+ * when the calibrated entries are no longer valid, this api allows
+ * the calibrated voltages to be reset.
+ */
+int omap_voltage_calib_reset(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+	struct omap_volt_data *volt_data;
+
+	if (IS_ERR_OR_NULL(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return -EINVAL;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	volt_data = vdd->volt_data;
+	/* reset the calibrated voltages as 0 */
+	while (volt_data->volt_nominal) {
+		volt_data->volt_calibrated = 0;
+		volt_data++;
+	}
+	return 0;
+}
+
+/**
  * omap_vp_get_curr_volt() - API to get the current vp voltage.
  * @voltdm:	pointer to the VDD.
  *
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index b6333ae..dba7939 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -67,6 +67,23 @@ config OMAP_SMARTREFLEX_CLASS3
 	  Class 3 implementation of Smartreflex employs continuous hardware
 	  voltage calibration.
 
+config OMAP_SMARTREFLEX_CLASS1P5
+	bool "Class 1.5 mode of Smartreflex Implementation"
+	depends on OMAP_SMARTREFLEX && TWL4030_CORE
+	help
+	  Say Y to enable Class 1.5 implementation of Smartreflex
+	  Class 1.5 implementation of Smartreflex employs software controlled
+	  hardware voltage calibration.
+
+config OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
+	int "Class 1.5 mode recalibration recalibration delay(ms)"
+	depends on OMAP_SMARTREFLEX_CLASS1P5
+	default 86400000
+	help
+	  Setup the recalibration delay in milliseconds. Use 0 for never doing
+	  a recalibration. Defaults to recommended recalibration every 24hrs.
+	  If you do not understand this, use the default.
+
 config OMAP_RESET_CLOCKS
 	bool "Reset unused clocks during boot"
 	depends on ARCH_OMAP
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
index 07f35b2..ee5c58f 100644
--- a/arch/arm/plat-omap/include/plat/smartreflex.h
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -167,6 +167,7 @@ struct omap_sr_pmic_data {
 #define SR_CLASS1	0x1
 #define SR_CLASS2	0x2
 #define SR_CLASS3	0x3
+#define SR_CLASS1P5	0x4
 
 /**
  * struct omap_sr_class_data - Smartreflex class driver info
@@ -187,7 +188,9 @@ struct omap_sr_pmic_data {
 struct omap_sr_class_data {
 	int (*enable)(struct voltagedomain *voltdm,
 			struct omap_volt_data *volt_data);
-	int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
+	int (*disable)(struct voltagedomain *voltdm,
+			struct omap_volt_data *volt_data,
+			int is_volt_reset);
 	int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
 	int (*class_deinit)(struct voltagedomain *voltdm,
 			void *class_priv_data);
@@ -235,7 +238,8 @@ struct omap_sr_data {
 /* Smartreflex module enable/disable interface */
 void omap_sr_enable(struct voltagedomain *voltdm,
 			struct omap_volt_data *volt_data);
-void omap_sr_disable(struct voltagedomain *voltdm);
+void omap_sr_disable(struct voltagedomain *voltdm,
+			struct omap_volt_data *volt_data);
 void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
 
 /* API to register the pmic specific data with the smartreflex driver. */
@@ -250,6 +254,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm);
 
 /* API to register the smartreflex class driver with the smartreflex driver */
 int sr_register_class(struct omap_sr_class_data *class_data);
+bool is_sr_enabled(struct voltagedomain *voltdm);
 #else
 static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
 static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
@@ -264,5 +269,9 @@ static inline void omap_sr_disable_reset_volt(
 		struct voltagedomain *voltdm) {}
 static inline void omap_sr_register_pmic(
 		struct omap_sr_pmic_data *pmic_data) {}
+static inline bool is_sr_enabled(struct voltagedomain *voltdm)
+{
+	return false;
+}
 #endif
 #endif
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index 332c581..54445f0 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -58,6 +58,8 @@
 #define OMAP4430_VDD_CORE_OPP50_UV		930000
 #define OMAP4430_VDD_CORE_OPP100_UV		1100000
 
+#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV	50000
+
 /**
  * struct voltagedomain - omap voltage domain global structure.
  * @name:	Name of the voltage domain which can be used as a unique
@@ -81,6 +83,8 @@ struct voltagedomain {
  */
 struct omap_volt_data {
 	u32	volt_nominal;
+	u32	volt_calibrated;
+	u32	volt_dynamic_nominal;
 	u32	sr_efuse_offs;
 	u8	sr_errminlimit;
 	u8	vp_errgain;
@@ -127,6 +131,7 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
 bool omap_vp_is_transdone(struct voltagedomain *voltdm);
 bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
 struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
+int omap_voltage_calib_reset(struct voltagedomain *voltdm);
 #ifdef CONFIG_PM
 int omap_voltage_register_pmic(struct voltagedomain *voltdm,
 		struct omap_volt_pmic_info *pmic_info);
@@ -160,7 +165,23 @@ static inline unsigned long omap_get_operation_voltage(
 {
 	if (IS_ERR_OR_NULL(vdata))
 		return 0;
-	return vdata->volt_nominal;
+	return (vdata->volt_calibrated) ? vdata->volt_calibrated :
+		(vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
+			vdata->volt_nominal;
 }
 
+/* what is my dynamic nominal? */
+static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
+{
+	if (IS_ERR_OR_NULL(vdata))
+		return 0;
+	if (vdata->volt_calibrated) {
+		unsigned long v = vdata->volt_calibrated +
+			OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
+		if (v > vdata->volt_nominal)
+			return vdata->volt_nominal;
+		return v;
+	}
+	return vdata->volt_nominal;
+}
 #endif
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 19/19] omap3430: sr: class3: restrict cpu to run on
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (17 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 18/19] omap3630+: sr: add support for class 1.5 Nishanth Menon
@ 2011-02-19 12:01 ` Nishanth Menon
  2011-03-03  0:33 ` [PATCH 00/19] OMAP3+: introduce SR class 1.5 Kevin Hilman
  19 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-02-19 12:01 UTC (permalink / raw)
  To: linux-omap; +Cc: Tony Lindgren, Kevin Hilman, Nishanth Menon

Use SmartReflex AVS Class3 initialization only for OMAP343x family of
processors.

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/mach-omap2/smartreflex-class3.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 5f7a33e..f99e517 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -11,6 +11,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <plat/cpu.h>
 #include <plat/smartreflex.h>
 
 static int sr_class3_enable(struct voltagedomain *voltdm,
@@ -49,6 +50,10 @@ static struct omap_sr_class_data class3_data = {
 /* Smartreflex Class3 init API to be called from board file */
 static int __init sr_class3_init(void)
 {
+	/* Enable this class only for OMAP343x */
+	if (!cpu_is_omap343x())
+		return -EINVAL;
+
 	pr_info("SmartReflex Class3 initialized\n");
 	return sr_register_class(&class3_data);
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 64+ messages in thread

* RE: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES
  2011-02-19 12:01 ` [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES Nishanth Menon
@ 2011-02-19 13:22   ` Vishwanath Sripathy
  2011-02-20  5:26     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Vishwanath Sripathy @ 2011-02-19 13:22 UTC (permalink / raw)
  To: Nishanth Menon, linux-omap; +Cc: Tony Lindgren, Kevin Hilman

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Nishanth Menon
> Sent: Saturday, February 19, 2011 5:32 PM
> To: linux-omap
> Cc: Tony Lindgren; Kevin Hilman; Nishanth Menon
> Subject: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES
>
> Enable hwmod entries for OMAP3630 for higher ES revisions as
> well. This is to ensure that SR can be used in all revisions of
> OMAP3630 as of this posting.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |    8 ++++++--
>  1 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> index ea1f49a..bbcbea6 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> @@ -1318,7 +1318,9 @@ static struct omap_hwmod
> omap36xx_sr1_hwmod = {
>  	},
>  	.slaves		= omap3_sr1_slaves,
>  	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
> -	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
> +	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1	|
> +					CHIP_IS_OMAP3630ES1_1	|
> +					CHIP_IS_OMAP3630ES1_2),
What's the need of this?
Here is the code snippet from id.c
-----snip-----
	case 0xb891:
		/* Handle 36xx devices */
		omap_chip.oc |= CHIP_IS_OMAP3630ES1;

		switch(rev) {
		case 0: /* Take care of early samples */
			omap_revision = OMAP3630_REV_ES1_0;
			break;
		case 1:
			omap_revision = OMAP3630_REV_ES1_1;
			omap_chip.oc |= CHIP_IS_OMAP3630ES1_1;
			break;
		case 2:
		default:
			omap_revision =  OMAP3630_REV_ES1_2;
			omap_chip.oc |= CHIP_IS_OMAP3630ES1_2;
		}
So it's clear that omap_chip.oc will have CHIP_IS_OMAP3630ES1 anyway on
all ES versions.

Vishwa

>  	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
>  	.mpu_irqs_cnt	=
> ARRAY_SIZE(omap3_smartreflex_mpu_irqs),
>  };
> @@ -1368,7 +1370,9 @@ static struct omap_hwmod
> omap36xx_sr2_hwmod = {
>  	},
>  	.slaves		= omap3_sr2_slaves,
>  	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
> -	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
> +	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1	|
> +					CHIP_IS_OMAP3630ES1_1	|
> +					CHIP_IS_OMAP3630ES1_2),
>  	.mpu_irqs	= omap3_smartreflex_core_irqs,
>  	.mpu_irqs_cnt	=
> ARRAY_SIZE(omap3_smartreflex_core_irqs),
>  };
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* RE: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-19 12:01 ` [PATCH 03/19] omap3+: voltage: remove initial voltage Nishanth Menon
@ 2011-02-19 13:24   ` Vishwanath Sripathy
  2011-02-20  5:12     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Vishwanath Sripathy @ 2011-02-19 13:24 UTC (permalink / raw)
  To: Nishanth Menon, linux-omap; +Cc: Tony Lindgren, Kevin Hilman

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Nishanth Menon
> Sent: Saturday, February 19, 2011 5:32 PM
> To: linux-omap
> Cc: Tony Lindgren; Kevin Hilman; Nishanth Menon
> Subject: [PATCH 03/19] omap3+: voltage: remove initial voltage
>
> omap2_set_init_voltage should setup the curr_volt based on which OPP
> the system is functioning at. Blindly setting a 1.2v setting in the
> initial structure may not even match the default voltages stored in
> the voltage table which are supported for the domain.
>
> For example, OMAP3430 core domain does not use 1.2v and ends up
> generating a warning on the first transition.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>  arch/arm/mach-omap2/voltage.c |    2 --
>  1 files changed, 0 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
> omap2/voltage.c
> index 12be525..280ee12 100644
> --- a/arch/arm/mach-omap2/voltage.c
> +++ b/arch/arm/mach-omap2/voltage.c
> @@ -863,7 +863,6 @@ static int __init
> omap3_vdd_data_configure(struct omap_vdd_info *vdd)
>  	sys_clk_speed /= 1000;
>
>  	/* Generic voltage parameters */
> -	vdd->curr_volt = 1200000;
>  	vdd->ocp_mod = OCP_MOD;
>  	vdd->prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
>  	vdd->read_reg = omap3_voltage_read_reg;
> @@ -1054,7 +1053,6 @@ static int __init
> omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>  	sys_clk_speed /= 1000;
>
>  	/* Generic voltage parameters */
> -	vdd->curr_volt = 1200000;
Where do you update this parameter upon initialization? Shouldn't you read
the VP register and find the actual current voltage and update this param?

Vishwa
>  	vdd->ocp_mod = OMAP4430_PRM_OCP_SOCKET_INST;
>  	vdd->read_reg = omap4_voltage_read_reg;
>  	vdd->write_reg = omap4_voltage_write_reg;
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* RE: [PATCH 15/19] omap3+: sr: introduce notifier_control
  2011-02-19 12:01 ` [PATCH 15/19] omap3+: sr: introduce notifier_control Nishanth Menon
@ 2011-02-19 13:40   ` Vishwanath Sripathy
  2011-02-20  4:50     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Vishwanath Sripathy @ 2011-02-19 13:40 UTC (permalink / raw)
  To: Nishanth Menon, linux-omap; +Cc: Tony Lindgren, Kevin Hilman

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Nishanth Menon
> Sent: Saturday, February 19, 2011 5:32 PM
> To: linux-omap
> Cc: Tony Lindgren; Kevin Hilman; Nishanth Menon
> Subject: [PATCH 15/19] omap3+: sr: introduce notifier_control
>
> We need some mechanism from class drivers to control when notifiers
> should be triggered and when not, currently we have none, which makes
> Class driver usage of the interrupt events almost impossible.
> Introduce an smartreflex driver api for doing the same.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>  arch/arm/mach-omap2/smartreflex.c             |   57
> +++++++++++++++++++++++++
>  arch/arm/plat-omap/include/plat/smartreflex.h |    8 ++++
>  2 files changed, 65 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-
> omap2/smartreflex.c
> index 165f6f3..ad23b8d 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -704,6 +704,63 @@ void sr_disable(struct voltagedomain *voltdm)
>  }
>
>  /**
> + * sr_notifier_control() - control the notifier mechanism
> + * @voltdm:	VDD pointer to which the SR module to be configured
> belongs to.
> + * @enable:	true to enable notifiers and false to disable the same
> + *
> + * SR modules allow an MCU interrupt mechanism that vary based on
> the IP
> + * revision, we allow the system to generate interrupt if the class
driver
> + * has capability to handle the same. it is upto the class driver to
> ensure
> + * the proper sequencing and handling for a clean implementation.
> returns
> + * 0 if all goes fine, else returns failure results
> + */
> +int sr_notifier_control(struct voltagedomain *voltdm, bool enable)
> +{
> +	struct omap_sr *sr = _sr_lookup(voltdm);
> +	u32 value = 0;
> +	if (IS_ERR_OR_NULL(sr)) {
> +		pr_warning("%s: sr corresponding to domain not found\n",
> +				__func__);
> +		return -EINVAL;
> +	}
> +	if (!sr->autocomp_active)
> +		return -EINVAL;
Why you do you return here? Class driver should still be able to place
it's request even if sr is disabled though it will be effective only after
sr is enabled.

Vishwa

> +
> +	/* if I could never register an isr, why bother?? */
> +	if (!(sr_class && sr_class->notify && sr_class->notify_flags &&
> +			sr->irq)) {
> +		dev_warn(&sr->pdev->dev,
> +			"%s: unable to setup irq without handling
> mechanism\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	switch (sr->ip_type) {
> +	case SR_TYPE_V1:
> +		value = notifier_to_irqen_v1(sr_class->notify_flags);
> +		sr_modify_reg(sr, ERRCONFIG_V1, value,
> +				(enable) ? value : 0);
> +		break;
> +	case SR_TYPE_V2:
> +		value = notifier_to_irqen_v2(sr_class->notify_flags);
> +		sr_write_reg(sr, (enable) ? IRQENABLE_SET :
> IRQENABLE_CLR,
> +				value);
> +		break;
> +	default:
> +		 dev_warn(&sr->pdev->dev, "%s: unknown type of
> sr??\n",
> +				 __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (enable)
> +		enable_irq(sr->irq);
> +	else
> +		disable_irq_nosync(sr->irq);
> +
> +	return 0;
> +}
> +
> +/**
>   * sr_register_class() - API to register a smartreflex class
parameters.
>   * @class_data:	The structure containing various sr class specific
> data.
>   *
> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h
> b/arch/arm/plat-omap/include/plat/smartreflex.h
> index ff07d1e..d420f44 100644
> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> @@ -242,6 +242,7 @@ void omap_sr_register_pmic(struct
> omap_sr_pmic_data *pmic_data);
>  /* Smartreflex driver hooks to be called from Smartreflex class driver
*/
>  int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
>  void sr_disable(struct voltagedomain *voltdm);
> +int sr_notifier_control(struct voltagedomain *voltdm, bool enable);
>  int sr_configure_errgen(struct voltagedomain *voltdm);
>  int sr_configure_minmax(struct voltagedomain *voltdm);
>
> @@ -250,6 +251,13 @@ int sr_register_class(struct
> omap_sr_class_data *class_data);
>  #else
>  static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
>  static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
> +
> +static inline int sr_notifier_control(struct voltagedomain *voltdm,
> +		bool enable)
> +{
> +	return -EINVAL;
> +}
> +
>  static inline void omap_sr_disable_reset_volt(
>  		struct voltagedomain *voltdm) {}
>  static inline void omap_sr_register_pmic(
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/19] omap3+: sr: introduce notifier_control
  2011-02-19 13:40   ` Vishwanath Sripathy
@ 2011-02-20  4:50     ` Nishanth Menon
  2011-02-23  6:46       ` Vishwanath Sripathy
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-20  4:50 UTC (permalink / raw)
  To: Vishwanath Sripathy; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

Vishwanath Sripathy wrote, on 02/19/2011 07:10 PM:

>> +int sr_notifier_control(struct voltagedomain *voltdm, bool enable)
>> +{
>> +	struct omap_sr *sr = _sr_lookup(voltdm);
>> +	u32 value = 0;
>> +	if (IS_ERR_OR_NULL(sr)) {
>> +		pr_warning("%s: sr corresponding to domain not found\n",
>> +				__func__);
>> +		return -EINVAL;
>> +	}
>> +	if (!sr->autocomp_active)
>> +		return -EINVAL;
> Why you do you return here? Class driver should still be able to place
> it's request even if sr is disabled though it will be effective only after
> sr is enabled.

my intents were as following: which useful event would come without SR 
avs being enabled? what kind of event do you expect with the AVS 
disabled which is useful for class driver, whose clase init alone was 
called and not class enable?

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-19 13:24   ` Vishwanath Sripathy
@ 2011-02-20  5:12     ` Nishanth Menon
  2011-02-23  6:54       ` Vishwanath Sripathy
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-20  5:12 UTC (permalink / raw)
  To: Vishwanath Sripathy; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
[..]
>> omap2_set_init_voltage should setup the curr_volt based on which OPP
>> the system is functioning at. Blindly setting a 1.2v setting in the
>> initial structure may not even match the default voltages stored in
>> the voltage table which are supported for the domain.
>>
>> For example, OMAP3430 core domain does not use 1.2v and ends up
>> generating a warning on the first transition.
>>
[..]
>> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
>> omap2/voltage.c
>> index 12be525..280ee12 100644
>> --- a/arch/arm/mach-omap2/voltage.c
>> +++ b/arch/arm/mach-omap2/voltage.c
[..]
>>   	/* Generic voltage parameters */
>> -	vdd->curr_volt = 1200000;
> Where do you update this parameter upon initialization? Shouldn't you read
> the VP register and find the actual current voltage and update this param?

The sequence is as follows:
a) omapx_vdd_data configure is called as part of sr init sequence.
	And the curr_volt with this patch is not updated at this stage.
b) somewhere down in the boot sequence, pm.c's omap2_set_init_voltage 
starts up. This looks up the current clk frequency from clock layer of 
the parent device for the domain, picks up the nominal voltages stored 
in the opp layer, then does a omap_voltage_scale_vdd to that voltage. In 
omap_voltage_scale_vdd, The current voltage is merely picked off the vp 
(in _pre_volt_scale). the last step it does is to setup vdd->curr_volt. 
This can then be used by dvfs layer etc to make appropriate decisions.

So, No, I dont think I need to update it here, it should happen as part 
of the pm init sequence.

Could you explain what problem do you foresee by doing this?

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES
  2011-02-19 13:22   ` Vishwanath Sripathy
@ 2011-02-20  5:26     ` Nishanth Menon
  2011-02-20  5:38       ` do we need CHIP_GE_OMAP3630ES1in .oc? (was Re: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES) Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-20  5:26 UTC (permalink / raw)
  To: Vishwanath Sripathy; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

Vishwanath Sripathy wrote, on 02/19/2011 06:52 PM:
>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of Nishanth Menon
>> Sent: Saturday, February 19, 2011 5:32 PM
>> To: linux-omap
>> Cc: Tony Lindgren; Kevin Hilman; Nishanth Menon
>> Subject: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES
>>
>> Enable hwmod entries for OMAP3630 for higher ES revisions as
>> well. This is to ensure that SR can be used in all revisions of
>> OMAP3630 as of this posting.
>>
>> Signed-off-by: Nishanth Menon<nm@ti.com>
>> ---
>>   arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |    8 ++++++--
>>   1 files changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> index ea1f49a..bbcbea6 100644
>> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>> @@ -1318,7 +1318,9 @@ static struct omap_hwmod
>> omap36xx_sr1_hwmod = {
>>   	},
>>   	.slaves		= omap3_sr1_slaves,
>>   	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
>> -	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
>> +	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1	|
>> +					CHIP_IS_OMAP3630ES1_1	|
>> +					CHIP_IS_OMAP3630ES1_2),
> What's the need of this?
> Here is the code snippet from id.c
> -----snip-----
> 	case 0xb891:
> 		/* Handle 36xx devices */
> 		omap_chip.oc |= CHIP_IS_OMAP3630ES1;
>
> 		switch(rev) {
> 		case 0: /* Take care of early samples */
> 			omap_revision = OMAP3630_REV_ES1_0;
> 			break;
> 		case 1:
> 			omap_revision = OMAP3630_REV_ES1_1;
> 			omap_chip.oc |= CHIP_IS_OMAP3630ES1_1;
> 			break;
> 		case 2:
> 		default:
> 			omap_revision =  OMAP3630_REV_ES1_2;
> 			omap_chip.oc |= CHIP_IS_OMAP3630ES1_2;
> 		}
> So it's clear that omap_chip.oc will have CHIP_IS_OMAP3630ES1 anyway on
> all ES versions.

Hmm... thanks for picking this up, but this is inconsistent and 
confusing implementation in id.c. So the way CHIP_IS_OMAP3630ES1 behaves 
is entirely different from CHIP_IS_OMAP3630ES1_1 or 
CHIP_IS_OMAP3630ES1_2 or any of the OMAP3430ES* which will only be set 
for the specific rev of the silicon.

I can post a patch later on to replace CHIP_IS_OMAP3630ES1 with 
CHIP_IS_OMAP3630ES_ALL which allows the code to be readable and make 
CHIP_IS_OMAP3630ES1 mean precisely what it should have meant like the 
rest of the ESs - only for ES1.0.


What do people think of this?

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* do we need CHIP_GE_OMAP3630ES1in .oc? (was Re: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES)
  2011-02-20  5:26     ` Nishanth Menon
@ 2011-02-20  5:38       ` Nishanth Menon
  2011-02-21  5:50         ` Anand Gadiyar
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-02-20  5:38 UTC (permalink / raw)
  To: Vishwanath Sripathy
  Cc: linux-omap, Tony Lindgren, Kevin Hilman, Gadiyar, Anand

Nishanth Menon wrote, on 02/20/2011 10:56 AM:
> Vishwanath Sripathy wrote, on 02/19/2011 06:52 PM:
>>> -----Original Message-----
>>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>>> owner@vger.kernel.org] On Behalf Of Nishanth Menon
>>> Sent: Saturday, February 19, 2011 5:32 PM
>>> To: linux-omap
>>> Cc: Tony Lindgren; Kevin Hilman; Nishanth Menon
>>> Subject: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES
>>>
>>> Enable hwmod entries for OMAP3630 for higher ES revisions as
>>> well. This is to ensure that SR can be used in all revisions of
>>> OMAP3630 as of this posting.
>>>
>>> Signed-off-by: Nishanth Menon<nm@ti.com>
>>> ---
>>> arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 8 ++++++--
>>> 1 files changed, 6 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>>> b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>>> index ea1f49a..bbcbea6 100644
>>> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>>> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
>>> @@ -1318,7 +1318,9 @@ static struct omap_hwmod
>>> omap36xx_sr1_hwmod = {
>>> },
>>> .slaves = omap3_sr1_slaves,
>>> .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves),
>>> - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
>>> + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1 |
>>> + CHIP_IS_OMAP3630ES1_1 |
>>> + CHIP_IS_OMAP3630ES1_2),
>> What's the need of this?
>> Here is the code snippet from id.c
>> -----snip-----
>> case 0xb891:
>> /* Handle 36xx devices */
>> omap_chip.oc |= CHIP_IS_OMAP3630ES1;
>>
>> switch(rev) {
>> case 0: /* Take care of early samples */
>> omap_revision = OMAP3630_REV_ES1_0;
>> break;
>> case 1:
>> omap_revision = OMAP3630_REV_ES1_1;
>> omap_chip.oc |= CHIP_IS_OMAP3630ES1_1;
>> break;
>> case 2:
>> default:
>> omap_revision = OMAP3630_REV_ES1_2;
>> omap_chip.oc |= CHIP_IS_OMAP3630ES1_2;
>> }
>> So it's clear that omap_chip.oc will have CHIP_IS_OMAP3630ES1 anyway on
>> all ES versions.
>
> Hmm... thanks for picking this up, but this is inconsistent and
> confusing implementation in id.c. So the way CHIP_IS_OMAP3630ES1 behaves
> is entirely different from CHIP_IS_OMAP3630ES1_1 or
> CHIP_IS_OMAP3630ES1_2 or any of the OMAP3430ES* which will only be set
> for the specific rev of the silicon.
>
> I can post a patch later on to replace CHIP_IS_OMAP3630ES1 with
> CHIP_IS_OMAP3630ES_ALL which allows the code to be readable and make
> CHIP_IS_OMAP3630ES1 mean precisely what it should have meant like the
> rest of the ESs - only for ES1.0.

Better might be to introduce and use CHIP_GE_OMAP3630ES1 in hwmod 
structs in that case - that should ease things up. but the ES1 story 
should be fixed I guess.


> What do people think of this?


+ Anand from commit b0a1a6ce0597662c06f970643da60b8ebb5cdd1c which 
introduced the code in id.c to hear his views as well.


-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* RE: do we need CHIP_GE_OMAP3630ES1in .oc? (was Re: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES)
  2011-02-20  5:38       ` do we need CHIP_GE_OMAP3630ES1in .oc? (was Re: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES) Nishanth Menon
@ 2011-02-21  5:50         ` Anand Gadiyar
  0 siblings, 0 replies; 64+ messages in thread
From: Anand Gadiyar @ 2011-02-21  5:50 UTC (permalink / raw)
  To: Nishanth Menon, Vishwanath Sripathy
  Cc: linux-omap, Tony Lindgren, Kevin Hilman

> Better might be to introduce and use CHIP_GE_OMAP3630ES1 in hwmod
> structs in that case - that should ease things up. but the ES1 story
> should be fixed I guess.
>
>
> > What do people think of this?
>
>
> + Anand from commit b0a1a6ce0597662c06f970643da60b8ebb5cdd1c which
> introduced the code in id.c to hear his views as well.

There's one instance where we needed to distinguish between ES1.0 and
all later revs of the 36xx - this was in commit 58dcfb3a0f
(omap: 3630: disable TLL SAR on 3630 ES1).

I chose to pick the same approach that was done for 3430 ES3.0 and below.

We keep two "struct powerdomain core_3xx*pwrdm" instances in
mach-omap2/powerdomains34xx.h with TLL SAR disabled in one. I couldn't
think up a better way to handle this at the time.

- Anand

^ permalink raw reply	[flat|nested] 64+ messages in thread

* RE: [PATCH 15/19] omap3+: sr: introduce notifier_control
  2011-02-20  4:50     ` Nishanth Menon
@ 2011-02-23  6:46       ` Vishwanath Sripathy
  2011-02-23  8:14         ` Menon, Nishanth
  0 siblings, 1 reply; 64+ messages in thread
From: Vishwanath Sripathy @ 2011-02-23  6:46 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

> -----Original Message-----
> From: Nishanth Menon [mailto:nm@ti.com]
> Sent: Sunday, February 20, 2011 10:20 AM
> To: Vishwanath Sripathy
> Cc: linux-omap; Tony Lindgren; Kevin Hilman
> Subject: Re: [PATCH 15/19] omap3+: sr: introduce notifier_control
>
> Vishwanath Sripathy wrote, on 02/19/2011 07:10 PM:
>
> >> +int sr_notifier_control(struct voltagedomain *voltdm, bool enable)
> >> +{
> >> +	struct omap_sr *sr = _sr_lookup(voltdm);
> >> +	u32 value = 0;
> >> +	if (IS_ERR_OR_NULL(sr)) {
> >> +		pr_warning("%s: sr corresponding to domain not found\n",
> >> +				__func__);
> >> +		return -EINVAL;
> >> +	}
> >> +	if (!sr->autocomp_active)
> >> +		return -EINVAL;
> > Why you do you return here? Class driver should still be able to place
> > it's request even if sr is disabled though it will be effective only
after
> > sr is enabled.
>
> my intents were as following: which useful event would come without SR
> avs being enabled? what kind of event do you expect with the AVS
> disabled which is useful for class driver, whose clase init alone was
> called and not class enable?
The point I am making here is, why should SR class driver be prevented to
register for some events when SR is disabled? If it is prevented here,
then it needs to keep track that the request is denied and needs to make
the request again when SR is enabled later.

Vishwa

>
> --
> Regards,
> Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* RE: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-20  5:12     ` Nishanth Menon
@ 2011-02-23  6:54       ` Vishwanath Sripathy
  2011-02-23  8:18         ` Menon, Nishanth
  0 siblings, 1 reply; 64+ messages in thread
From: Vishwanath Sripathy @ 2011-02-23  6:54 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

> -----Original Message-----
> From: Nishanth Menon [mailto:nm@ti.com]
> Sent: Sunday, February 20, 2011 10:42 AM
> To: Vishwanath Sripathy
> Cc: linux-omap; Tony Lindgren; Kevin Hilman
> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>
> Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
> [..]
> >> omap2_set_init_voltage should setup the curr_volt based on which
> OPP
> >> the system is functioning at. Blindly setting a 1.2v setting in the
> >> initial structure may not even match the default voltages stored in
> >> the voltage table which are supported for the domain.
> >>
> >> For example, OMAP3430 core domain does not use 1.2v and ends up
> >> generating a warning on the first transition.
> >>
> [..]
> >> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
> >> omap2/voltage.c
> >> index 12be525..280ee12 100644
> >> --- a/arch/arm/mach-omap2/voltage.c
> >> +++ b/arch/arm/mach-omap2/voltage.c
> [..]
> >>   	/* Generic voltage parameters */
> >> -	vdd->curr_volt = 1200000;
> > Where do you update this parameter upon initialization? Shouldn't you
> read
> > the VP register and find the actual current voltage and update this
> param?
>
> The sequence is as follows:
> a) omapx_vdd_data configure is called as part of sr init sequence.
> 	And the curr_volt with this patch is not updated at this stage.
> b) somewhere down in the boot sequence, pm.c's
> omap2_set_init_voltage
> starts up. This looks up the current clk frequency from clock layer of
> the parent device for the domain, picks up the nominal voltages stored
> in the opp layer, then does a omap_voltage_scale_vdd to that voltage. In
> omap_voltage_scale_vdd, The current voltage is merely picked off the vp
> (in _pre_volt_scale). the last step it does is to setup vdd->curr_volt.
> This can then be used by dvfs layer etc to make appropriate decisions.
>
> So, No, I dont think I need to update it here, it should happen as part
> of the pm init sequence.
>
> Could you explain what problem do you foresee by doing this?
What if omap_voltage_scale_vdd fails when called from
omap2_set_init_voltage? Or omap2_set_init_voltage returns error even
before calling omap_voltage_scale_vdd because it could not find the
matching voltage for the frequency set by bootloader?

Your assumption that curr_volt is always set by omap2_set_init_voltage
need not be true always.

Vishwa
>
> --
> Regards,
> Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 15/19] omap3+: sr: introduce notifier_control
  2011-02-23  6:46       ` Vishwanath Sripathy
@ 2011-02-23  8:14         ` Menon, Nishanth
  0 siblings, 0 replies; 64+ messages in thread
From: Menon, Nishanth @ 2011-02-23  8:14 UTC (permalink / raw)
  To: Vishwanath Sripathy; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

On Wed, Feb 23, 2011 at 12:16, Vishwanath Sripathy <vishwanath.bs@ti.com> wrote:
>
[...]
> > >> +int sr_notifier_control(struct voltagedomain *voltdm, bool enable)
> > >> +{
> > >> +  struct omap_sr *sr = _sr_lookup(voltdm);
> > >> +  u32 value = 0;
> > >> +  if (IS_ERR_OR_NULL(sr)) {
> > >> +          pr_warning("%s: sr corresponding to domain not found\n",
> > >> +                          __func__);
> > >> +          return -EINVAL;
> > >> +  }
> > >> +  if (!sr->autocomp_active)
> > >> +          return -EINVAL;
> > > Why you do you return here? Class driver should still be able to place
> > > it's request even if sr is disabled though it will be effective only
> after
> > > sr is enabled.
> >
> > my intents were as following: which useful event would come without SR
> > avs being enabled? what kind of event do you expect with the AVS
> > disabled which is useful for class driver, whose clase init alone was
> > called and not class enable?
> The point I am making here is, why should SR class driver be prevented to
> register for some events when SR is disabled? If it is prevented here,
> then it needs to keep track that the request is denied and needs to make
> the request again when SR is enabled later.
Let me try another way:
a) none of the notifications(SR_NOTIFY_MCUACCUM, SR_NOTIFY_MCUVALID,
SR_NOTIFY_MCUBOUND, SR_NOTIFY_MCUDISACK)
are possible once the SR class is disabled (class1,1.5,2,3) -
essentially coz the SR is expected to be disabled after class->deinit
is called (deinit is called when the autocomp is disabled for the
class driver).
b) class drivers are expected to release all resources once class
deinit is called, essentially meaning that SR module cannot trust to
have a notifier still capable of handling notifications once the
deinit is called.

So I come back to my question - "why does SR class driver need to
enable notification if it was told to be disabled?". Can you
illustrate with an example what I am missing?

Regards,
Nishanth Menon
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-23  6:54       ` Vishwanath Sripathy
@ 2011-02-23  8:18         ` Menon, Nishanth
  2011-02-23  8:59           ` Vishwanath Sripathy
  0 siblings, 1 reply; 64+ messages in thread
From: Menon, Nishanth @ 2011-02-23  8:18 UTC (permalink / raw)
  To: Vishwanath Sripathy; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

 Wed, Feb 23, 2011 at 12:24, Vishwanath Sripathy <vishwanath.bs@ti.com> wrote:
>> -----Original Message-----
>> From: Nishanth Menon [mailto:nm@ti.com]
>> Sent: Sunday, February 20, 2011 10:42 AM
>> To: Vishwanath Sripathy
>> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>>
>> Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
>> [..]
>> >> omap2_set_init_voltage should setup the curr_volt based on which
>> OPP
>> >> the system is functioning at. Blindly setting a 1.2v setting in the
>> >> initial structure may not even match the default voltages stored in
>> >> the voltage table which are supported for the domain.
>> >>
>> >> For example, OMAP3430 core domain does not use 1.2v and ends up
>> >> generating a warning on the first transition.
>> >>
>> [..]
>> >> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
>> >> omap2/voltage.c
>> >> index 12be525..280ee12 100644
>> >> --- a/arch/arm/mach-omap2/voltage.c
>> >> +++ b/arch/arm/mach-omap2/voltage.c
>> [..]
>> >>    /* Generic voltage parameters */
>> >> -  vdd->curr_volt = 1200000;
>> > Where do you update this parameter upon initialization? Shouldn't you
>> read
>> > the VP register and find the actual current voltage and update this
>> param?
>>
>> The sequence is as follows:
>> a) omapx_vdd_data configure is called as part of sr init sequence.
>>       And the curr_volt with this patch is not updated at this stage.
>> b) somewhere down in the boot sequence, pm.c's
>> omap2_set_init_voltage
>> starts up. This looks up the current clk frequency from clock layer of
>> the parent device for the domain, picks up the nominal voltages stored
>> in the opp layer, then does a omap_voltage_scale_vdd to that voltage. In
>> omap_voltage_scale_vdd, The current voltage is merely picked off the vp
>> (in _pre_volt_scale). the last step it does is to setup vdd->curr_volt.
>> This can then be used by dvfs layer etc to make appropriate decisions.
>>
>> So, No, I dont think I need to update it here, it should happen as part
>> of the pm init sequence.
>>
>> Could you explain what problem do you foresee by doing this?
> What if omap_voltage_scale_vdd fails when called from
> omap2_set_init_voltage? Or omap2_set_init_voltage returns error even
> before calling omap_voltage_scale_vdd because it could not find the
> matching voltage for the frequency set by bootloader?
>
> Your assumption that curr_volt is always set by omap2_set_init_voltage
> need not be true always.

set_init_voltage's job is to set the initial voltage. if it is
incapable of doing it, I say fix that instead of hacking in some
random number as curr_volt.

The logic involved for set_init_voltage is what we need for filling in
cur_volt. just replicating the logic makes no sense to me.

Regards,
Nishanth Menon
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* RE: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-23  8:18         ` Menon, Nishanth
@ 2011-02-23  8:59           ` Vishwanath Sripathy
  2011-02-23  9:08             ` Menon, Nishanth
  0 siblings, 1 reply; 64+ messages in thread
From: Vishwanath Sripathy @ 2011-02-23  8:59 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

> -----Original Message-----
> From: Menon, Nishanth [mailto:nm@ti.com]
> Sent: Wednesday, February 23, 2011 1:48 PM
> To: Vishwanath Sripathy
> Cc: linux-omap; Tony Lindgren; Kevin Hilman
> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>
>  Wed, Feb 23, 2011 at 12:24, Vishwanath Sripathy
> <vishwanath.bs@ti.com> wrote:
> >> -----Original Message-----
> >> From: Nishanth Menon [mailto:nm@ti.com]
> >> Sent: Sunday, February 20, 2011 10:42 AM
> >> To: Vishwanath Sripathy
> >> Cc: linux-omap; Tony Lindgren; Kevin Hilman
> >> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
> >>
> >> Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
> >> [..]
> >> >> omap2_set_init_voltage should setup the curr_volt based on
> which
> >> OPP
> >> >> the system is functioning at. Blindly setting a 1.2v setting in
the
> >> >> initial structure may not even match the default voltages stored
> in
> >> >> the voltage table which are supported for the domain.
> >> >>
> >> >> For example, OMAP3430 core domain does not use 1.2v and ends
> up
> >> >> generating a warning on the first transition.
> >> >>
> >> [..]
> >> >> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
> >> >> omap2/voltage.c
> >> >> index 12be525..280ee12 100644
> >> >> --- a/arch/arm/mach-omap2/voltage.c
> >> >> +++ b/arch/arm/mach-omap2/voltage.c
> >> [..]
> >> >>    /* Generic voltage parameters */
> >> >> -  vdd->curr_volt = 1200000;
> >> > Where do you update this parameter upon initialization? Shouldn't
> you
> >> read
> >> > the VP register and find the actual current voltage and update this
> >> param?
> >>
> >> The sequence is as follows:
> >> a) omapx_vdd_data configure is called as part of sr init sequence.
> >>       And the curr_volt with this patch is not updated at this stage.
> >> b) somewhere down in the boot sequence, pm.c's
> >> omap2_set_init_voltage
> >> starts up. This looks up the current clk frequency from clock layer
of
> >> the parent device for the domain, picks up the nominal voltages
> stored
> >> in the opp layer, then does a omap_voltage_scale_vdd to that
> voltage. In
> >> omap_voltage_scale_vdd, The current voltage is merely picked off
> the vp
> >> (in _pre_volt_scale). the last step it does is to setup
vdd->curr_volt.
> >> This can then be used by dvfs layer etc to make appropriate
> decisions.
> >>
> >> So, No, I dont think I need to update it here, it should happen as
> part
> >> of the pm init sequence.
> >>
> >> Could you explain what problem do you foresee by doing this?
> > What if omap_voltage_scale_vdd fails when called from
> > omap2_set_init_voltage? Or omap2_set_init_voltage returns error
> even
> > before calling omap_voltage_scale_vdd because it could not find the
> > matching voltage for the frequency set by bootloader?
> >
> > Your assumption that curr_volt is always set by
> omap2_set_init_voltage
> > need not be true always.
>
> set_init_voltage's job is to set the initial voltage. if it is
> incapable of doing it, I say fix that instead of hacking in some
> random number as curr_volt.
I never said to use random numbers. All I suggested was that instead of
relying on some others function's behavior, read the VP register to fill
in the right values. If set_init_voltage succeeds, it will anyway update
with right voltage.

Vishwa
>
> The logic involved for set_init_voltage is what we need for filling in
> cur_volt. just replicating the logic makes no sense to me.
>
> Regards,
> Nishanth Menon
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-23  8:59           ` Vishwanath Sripathy
@ 2011-02-23  9:08             ` Menon, Nishanth
  2011-03-02 23:52               ` Kevin Hilman
  0 siblings, 1 reply; 64+ messages in thread
From: Menon, Nishanth @ 2011-02-23  9:08 UTC (permalink / raw)
  To: Vishwanath Sripathy; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

On Wed, Feb 23, 2011 at 14:29, Vishwanath Sripathy <vishwanath.bs@ti.com> wrote:
>> -----Original Message-----
>> From: Menon, Nishanth [mailto:nm@ti.com]
>> Sent: Wednesday, February 23, 2011 1:48 PM
>> To: Vishwanath Sripathy
>> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>>
>>  Wed, Feb 23, 2011 at 12:24, Vishwanath Sripathy
>> <vishwanath.bs@ti.com> wrote:
>> >> -----Original Message-----
>> >> From: Nishanth Menon [mailto:nm@ti.com]
>> >> Sent: Sunday, February 20, 2011 10:42 AM
>> >> To: Vishwanath Sripathy
>> >> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>> >> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>> >>
>> >> Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
>> >> [..]
>> >> >> omap2_set_init_voltage should setup the curr_volt based on
>> which
>> >> OPP
>> >> >> the system is functioning at. Blindly setting a 1.2v setting in
> the
>> >> >> initial structure may not even match the default voltages stored
>> in
>> >> >> the voltage table which are supported for the domain.
>> >> >>
>> >> >> For example, OMAP3430 core domain does not use 1.2v and ends
>> up
>> >> >> generating a warning on the first transition.
>> >> >>
>> >> [..]
>> >> >> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
>> >> >> omap2/voltage.c
>> >> >> index 12be525..280ee12 100644
>> >> >> --- a/arch/arm/mach-omap2/voltage.c
>> >> >> +++ b/arch/arm/mach-omap2/voltage.c
>> >> [..]
>> >> >>    /* Generic voltage parameters */
>> >> >> -  vdd->curr_volt = 1200000;
>> >> > Where do you update this parameter upon initialization? Shouldn't
>> you
>> >> read
>> >> > the VP register and find the actual current voltage and update this
>> >> param?
>> >>
>> >> The sequence is as follows:
>> >> a) omapx_vdd_data configure is called as part of sr init sequence.
>> >>       And the curr_volt with this patch is not updated at this stage.
>> >> b) somewhere down in the boot sequence, pm.c's
>> >> omap2_set_init_voltage
>> >> starts up. This looks up the current clk frequency from clock layer
> of
>> >> the parent device for the domain, picks up the nominal voltages
>> stored
>> >> in the opp layer, then does a omap_voltage_scale_vdd to that
>> voltage. In
>> >> omap_voltage_scale_vdd, The current voltage is merely picked off
>> the vp
>> >> (in _pre_volt_scale). the last step it does is to setup
> vdd->curr_volt.
>> >> This can then be used by dvfs layer etc to make appropriate
>> decisions.
>> >>
>> >> So, No, I dont think I need to update it here, it should happen as
>> part
>> >> of the pm init sequence.
>> >>
>> >> Could you explain what problem do you foresee by doing this?
>> > What if omap_voltage_scale_vdd fails when called from
>> > omap2_set_init_voltage? Or omap2_set_init_voltage returns error
>> even
>> > before calling omap_voltage_scale_vdd because it could not find the
>> > matching voltage for the frequency set by bootloader?
>> >
>> > Your assumption that curr_volt is always set by
>> omap2_set_init_voltage
>> > need not be true always.
>>
>> set_init_voltage's job is to set the initial voltage. if it is
>> incapable of doing it, I say fix that instead of hacking in some
>> random number as curr_volt.
> I never said to use random numbers. All I suggested was that instead of
> relying on some others function's behavior, read the VP register to fill
> in the right values. If set_init_voltage succeeds, it will anyway update
> with right voltage.
OK, lets take this argument for a moment.
Q: which voltage to set as curr_volt?
a) what if the update was done over vcbypass by bootloader? Cannot
trust the vp register for the value.
b) what if the voltage was updated over i2c1 to the PMIC by
bootloader? cant trust vp register again.
c) use some number like 1.2v - which we are aligned is wrong.

in short, what should we do for a accurate curr_volt? vp register may
not be correct, instead, the right steps to do:
find my current freq, check the OPP table for the voltage needed,
setup the voltage for it, update curr_volt for it. this is trust
worthy, rest are not.

This is what set_init_voltage does, replicating that logic in
voltage.c makes no sense again to me.

Regards,
Nishanth Menon
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values
  2011-02-19 12:01 ` [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values Nishanth Menon
@ 2011-02-24  5:28   ` Gulati, Shweta
  2011-02-24  8:29     ` Gulati, Shweta
  2011-02-24 17:22     ` Menon, Nishanth
  0 siblings, 2 replies; 64+ messages in thread
From: Gulati, Shweta @ 2011-02-24  5:28 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

Hi,

On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm@ti.com> wrote:
> Voltage values can get confusing in meaning with various Smartreflex
> classes being active. Depending on the class used, the actual voltage
> selected might be a variant. Hence pass the volt_data pointers through
> the structure. Each voltage domain contains a set of volt_data structs.
> Each of those volt_data struct represents a voltage point that is supported
> for that domain. Hence, this is a more accurate representation of the
> voltage point we are interested in going to, and the actual translation
> of this voltage point to the voltage value is done inside the voltage layer
> which allows the users of the voltage layer to be blissfully ignorant
> of any complexity of the underneath layers.
Volt_data has efuse, Errgain and errminlimit other than nom_volt
How does this data differs in different SR Class implementation which
is why using volt_data is required?
>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>  arch/arm/mach-omap2/pm.c                  |    3 +-
>  arch/arm/mach-omap2/smartreflex-class3.c  |    3 +-
>  arch/arm/mach-omap2/voltage.c             |   72 +++++++++++++++--------------
>  arch/arm/plat-omap/include/plat/voltage.h |   13 ++++-
>  4 files changed, 53 insertions(+), 38 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
> index d5a102c..669998b 100644
> --- a/arch/arm/mach-omap2/pm.c
> +++ b/arch/arm/mach-omap2/pm.c
> @@ -209,7 +209,8 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
>                goto exit;
>        }
>
> -       omap_voltage_scale_vdd(voltdm, bootup_volt);
> +       omap_voltage_scale_vdd(voltdm,
> +                       omap_voltage_get_voltdata(voltdm, bootup_volt));
>        return 0;
>
>  exit:
> diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
> index 60e7055..2195668 100644
> --- a/arch/arm/mach-omap2/smartreflex-class3.c
> +++ b/arch/arm/mach-omap2/smartreflex-class3.c
> @@ -15,7 +15,8 @@
>
>  static int sr_class3_enable(struct voltagedomain *voltdm)
>  {
> -       unsigned long volt = omap_voltage_get_nom_volt(voltdm);
> +       unsigned long volt = omap_get_operation_voltage(
> +               omap_voltage_get_nom_volt(voltdm));
>
>        if (!volt) {
>                pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n",
> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
> index 3ee8a80..08f0abf 100644
> --- a/arch/arm/mach-omap2/voltage.c
> +++ b/arch/arm/mach-omap2/voltage.c
> @@ -146,14 +146,14 @@ struct omap_vdd_info {
>        struct vc_reg_info vc_reg;
>        struct voltagedomain voltdm;
>        struct dentry *debug_dir;
> -       u32 curr_volt;
> +       struct omap_volt_data *curr_volt;
>        u16 ocp_mod;
>        u8 prm_irqst_reg;
>        bool vp_enabled;
>        u32 (*read_reg) (u16 mod, u8 offset);
>        void (*write_reg) (u32 val, u16 mod, u8 offset);
>        int (*volt_scale) (struct omap_vdd_info *vdd,
> -               unsigned long target_volt);
> +               struct omap_volt_data *target_volt);
>  };
>
>  static struct omap_vdd_info *vdd_info;
> @@ -361,13 +361,15 @@ static int vp_volt_debug_get(void *data, u64 *val)
>  static int nom_volt_debug_get(void *data, u64 *val)
>  {
>        struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> +       struct omap_volt_data *volt_data;
>
>        if (!vdd) {
>                pr_warning("Wrong paramater passed\n");
>                return -EINVAL;
>        }
> +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
>
> -       *val = omap_voltage_get_nom_volt(&vdd->voltdm);
> +       *val = volt_data->volt_nominal;
>
>        return 0;
>  }
> @@ -382,7 +384,8 @@ static void vp_latch_vsel(struct omap_vdd_info *vdd)
>        unsigned long uvdc;
>        char vsel;
>
> -       uvdc = omap_voltage_get_nom_volt(&vdd->voltdm);
> +       uvdc = omap_get_operation_voltage(
> +                       omap_voltage_get_nom_volt(&vdd->voltdm));
>        if (!uvdc) {
>                pr_warning("%s: unable to find current voltage for vdd_%s\n",
>                        __func__, vdd->voltdm.name);
> @@ -505,12 +508,18 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
>
>  /* Voltage scale and accessory APIs */
>  static int _pre_volt_scale(struct omap_vdd_info *vdd,
> -               unsigned long target_volt, u8 *target_vsel, u8 *current_vsel)
> +               struct omap_volt_data *target_volt, u8 *target_vsel,
> +               u8 *current_vsel)
>  {
> -       struct omap_volt_data *volt_data;
>        u32 vc_cmdval, vp_errgain_val;
>        u16 vp_mod, vc_mod;
>
> +       if (IS_ERR_OR_NULL(target_volt) || IS_ERR_OR_NULL(vdd) ||
> +                       !target_vsel || !current_vsel) {
> +               pr_err("%s: invalid parms!\n", __func__);
> +               return -EINVAL;
> +       }
> +
>        /* Check if suffiecient pmic info is available for this vdd */
>        if (!vdd->pmic_info) {
>                pr_err("%s: Insufficient pmic info to scale the vdd_%s\n",
> @@ -534,12 +543,8 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
>        vp_mod = vdd->vp_reg.prm_mod;
>        vc_mod = vdd->vc_reg.prm_mod;
>
> -       /* Get volt_data corresponding to target_volt */
> -       volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
> -       if (IS_ERR(volt_data))
> -               volt_data = NULL;
> -
> -       *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt);
> +       *target_vsel = vdd->pmic_info->uv_to_vsel(
> +                       omap_get_operation_voltage(target_volt));
>        *current_vsel = vdd->read_reg(vp_mod, vdd->vp_offs.voltage);
>
>        /* Setting the ON voltage to the new target voltage */
> @@ -549,22 +554,21 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
>        vdd->write_reg(vc_cmdval, vc_mod, vdd->vc_reg.cmdval_reg);
>
>        /* Setting vp errorgain based on the voltage */
> -       if (volt_data) {
> -               vp_errgain_val = vdd->read_reg(vp_mod,
> -                               vdd->vp_offs.vpconfig);
> -               vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
> -               vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
> -               vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
> -                               vdd->vp_reg.vpconfig_errorgain_shift;
> -               vdd->write_reg(vp_errgain_val, vp_mod,
> -                               vdd->vp_offs.vpconfig);
> -       }
> +       vp_errgain_val = vdd->read_reg(vp_mod,
> +                       vdd->vp_offs.vpconfig);
> +       vdd->vp_reg.vpconfig_errorgain = target_volt->vp_errgain;
> +       vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
> +       vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
> +                       vdd->vp_reg.vpconfig_errorgain_shift;
> +       vdd->write_reg(vp_errgain_val, vp_mod,
> +                       vdd->vp_offs.vpconfig);
>
>        return 0;
>  }
>
>  static void _post_volt_scale(struct omap_vdd_info *vdd,
> -               unsigned long target_volt, u8 target_vsel, u8 current_vsel)
> +               struct omap_volt_data *target_volt, u8 target_vsel,
> +               u8 current_vsel)
>  {
>        u32 smps_steps = 0, smps_delay = 0;
>
> @@ -579,7 +583,7 @@ static void _post_volt_scale(struct omap_vdd_info *vdd,
>
>  /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
>  static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
> -               unsigned long target_volt)
> +               struct omap_volt_data *target_volt)
>  {
>        u32 loop_cnt = 0, retries_cnt = 0;
>        u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
> @@ -632,7 +636,7 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
>
>  /* VP force update method of voltage scaling */
>  static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
> -               unsigned long target_volt)
> +               struct omap_volt_data *target_volt)
>  {
>        u32 vpconfig;
>        u16 mod, ocp_mod;
> @@ -1118,16 +1122,15 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>  * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
>  * @voltdm:    pointer to the VDD for which current voltage info is needed
>  *
> - * API to get the current non-auto-compensated voltage for a VDD.
> - * Returns 0 in case of error else returns the current voltage for the VDD.
> + * API to get the current non-auto-compensated voltage data pointer for a VDD.
>  */
> -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
> +struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
>  {
>        struct omap_vdd_info *vdd;
>
>        if (IS_ERR_OR_NULL(voltdm)) {
>                pr_warning("%s: VDD specified does not exist!\n", __func__);
> -               return 0;
> +               return ERR_PTR(-ENODATA);
>        }
The change to return volt_data instead of nominal voltage in function
definition is not there.
Am I missing something?
>
>        vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
> @@ -1269,18 +1272,19 @@ void omap_vp_disable(struct voltagedomain *voltdm)
>  * omap_voltage_scale_vdd() - API to scale voltage of a particular
>  *                             voltage domain.
>  * @voltdm:    pointer to the VDD which is to be scaled.
> - * @target_volt:       The target voltage of the voltage domain
> + * @target_volt:       The target voltage data for the voltage domain
>  *
>  * This API should be called by the kernel to do the voltage scaling
>  * for a particular voltage domain during dvfs or any other situation.
>  */
>  int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
> -               unsigned long target_volt)
> +               struct omap_volt_data *target_volt)
>  {
>        struct omap_vdd_info *vdd;
>
> -       if (!voltdm || IS_ERR(voltdm)) {
> -               pr_warning("%s: VDD specified does not exist!\n", __func__);
> +       if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(target_volt)) {
> +               pr_warning("%s: Bad Params vdm=%p tv=%p!\n", __func__,
> +                               voltdm, target_volt);
>                return -EINVAL;
>        }
>
> @@ -1306,7 +1310,7 @@ int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
>  */
>  void omap_voltage_reset(struct voltagedomain *voltdm)
>  {
> -       unsigned long target_uvdc;
> +       struct omap_volt_data *target_uvdc;
>
>        if (IS_ERR_OR_NULL(voltdm)) {
>                pr_warning("%s: VDD specified does not exist!\n", __func__);
> diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
> index 5bd204e..52df49f 100644
> --- a/arch/arm/plat-omap/include/plat/voltage.h
> +++ b/arch/arm/plat-omap/include/plat/voltage.h
> @@ -117,13 +117,13 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm);
>  void omap_vp_enable(struct voltagedomain *voltdm);
>  void omap_vp_disable(struct voltagedomain *voltdm);
>  int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
> -               unsigned long target_volt);
> +               struct omap_volt_data *target_volt);
>  void omap_voltage_reset(struct voltagedomain *voltdm);
>  void omap_voltage_get_volttable(struct voltagedomain *voltdm,
>                struct omap_volt_data **volt_data);
>  struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
>                unsigned long volt);
> -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
> +struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
>  struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
>  #ifdef CONFIG_PM
>  int omap_voltage_register_pmic(struct voltagedomain *voltdm,
> @@ -152,4 +152,13 @@ static inline struct voltagedomain *omap_voltage_domain_lookup(char *name)
>  }
>  #endif
>
> +/* convert volt data to the voltage for the voltage data */
> +static inline unsigned long omap_get_operation_voltage(
> +               struct omap_volt_data *vdata)
> +{
> +       if (IS_ERR_OR_NULL(vdata))
> +               return 0;
> +       return vdata->volt_nominal;
> +}
> +
>  #endif
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

-- 
Thanks,
Regards,
Shweta
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values
  2011-02-24  5:28   ` Gulati, Shweta
@ 2011-02-24  8:29     ` Gulati, Shweta
  2011-02-24 17:22     ` Menon, Nishanth
  1 sibling, 0 replies; 64+ messages in thread
From: Gulati, Shweta @ 2011-02-24  8:29 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

Hi,

On Thu, Feb 24, 2011 at 10:58 AM, Gulati, Shweta <shweta.gulati@ti.com> wrote:
> Hi,
>
> On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm@ti.com> wrote:
>> Voltage values can get confusing in meaning with various Smartreflex
>> classes being active. Depending on the class used, the actual voltage
>> selected might be a variant. Hence pass the volt_data pointers through
>> the structure. Each voltage domain contains a set of volt_data structs.
>> Each of those volt_data struct represents a voltage point that is supported
>> for that domain. Hence, this is a more accurate representation of the
>> voltage point we are interested in going to, and the actual translation
>> of this voltage point to the voltage value is done inside the voltage layer
>> which allows the users of the voltage layer to be blissfully ignorant
>> of any complexity of the underneath layers.
> Volt_data has efuse, Errgain and errminlimit other than nom_volt
> How does this data differs in different SR Class implementation which
> is why using volt_data is required?
>>
>> Signed-off-by: Nishanth Menon <nm@ti.com>
>> ---
>>  arch/arm/mach-omap2/pm.c                  |    3 +-
>>  arch/arm/mach-omap2/smartreflex-class3.c  |    3 +-
>>  arch/arm/mach-omap2/voltage.c             |   72 +++++++++++++++--------------
>>  arch/arm/plat-omap/include/plat/voltage.h |   13 ++++-
>>  4 files changed, 53 insertions(+), 38 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
>> index d5a102c..669998b 100644
>> --- a/arch/arm/mach-omap2/pm.c
>> +++ b/arch/arm/mach-omap2/pm.c
>> @@ -209,7 +209,8 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
>>                goto exit;
>>        }
>>
>> -       omap_voltage_scale_vdd(voltdm, bootup_volt);
>> +       omap_voltage_scale_vdd(voltdm,
>> +                       omap_voltage_get_voltdata(voltdm, bootup_volt));
>>        return 0;
>>
>>  exit:
>> diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
>> index 60e7055..2195668 100644
>> --- a/arch/arm/mach-omap2/smartreflex-class3.c
>> +++ b/arch/arm/mach-omap2/smartreflex-class3.c
>> @@ -15,7 +15,8 @@
>>
>>  static int sr_class3_enable(struct voltagedomain *voltdm)
>>  {
>> -       unsigned long volt = omap_voltage_get_nom_volt(voltdm);
>> +       unsigned long volt = omap_get_operation_voltage(
>> +               omap_voltage_get_nom_volt(voltdm));
>>
>>        if (!volt) {
>>                pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n",
>> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
>> index 3ee8a80..08f0abf 100644
>> --- a/arch/arm/mach-omap2/voltage.c
>> +++ b/arch/arm/mach-omap2/voltage.c
>> @@ -146,14 +146,14 @@ struct omap_vdd_info {
>>        struct vc_reg_info vc_reg;
>>        struct voltagedomain voltdm;
>>        struct dentry *debug_dir;
>> -       u32 curr_volt;
>> +       struct omap_volt_data *curr_volt;
>>        u16 ocp_mod;
>>        u8 prm_irqst_reg;
>>        bool vp_enabled;
>>        u32 (*read_reg) (u16 mod, u8 offset);
>>        void (*write_reg) (u32 val, u16 mod, u8 offset);
>>        int (*volt_scale) (struct omap_vdd_info *vdd,
>> -               unsigned long target_volt);
>> +               struct omap_volt_data *target_volt);
>>  };
>>
>>  static struct omap_vdd_info *vdd_info;
>> @@ -361,13 +361,15 @@ static int vp_volt_debug_get(void *data, u64 *val)
>>  static int nom_volt_debug_get(void *data, u64 *val)
>>  {
>>        struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
>> +       struct omap_volt_data *volt_data;
>>
>>        if (!vdd) {
>>                pr_warning("Wrong paramater passed\n");
>>                return -EINVAL;
>>        }
>> +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
>>
>> -       *val = omap_voltage_get_nom_volt(&vdd->voltdm);
>> +       *val = volt_data->volt_nominal;
>>
>>        return 0;
>>  }
>> @@ -382,7 +384,8 @@ static void vp_latch_vsel(struct omap_vdd_info *vdd)
>>        unsigned long uvdc;
>>        char vsel;
>>
>> -       uvdc = omap_voltage_get_nom_volt(&vdd->voltdm);
>> +       uvdc = omap_get_operation_voltage(
>> +                       omap_voltage_get_nom_volt(&vdd->voltdm));
>>        if (!uvdc) {
>>                pr_warning("%s: unable to find current voltage for vdd_%s\n",
>>                        __func__, vdd->voltdm.name);
>> @@ -505,12 +508,18 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
>>
>>  /* Voltage scale and accessory APIs */
>>  static int _pre_volt_scale(struct omap_vdd_info *vdd,
>> -               unsigned long target_volt, u8 *target_vsel, u8 *current_vsel)
>> +               struct omap_volt_data *target_volt, u8 *target_vsel,
>> +               u8 *current_vsel)
>>  {
>> -       struct omap_volt_data *volt_data;
>>        u32 vc_cmdval, vp_errgain_val;
>>        u16 vp_mod, vc_mod;
>>
>> +       if (IS_ERR_OR_NULL(target_volt) || IS_ERR_OR_NULL(vdd) ||
>> +                       !target_vsel || !current_vsel) {
>> +               pr_err("%s: invalid parms!\n", __func__);
>> +               return -EINVAL;
>> +       }
>> +
>>        /* Check if suffiecient pmic info is available for this vdd */
>>        if (!vdd->pmic_info) {
>>                pr_err("%s: Insufficient pmic info to scale the vdd_%s\n",
>> @@ -534,12 +543,8 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
>>        vp_mod = vdd->vp_reg.prm_mod;
>>        vc_mod = vdd->vc_reg.prm_mod;
>>
>> -       /* Get volt_data corresponding to target_volt */
>> -       volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
>> -       if (IS_ERR(volt_data))
>> -               volt_data = NULL;
>> -
>> -       *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt);
>> +       *target_vsel = vdd->pmic_info->uv_to_vsel(
>> +                       omap_get_operation_voltage(target_volt));
>>        *current_vsel = vdd->read_reg(vp_mod, vdd->vp_offs.voltage);
>>
>>        /* Setting the ON voltage to the new target voltage */
>> @@ -549,22 +554,21 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
>>        vdd->write_reg(vc_cmdval, vc_mod, vdd->vc_reg.cmdval_reg);
>>
>>        /* Setting vp errorgain based on the voltage */
>> -       if (volt_data) {
>> -               vp_errgain_val = vdd->read_reg(vp_mod,
>> -                               vdd->vp_offs.vpconfig);
>> -               vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
>> -               vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
>> -               vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
>> -                               vdd->vp_reg.vpconfig_errorgain_shift;
>> -               vdd->write_reg(vp_errgain_val, vp_mod,
>> -                               vdd->vp_offs.vpconfig);
>> -       }
>> +       vp_errgain_val = vdd->read_reg(vp_mod,
>> +                       vdd->vp_offs.vpconfig);
>> +       vdd->vp_reg.vpconfig_errorgain = target_volt->vp_errgain;
>> +       vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
>> +       vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
>> +                       vdd->vp_reg.vpconfig_errorgain_shift;
>> +       vdd->write_reg(vp_errgain_val, vp_mod,
>> +                       vdd->vp_offs.vpconfig);
>>
>>        return 0;
>>  }
>>
>>  static void _post_volt_scale(struct omap_vdd_info *vdd,
>> -               unsigned long target_volt, u8 target_vsel, u8 current_vsel)
>> +               struct omap_volt_data *target_volt, u8 target_vsel,
>> +               u8 current_vsel)
>>  {
>>        u32 smps_steps = 0, smps_delay = 0;
>>
>> @@ -579,7 +583,7 @@ static void _post_volt_scale(struct omap_vdd_info *vdd,
>>
>>  /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
>>  static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
>> -               unsigned long target_volt)
>> +               struct omap_volt_data *target_volt)
>>  {
>>        u32 loop_cnt = 0, retries_cnt = 0;
>>        u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
>> @@ -632,7 +636,7 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
>>
>>  /* VP force update method of voltage scaling */
>>  static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
>> -               unsigned long target_volt)
>> +               struct omap_volt_data *target_volt)
>>  {
>>        u32 vpconfig;
>>        u16 mod, ocp_mod;
>> @@ -1118,16 +1122,15 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
>>  * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
>>  * @voltdm:    pointer to the VDD for which current voltage info is needed
>>  *
>> - * API to get the current non-auto-compensated voltage for a VDD.
>> - * Returns 0 in case of error else returns the current voltage for the VDD.
>> + * API to get the current non-auto-compensated voltage data pointer for a VDD.
>>  */
>> -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
>> +struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
>>  {
>>        struct omap_vdd_info *vdd;
>>
>>        if (IS_ERR_OR_NULL(voltdm)) {
>>                pr_warning("%s: VDD specified does not exist!\n", __func__);
>> -               return 0;
>> +               return ERR_PTR(-ENODATA);
>>        }
> The change to return volt_data instead of nominal voltage in function
> definition is not there.
> Am I missing something?
I checked it, Change is there in omap_vdd_info, missed it.
>>
>>        vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
>> @@ -1269,18 +1272,19 @@ void omap_vp_disable(struct voltagedomain *voltdm)
>>  * omap_voltage_scale_vdd() - API to scale voltage of a particular
>>  *                             voltage domain.
>>  * @voltdm:    pointer to the VDD which is to be scaled.
>> - * @target_volt:       The target voltage of the voltage domain
>> + * @target_volt:       The target voltage data for the voltage domain
>>  *
>>  * This API should be called by the kernel to do the voltage scaling
>>  * for a particular voltage domain during dvfs or any other situation.
>>  */
>>  int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
>> -               unsigned long target_volt)
>> +               struct omap_volt_data *target_volt)
>>  {
>>        struct omap_vdd_info *vdd;
>>
>> -       if (!voltdm || IS_ERR(voltdm)) {
>> -               pr_warning("%s: VDD specified does not exist!\n", __func__);
>> +       if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(target_volt)) {
>> +               pr_warning("%s: Bad Params vdm=%p tv=%p!\n", __func__,
>> +                               voltdm, target_volt);
>>                return -EINVAL;
>>        }
>>
>> @@ -1306,7 +1310,7 @@ int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
>>  */
>>  void omap_voltage_reset(struct voltagedomain *voltdm)
>>  {
>> -       unsigned long target_uvdc;
>> +       struct omap_volt_data *target_uvdc;
>>
>>        if (IS_ERR_OR_NULL(voltdm)) {
>>                pr_warning("%s: VDD specified does not exist!\n", __func__);
>> diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
>> index 5bd204e..52df49f 100644
>> --- a/arch/arm/plat-omap/include/plat/voltage.h
>> +++ b/arch/arm/plat-omap/include/plat/voltage.h
>> @@ -117,13 +117,13 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm);
>>  void omap_vp_enable(struct voltagedomain *voltdm);
>>  void omap_vp_disable(struct voltagedomain *voltdm);
>>  int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
>> -               unsigned long target_volt);
>> +               struct omap_volt_data *target_volt);
>>  void omap_voltage_reset(struct voltagedomain *voltdm);
>>  void omap_voltage_get_volttable(struct voltagedomain *voltdm,
>>                struct omap_volt_data **volt_data);
>>  struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
>>                unsigned long volt);
>> -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
>> +struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
>>  struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
>>  #ifdef CONFIG_PM
>>  int omap_voltage_register_pmic(struct voltagedomain *voltdm,
>> @@ -152,4 +152,13 @@ static inline struct voltagedomain *omap_voltage_domain_lookup(char *name)
>>  }
>>  #endif
>>
>> +/* convert volt data to the voltage for the voltage data */
>> +static inline unsigned long omap_get_operation_voltage(
>> +               struct omap_volt_data *vdata)
>> +{
>> +       if (IS_ERR_OR_NULL(vdata))
>> +               return 0;
>> +       return vdata->volt_nominal;
>> +}
>> +
>>  #endif
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
> --
> Thanks,
> Regards,
> Shweta
>



-- 
Thanks,
Regards,
Shweta
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values
  2011-02-24  5:28   ` Gulati, Shweta
  2011-02-24  8:29     ` Gulati, Shweta
@ 2011-02-24 17:22     ` Menon, Nishanth
  1 sibling, 0 replies; 64+ messages in thread
From: Menon, Nishanth @ 2011-02-24 17:22 UTC (permalink / raw)
  To: Gulati, Shweta; +Cc: linux-omap, Tony Lindgren, Kevin Hilman

On Thu, Feb 24, 2011 at 10:58, Gulati, Shweta <shweta.gulati@ti.com> wrote:
> Hi,
>
> On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm@ti.com> wrote:
>> Voltage values can get confusing in meaning with various Smartreflex
>> classes being active. Depending on the class used, the actual voltage
>> selected might be a variant. Hence pass the volt_data pointers through
>> the structure. Each voltage domain contains a set of volt_data structs.
>> Each of those volt_data struct represents a voltage point that is supported
>> for that domain. Hence, this is a more accurate representation of the
>> voltage point we are interested in going to, and the actual translation
>> of this voltage point to the voltage value is done inside the voltage layer
>> which allows the users of the voltage layer to be blissfully ignorant
>> of any complexity of the underneath layers.
> Volt_data has efuse, Errgain and errminlimit other than nom_volt
> How does this data differs in different SR Class implementation which
> is why using volt_data is required?
fair question. let me try it this way.
with smart reflex class 3:
a) you dont have SR enabled, you will go to volt_nominal
b) you have SR enabled, you go to volt_nominal, then enable SR and
expect it to adjust voltage.
we dont really care about the resultant voltage(until the next scale
ofcourse). but when we ask voltage layer to scale to voltage x for OPP
y, it always means x is the nominal voltage for OPP y.

Now with class 1.5 as introduced in
http://marc.info/?l=linux-omap&m=129811707718325&w=2,
a) if you are booting for the first time OR if you never enable SR,
you go to volt_nominal
b) if you enable SR and the OPP is calibrated, you will not enable SR
again when that OPP is accessed anymore, but when you set voltage, the
voltage achieved will be volt_calibrated
c) if recalibration timeout triggers, the calibrated values are
nullified, and you set voltage, the voltage achieved will be
volt_dynamic_nominal

so, voltage for that OPP you are setting has not 1 single value
anymore, but 3 possible valid values depending on which state the
system is at.

This is the motivation of decoupling values representing voltage in
this patch and instead we use a "voltage object" represented by the
pointer to volt_data to decide adequately the OPP voltage we go to.
The decision as to what the "voltage object" means in uVolts is left
to the voltage layer. upper layers (or users of voltage layer) are not
aware of the system conditions relevant to voltage - only voltage.c
has that view - hence we do the translation there.

[...]

Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 18/19] omap3630+: sr: add support for class 1.5
  2011-02-19 12:01 ` [PATCH 18/19] omap3630+: sr: add support for class 1.5 Nishanth Menon
@ 2011-03-01  9:53   ` Gulati, Shweta
  2011-03-01 10:17     ` Menon, Nishanth
  0 siblings, 1 reply; 64+ messages in thread
From: Gulati, Shweta @ 2011-03-01  9:53 UTC (permalink / raw)
  To: Nishanth Menon
  Cc: linux-omap, Tony Lindgren, Kevin Hilman, Ambresh K,
	Eduardo Valentin, Igor Dmitriev, Paul,
	Peter 'p2' De Schrijver

Hi,

On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm@ti.com> wrote:
> Traditional SmartReflex AVS(Automatic Voltage Scaling) classes are:
> * Class 0 - Product test calibration
>        Silicon is calibration at production floor and fused with voltages
>        for each OPP
> * Class 1 - Boot time calibration
>        Silicon is calibrated once at boot time and voltages are stored for
>        the lifetime of operation.
> * Class 2 - continuous s/w calibration
>        SR module notifies s/w for any change in the system which is desired
>        and the s/w makes runtime decisions in terms of setting the voltage,
>        this mechanism could be used in the system which does not have PMIC
>        capable of SR without using the voltage controller and voltage
>        processor blocks.
> * Class 3 - continuous h/w calibration
>        SR module is switch on after reaching a voltage level and SR
>        continuously monitors the system and makes runtime adjustments without
>        s/w involvement.
>
> OMAP3430 has used SmartReflex AVS and with a a PMIC which understands the SR
> protocol, Class 3 has been used. With OMAP3630 onwards, a new SmartReflex AVS
> class of operation Class 1.5 was introduced.
> * Class 1.5 - periodic s/w calibration
>        This uses the h/w calibration loop and at the end of calibration
>        stores the voltages to be used run time, periodic recalibration is
>        performed as well.
>
> The operational mode is describes as the following:
> * SmartReflex AVS h/w calibration loop is essential to identify the optimal
>        voltage for a given OPP.
> * Once this optimal voltage is detected, SmartReflex AVS loop is disabled in
>        class 1.5 mode of operation.
> * Until there is a need for a recalibration, any further transition to an OPP
>        voltage which is calibrated can use the calibrated voltage and does not
>        require enabling the SR AVS h/w loop.
> * On a periodic basis (recommendation being once approximately every 24 hours),
>        software is expected to perform a recalibration to find a new optimal
>        voltage which is compensated for device aging.
>        - For performing this recalibration, the start voltage does not need to
>        be the nominal voltage anymore. instead, the system can start with a
>        voltage which is 50mV higher than the previously calibrated voltage to
>        identify the new optimal voltage as the aging factor within a period of
>        1 day is not going to be anywhere close to 50mV.
>        - This "new starting point" for recalibration is called a dynamic
>        nominal voltage for that voltage point.
> In short, with the introduction of SmartReflex class 1.5, there are three new
> voltages possible in a system's dvfs transition:
> * Nominal Voltage - The maximum voltage needed for a worst possible device
>        in the worst possible conditions. This is the voltage we choose as
>        the starting point for the h/w loop to optimize for the first time
>        calibration on system bootup.
> * Dynamic Nominal Voltage - Worst case voltage for a specific device in
>        considering the system aging on the worst process device.
> * Calibrated Voltage - Best voltage for the current device at a given point
>        of time.
>
> In terms of the implementation, doing calibration involves waiting for the
> smartreflex h/w loop to settle down, and doing this as part of the dvfs flow
> itself is to increase the latency of dvfs transition when there is a need to
> calibrate that opp. instead, the calibration is performed "out of path" using
> a workqueue statemachine. The workqueue waits for the system stabilization,
> then enables VP interrupts to monitor for system instability interms of voltage
> oscillations that are reported back to the system as interrupts, in case of
> prolonged system oscillations, nominal voltage is chosen as a safe voltage and
> this event is logged in the system log for developer debug and fixing.
>
> For the recalibration, a common workqueue for all domains is started at the
> start of the class initialization and it resets the calibrated voltages
> on a periodic basis. For distros that may choose not to do the recommended
> periodic recalibration, instead choose to perform boot time calibration,
> kconfig configuration option is provided to do so.
>
> TODO:
> a) Cpuidle and suspend paths are not integrated with SmartReflex driver at
>   this point.
> b) Since the SR registers are accessed and controlled in parallel to DVFS
>   some sort of mechanism is necessary to be introduced along with OMAP
>   dvfs layer to ensure mutual exclusivity
> c) Additional debug interfaces for vmin analysis for platform characterization
>   and addition of system margin needs to be introduced from smartreflex
>   perspective.
>
> This implementation also includes the following contributors:
> Tony Lindgren for suggestion on using interrupt based mechanism instead of
> polling to detect voltage oscillations.
> Peter 'p2' De Schrijver for debating alternatives on recalibration mechanisms
> Paul Walmsey, Eduardo Valentin, Ambresh K, Igor Dmitriev and quiet a few others
> for patient review, testing and reporting of issues of a previous incarnation
> of this implemenation. Last, but not the least, the TI H/w team in introducing
> this new SR AVS class and patiently debating it's various facets.
>
> Cc: Ambresh K <ambresh@ti.com>
> Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
> Cc: Igor Dmitriev <ext-dmitriev.igor@nokia.com>
> Cc: Paul <paul@pwsan.com>
> Cc: Peter 'p2' De Schrijver <Peter.De-Schrijver@nokia.com>
> Cc: Tony Lindgren <tony@atomide.com>
>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>  arch/arm/mach-omap2/Makefile                  |    1 +
>  arch/arm/mach-omap2/smartreflex-class1p5.c    |  556 +++++++++++++++++++++++++
>  arch/arm/mach-omap2/smartreflex-class3.c      |    4 +-
>  arch/arm/mach-omap2/smartreflex.c             |   34 ++-
>  arch/arm/mach-omap2/voltage.c                 |   69 +++
>  arch/arm/plat-omap/Kconfig                    |   17 +
>  arch/arm/plat-omap/include/plat/smartreflex.h |   13 +-
>  arch/arm/plat-omap/include/plat/voltage.h     |   23 +-
>  8 files changed, 709 insertions(+), 8 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 1c0c2b0..1a82e6d 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -66,6 +66,7 @@ obj-$(CONFIG_ARCH_OMAP4)              += pm44xx.o voltage.o pm_bus.o
>  obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
>  obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
>  obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)  += smartreflex-class3.o
> +obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS1P5)        += smartreflex-class1p5.o
>
>  AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
>  AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a
> diff --git a/arch/arm/mach-omap2/smartreflex-class1p5.c b/arch/arm/mach-omap2/smartreflex-class1p5.c
> new file mode 100644
> index 0000000..832f10b
> --- /dev/null
> +++ b/arch/arm/mach-omap2/smartreflex-class1p5.c
> @@ -0,0 +1,556 @@
> +/*
> + * Smart reflex Class 1.5 specific implementations
> + *
> + * Copyright (C) 2010-2011 Texas Instruments, Inc.
> + * Nishanth Menon <nm@ti.com>
> + *
> + * Smart reflex class 1.5 is also called periodic SW Calibration
> + * Some of the highlights are as follows:
> + * – Host CPU triggers OPP calibration when transitioning to non calibrated
> + *   OPP
> + * – SR-AVS + VP modules are used to perform calibration
> + * – Once completed, the SmartReflex-AVS module can be disabled
> + * – Enables savings based on process, supply DC accuracy and aging
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/fs.h>
> +#include <linux/string.h>
> +#include <linux/uaccess.h>
> +#include <linux/kobject.h>
> +#include <linux/workqueue.h>
> +#include <linux/opp.h>
> +
> +#include <plat/smartreflex.h>
> +#include <plat/voltage.h>
> +
> +#define MAX_VDDS 3
> +#define SR1P5_SAMPLING_DELAY_MS        1
> +#define SR1P5_STABLE_SAMPLES   5
> +#define SR1P5_MAX_TRIGGERS     5
> +
> +/*
> + * we expect events in 10uS, if we dont get 2wice times as much,
> + * we could kind of ignore this as a missed event.
> + */
> +#define MAX_CHECK_VPTRANS_US   20
> +
> +/**
> + * struct sr_class1p5_work_data - data meant to be used by calibration work
> + * @work:      calibration work
> + * @voltdm:            voltage domain for which we are triggering
> + * @vdata:     voltage data we are calibrating
> + * @num_calib_triggers:        number of triggers from calibration loop
> + * @num_osc_samples:   number of samples collected by isr
> + * @work_active:       have we scheduled a work item?
> + */
> +struct sr_class1p5_work_data {
> +       struct delayed_work work;
> +       struct voltagedomain *voltdm;
> +       struct omap_volt_data *vdata;
> +       u8 num_calib_triggers;
> +       u8 num_osc_samples;
> +       bool work_active;
> +};
> +
> +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> +/* recal_work: recalibration calibration work */
> +static struct delayed_work recal_work;
> +#endif
> +
> +/**
> + * struct sr_class1p5_data - private data for class 1p5
> + * @work_data:         work item data per voltage domain
> + */
> +struct sr_class1p5_data {
> +       struct sr_class1p5_work_data work_data[MAX_VDDS];
> +};
> +
> +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> +                                   bool recal);
> +
> +/* our instance of class 1p5 private data */
> +static struct sr_class1p5_data class_1p5_data;
> +
> +static struct sr_class1p5_work_data *get_sr1p5_work(struct voltagedomain
> +                                                   *voltdm)
> +{
> +       int idx;
> +       for (idx = 0; idx < MAX_VDDS; idx++) {
> +               if (class_1p5_data.work_data[idx].voltdm && !strcmp
> +                   (class_1p5_data.work_data[idx].voltdm->name, voltdm->name))
> +                       return &class_1p5_data.work_data[idx];
> +       }
> +       return ERR_PTR(-ENODATA);
> +}
> +
> +/**
> + * sr_class1p5_notify() - isr notifier for status events
> + * @voltdm:    voltage domain for which we were triggered
> + * @status:    notifier event to use
> + *
> + * This basically collects data for the work to use.
> + */
> +static int sr_class1p5_notify(struct voltagedomain *voltdm, u32 status)
> +{
> +       struct sr_class1p5_work_data *work_data;
> +       int idx = 0;
> +       work_data = get_sr1p5_work(voltdm);
> +
> +       if (unlikely(!work_data)) {
> +               pr_err("%s:%s no work data!!\n", __func__, voltdm->name);
> +               return -EINVAL;
> +       }
> +
> +       /* Wait for transdone so that we know the voltage to read */
> +       do {
> +               if (omap_vp_is_transdone(voltdm))
> +                       break;
> +               idx++;
> +               /* get some constant delay */
> +               udelay(1);
> +       } while (idx < MAX_CHECK_VPTRANS_US);
> +
> +       /*
> +        * If we timeout, we still read the data,
> +        * if we are oscillating+irq latencies are too high, we could
> +        * have scenarios where we miss transdone event. since
> +        * we waited long enough, it is still safe to read the voltage
> +        * as we would have waited long enough - still flag it..
> +        */
> +       if (idx >= MAX_CHECK_VPTRANS_US)
> +               pr_warning("%s: timed out waiting for transdone!!\n", __func__);
> +
> +       omap_vp_clear_transdone(voltdm);
> +
> +       idx = (work_data->num_osc_samples) % SR1P5_STABLE_SAMPLES;
> +       work_data->num_osc_samples++;
> +
> +       return 0;
> +}
> +
> +/**
> + * do_calibrate() - work which actually does the calibration
> + * @work: pointer to the work
> + *
> + * calibration routine uses the following logic:
> + * on the first trigger, we start the isr to collect sr voltages
> + * wait for stabilization delay (reschdule self instead of sleeping)
> + * after the delay, see if we collected any isr events
> + * if none, we have calibrated voltage.
> + * if there are any, we retry untill we giveup.
> + * on retry timeout, select a voltage to use as safe voltage.
> + */
> +static void do_calibrate(struct work_struct *work)
> +{
> +       struct sr_class1p5_work_data *work_data =
> +           container_of(work, struct sr_class1p5_work_data, work.work);
> +       unsigned long u_volt_safe = 0, u_volt_current = 0;
> +       struct omap_volt_data *volt_data;
> +       struct voltagedomain *voltdm;
> +
> +       if (unlikely(!work_data)) {
> +               pr_err("%s: ooops.. null work_data?\n", __func__);
> +               return;
> +       }
> +
> +       /*
> +        * TODO:Handle the case where we might have just been scheduled AND
> +        * 1.5 disable was called. check and HOLD dvfs
> +        */
> +
> +       voltdm = work_data->voltdm;
> +       /*
> +        * In the unlikely case that we did get through when unplanned,
> +        * flag and return.
> +        */
> +       if (unlikely(!work_data->work_active)) {
> +               pr_err("%s:%s unplanned work invocation!\n", __func__,
> +                      voltdm->name);
> +               /* TODO release the dvfs */
> +               return;
> +       }
> +
> +       work_data->num_calib_triggers++;
> +       /* if we are triggered first time, we need to start isr to sample */
> +       if (work_data->num_calib_triggers == 1)
> +               goto start_sampling;
> +
> +       /* Stop isr from interrupting our measurements :) */
> +       sr_notifier_control(voltdm, false);
> +
> +       volt_data = work_data->vdata;
> +
> +       /* if there are no samples captured.. SR is silent, aka stability! */
> +       if (!work_data->num_osc_samples) {
> +               u_volt_safe = omap_vp_get_curr_volt(voltdm);
> +               u_volt_current = u_volt_safe;
> +               goto done_calib;
> +       }
> +       if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) {
> +               pr_warning("%s: %s recalib timeout!\n", __func__,
> +                          work_data->voltdm->name);
> +               goto oscillating_calib;
> +       }
> +
> +       /* we have potential oscillations/first sample */
> +start_sampling:
> +       work_data->num_osc_samples = 0;
> +       /* Clear pending events */
> +       sr_notifier_control(voltdm, false);
> +       /* Clear all transdones */
> +       while (omap_vp_is_transdone(voltdm))
> +               omap_vp_clear_transdone(voltdm);
> +       /* trigger sampling */
> +       sr_notifier_control(voltdm, true);
> +       schedule_delayed_work(&work_data->work,
> +                             msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> +                                              SR1P5_STABLE_SAMPLES));
> +       /* TODO: release dvfs */
> +       return;
> +
> +oscillating_calib:
> +       /* Use the nominal voltage as the safe voltage */
> +       u_volt_safe = volt_data->volt_nominal;
> +       /* pick up current voltage to switch if needed */
> +       u_volt_current = omap_vp_get_curr_volt(voltdm);
> +
> +       /* Fall through to close up common stuff */
> +done_calib:
> +       omap_vp_disable(voltdm);
> +       sr_disable(voltdm);
> +
> +       volt_data->volt_calibrated = u_volt_safe;
> +       /* Setup my dynamic voltage for the next calibration for this opp */
> +       volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data);
> +
> +       /*
> +        * if the voltage we decided as safe is not the current voltage,
> +        * switch
> +        */
> +       if (volt_data->volt_calibrated != u_volt_current) {
> +               pr_debug("%s:%s reconfiguring to voltage %d\n",
> +                        __func__, voltdm->name, volt_data->volt_calibrated);
> +               omap_voltage_scale_vdd(voltdm, volt_data);
> +       }
> +
> +       /*
> +        * TODO: Setup my wakeup voltage to allow immediate going to OFF and
> +        * on - Pending twl and voltage layer cleanups.
> +        * This is necessary, as this is not done as part of regular
> +        * Dvfs flow.
> +        * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated);
> +        */
> +       work_data->work_active = false;
> +       /* TODO: release dvfs */
> +}
> +
> +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> +/**
> + * do_recalibrate() - work which actually does the calibration
> + * @work: pointer to the work
> + *
> + * on a periodic basis, we come and reset our calibration setup
> + * so that a recalibration of the OPPs take place. This takes
> + * care of aging factor in the system.
> + */
> +static void do_recalibrate(struct work_struct *work)
> +{
> +       struct voltagedomain *voltdm;
> +       int idx;
> +       static struct sr_class1p5_work_data *work_data;
> +
> +       for (idx = 0; idx < MAX_VDDS; idx++) {
> +               work_data = &class_1p5_data.work_data[idx];
> +               voltdm = work_data->voltdm;
> +               if (voltdm) {
> +                       /* if sr is not enabled, we check later */
> +                       if (!is_sr_enabled(voltdm))
> +                               continue;
> +                       /* TODO: Pause the dvfs transitions */
> +                       /* if sr is not enabled, we check later */
> +
> +                       /* Reset and force a recalibration for current opp */
> +                       sr_class1p5_reset_calib(voltdm, true, true);
> +
> +                       /* TODO: unpause DVFS transitions */
> +               }
> +       }
> +       /* We come back again after time the usual delay */
> +       schedule_delayed_work(&recal_work,
> +             msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> +}
> +#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */
> +
> +/**
> + * sr_class1p5_enable() - class 1.5 mode of enable
> + * @voltdm:            voltage domain to enable SR for
> + * @volt_data: voltdata to the voltage transition taking place
> + *
> + * when this gets called, we use the h/w loop to setup our voltages
> + * to an calibrated voltage, detect any oscillations, recover from the same
> + * and finally store the optimized voltage as the calibrated voltage in the
> + * system
> + */
> +static int sr_class1p5_enable(struct voltagedomain *voltdm,
> +                             struct omap_volt_data *volt_data)
> +{
> +       int r;
> +       struct sr_class1p5_work_data *work_data;
> +       /* if already calibrated, nothing to do here.. */
> +       if (volt_data->volt_calibrated)
> +               return 0;
> +
> +       work_data = get_sr1p5_work(voltdm);
> +       if (unlikely(!work_data)) {
> +               pr_err("%s: aieeee.. bad work data??\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       if (work_data->work_active)
> +               return 0;
> +
> +       omap_vp_enable(voltdm);
> +       r = sr_enable(voltdm, volt_data);
> +       if (r) {
> +               pr_err("%s: sr[%s] failed\n", __func__, voltdm->name);
> +               omap_vp_disable(voltdm);
> +               return r;
> +       }
> +       work_data->vdata = volt_data;
> +       work_data->work_active = true;
> +       work_data->num_calib_triggers = 0;
> +       /* program the workqueue and leave it to calibrate offline.. */
> +       schedule_delayed_work(&work_data->work,
> +                             msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> +                                              SR1P5_STABLE_SAMPLES));
> +
> +       return 0;
> +}
> +
> +/**
> + * sr_class1p5_disable() - disable for class 1p5
> + * @voltdm: voltage domain for the sr which needs disabling
> + * @volt_data: voltagedata to disable
> + * @is_volt_reset: reset the voltage?
> + *
> + * we dont do anything if the class 1p5 is being used. this is because we
> + * already disable sr at the end of calibration and no h/w loop is actually
> + * active when this is called.
> + */
> +static int sr_class1p5_disable(struct voltagedomain *voltdm,
> +                              struct omap_volt_data *volt_data,
> +                              int is_volt_reset)
> +{
> +       struct sr_class1p5_work_data *work_data;
> +
> +       work_data = get_sr1p5_work(voltdm);
> +       if (work_data->work_active) {
> +               /* if volt reset and work is active, we dont allow this */
> +               if (is_volt_reset)
> +                       return -EBUSY;
> +               /* flag work is dead and remove the old work */
> +               work_data->work_active = false;
> +               cancel_delayed_work_sync(&work_data->work);
> +               sr_notifier_control(voltdm, false);
> +               omap_vp_disable(voltdm);
> +               sr_disable(voltdm);
> +       }
> +
> +       /* if already calibrated, nothin special to do here.. */
> +       if (volt_data->volt_calibrated)
> +               return 0;
> +
> +       if (is_volt_reset)
> +               omap_voltage_reset(voltdm);
> +       return 0;
> +}
> +
> +/**
> + * sr_class1p5_configure() - configuration function
> + * @voldm:     configure for which voltage domain
> + *
> + * we dont do much here other than setup some registers for
> + * the sr module involved.
> + */
> +static int sr_class1p5_configure(struct voltagedomain *voltdm)
> +{
> +       return sr_configure_errgen(voltdm);
> +}
> +
> +/**
> + * sr_class1p5_reset_calib() - reset all calibrated voltages
> + * @srid:      srid to reset the calibration for
> + * @reset:     reset voltage before we recal?
> + * @recal:     should I recalibrate my current opp?
> + *
> + * if we call this, it means either periodic calibration trigger was
> + * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
> + * meaning we cant trust the calib voltages anymore, it is better to use
> + * nominal in the system
> + */
> +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> +                                   bool recal)
> +{
> +       struct sr_class1p5_work_data *work_data;
> +
> +       /* I dont need to go further if sr is not present */
> +       if (!is_sr_enabled(voltdm))
> +               return;
> +
> +       work_data = get_sr1p5_work(voltdm);
> +
> +       if (work_data->work_active)
> +               sr_class1p5_disable(voltdm, work_data->vdata, 0);
> +
> +       omap_voltage_calib_reset(voltdm);
> +
> +       /*
> +        * I should now reset the voltages to my nominal to be safe
> +        */
> +       if (reset)
> +               omap_voltage_reset(voltdm);
> +
> +       /*
> +        * I should fire a recalibration for current opp if needed
> +        * Note: i have just reset my calibrated voltages, and if
> +        * i call sr_enable equivalent, I will cause a recalibration
> +        * loop, even though the function is called sr_enable.. we
> +        * are in class 1.5 ;)
> +        */
> +       if (reset && recal)
> +               sr_class1p5_enable(voltdm, work_data->vdata);
> +}
> +
> +/**
> + * sr_class1p5_cinit() - class 1p5 init
> + * @voltdm:            sr voltage domain
> + * @class_priv_data:   private data for the class
> + *
> + * we do class specific initialization like creating sysfs/debugfs entries
> + * needed, spawning of a kthread if needed etc.
> + */
> +static int sr_class1p5_cinit(struct voltagedomain *voltdm,
> +                            void *class_priv_data)
> +{
> +       struct sr_class1p5_work_data *work_data;
> +       int idx;
> +
> +       if (!class_priv_data) {
> +               pr_err("%s: bad param? no priv data!\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       /* setup our work params */
> +       work_data = get_sr1p5_work(voltdm);
> +       if (!IS_ERR_OR_NULL(work_data)) {
> +               pr_err("%s: ooopps.. class already initialized for %s! bug??\n",
> +                      __func__, voltdm->name);
> +               return -EINVAL;
> +       }
> +       work_data = NULL;
> +       /* get the next spare work_data */
> +       for (idx = 0; idx < MAX_VDDS; idx++) {
> +               if (!class_1p5_data.work_data[idx].voltdm) {
> +                       work_data = &class_1p5_data.work_data[idx];
> +                       break;
> +               }
> +       }
> +       if (!work_data) {
> +               pr_err("%s: no more space for work data for domains!\n",
> +                       __func__);
> +               return -ENOMEM;
> +       }
> +       work_data->voltdm = voltdm;
> +       INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, do_calibrate);
> +       return 0;
> +}
> +
> +/**
> + * sr_class1p5_cdeinit() - class 1p5 deinitialization
> + * @voltdm:    voltage domain for which to do this.
> + * @class_priv_data: class private data for deinitialiation
> + *
> + * currently only resets the calibrated voltage forcing dvfs voltages
> + * to be used in the system
> + */
> +static int sr_class1p5_cdeinit(struct voltagedomain *voltdm,
> +                              void *class_priv_data)
> +{
> +       struct sr_class1p5_work_data *work_data;
> +
> +       /* setup our work params */
> +       work_data = get_sr1p5_work(voltdm);
> +       if (IS_ERR_OR_NULL(work_data)) {
> +               pr_err("%s: ooopps.. class not initialized for %s! bug??\n",
> +                      __func__, voltdm->name);
> +               return -EINVAL;
> +       }
> +
> +       /*
> +        * we dont have SR periodic calib anymore.. so reset calibs
> +        * we are already protected by sr debugfs lock, so no lock needed
> +        * here.
> +        */
> +       sr_class1p5_reset_calib(voltdm, true, false);
> +
> +       /* reset all data for this work data */
> +       memset(work_data, 0, sizeof(*work_data));
> +
> +       return 0;
> +}
> +
> +/* SR class1p5 structure */
> +static struct omap_sr_class_data class1p5_data = {
> +       .enable = sr_class1p5_enable,
> +       .disable = sr_class1p5_disable,
> +       .configure = sr_class1p5_configure,
> +       .class_type = SR_CLASS1P5,
> +       .class_init = sr_class1p5_cinit,
> +       .class_deinit = sr_class1p5_cdeinit,
> +       .notify = sr_class1p5_notify,
> +       /*
> +        * trigger for bound - this tells VP that SR has a voltage
> +        * change. we should ensure transdone is set before reading
> +        * vp voltage.
> +        */
> +       .notify_flags = SR_NOTIFY_MCUBOUND,
> +       .class_priv_data = (void *)&class_1p5_data,
> +};
> +
> +/**
> + * sr_class1p5_init() - register class 1p5 as default
> + *
> + * board files call this function to use class 1p5, we register with the
> + * smartreflex subsystem
> + */
> +static int __init sr_class1p5_init(void)
> +{
> +       int r;
> +
> +       /* Enable this class only for OMAP3630 and OMAP4 */
> +       if (!(cpu_is_omap3630() || cpu_is_omap44xx()))
> +               return -EINVAL;
> +
> +       r = sr_register_class(&class1p5_data);
> +       if (r) {
> +               pr_err("SmartReflex class 1.5 driver: "
> +                      "failed to register with %d\n", r);
> +       } else {
> +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> +               INIT_DELAYED_WORK_DEFERRABLE(&recal_work, do_recalibrate);
> +               schedule_delayed_work(&recal_work, msecs_to_jiffies(
> +                               CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> +#endif
> +               pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n",
> +                       CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY);
> +       }
> +       return r;
> +}
> +late_initcall(sr_class1p5_init);
> diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
> index 7ac88da..5f7a33e 100644
> --- a/arch/arm/mach-omap2/smartreflex-class3.c
> +++ b/arch/arm/mach-omap2/smartreflex-class3.c
> @@ -21,7 +21,9 @@ static int sr_class3_enable(struct voltagedomain *voltdm,
>        return sr_enable(voltdm, volt_data);
>  }
>
> -static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
> +static int sr_class3_disable(struct voltagedomain *voltdm,
> +                               struct omap_volt_data *vdata,
> +                               int is_volt_reset)
>  {
>        omap_vp_disable(voltdm);
>        sr_disable(voltdm);
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> index 3a5f2f6..bb55b65 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -317,7 +317,9 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
>        }
>
>        if (sr->autocomp_active) {
> -               sr_class->disable(sr->voltdm, 1);
> +               sr_class->disable(sr->voltdm,
> +                               omap_voltage_get_nom_volt(sr->voltdm),
> +                               1);
>                if (sr_class->class_deinit &&
>                    sr_class->class_deinit(sr->voltdm,
>                            sr_class->class_priv_data)) {
> @@ -471,6 +473,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
>  /* Public Functions */
>
>  /**
> + * is_sr_enabled() - is Smart reflex enabled for this domain?
> + * @voltdm: voltage domain to check
> + *
> + * Returns 0 if SR is enabled for this domain, else returns err
> + */
> +bool is_sr_enabled(struct voltagedomain *voltdm)
> +{
> +       struct omap_sr *sr;
> +       if (IS_ERR_OR_NULL(voltdm)) {
> +               pr_warning("%s: invalid param voltdm\n", __func__);
> +               return false;
> +       }
> +       sr = _sr_lookup(voltdm);
> +       if (IS_ERR(sr)) {
> +               pr_warning("%s: omap_sr struct for sr_%s not found\n",
> +                       __func__, voltdm->name);
> +               return false;
> +       }
> +       return sr->autocomp_active;
> +}
> +
> +/**
>  * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
>  *                      error generator module.
>  * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
> @@ -839,6 +863,7 @@ void omap_sr_enable(struct voltagedomain *voltdm,
>  * omap_sr_disable() - API to disable SR without resetting the voltage
>  *                     processor voltage
>  * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
> + * @volt_data: Voltage data to go to
>  *
>  * This API is to be called from the kernel in order to disable
>  * a particular smartreflex module. This API will in turn call
> @@ -846,7 +871,8 @@ void omap_sr_enable(struct voltagedomain *voltdm,
>  * the smartreflex class disable not to reset the VP voltage after
>  * disabling smartreflex.
>  */
> -void omap_sr_disable(struct voltagedomain *voltdm)
> +void omap_sr_disable(struct voltagedomain *voltdm,
> +               struct omap_volt_data *vdata)
>  {
>        struct omap_sr *sr = _sr_lookup(voltdm);
>
> @@ -865,7 +891,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
>                return;
>        }
>
> -       sr_class->disable(voltdm, 0);
> +       sr_class->disable(voltdm, vdata, 0);
>  }
>
>  /**
> @@ -898,7 +924,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
>                return;
>        }
>
> -       sr_class->disable(voltdm, 1);
> +       sr_class->disable(voltdm, omap_voltage_get_nom_volt(voltdm), 1);
>  }
>
>  /**
> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
> index 77cb0cd..c451835 100644
> --- a/arch/arm/mach-omap2/voltage.c
> +++ b/arch/arm/mach-omap2/voltage.c
> @@ -374,9 +374,45 @@ static int nom_volt_debug_get(void *data, u64 *val)
>        return 0;
>  }
>
> +static int dyn_volt_debug_get(void *data, u64 *val)
> +{
> +       struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> +       struct omap_volt_data *volt_data;
> +
> +       if (!vdd) {
> +               pr_warning("Wrong paramater passed\n");
> +               return -EINVAL;
> +       }
> +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> +
> +       *val = volt_data->volt_dynamic_nominal;
> +
> +       return 0;
> +}
> +
> +static int calib_volt_debug_get(void *data, u64 *val)
> +{
> +       struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> +       struct omap_volt_data *volt_data;
> +
> +       if (!vdd) {
> +               pr_warning("Wrong paramater passed\n");
> +               return -EINVAL;
> +       }
> +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> +
> +       *val = volt_data->volt_calibrated;
> +
> +       return 0;
> +}
> +
>  DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");
>  DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
>                                                                "%llu\n");
> +DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL,
> +                                                               "%llu\n");
> +DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL,
> +                                                               "%llu\n");
>  static void vp_latch_vsel(struct omap_vdd_info *vdd)
>  {
>        u32 vpconfig;
> @@ -504,6 +540,12 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
>        (void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
>                                vdd->debug_dir, (void *) vdd,
>                                &nom_volt_debug_fops);
> +       (void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO,
> +                               vdd->debug_dir, (void *) vdd,
> +                               &dyn_volt_debug_fops);
> +       (void) debugfs_create_file("curr_calibrated_volt", S_IRUGO,
> +                               vdd->debug_dir, (void *) vdd,
> +                               &calib_volt_debug_fops);
>  }
>
>  /* Voltage scale and accessory APIs */
> @@ -1132,6 +1174,33 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
>  }
>
>  /**
> + * omap_voltage_calib_reset() - reset the calibrated voltage entries
> + * @voltdm: voltage domain to reset the entries for
> + *
> + * when the calibrated entries are no longer valid, this api allows
> + * the calibrated voltages to be reset.
> + */
> +int omap_voltage_calib_reset(struct voltagedomain *voltdm)
> +{
> +       struct omap_vdd_info *vdd;
> +       struct omap_volt_data *volt_data;
> +
> +       if (IS_ERR_OR_NULL(voltdm)) {
> +               pr_warning("%s: VDD specified does not exist!\n", __func__);
> +               return -EINVAL;
> +       }
> +
> +       vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
> +       volt_data = vdd->volt_data;
> +       /* reset the calibrated voltages as 0 */
> +       while (volt_data->volt_nominal) {
> +               volt_data->volt_calibrated = 0;
> +               volt_data++;
> +       }
> +       return 0;
> +}
> +
> +/**
>  * omap_vp_get_curr_volt() - API to get the current vp voltage.
>  * @voltdm:    pointer to the VDD.
>  *
> diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> index b6333ae..dba7939 100644
> --- a/arch/arm/plat-omap/Kconfig
> +++ b/arch/arm/plat-omap/Kconfig
> @@ -67,6 +67,23 @@ config OMAP_SMARTREFLEX_CLASS3
>          Class 3 implementation of Smartreflex employs continuous hardware
>          voltage calibration.
>
> +config OMAP_SMARTREFLEX_CLASS1P5
> +       bool "Class 1.5 mode of Smartreflex Implementation"
> +       depends on OMAP_SMARTREFLEX && TWL4030_CORE
> +       help
> +         Say Y to enable Class 1.5 implementation of Smartreflex
> +         Class 1.5 implementation of Smartreflex employs software controlled
> +         hardware voltage calibration.
> +
> +config OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> +       int "Class 1.5 mode recalibration recalibration delay(ms)"
> +       depends on OMAP_SMARTREFLEX_CLASS1P5
> +       default 86400000
> +       help
> +         Setup the recalibration delay in milliseconds. Use 0 for never doing
> +         a recalibration. Defaults to recommended recalibration every 24hrs.
> +         If you do not understand this, use the default.
> +
>  config OMAP_RESET_CLOCKS
>        bool "Reset unused clocks during boot"
>        depends on ARCH_OMAP
> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
> index 07f35b2..ee5c58f 100644
> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> @@ -167,6 +167,7 @@ struct omap_sr_pmic_data {
>  #define SR_CLASS1      0x1
>  #define SR_CLASS2      0x2
>  #define SR_CLASS3      0x3
> +#define SR_CLASS1P5    0x4
>
>  /**
>  * struct omap_sr_class_data - Smartreflex class driver info
> @@ -187,7 +188,9 @@ struct omap_sr_pmic_data {
>  struct omap_sr_class_data {
>        int (*enable)(struct voltagedomain *voltdm,
>                        struct omap_volt_data *volt_data);
> -       int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
> +       int (*disable)(struct voltagedomain *voltdm,
> +                       struct omap_volt_data *volt_data,
> +                       int is_volt_reset);
>        int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
>        int (*class_deinit)(struct voltagedomain *voltdm,
>                        void *class_priv_data);
> @@ -235,7 +238,8 @@ struct omap_sr_data {
>  /* Smartreflex module enable/disable interface */
>  void omap_sr_enable(struct voltagedomain *voltdm,
>                        struct omap_volt_data *volt_data);
> -void omap_sr_disable(struct voltagedomain *voltdm);
> +void omap_sr_disable(struct voltagedomain *voltdm,
> +                       struct omap_volt_data *volt_data);
>  void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
>
>  /* API to register the pmic specific data with the smartreflex driver. */
> @@ -250,6 +254,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm);
>
>  /* API to register the smartreflex class driver with the smartreflex driver */
>  int sr_register_class(struct omap_sr_class_data *class_data);
> +bool is_sr_enabled(struct voltagedomain *voltdm);
>  #else
>  static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
>  static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
> @@ -264,5 +269,9 @@ static inline void omap_sr_disable_reset_volt(
>                struct voltagedomain *voltdm) {}
>  static inline void omap_sr_register_pmic(
>                struct omap_sr_pmic_data *pmic_data) {}
> +static inline bool is_sr_enabled(struct voltagedomain *voltdm)
> +{
> +       return false;
> +}
>  #endif
>  #endif
> diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
> index 332c581..54445f0 100644
> --- a/arch/arm/plat-omap/include/plat/voltage.h
> +++ b/arch/arm/plat-omap/include/plat/voltage.h
> @@ -58,6 +58,8 @@
>  #define OMAP4430_VDD_CORE_OPP50_UV             930000
>  #define OMAP4430_VDD_CORE_OPP100_UV            1100000
>
> +#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV    50000
> +
>  /**
>  * struct voltagedomain - omap voltage domain global structure.
>  * @name:      Name of the voltage domain which can be used as a unique
> @@ -81,6 +83,8 @@ struct voltagedomain {
>  */
>  struct omap_volt_data {
>        u32     volt_nominal;
> +       u32     volt_calibrated;
> +       u32     volt_dynamic_nominal;
>        u32     sr_efuse_offs;
>        u8      sr_errminlimit;
>        u8      vp_errgain;
> @@ -127,6 +131,7 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
>  bool omap_vp_is_transdone(struct voltagedomain *voltdm);
>  bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
>  struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
> +int omap_voltage_calib_reset(struct voltagedomain *voltdm);
>  #ifdef CONFIG_PM
>  int omap_voltage_register_pmic(struct voltagedomain *voltdm,
>                struct omap_volt_pmic_info *pmic_info);
> @@ -160,7 +165,23 @@ static inline unsigned long omap_get_operation_voltage(
>  {
>        if (IS_ERR_OR_NULL(vdata))
>                return 0;
> -       return vdata->volt_nominal;
> +       return (vdata->volt_calibrated) ? vdata->volt_calibrated :
> +               (vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
> +                       vdata->volt_nominal;
>  }
>
> +/* what is my dynamic nominal? */
> +static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
> +{
> +       if (IS_ERR_OR_NULL(vdata))
> +               return 0;
> +       if (vdata->volt_calibrated) {
> +               unsigned long v = vdata->volt_calibrated +
> +                       OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
> +               if (v > vdata->volt_nominal)
> +                       return vdata->volt_nominal;
> +               return v;
> +       }
> +       return vdata->volt_nominal;
> +}
>  #endif
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
I have tested this Patch Series on OMAP 3630 SDP,  for MPU and IVA Powerdomains
it throws error log "Unable to refer to NULL pointer" if
curr_nominal_volt, curr_calibrated_volt
or curr_dynamical_volt is accessed through debugfs.
Could you please provide fix for this.

-- 
Thanks,
Regards,
Shweta
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 18/19] omap3630+: sr: add support for class 1.5
  2011-03-01  9:53   ` Gulati, Shweta
@ 2011-03-01 10:17     ` Menon, Nishanth
  2011-03-01 12:20       ` Gulati, Shweta
  0 siblings, 1 reply; 64+ messages in thread
From: Menon, Nishanth @ 2011-03-01 10:17 UTC (permalink / raw)
  To: Gulati, Shweta
  Cc: linux-omap, Tony Lindgren, Kevin Hilman, Ambresh K,
	Eduardo Valentin, Igor Dmitriev, Paul,
	Peter 'p2' De Schrijver

On Tue, Mar 1, 2011 at 15:23, Gulati, Shweta <shweta.gulati@ti.com> wrote:
>
> Hi,
>
> On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm@ti.com> wrote:
> > Traditional SmartReflex AVS(Automatic Voltage Scaling) classes are:
> > * Class 0 - Product test calibration
> >        Silicon is calibration at production floor and fused with voltages
> >        for each OPP
> > * Class 1 - Boot time calibration
> >        Silicon is calibrated once at boot time and voltages are stored for
> >        the lifetime of operation.
> > * Class 2 - continuous s/w calibration
> >        SR module notifies s/w for any change in the system which is desired
> >        and the s/w makes runtime decisions in terms of setting the voltage,
> >        this mechanism could be used in the system which does not have PMIC
> >        capable of SR without using the voltage controller and voltage
> >        processor blocks.
> > * Class 3 - continuous h/w calibration
> >        SR module is switch on after reaching a voltage level and SR
> >        continuously monitors the system and makes runtime adjustments without
> >        s/w involvement.
> >
> > OMAP3430 has used SmartReflex AVS and with a a PMIC which understands the SR
> > protocol, Class 3 has been used. With OMAP3630 onwards, a new SmartReflex AVS
> > class of operation Class 1.5 was introduced.
> > * Class 1.5 - periodic s/w calibration
> >        This uses the h/w calibration loop and at the end of calibration
> >        stores the voltages to be used run time, periodic recalibration is
> >        performed as well.
> >
> > The operational mode is describes as the following:
> > * SmartReflex AVS h/w calibration loop is essential to identify the optimal
> >        voltage for a given OPP.
> > * Once this optimal voltage is detected, SmartReflex AVS loop is disabled in
> >        class 1.5 mode of operation.
> > * Until there is a need for a recalibration, any further transition to an OPP
> >        voltage which is calibrated can use the calibrated voltage and does not
> >        require enabling the SR AVS h/w loop.
> > * On a periodic basis (recommendation being once approximately every 24 hours),
> >        software is expected to perform a recalibration to find a new optimal
> >        voltage which is compensated for device aging.
> >        - For performing this recalibration, the start voltage does not need to
> >        be the nominal voltage anymore. instead, the system can start with a
> >        voltage which is 50mV higher than the previously calibrated voltage to
> >        identify the new optimal voltage as the aging factor within a period of
> >        1 day is not going to be anywhere close to 50mV.
> >        - This "new starting point" for recalibration is called a dynamic
> >        nominal voltage for that voltage point.
> > In short, with the introduction of SmartReflex class 1.5, there are three new
> > voltages possible in a system's dvfs transition:
> > * Nominal Voltage - The maximum voltage needed for a worst possible device
> >        in the worst possible conditions. This is the voltage we choose as
> >        the starting point for the h/w loop to optimize for the first time
> >        calibration on system bootup.
> > * Dynamic Nominal Voltage - Worst case voltage for a specific device in
> >        considering the system aging on the worst process device.
> > * Calibrated Voltage - Best voltage for the current device at a given point
> >        of time.
> >
> > In terms of the implementation, doing calibration involves waiting for the
> > smartreflex h/w loop to settle down, and doing this as part of the dvfs flow
> > itself is to increase the latency of dvfs transition when there is a need to
> > calibrate that opp. instead, the calibration is performed "out of path" using
> > a workqueue statemachine. The workqueue waits for the system stabilization,
> > then enables VP interrupts to monitor for system instability interms of voltage
> > oscillations that are reported back to the system as interrupts, in case of
> > prolonged system oscillations, nominal voltage is chosen as a safe voltage and
> > this event is logged in the system log for developer debug and fixing.
> >
> > For the recalibration, a common workqueue for all domains is started at the
> > start of the class initialization and it resets the calibrated voltages
> > on a periodic basis. For distros that may choose not to do the recommended
> > periodic recalibration, instead choose to perform boot time calibration,
> > kconfig configuration option is provided to do so.
> >
> > TODO:
> > a) Cpuidle and suspend paths are not integrated with SmartReflex driver at
> >   this point.
> > b) Since the SR registers are accessed and controlled in parallel to DVFS
> >   some sort of mechanism is necessary to be introduced along with OMAP
> >   dvfs layer to ensure mutual exclusivity
> > c) Additional debug interfaces for vmin analysis for platform characterization
> >   and addition of system margin needs to be introduced from smartreflex
> >   perspective.
> >
> > This implementation also includes the following contributors:
> > Tony Lindgren for suggestion on using interrupt based mechanism instead of
> > polling to detect voltage oscillations.
> > Peter 'p2' De Schrijver for debating alternatives on recalibration mechanisms
> > Paul Walmsey, Eduardo Valentin, Ambresh K, Igor Dmitriev and quiet a few others
> > for patient review, testing and reporting of issues of a previous incarnation
> > of this implemenation. Last, but not the least, the TI H/w team in introducing
> > this new SR AVS class and patiently debating it's various facets.
> >
> > Cc: Ambresh K <ambresh@ti.com>
> > Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
> > Cc: Igor Dmitriev <ext-dmitriev.igor@nokia.com>
> > Cc: Paul <paul@pwsan.com>
> > Cc: Peter 'p2' De Schrijver <Peter.De-Schrijver@nokia.com>
> > Cc: Tony Lindgren <tony@atomide.com>
> >
> > Signed-off-by: Nishanth Menon <nm@ti.com>
> > ---
> >  arch/arm/mach-omap2/Makefile                  |    1 +
> >  arch/arm/mach-omap2/smartreflex-class1p5.c    |  556 +++++++++++++++++++++++++
> >  arch/arm/mach-omap2/smartreflex-class3.c      |    4 +-
> >  arch/arm/mach-omap2/smartreflex.c             |   34 ++-
> >  arch/arm/mach-omap2/voltage.c                 |   69 +++
> >  arch/arm/plat-omap/Kconfig                    |   17 +
> >  arch/arm/plat-omap/include/plat/smartreflex.h |   13 +-
> >  arch/arm/plat-omap/include/plat/voltage.h     |   23 +-
> >  8 files changed, 709 insertions(+), 8 deletions(-)
> >  create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c
> >
> > diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> > index 1c0c2b0..1a82e6d 100644
> > --- a/arch/arm/mach-omap2/Makefile
> > +++ b/arch/arm/mach-omap2/Makefile
> > @@ -66,6 +66,7 @@ obj-$(CONFIG_ARCH_OMAP4)              += pm44xx.o voltage.o pm_bus.o
> >  obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
> >  obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
> >  obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)  += smartreflex-class3.o
> > +obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS1P5)        += smartreflex-class1p5.o
> >
> >  AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
> >  AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a
> > diff --git a/arch/arm/mach-omap2/smartreflex-class1p5.c b/arch/arm/mach-omap2/smartreflex-class1p5.c
> > new file mode 100644
> > index 0000000..832f10b
> > --- /dev/null
> > +++ b/arch/arm/mach-omap2/smartreflex-class1p5.c
> > @@ -0,0 +1,556 @@
> > +/*
> > + * Smart reflex Class 1.5 specific implementations
> > + *
> > + * Copyright (C) 2010-2011 Texas Instruments, Inc.
> > + * Nishanth Menon <nm@ti.com>
> > + *
> > + * Smart reflex class 1.5 is also called periodic SW Calibration
> > + * Some of the highlights are as follows:
> > + * – Host CPU triggers OPP calibration when transitioning to non calibrated
> > + *   OPP
> > + * – SR-AVS + VP modules are used to perform calibration
> > + * – Once completed, the SmartReflex-AVS module can be disabled
> > + * – Enables savings based on process, supply DC accuracy and aging
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +#include <linux/kernel.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/fs.h>
> > +#include <linux/string.h>
> > +#include <linux/uaccess.h>
> > +#include <linux/kobject.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/opp.h>
> > +
> > +#include <plat/smartreflex.h>
> > +#include <plat/voltage.h>
> > +
> > +#define MAX_VDDS 3
> > +#define SR1P5_SAMPLING_DELAY_MS        1
> > +#define SR1P5_STABLE_SAMPLES   5
> > +#define SR1P5_MAX_TRIGGERS     5
> > +
> > +/*
> > + * we expect events in 10uS, if we dont get 2wice times as much,
> > + * we could kind of ignore this as a missed event.
> > + */
> > +#define MAX_CHECK_VPTRANS_US   20
> > +
> > +/**
> > + * struct sr_class1p5_work_data - data meant to be used by calibration work
> > + * @work:      calibration work
> > + * @voltdm:            voltage domain for which we are triggering
> > + * @vdata:     voltage data we are calibrating
> > + * @num_calib_triggers:        number of triggers from calibration loop
> > + * @num_osc_samples:   number of samples collected by isr
> > + * @work_active:       have we scheduled a work item?
> > + */
> > +struct sr_class1p5_work_data {
> > +       struct delayed_work work;
> > +       struct voltagedomain *voltdm;
> > +       struct omap_volt_data *vdata;
> > +       u8 num_calib_triggers;
> > +       u8 num_osc_samples;
> > +       bool work_active;
> > +};
> > +
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +/* recal_work: recalibration calibration work */
> > +static struct delayed_work recal_work;
> > +#endif
> > +
> > +/**
> > + * struct sr_class1p5_data - private data for class 1p5
> > + * @work_data:         work item data per voltage domain
> > + */
> > +struct sr_class1p5_data {
> > +       struct sr_class1p5_work_data work_data[MAX_VDDS];
> > +};
> > +
> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> > +                                   bool recal);
> > +
> > +/* our instance of class 1p5 private data */
> > +static struct sr_class1p5_data class_1p5_data;
> > +
> > +static struct sr_class1p5_work_data *get_sr1p5_work(struct voltagedomain
> > +                                                   *voltdm)
> > +{
> > +       int idx;
> > +       for (idx = 0; idx < MAX_VDDS; idx++) {
> > +               if (class_1p5_data.work_data[idx].voltdm && !strcmp
> > +                   (class_1p5_data.work_data[idx].voltdm->name, voltdm->name))
> > +                       return &class_1p5_data.work_data[idx];
> > +       }
> > +       return ERR_PTR(-ENODATA);
> > +}
> > +
> > +/**
> > + * sr_class1p5_notify() - isr notifier for status events
> > + * @voltdm:    voltage domain for which we were triggered
> > + * @status:    notifier event to use
> > + *
> > + * This basically collects data for the work to use.
> > + */
> > +static int sr_class1p5_notify(struct voltagedomain *voltdm, u32 status)
> > +{
> > +       struct sr_class1p5_work_data *work_data;
> > +       int idx = 0;
> > +       work_data = get_sr1p5_work(voltdm);
> > +
> > +       if (unlikely(!work_data)) {
> > +               pr_err("%s:%s no work data!!\n", __func__, voltdm->name);
> > +               return -EINVAL;
> > +       }
> > +
> > +       /* Wait for transdone so that we know the voltage to read */
> > +       do {
> > +               if (omap_vp_is_transdone(voltdm))
> > +                       break;
> > +               idx++;
> > +               /* get some constant delay */
> > +               udelay(1);
> > +       } while (idx < MAX_CHECK_VPTRANS_US);
> > +
> > +       /*
> > +        * If we timeout, we still read the data,
> > +        * if we are oscillating+irq latencies are too high, we could
> > +        * have scenarios where we miss transdone event. since
> > +        * we waited long enough, it is still safe to read the voltage
> > +        * as we would have waited long enough - still flag it..
> > +        */
> > +       if (idx >= MAX_CHECK_VPTRANS_US)
> > +               pr_warning("%s: timed out waiting for transdone!!\n", __func__);
> > +
> > +       omap_vp_clear_transdone(voltdm);
> > +
> > +       idx = (work_data->num_osc_samples) % SR1P5_STABLE_SAMPLES;
> > +       work_data->num_osc_samples++;
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * do_calibrate() - work which actually does the calibration
> > + * @work: pointer to the work
> > + *
> > + * calibration routine uses the following logic:
> > + * on the first trigger, we start the isr to collect sr voltages
> > + * wait for stabilization delay (reschdule self instead of sleeping)
> > + * after the delay, see if we collected any isr events
> > + * if none, we have calibrated voltage.
> > + * if there are any, we retry untill we giveup.
> > + * on retry timeout, select a voltage to use as safe voltage.
> > + */
> > +static void do_calibrate(struct work_struct *work)
> > +{
> > +       struct sr_class1p5_work_data *work_data =
> > +           container_of(work, struct sr_class1p5_work_data, work.work);
> > +       unsigned long u_volt_safe = 0, u_volt_current = 0;
> > +       struct omap_volt_data *volt_data;
> > +       struct voltagedomain *voltdm;
> > +
> > +       if (unlikely(!work_data)) {
> > +               pr_err("%s: ooops.. null work_data?\n", __func__);
> > +               return;
> > +       }
> > +
> > +       /*
> > +        * TODO:Handle the case where we might have just been scheduled AND
> > +        * 1.5 disable was called. check and HOLD dvfs
> > +        */
> > +
> > +       voltdm = work_data->voltdm;
> > +       /*
> > +        * In the unlikely case that we did get through when unplanned,
> > +        * flag and return.
> > +        */
> > +       if (unlikely(!work_data->work_active)) {
> > +               pr_err("%s:%s unplanned work invocation!\n", __func__,
> > +                      voltdm->name);
> > +               /* TODO release the dvfs */
> > +               return;
> > +       }
> > +
> > +       work_data->num_calib_triggers++;
> > +       /* if we are triggered first time, we need to start isr to sample */
> > +       if (work_data->num_calib_triggers == 1)
> > +               goto start_sampling;
> > +
> > +       /* Stop isr from interrupting our measurements :) */
> > +       sr_notifier_control(voltdm, false);
> > +
> > +       volt_data = work_data->vdata;
> > +
> > +       /* if there are no samples captured.. SR is silent, aka stability! */
> > +       if (!work_data->num_osc_samples) {
> > +               u_volt_safe = omap_vp_get_curr_volt(voltdm);
> > +               u_volt_current = u_volt_safe;
> > +               goto done_calib;
> > +       }
> > +       if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) {
> > +               pr_warning("%s: %s recalib timeout!\n", __func__,
> > +                          work_data->voltdm->name);
> > +               goto oscillating_calib;
> > +       }
> > +
> > +       /* we have potential oscillations/first sample */
> > +start_sampling:
> > +       work_data->num_osc_samples = 0;
> > +       /* Clear pending events */
> > +       sr_notifier_control(voltdm, false);
> > +       /* Clear all transdones */
> > +       while (omap_vp_is_transdone(voltdm))
> > +               omap_vp_clear_transdone(voltdm);
> > +       /* trigger sampling */
> > +       sr_notifier_control(voltdm, true);
> > +       schedule_delayed_work(&work_data->work,
> > +                             msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> > +                                              SR1P5_STABLE_SAMPLES));
> > +       /* TODO: release dvfs */
> > +       return;
> > +
> > +oscillating_calib:
> > +       /* Use the nominal voltage as the safe voltage */
> > +       u_volt_safe = volt_data->volt_nominal;
> > +       /* pick up current voltage to switch if needed */
> > +       u_volt_current = omap_vp_get_curr_volt(voltdm);
> > +
> > +       /* Fall through to close up common stuff */
> > +done_calib:
> > +       omap_vp_disable(voltdm);
> > +       sr_disable(voltdm);
> > +
> > +       volt_data->volt_calibrated = u_volt_safe;
> > +       /* Setup my dynamic voltage for the next calibration for this opp */
> > +       volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data);
> > +
> > +       /*
> > +        * if the voltage we decided as safe is not the current voltage,
> > +        * switch
> > +        */
> > +       if (volt_data->volt_calibrated != u_volt_current) {
> > +               pr_debug("%s:%s reconfiguring to voltage %d\n",
> > +                        __func__, voltdm->name, volt_data->volt_calibrated);
> > +               omap_voltage_scale_vdd(voltdm, volt_data);
> > +       }
> > +
> > +       /*
> > +        * TODO: Setup my wakeup voltage to allow immediate going to OFF and
> > +        * on - Pending twl and voltage layer cleanups.
> > +        * This is necessary, as this is not done as part of regular
> > +        * Dvfs flow.
> > +        * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated);
> > +        */
> > +       work_data->work_active = false;
> > +       /* TODO: release dvfs */
> > +}
> > +
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +/**
> > + * do_recalibrate() - work which actually does the calibration
> > + * @work: pointer to the work
> > + *
> > + * on a periodic basis, we come and reset our calibration setup
> > + * so that a recalibration of the OPPs take place. This takes
> > + * care of aging factor in the system.
> > + */
> > +static void do_recalibrate(struct work_struct *work)
> > +{
> > +       struct voltagedomain *voltdm;
> > +       int idx;
> > +       static struct sr_class1p5_work_data *work_data;
> > +
> > +       for (idx = 0; idx < MAX_VDDS; idx++) {
> > +               work_data = &class_1p5_data.work_data[idx];
> > +               voltdm = work_data->voltdm;
> > +               if (voltdm) {
> > +                       /* if sr is not enabled, we check later */
> > +                       if (!is_sr_enabled(voltdm))
> > +                               continue;
> > +                       /* TODO: Pause the dvfs transitions */
> > +                       /* if sr is not enabled, we check later */
> > +
> > +                       /* Reset and force a recalibration for current opp */
> > +                       sr_class1p5_reset_calib(voltdm, true, true);
> > +
> > +                       /* TODO: unpause DVFS transitions */
> > +               }
> > +       }
> > +       /* We come back again after time the usual delay */
> > +       schedule_delayed_work(&recal_work,
> > +             msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> > +}
> > +#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */
> > +
> > +/**
> > + * sr_class1p5_enable() - class 1.5 mode of enable
> > + * @voltdm:            voltage domain to enable SR for
> > + * @volt_data: voltdata to the voltage transition taking place
> > + *
> > + * when this gets called, we use the h/w loop to setup our voltages
> > + * to an calibrated voltage, detect any oscillations, recover from the same
> > + * and finally store the optimized voltage as the calibrated voltage in the
> > + * system
> > + */
> > +static int sr_class1p5_enable(struct voltagedomain *voltdm,
> > +                             struct omap_volt_data *volt_data)
> > +{
> > +       int r;
> > +       struct sr_class1p5_work_data *work_data;
> > +       /* if already calibrated, nothing to do here.. */
> > +       if (volt_data->volt_calibrated)
> > +               return 0;
> > +
> > +       work_data = get_sr1p5_work(voltdm);
> > +       if (unlikely(!work_data)) {
> > +               pr_err("%s: aieeee.. bad work data??\n", __func__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       if (work_data->work_active)
> > +               return 0;
> > +
> > +       omap_vp_enable(voltdm);
> > +       r = sr_enable(voltdm, volt_data);
> > +       if (r) {
> > +               pr_err("%s: sr[%s] failed\n", __func__, voltdm->name);
> > +               omap_vp_disable(voltdm);
> > +               return r;
> > +       }
> > +       work_data->vdata = volt_data;
> > +       work_data->work_active = true;
> > +       work_data->num_calib_triggers = 0;
> > +       /* program the workqueue and leave it to calibrate offline.. */
> > +       schedule_delayed_work(&work_data->work,
> > +                             msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> > +                                              SR1P5_STABLE_SAMPLES));
> > +
> > +       return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_disable() - disable for class 1p5
> > + * @voltdm: voltage domain for the sr which needs disabling
> > + * @volt_data: voltagedata to disable
> > + * @is_volt_reset: reset the voltage?
> > + *
> > + * we dont do anything if the class 1p5 is being used. this is because we
> > + * already disable sr at the end of calibration and no h/w loop is actually
> > + * active when this is called.
> > + */
> > +static int sr_class1p5_disable(struct voltagedomain *voltdm,
> > +                              struct omap_volt_data *volt_data,
> > +                              int is_volt_reset)
> > +{
> > +       struct sr_class1p5_work_data *work_data;
> > +
> > +       work_data = get_sr1p5_work(voltdm);
> > +       if (work_data->work_active) {
> > +               /* if volt reset and work is active, we dont allow this */
> > +               if (is_volt_reset)
> > +                       return -EBUSY;
> > +               /* flag work is dead and remove the old work */
> > +               work_data->work_active = false;
> > +               cancel_delayed_work_sync(&work_data->work);
> > +               sr_notifier_control(voltdm, false);
> > +               omap_vp_disable(voltdm);
> > +               sr_disable(voltdm);
> > +       }
> > +
> > +       /* if already calibrated, nothin special to do here.. */
> > +       if (volt_data->volt_calibrated)
> > +               return 0;
> > +
> > +       if (is_volt_reset)
> > +               omap_voltage_reset(voltdm);
> > +       return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_configure() - configuration function
> > + * @voldm:     configure for which voltage domain
> > + *
> > + * we dont do much here other than setup some registers for
> > + * the sr module involved.
> > + */
> > +static int sr_class1p5_configure(struct voltagedomain *voltdm)
> > +{
> > +       return sr_configure_errgen(voltdm);
> > +}
> > +
> > +/**
> > + * sr_class1p5_reset_calib() - reset all calibrated voltages
> > + * @srid:      srid to reset the calibration for
> > + * @reset:     reset voltage before we recal?
> > + * @recal:     should I recalibrate my current opp?
> > + *
> > + * if we call this, it means either periodic calibration trigger was
> > + * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
> > + * meaning we cant trust the calib voltages anymore, it is better to use
> > + * nominal in the system
> > + */
> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> > +                                   bool recal)
> > +{
> > +       struct sr_class1p5_work_data *work_data;
> > +
> > +       /* I dont need to go further if sr is not present */
> > +       if (!is_sr_enabled(voltdm))
> > +               return;
> > +
> > +       work_data = get_sr1p5_work(voltdm);
> > +
> > +       if (work_data->work_active)
> > +               sr_class1p5_disable(voltdm, work_data->vdata, 0);
> > +
> > +       omap_voltage_calib_reset(voltdm);
> > +
> > +       /*
> > +        * I should now reset the voltages to my nominal to be safe
> > +        */
> > +       if (reset)
> > +               omap_voltage_reset(voltdm);
> > +
> > +       /*
> > +        * I should fire a recalibration for current opp if needed
> > +        * Note: i have just reset my calibrated voltages, and if
> > +        * i call sr_enable equivalent, I will cause a recalibration
> > +        * loop, even though the function is called sr_enable.. we
> > +        * are in class 1.5 ;)
> > +        */
> > +       if (reset && recal)
> > +               sr_class1p5_enable(voltdm, work_data->vdata);
> > +}
> > +
> > +/**
> > + * sr_class1p5_cinit() - class 1p5 init
> > + * @voltdm:            sr voltage domain
> > + * @class_priv_data:   private data for the class
> > + *
> > + * we do class specific initialization like creating sysfs/debugfs entries
> > + * needed, spawning of a kthread if needed etc.
> > + */
> > +static int sr_class1p5_cinit(struct voltagedomain *voltdm,
> > +                            void *class_priv_data)
> > +{
> > +       struct sr_class1p5_work_data *work_data;
> > +       int idx;
> > +
> > +       if (!class_priv_data) {
> > +               pr_err("%s: bad param? no priv data!\n", __func__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       /* setup our work params */
> > +       work_data = get_sr1p5_work(voltdm);
> > +       if (!IS_ERR_OR_NULL(work_data)) {
> > +               pr_err("%s: ooopps.. class already initialized for %s! bug??\n",
> > +                      __func__, voltdm->name);
> > +               return -EINVAL;
> > +       }
> > +       work_data = NULL;
> > +       /* get the next spare work_data */
> > +       for (idx = 0; idx < MAX_VDDS; idx++) {
> > +               if (!class_1p5_data.work_data[idx].voltdm) {
> > +                       work_data = &class_1p5_data.work_data[idx];
> > +                       break;
> > +               }
> > +       }
> > +       if (!work_data) {
> > +               pr_err("%s: no more space for work data for domains!\n",
> > +                       __func__);
> > +               return -ENOMEM;
> > +       }
> > +       work_data->voltdm = voltdm;
> > +       INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, do_calibrate);
> > +       return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_cdeinit() - class 1p5 deinitialization
> > + * @voltdm:    voltage domain for which to do this.
> > + * @class_priv_data: class private data for deinitialiation
> > + *
> > + * currently only resets the calibrated voltage forcing dvfs voltages
> > + * to be used in the system
> > + */
> > +static int sr_class1p5_cdeinit(struct voltagedomain *voltdm,
> > +                              void *class_priv_data)
> > +{
> > +       struct sr_class1p5_work_data *work_data;
> > +
> > +       /* setup our work params */
> > +       work_data = get_sr1p5_work(voltdm);
> > +       if (IS_ERR_OR_NULL(work_data)) {
> > +               pr_err("%s: ooopps.. class not initialized for %s! bug??\n",
> > +                      __func__, voltdm->name);
> > +               return -EINVAL;
> > +       }
> > +
> > +       /*
> > +        * we dont have SR periodic calib anymore.. so reset calibs
> > +        * we are already protected by sr debugfs lock, so no lock needed
> > +        * here.
> > +        */
> > +       sr_class1p5_reset_calib(voltdm, true, false);
> > +
> > +       /* reset all data for this work data */
> > +       memset(work_data, 0, sizeof(*work_data));
> > +
> > +       return 0;
> > +}
> > +
> > +/* SR class1p5 structure */
> > +static struct omap_sr_class_data class1p5_data = {
> > +       .enable = sr_class1p5_enable,
> > +       .disable = sr_class1p5_disable,
> > +       .configure = sr_class1p5_configure,
> > +       .class_type = SR_CLASS1P5,
> > +       .class_init = sr_class1p5_cinit,
> > +       .class_deinit = sr_class1p5_cdeinit,
> > +       .notify = sr_class1p5_notify,
> > +       /*
> > +        * trigger for bound - this tells VP that SR has a voltage
> > +        * change. we should ensure transdone is set before reading
> > +        * vp voltage.
> > +        */
> > +       .notify_flags = SR_NOTIFY_MCUBOUND,
> > +       .class_priv_data = (void *)&class_1p5_data,
> > +};
> > +
> > +/**
> > + * sr_class1p5_init() - register class 1p5 as default
> > + *
> > + * board files call this function to use class 1p5, we register with the
> > + * smartreflex subsystem
> > + */
> > +static int __init sr_class1p5_init(void)
> > +{
> > +       int r;
> > +
> > +       /* Enable this class only for OMAP3630 and OMAP4 */
> > +       if (!(cpu_is_omap3630() || cpu_is_omap44xx()))
> > +               return -EINVAL;
> > +
> > +       r = sr_register_class(&class1p5_data);
> > +       if (r) {
> > +               pr_err("SmartReflex class 1.5 driver: "
> > +                      "failed to register with %d\n", r);
> > +       } else {
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +               INIT_DELAYED_WORK_DEFERRABLE(&recal_work, do_recalibrate);
> > +               schedule_delayed_work(&recal_work, msecs_to_jiffies(
> > +                               CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> > +#endif
> > +               pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n",
> > +                       CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY);
> > +       }
> > +       return r;
> > +}
> > +late_initcall(sr_class1p5_init);
> > diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
> > index 7ac88da..5f7a33e 100644
> > --- a/arch/arm/mach-omap2/smartreflex-class3.c
> > +++ b/arch/arm/mach-omap2/smartreflex-class3.c
> > @@ -21,7 +21,9 @@ static int sr_class3_enable(struct voltagedomain *voltdm,
> >        return sr_enable(voltdm, volt_data);
> >  }
> >
> > -static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
> > +static int sr_class3_disable(struct voltagedomain *voltdm,
> > +                               struct omap_volt_data *vdata,
> > +                               int is_volt_reset)
> >  {
> >        omap_vp_disable(voltdm);
> >        sr_disable(voltdm);
> > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> > index 3a5f2f6..bb55b65 100644
> > --- a/arch/arm/mach-omap2/smartreflex.c
> > +++ b/arch/arm/mach-omap2/smartreflex.c
> > @@ -317,7 +317,9 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
> >        }
> >
> >        if (sr->autocomp_active) {
> > -               sr_class->disable(sr->voltdm, 1);
> > +               sr_class->disable(sr->voltdm,
> > +                               omap_voltage_get_nom_volt(sr->voltdm),
> > +                               1);
> >                if (sr_class->class_deinit &&
> >                    sr_class->class_deinit(sr->voltdm,
> >                            sr_class->class_priv_data)) {
> > @@ -471,6 +473,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
> >  /* Public Functions */
> >
> >  /**
> > + * is_sr_enabled() - is Smart reflex enabled for this domain?
> > + * @voltdm: voltage domain to check
> > + *
> > + * Returns 0 if SR is enabled for this domain, else returns err
> > + */
> > +bool is_sr_enabled(struct voltagedomain *voltdm)
> > +{
> > +       struct omap_sr *sr;
> > +       if (IS_ERR_OR_NULL(voltdm)) {
> > +               pr_warning("%s: invalid param voltdm\n", __func__);
> > +               return false;
> > +       }
> > +       sr = _sr_lookup(voltdm);
> > +       if (IS_ERR(sr)) {
> > +               pr_warning("%s: omap_sr struct for sr_%s not found\n",
> > +                       __func__, voltdm->name);
> > +               return false;
> > +       }
> > +       return sr->autocomp_active;
> > +}
> > +
> > +/**
> >  * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
> >  *                      error generator module.
> >  * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
> > @@ -839,6 +863,7 @@ void omap_sr_enable(struct voltagedomain *voltdm,
> >  * omap_sr_disable() - API to disable SR without resetting the voltage
> >  *                     processor voltage
> >  * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
> > + * @volt_data: Voltage data to go to
> >  *
> >  * This API is to be called from the kernel in order to disable
> >  * a particular smartreflex module. This API will in turn call
> > @@ -846,7 +871,8 @@ void omap_sr_enable(struct voltagedomain *voltdm,
> >  * the smartreflex class disable not to reset the VP voltage after
> >  * disabling smartreflex.
> >  */
> > -void omap_sr_disable(struct voltagedomain *voltdm)
> > +void omap_sr_disable(struct voltagedomain *voltdm,
> > +               struct omap_volt_data *vdata)
> >  {
> >        struct omap_sr *sr = _sr_lookup(voltdm);
> >
> > @@ -865,7 +891,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
> >                return;
> >        }
> >
> > -       sr_class->disable(voltdm, 0);
> > +       sr_class->disable(voltdm, vdata, 0);
> >  }
> >
> >  /**
> > @@ -898,7 +924,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
> >                return;
> >        }
> >
> > -       sr_class->disable(voltdm, 1);
> > +       sr_class->disable(voltdm, omap_voltage_get_nom_volt(voltdm), 1);
> >  }
> >
> >  /**
> > diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
> > index 77cb0cd..c451835 100644
> > --- a/arch/arm/mach-omap2/voltage.c
> > +++ b/arch/arm/mach-omap2/voltage.c
> > @@ -374,9 +374,45 @@ static int nom_volt_debug_get(void *data, u64 *val)
> >        return 0;
> >  }
> >
> > +static int dyn_volt_debug_get(void *data, u64 *val)
> > +{
> > +       struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> > +       struct omap_volt_data *volt_data;
> > +
> > +       if (!vdd) {
> > +               pr_warning("Wrong paramater passed\n");
> > +               return -EINVAL;
> > +       }
> > +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> > +
> > +       *val = volt_data->volt_dynamic_nominal;
> > +
> > +       return 0;
> > +}
> > +
> > +static int calib_volt_debug_get(void *data, u64 *val)
> > +{
> > +       struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> > +       struct omap_volt_data *volt_data;
> > +
> > +       if (!vdd) {
> > +               pr_warning("Wrong paramater passed\n");
> > +               return -EINVAL;
> > +       }
> > +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> > +
> > +       *val = volt_data->volt_calibrated;
> > +
> > +       return 0;
> > +}
> > +
> >  DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");
> >  DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
> >                                                                "%llu\n");
> > +DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL,
> > +                                                               "%llu\n");
> > +DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL,
> > +                                                               "%llu\n");
> >  static void vp_latch_vsel(struct omap_vdd_info *vdd)
> >  {
> >        u32 vpconfig;
> > @@ -504,6 +540,12 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
> >        (void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
> >                                vdd->debug_dir, (void *) vdd,
> >                                &nom_volt_debug_fops);
> > +       (void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO,
> > +                               vdd->debug_dir, (void *) vdd,
> > +                               &dyn_volt_debug_fops);
> > +       (void) debugfs_create_file("curr_calibrated_volt", S_IRUGO,
> > +                               vdd->debug_dir, (void *) vdd,
> > +                               &calib_volt_debug_fops);
> >  }
> >
> >  /* Voltage scale and accessory APIs */
> > @@ -1132,6 +1174,33 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
> >  }
> >
> >  /**
> > + * omap_voltage_calib_reset() - reset the calibrated voltage entries
> > + * @voltdm: voltage domain to reset the entries for
> > + *
> > + * when the calibrated entries are no longer valid, this api allows
> > + * the calibrated voltages to be reset.
> > + */
> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm)
> > +{
> > +       struct omap_vdd_info *vdd;
> > +       struct omap_volt_data *volt_data;
> > +
> > +       if (IS_ERR_OR_NULL(voltdm)) {
> > +               pr_warning("%s: VDD specified does not exist!\n", __func__);
> > +               return -EINVAL;
> > +       }
> > +
> > +       vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
> > +       volt_data = vdd->volt_data;
> > +       /* reset the calibrated voltages as 0 */
> > +       while (volt_data->volt_nominal) {
> > +               volt_data->volt_calibrated = 0;
> > +               volt_data++;
> > +       }
> > +       return 0;
> > +}
> > +
> > +/**
> >  * omap_vp_get_curr_volt() - API to get the current vp voltage.
> >  * @voltdm:    pointer to the VDD.
> >  *
> > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> > index b6333ae..dba7939 100644
> > --- a/arch/arm/plat-omap/Kconfig
> > +++ b/arch/arm/plat-omap/Kconfig
> > @@ -67,6 +67,23 @@ config OMAP_SMARTREFLEX_CLASS3
> >          Class 3 implementation of Smartreflex employs continuous hardware
> >          voltage calibration.
> >
> > +config OMAP_SMARTREFLEX_CLASS1P5
> > +       bool "Class 1.5 mode of Smartreflex Implementation"
> > +       depends on OMAP_SMARTREFLEX && TWL4030_CORE
> > +       help
> > +         Say Y to enable Class 1.5 implementation of Smartreflex
> > +         Class 1.5 implementation of Smartreflex employs software controlled
> > +         hardware voltage calibration.
> > +
> > +config OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +       int "Class 1.5 mode recalibration recalibration delay(ms)"
> > +       depends on OMAP_SMARTREFLEX_CLASS1P5
> > +       default 86400000
> > +       help
> > +         Setup the recalibration delay in milliseconds. Use 0 for never doing
> > +         a recalibration. Defaults to recommended recalibration every 24hrs.
> > +         If you do not understand this, use the default.
> > +
> >  config OMAP_RESET_CLOCKS
> >        bool "Reset unused clocks during boot"
> >        depends on ARCH_OMAP
> > diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
> > index 07f35b2..ee5c58f 100644
> > --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> > +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> > @@ -167,6 +167,7 @@ struct omap_sr_pmic_data {
> >  #define SR_CLASS1      0x1
> >  #define SR_CLASS2      0x2
> >  #define SR_CLASS3      0x3
> > +#define SR_CLASS1P5    0x4
> >
> >  /**
> >  * struct omap_sr_class_data - Smartreflex class driver info
> > @@ -187,7 +188,9 @@ struct omap_sr_pmic_data {
> >  struct omap_sr_class_data {
> >        int (*enable)(struct voltagedomain *voltdm,
> >                        struct omap_volt_data *volt_data);
> > -       int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
> > +       int (*disable)(struct voltagedomain *voltdm,
> > +                       struct omap_volt_data *volt_data,
> > +                       int is_volt_reset);
> >        int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
> >        int (*class_deinit)(struct voltagedomain *voltdm,
> >                        void *class_priv_data);
> > @@ -235,7 +238,8 @@ struct omap_sr_data {
> >  /* Smartreflex module enable/disable interface */
> >  void omap_sr_enable(struct voltagedomain *voltdm,
> >                        struct omap_volt_data *volt_data);
> > -void omap_sr_disable(struct voltagedomain *voltdm);
> > +void omap_sr_disable(struct voltagedomain *voltdm,
> > +                       struct omap_volt_data *volt_data);
> >  void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
> >
> >  /* API to register the pmic specific data with the smartreflex driver. */
> > @@ -250,6 +254,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm);
> >
> >  /* API to register the smartreflex class driver with the smartreflex driver */
> >  int sr_register_class(struct omap_sr_class_data *class_data);
> > +bool is_sr_enabled(struct voltagedomain *voltdm);
> >  #else
> >  static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
> >  static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
> > @@ -264,5 +269,9 @@ static inline void omap_sr_disable_reset_volt(
> >                struct voltagedomain *voltdm) {}
> >  static inline void omap_sr_register_pmic(
> >                struct omap_sr_pmic_data *pmic_data) {}
> > +static inline bool is_sr_enabled(struct voltagedomain *voltdm)
> > +{
> > +       return false;
> > +}
> >  #endif
> >  #endif
> > diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
> > index 332c581..54445f0 100644
> > --- a/arch/arm/plat-omap/include/plat/voltage.h
> > +++ b/arch/arm/plat-omap/include/plat/voltage.h
> > @@ -58,6 +58,8 @@
> >  #define OMAP4430_VDD_CORE_OPP50_UV             930000
> >  #define OMAP4430_VDD_CORE_OPP100_UV            1100000
> >
> > +#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV    50000
> > +
> >  /**
> >  * struct voltagedomain - omap voltage domain global structure.
> >  * @name:      Name of the voltage domain which can be used as a unique
> > @@ -81,6 +83,8 @@ struct voltagedomain {
> >  */
> >  struct omap_volt_data {
> >        u32     volt_nominal;
> > +       u32     volt_calibrated;
> > +       u32     volt_dynamic_nominal;
> >        u32     sr_efuse_offs;
> >        u8      sr_errminlimit;
> >        u8      vp_errgain;
> > @@ -127,6 +131,7 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
> >  bool omap_vp_is_transdone(struct voltagedomain *voltdm);
> >  bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
> >  struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm);
> >  #ifdef CONFIG_PM
> >  int omap_voltage_register_pmic(struct voltagedomain *voltdm,
> >                struct omap_volt_pmic_info *pmic_info);
> > @@ -160,7 +165,23 @@ static inline unsigned long omap_get_operation_voltage(
> >  {
> >        if (IS_ERR_OR_NULL(vdata))
> >                return 0;
> > -       return vdata->volt_nominal;
> > +       return (vdata->volt_calibrated) ? vdata->volt_calibrated :
> > +               (vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
> > +                       vdata->volt_nominal;
> >  }
> >
> > +/* what is my dynamic nominal? */
> > +static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
> > +{
> > +       if (IS_ERR_OR_NULL(vdata))
> > +               return 0;
> > +       if (vdata->volt_calibrated) {
> > +               unsigned long v = vdata->volt_calibrated +
> > +                       OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
> > +               if (v > vdata->volt_nominal)
> > +                       return vdata->volt_nominal;
> > +               return v;
> > +       }
> > +       return vdata->volt_nominal;
> > +}
> >  #endif
> > --
> > 1.7.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> I have tested this Patch Series on OMAP 3630 SDP,  for MPU and IVA Powerdomains
Could you clarify on null pointer issue: on SDP3630? or OMAP4SDP? I
see there is a risk with OMAP4 where there is a bug in the following
scenario:
bootloader setups the OPP frequency for an OPP(e.g. 1GHz) which is
disabled by default on OPP table in kernel. this needs to be cleanly
fixed in pm.c, at the same time, the exposed functions in class1p5
needs parameter validation as well.

> it throws error log "Unable to refer to NULL pointer" if
> curr_nominal_volt, curr_calibrated_volt
> or curr_dynamical_volt is accessed through debugfs.
> Could you please provide fix for this.


Regards,
Nishanth Menon
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 18/19] omap3630+: sr: add support for class 1.5
  2011-03-01 10:17     ` Menon, Nishanth
@ 2011-03-01 12:20       ` Gulati, Shweta
  0 siblings, 0 replies; 64+ messages in thread
From: Gulati, Shweta @ 2011-03-01 12:20 UTC (permalink / raw)
  To: Menon, Nishanth
  Cc: linux-omap, Tony Lindgren, Kevin Hilman, Ambresh K,
	Eduardo Valentin, Igor Dmitriev, Paul,
	Peter 'p2' De Schrijver

Hi,

On Tue, Mar 1, 2011 at 3:47 PM, Menon, Nishanth <nm@ti.com> wrote:
> On Tue, Mar 1, 2011 at 15:23, Gulati, Shweta <shweta.gulati@ti.com> wrote:
>>
>> Hi,
>>
>> On Sat, Feb 19, 2011 at 5:31 PM, Nishanth Menon <nm@ti.com> wrote:
>> > Traditional SmartReflex AVS(Automatic Voltage Scaling) classes are:
>> > * Class 0 - Product test calibration
>> >        Silicon is calibration at production floor and fused with voltages
>> >        for each OPP
>> > * Class 1 - Boot time calibration
>> >        Silicon is calibrated once at boot time and voltages are stored for
>> >        the lifetime of operation.
>> > * Class 2 - continuous s/w calibration
>> >        SR module notifies s/w for any change in the system which is desired
>> >        and the s/w makes runtime decisions in terms of setting the voltage,
>> >        this mechanism could be used in the system which does not have PMIC
>> >        capable of SR without using the voltage controller and voltage
>> >        processor blocks.
>> > * Class 3 - continuous h/w calibration
>> >        SR module is switch on after reaching a voltage level and SR
>> >        continuously monitors the system and makes runtime adjustments without
>> >        s/w involvement.
>> >
>> > OMAP3430 has used SmartReflex AVS and with a a PMIC which understands the SR
>> > protocol, Class 3 has been used. With OMAP3630 onwards, a new SmartReflex AVS
>> > class of operation Class 1.5 was introduced.
>> > * Class 1.5 - periodic s/w calibration
>> >        This uses the h/w calibration loop and at the end of calibration
>> >        stores the voltages to be used run time, periodic recalibration is
>> >        performed as well.
>> >
>> > The operational mode is describes as the following:
>> > * SmartReflex AVS h/w calibration loop is essential to identify the optimal
>> >        voltage for a given OPP.
>> > * Once this optimal voltage is detected, SmartReflex AVS loop is disabled in
>> >        class 1.5 mode of operation.
>> > * Until there is a need for a recalibration, any further transition to an OPP
>> >        voltage which is calibrated can use the calibrated voltage and does not
>> >        require enabling the SR AVS h/w loop.
>> > * On a periodic basis (recommendation being once approximately every 24 hours),
>> >        software is expected to perform a recalibration to find a new optimal
>> >        voltage which is compensated for device aging.
>> >        - For performing this recalibration, the start voltage does not need to
>> >        be the nominal voltage anymore. instead, the system can start with a
>> >        voltage which is 50mV higher than the previously calibrated voltage to
>> >        identify the new optimal voltage as the aging factor within a period of
>> >        1 day is not going to be anywhere close to 50mV.
>> >        - This "new starting point" for recalibration is called a dynamic
>> >        nominal voltage for that voltage point.
>> > In short, with the introduction of SmartReflex class 1.5, there are three new
>> > voltages possible in a system's dvfs transition:
>> > * Nominal Voltage - The maximum voltage needed for a worst possible device
>> >        in the worst possible conditions. This is the voltage we choose as
>> >        the starting point for the h/w loop to optimize for the first time
>> >        calibration on system bootup.
>> > * Dynamic Nominal Voltage - Worst case voltage for a specific device in
>> >        considering the system aging on the worst process device.
>> > * Calibrated Voltage - Best voltage for the current device at a given point
>> >        of time.
>> >
>> > In terms of the implementation, doing calibration involves waiting for the
>> > smartreflex h/w loop to settle down, and doing this as part of the dvfs flow
>> > itself is to increase the latency of dvfs transition when there is a need to
>> > calibrate that opp. instead, the calibration is performed "out of path" using
>> > a workqueue statemachine. The workqueue waits for the system stabilization,
>> > then enables VP interrupts to monitor for system instability interms of voltage
>> > oscillations that are reported back to the system as interrupts, in case of
>> > prolonged system oscillations, nominal voltage is chosen as a safe voltage and
>> > this event is logged in the system log for developer debug and fixing.
>> >
>> > For the recalibration, a common workqueue for all domains is started at the
>> > start of the class initialization and it resets the calibrated voltages
>> > on a periodic basis. For distros that may choose not to do the recommended
>> > periodic recalibration, instead choose to perform boot time calibration,
>> > kconfig configuration option is provided to do so.
>> >
>> > TODO:
>> > a) Cpuidle and suspend paths are not integrated with SmartReflex driver at
>> >   this point.
>> > b) Since the SR registers are accessed and controlled in parallel to DVFS
>> >   some sort of mechanism is necessary to be introduced along with OMAP
>> >   dvfs layer to ensure mutual exclusivity
>> > c) Additional debug interfaces for vmin analysis for platform characterization
>> >   and addition of system margin needs to be introduced from smartreflex
>> >   perspective.
>> >
>> > This implementation also includes the following contributors:
>> > Tony Lindgren for suggestion on using interrupt based mechanism instead of
>> > polling to detect voltage oscillations.
>> > Peter 'p2' De Schrijver for debating alternatives on recalibration mechanisms
>> > Paul Walmsey, Eduardo Valentin, Ambresh K, Igor Dmitriev and quiet a few others
>> > for patient review, testing and reporting of issues of a previous incarnation
>> > of this implemenation. Last, but not the least, the TI H/w team in introducing
>> > this new SR AVS class and patiently debating it's various facets.
>> >
>> > Cc: Ambresh K <ambresh@ti.com>
>> > Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
>> > Cc: Igor Dmitriev <ext-dmitriev.igor@nokia.com>
>> > Cc: Paul <paul@pwsan.com>
>> > Cc: Peter 'p2' De Schrijver <Peter.De-Schrijver@nokia.com>
>> > Cc: Tony Lindgren <tony@atomide.com>
>> >
>> > Signed-off-by: Nishanth Menon <nm@ti.com>
>> > ---
>> >  arch/arm/mach-omap2/Makefile                  |    1 +
>> >  arch/arm/mach-omap2/smartreflex-class1p5.c    |  556 +++++++++++++++++++++++++
>> >  arch/arm/mach-omap2/smartreflex-class3.c      |    4 +-
>> >  arch/arm/mach-omap2/smartreflex.c             |   34 ++-
>> >  arch/arm/mach-omap2/voltage.c                 |   69 +++
>> >  arch/arm/plat-omap/Kconfig                    |   17 +
>> >  arch/arm/plat-omap/include/plat/smartreflex.h |   13 +-
>> >  arch/arm/plat-omap/include/plat/voltage.h     |   23 +-
>> >  8 files changed, 709 insertions(+), 8 deletions(-)
>> >  create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c
>> >
>> > diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
>> > index 1c0c2b0..1a82e6d 100644
>> > --- a/arch/arm/mach-omap2/Makefile
>> > +++ b/arch/arm/mach-omap2/Makefile
>> > @@ -66,6 +66,7 @@ obj-$(CONFIG_ARCH_OMAP4)              += pm44xx.o voltage.o pm_bus.o
>> >  obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
>> >  obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
>> >  obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)  += smartreflex-class3.o
>> > +obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS1P5)        += smartreflex-class1p5.o
>> >
>> >  AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
>> >  AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a
>> > diff --git a/arch/arm/mach-omap2/smartreflex-class1p5.c b/arch/arm/mach-omap2/smartreflex-class1p5.c
>> > new file mode 100644
>> > index 0000000..832f10b
>> > --- /dev/null
>> > +++ b/arch/arm/mach-omap2/smartreflex-class1p5.c
>> > @@ -0,0 +1,556 @@
>> > +/*
>> > + * Smart reflex Class 1.5 specific implementations
>> > + *
>> > + * Copyright (C) 2010-2011 Texas Instruments, Inc.
>> > + * Nishanth Menon <nm@ti.com>
>> > + *
>> > + * Smart reflex class 1.5 is also called periodic SW Calibration
>> > + * Some of the highlights are as follows:
>> > + * – Host CPU triggers OPP calibration when transitioning to non calibrated
>> > + *   OPP
>> > + * – SR-AVS + VP modules are used to perform calibration
>> > + * – Once completed, the SmartReflex-AVS module can be disabled
>> > + * – Enables savings based on process, supply DC accuracy and aging
>> > + *
>> > + * This program is free software; you can redistribute it and/or modify
>> > + * it under the terms of the GNU General Public License version 2 as
>> > + * published by the Free Software Foundation.
>> > + */
>> > +#include <linux/kernel.h>
>> > +#include <linux/delay.h>
>> > +#include <linux/err.h>
>> > +#include <linux/io.h>
>> > +#include <linux/fs.h>
>> > +#include <linux/string.h>
>> > +#include <linux/uaccess.h>
>> > +#include <linux/kobject.h>
>> > +#include <linux/workqueue.h>
>> > +#include <linux/opp.h>
>> > +
>> > +#include <plat/smartreflex.h>
>> > +#include <plat/voltage.h>
>> > +
>> > +#define MAX_VDDS 3
>> > +#define SR1P5_SAMPLING_DELAY_MS        1
>> > +#define SR1P5_STABLE_SAMPLES   5
>> > +#define SR1P5_MAX_TRIGGERS     5
>> > +
>> > +/*
>> > + * we expect events in 10uS, if we dont get 2wice times as much,
>> > + * we could kind of ignore this as a missed event.
>> > + */
>> > +#define MAX_CHECK_VPTRANS_US   20
>> > +
>> > +/**
>> > + * struct sr_class1p5_work_data - data meant to be used by calibration work
>> > + * @work:      calibration work
>> > + * @voltdm:            voltage domain for which we are triggering
>> > + * @vdata:     voltage data we are calibrating
>> > + * @num_calib_triggers:        number of triggers from calibration loop
>> > + * @num_osc_samples:   number of samples collected by isr
>> > + * @work_active:       have we scheduled a work item?
>> > + */
>> > +struct sr_class1p5_work_data {
>> > +       struct delayed_work work;
>> > +       struct voltagedomain *voltdm;
>> > +       struct omap_volt_data *vdata;
>> > +       u8 num_calib_triggers;
>> > +       u8 num_osc_samples;
>> > +       bool work_active;
>> > +};
>> > +
>> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
>> > +/* recal_work: recalibration calibration work */
>> > +static struct delayed_work recal_work;
>> > +#endif
>> > +
>> > +/**
>> > + * struct sr_class1p5_data - private data for class 1p5
>> > + * @work_data:         work item data per voltage domain
>> > + */
>> > +struct sr_class1p5_data {
>> > +       struct sr_class1p5_work_data work_data[MAX_VDDS];
>> > +};
>> > +
>> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
>> > +                                   bool recal);
>> > +
>> > +/* our instance of class 1p5 private data */
>> > +static struct sr_class1p5_data class_1p5_data;
>> > +
>> > +static struct sr_class1p5_work_data *get_sr1p5_work(struct voltagedomain
>> > +                                                   *voltdm)
>> > +{
>> > +       int idx;
>> > +       for (idx = 0; idx < MAX_VDDS; idx++) {
>> > +               if (class_1p5_data.work_data[idx].voltdm && !strcmp
>> > +                   (class_1p5_data.work_data[idx].voltdm->name, voltdm->name))
>> > +                       return &class_1p5_data.work_data[idx];
>> > +       }
>> > +       return ERR_PTR(-ENODATA);
>> > +}
>> > +
>> > +/**
>> > + * sr_class1p5_notify() - isr notifier for status events
>> > + * @voltdm:    voltage domain for which we were triggered
>> > + * @status:    notifier event to use
>> > + *
>> > + * This basically collects data for the work to use.
>> > + */
>> > +static int sr_class1p5_notify(struct voltagedomain *voltdm, u32 status)
>> > +{
>> > +       struct sr_class1p5_work_data *work_data;
>> > +       int idx = 0;
>> > +       work_data = get_sr1p5_work(voltdm);
>> > +
>> > +       if (unlikely(!work_data)) {
>> > +               pr_err("%s:%s no work data!!\n", __func__, voltdm->name);
>> > +               return -EINVAL;
>> > +       }
>> > +
>> > +       /* Wait for transdone so that we know the voltage to read */
>> > +       do {
>> > +               if (omap_vp_is_transdone(voltdm))
>> > +                       break;
>> > +               idx++;
>> > +               /* get some constant delay */
>> > +               udelay(1);
>> > +       } while (idx < MAX_CHECK_VPTRANS_US);
>> > +
>> > +       /*
>> > +        * If we timeout, we still read the data,
>> > +        * if we are oscillating+irq latencies are too high, we could
>> > +        * have scenarios where we miss transdone event. since
>> > +        * we waited long enough, it is still safe to read the voltage
>> > +        * as we would have waited long enough - still flag it..
>> > +        */
>> > +       if (idx >= MAX_CHECK_VPTRANS_US)
>> > +               pr_warning("%s: timed out waiting for transdone!!\n", __func__);
>> > +
>> > +       omap_vp_clear_transdone(voltdm);
>> > +
>> > +       idx = (work_data->num_osc_samples) % SR1P5_STABLE_SAMPLES;
>> > +       work_data->num_osc_samples++;
>> > +
>> > +       return 0;
>> > +}
>> > +
>> > +/**
>> > + * do_calibrate() - work which actually does the calibration
>> > + * @work: pointer to the work
>> > + *
>> > + * calibration routine uses the following logic:
>> > + * on the first trigger, we start the isr to collect sr voltages
>> > + * wait for stabilization delay (reschdule self instead of sleeping)
>> > + * after the delay, see if we collected any isr events
>> > + * if none, we have calibrated voltage.
>> > + * if there are any, we retry untill we giveup.
>> > + * on retry timeout, select a voltage to use as safe voltage.
>> > + */
>> > +static void do_calibrate(struct work_struct *work)
>> > +{
>> > +       struct sr_class1p5_work_data *work_data =
>> > +           container_of(work, struct sr_class1p5_work_data, work.work);
>> > +       unsigned long u_volt_safe = 0, u_volt_current = 0;
>> > +       struct omap_volt_data *volt_data;
>> > +       struct voltagedomain *voltdm;
>> > +
>> > +       if (unlikely(!work_data)) {
>> > +               pr_err("%s: ooops.. null work_data?\n", __func__);
>> > +               return;
>> > +       }
>> > +
>> > +       /*
>> > +        * TODO:Handle the case where we might have just been scheduled AND
>> > +        * 1.5 disable was called. check and HOLD dvfs
>> > +        */
>> > +
>> > +       voltdm = work_data->voltdm;
>> > +       /*
>> > +        * In the unlikely case that we did get through when unplanned,
>> > +        * flag and return.
>> > +        */
>> > +       if (unlikely(!work_data->work_active)) {
>> > +               pr_err("%s:%s unplanned work invocation!\n", __func__,
>> > +                      voltdm->name);
>> > +               /* TODO release the dvfs */
>> > +               return;
>> > +       }
>> > +
>> > +       work_data->num_calib_triggers++;
>> > +       /* if we are triggered first time, we need to start isr to sample */
>> > +       if (work_data->num_calib_triggers == 1)
>> > +               goto start_sampling;
>> > +
>> > +       /* Stop isr from interrupting our measurements :) */
>> > +       sr_notifier_control(voltdm, false);
>> > +
>> > +       volt_data = work_data->vdata;
>> > +
>> > +       /* if there are no samples captured.. SR is silent, aka stability! */
>> > +       if (!work_data->num_osc_samples) {
>> > +               u_volt_safe = omap_vp_get_curr_volt(voltdm);
>> > +               u_volt_current = u_volt_safe;
>> > +               goto done_calib;
>> > +       }
>> > +       if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) {
>> > +               pr_warning("%s: %s recalib timeout!\n", __func__,
>> > +                          work_data->voltdm->name);
>> > +               goto oscillating_calib;
>> > +       }
>> > +
>> > +       /* we have potential oscillations/first sample */
>> > +start_sampling:
>> > +       work_data->num_osc_samples = 0;
>> > +       /* Clear pending events */
>> > +       sr_notifier_control(voltdm, false);
>> > +       /* Clear all transdones */
>> > +       while (omap_vp_is_transdone(voltdm))
>> > +               omap_vp_clear_transdone(voltdm);
>> > +       /* trigger sampling */
>> > +       sr_notifier_control(voltdm, true);
>> > +       schedule_delayed_work(&work_data->work,
>> > +                             msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
>> > +                                              SR1P5_STABLE_SAMPLES));
>> > +       /* TODO: release dvfs */
>> > +       return;
>> > +
>> > +oscillating_calib:
>> > +       /* Use the nominal voltage as the safe voltage */
>> > +       u_volt_safe = volt_data->volt_nominal;
>> > +       /* pick up current voltage to switch if needed */
>> > +       u_volt_current = omap_vp_get_curr_volt(voltdm);
>> > +
>> > +       /* Fall through to close up common stuff */
>> > +done_calib:
>> > +       omap_vp_disable(voltdm);
>> > +       sr_disable(voltdm);
>> > +
>> > +       volt_data->volt_calibrated = u_volt_safe;
>> > +       /* Setup my dynamic voltage for the next calibration for this opp */
>> > +       volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data);
>> > +
>> > +       /*
>> > +        * if the voltage we decided as safe is not the current voltage,
>> > +        * switch
>> > +        */
>> > +       if (volt_data->volt_calibrated != u_volt_current) {
>> > +               pr_debug("%s:%s reconfiguring to voltage %d\n",
>> > +                        __func__, voltdm->name, volt_data->volt_calibrated);
>> > +               omap_voltage_scale_vdd(voltdm, volt_data);
>> > +       }
>> > +
>> > +       /*
>> > +        * TODO: Setup my wakeup voltage to allow immediate going to OFF and
>> > +        * on - Pending twl and voltage layer cleanups.
>> > +        * This is necessary, as this is not done as part of regular
>> > +        * Dvfs flow.
>> > +        * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated);
>> > +        */
>> > +       work_data->work_active = false;
>> > +       /* TODO: release dvfs */
>> > +}
>> > +
>> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
>> > +/**
>> > + * do_recalibrate() - work which actually does the calibration
>> > + * @work: pointer to the work
>> > + *
>> > + * on a periodic basis, we come and reset our calibration setup
>> > + * so that a recalibration of the OPPs take place. This takes
>> > + * care of aging factor in the system.
>> > + */
>> > +static void do_recalibrate(struct work_struct *work)
>> > +{
>> > +       struct voltagedomain *voltdm;
>> > +       int idx;
>> > +       static struct sr_class1p5_work_data *work_data;
>> > +
>> > +       for (idx = 0; idx < MAX_VDDS; idx++) {
>> > +               work_data = &class_1p5_data.work_data[idx];
>> > +               voltdm = work_data->voltdm;
>> > +               if (voltdm) {
>> > +                       /* if sr is not enabled, we check later */
>> > +                       if (!is_sr_enabled(voltdm))
>> > +                               continue;
>> > +                       /* TODO: Pause the dvfs transitions */
>> > +                       /* if sr is not enabled, we check later */
>> > +
>> > +                       /* Reset and force a recalibration for current opp */
>> > +                       sr_class1p5_reset_calib(voltdm, true, true);
>> > +
>> > +                       /* TODO: unpause DVFS transitions */
>> > +               }
>> > +       }
>> > +       /* We come back again after time the usual delay */
>> > +       schedule_delayed_work(&recal_work,
>> > +             msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
>> > +}
>> > +#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */
>> > +
>> > +/**
>> > + * sr_class1p5_enable() - class 1.5 mode of enable
>> > + * @voltdm:            voltage domain to enable SR for
>> > + * @volt_data: voltdata to the voltage transition taking place
>> > + *
>> > + * when this gets called, we use the h/w loop to setup our voltages
>> > + * to an calibrated voltage, detect any oscillations, recover from the same
>> > + * and finally store the optimized voltage as the calibrated voltage in the
>> > + * system
>> > + */
>> > +static int sr_class1p5_enable(struct voltagedomain *voltdm,
>> > +                             struct omap_volt_data *volt_data)
>> > +{
>> > +       int r;
>> > +       struct sr_class1p5_work_data *work_data;
>> > +       /* if already calibrated, nothing to do here.. */
>> > +       if (volt_data->volt_calibrated)
>> > +               return 0;
>> > +
>> > +       work_data = get_sr1p5_work(voltdm);
>> > +       if (unlikely(!work_data)) {
>> > +               pr_err("%s: aieeee.. bad work data??\n", __func__);
>> > +               return -EINVAL;
>> > +       }
>> > +
>> > +       if (work_data->work_active)
>> > +               return 0;
>> > +
>> > +       omap_vp_enable(voltdm);
>> > +       r = sr_enable(voltdm, volt_data);
>> > +       if (r) {
>> > +               pr_err("%s: sr[%s] failed\n", __func__, voltdm->name);
>> > +               omap_vp_disable(voltdm);
>> > +               return r;
>> > +       }
>> > +       work_data->vdata = volt_data;
>> > +       work_data->work_active = true;
>> > +       work_data->num_calib_triggers = 0;
>> > +       /* program the workqueue and leave it to calibrate offline.. */
>> > +       schedule_delayed_work(&work_data->work,
>> > +                             msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
>> > +                                              SR1P5_STABLE_SAMPLES));
>> > +
>> > +       return 0;
>> > +}
>> > +
>> > +/**
>> > + * sr_class1p5_disable() - disable for class 1p5
>> > + * @voltdm: voltage domain for the sr which needs disabling
>> > + * @volt_data: voltagedata to disable
>> > + * @is_volt_reset: reset the voltage?
>> > + *
>> > + * we dont do anything if the class 1p5 is being used. this is because we
>> > + * already disable sr at the end of calibration and no h/w loop is actually
>> > + * active when this is called.
>> > + */
>> > +static int sr_class1p5_disable(struct voltagedomain *voltdm,
>> > +                              struct omap_volt_data *volt_data,
>> > +                              int is_volt_reset)
>> > +{
>> > +       struct sr_class1p5_work_data *work_data;
>> > +
>> > +       work_data = get_sr1p5_work(voltdm);
>> > +       if (work_data->work_active) {
>> > +               /* if volt reset and work is active, we dont allow this */
>> > +               if (is_volt_reset)
>> > +                       return -EBUSY;
>> > +               /* flag work is dead and remove the old work */
>> > +               work_data->work_active = false;
>> > +               cancel_delayed_work_sync(&work_data->work);
>> > +               sr_notifier_control(voltdm, false);
>> > +               omap_vp_disable(voltdm);
>> > +               sr_disable(voltdm);
>> > +       }
>> > +
>> > +       /* if already calibrated, nothin special to do here.. */
>> > +       if (volt_data->volt_calibrated)
>> > +               return 0;
>> > +
>> > +       if (is_volt_reset)
>> > +               omap_voltage_reset(voltdm);
>> > +       return 0;
>> > +}
>> > +
>> > +/**
>> > + * sr_class1p5_configure() - configuration function
>> > + * @voldm:     configure for which voltage domain
>> > + *
>> > + * we dont do much here other than setup some registers for
>> > + * the sr module involved.
>> > + */
>> > +static int sr_class1p5_configure(struct voltagedomain *voltdm)
>> > +{
>> > +       return sr_configure_errgen(voltdm);
>> > +}
>> > +
>> > +/**
>> > + * sr_class1p5_reset_calib() - reset all calibrated voltages
>> > + * @srid:      srid to reset the calibration for
>> > + * @reset:     reset voltage before we recal?
>> > + * @recal:     should I recalibrate my current opp?
>> > + *
>> > + * if we call this, it means either periodic calibration trigger was
>> > + * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
>> > + * meaning we cant trust the calib voltages anymore, it is better to use
>> > + * nominal in the system
>> > + */
>> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
>> > +                                   bool recal)
>> > +{
>> > +       struct sr_class1p5_work_data *work_data;
>> > +
>> > +       /* I dont need to go further if sr is not present */
>> > +       if (!is_sr_enabled(voltdm))
>> > +               return;
>> > +
>> > +       work_data = get_sr1p5_work(voltdm);
>> > +
>> > +       if (work_data->work_active)
>> > +               sr_class1p5_disable(voltdm, work_data->vdata, 0);
>> > +
>> > +       omap_voltage_calib_reset(voltdm);
>> > +
>> > +       /*
>> > +        * I should now reset the voltages to my nominal to be safe
>> > +        */
>> > +       if (reset)
>> > +               omap_voltage_reset(voltdm);
>> > +
>> > +       /*
>> > +        * I should fire a recalibration for current opp if needed
>> > +        * Note: i have just reset my calibrated voltages, and if
>> > +        * i call sr_enable equivalent, I will cause a recalibration
>> > +        * loop, even though the function is called sr_enable.. we
>> > +        * are in class 1.5 ;)
>> > +        */
>> > +       if (reset && recal)
>> > +               sr_class1p5_enable(voltdm, work_data->vdata);
>> > +}
>> > +
>> > +/**
>> > + * sr_class1p5_cinit() - class 1p5 init
>> > + * @voltdm:            sr voltage domain
>> > + * @class_priv_data:   private data for the class
>> > + *
>> > + * we do class specific initialization like creating sysfs/debugfs entries
>> > + * needed, spawning of a kthread if needed etc.
>> > + */
>> > +static int sr_class1p5_cinit(struct voltagedomain *voltdm,
>> > +                            void *class_priv_data)
>> > +{
>> > +       struct sr_class1p5_work_data *work_data;
>> > +       int idx;
>> > +
>> > +       if (!class_priv_data) {
>> > +               pr_err("%s: bad param? no priv data!\n", __func__);
>> > +               return -EINVAL;
>> > +       }
>> > +
>> > +       /* setup our work params */
>> > +       work_data = get_sr1p5_work(voltdm);
>> > +       if (!IS_ERR_OR_NULL(work_data)) {
>> > +               pr_err("%s: ooopps.. class already initialized for %s! bug??\n",
>> > +                      __func__, voltdm->name);
>> > +               return -EINVAL;
>> > +       }
>> > +       work_data = NULL;
>> > +       /* get the next spare work_data */
>> > +       for (idx = 0; idx < MAX_VDDS; idx++) {
>> > +               if (!class_1p5_data.work_data[idx].voltdm) {
>> > +                       work_data = &class_1p5_data.work_data[idx];
>> > +                       break;
>> > +               }
>> > +       }
>> > +       if (!work_data) {
>> > +               pr_err("%s: no more space for work data for domains!\n",
>> > +                       __func__);
>> > +               return -ENOMEM;
>> > +       }
>> > +       work_data->voltdm = voltdm;
>> > +       INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, do_calibrate);
>> > +       return 0;
>> > +}
>> > +
>> > +/**
>> > + * sr_class1p5_cdeinit() - class 1p5 deinitialization
>> > + * @voltdm:    voltage domain for which to do this.
>> > + * @class_priv_data: class private data for deinitialiation
>> > + *
>> > + * currently only resets the calibrated voltage forcing dvfs voltages
>> > + * to be used in the system
>> > + */
>> > +static int sr_class1p5_cdeinit(struct voltagedomain *voltdm,
>> > +                              void *class_priv_data)
>> > +{
>> > +       struct sr_class1p5_work_data *work_data;
>> > +
>> > +       /* setup our work params */
>> > +       work_data = get_sr1p5_work(voltdm);
>> > +       if (IS_ERR_OR_NULL(work_data)) {
>> > +               pr_err("%s: ooopps.. class not initialized for %s! bug??\n",
>> > +                      __func__, voltdm->name);
>> > +               return -EINVAL;
>> > +       }
>> > +
>> > +       /*
>> > +        * we dont have SR periodic calib anymore.. so reset calibs
>> > +        * we are already protected by sr debugfs lock, so no lock needed
>> > +        * here.
>> > +        */
>> > +       sr_class1p5_reset_calib(voltdm, true, false);
>> > +
>> > +       /* reset all data for this work data */
>> > +       memset(work_data, 0, sizeof(*work_data));
>> > +
>> > +       return 0;
>> > +}
>> > +
>> > +/* SR class1p5 structure */
>> > +static struct omap_sr_class_data class1p5_data = {
>> > +       .enable = sr_class1p5_enable,
>> > +       .disable = sr_class1p5_disable,
>> > +       .configure = sr_class1p5_configure,
>> > +       .class_type = SR_CLASS1P5,
>> > +       .class_init = sr_class1p5_cinit,
>> > +       .class_deinit = sr_class1p5_cdeinit,
>> > +       .notify = sr_class1p5_notify,
>> > +       /*
>> > +        * trigger for bound - this tells VP that SR has a voltage
>> > +        * change. we should ensure transdone is set before reading
>> > +        * vp voltage.
>> > +        */
>> > +       .notify_flags = SR_NOTIFY_MCUBOUND,
>> > +       .class_priv_data = (void *)&class_1p5_data,
>> > +};
>> > +
>> > +/**
>> > + * sr_class1p5_init() - register class 1p5 as default
>> > + *
>> > + * board files call this function to use class 1p5, we register with the
>> > + * smartreflex subsystem
>> > + */
>> > +static int __init sr_class1p5_init(void)
>> > +{
>> > +       int r;
>> > +
>> > +       /* Enable this class only for OMAP3630 and OMAP4 */
>> > +       if (!(cpu_is_omap3630() || cpu_is_omap44xx()))
>> > +               return -EINVAL;
>> > +
>> > +       r = sr_register_class(&class1p5_data);
>> > +       if (r) {
>> > +               pr_err("SmartReflex class 1.5 driver: "
>> > +                      "failed to register with %d\n", r);
>> > +       } else {
>> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
>> > +               INIT_DELAYED_WORK_DEFERRABLE(&recal_work, do_recalibrate);
>> > +               schedule_delayed_work(&recal_work, msecs_to_jiffies(
>> > +                               CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
>> > +#endif
>> > +               pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n",
>> > +                       CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY);
>> > +       }
>> > +       return r;
>> > +}
>> > +late_initcall(sr_class1p5_init);
>> > diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
>> > index 7ac88da..5f7a33e 100644
>> > --- a/arch/arm/mach-omap2/smartreflex-class3.c
>> > +++ b/arch/arm/mach-omap2/smartreflex-class3.c
>> > @@ -21,7 +21,9 @@ static int sr_class3_enable(struct voltagedomain *voltdm,
>> >        return sr_enable(voltdm, volt_data);
>> >  }
>> >
>> > -static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
>> > +static int sr_class3_disable(struct voltagedomain *voltdm,
>> > +                               struct omap_volt_data *vdata,
>> > +                               int is_volt_reset)
>> >  {
>> >        omap_vp_disable(voltdm);
>> >        sr_disable(voltdm);
>> > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
>> > index 3a5f2f6..bb55b65 100644
>> > --- a/arch/arm/mach-omap2/smartreflex.c
>> > +++ b/arch/arm/mach-omap2/smartreflex.c
>> > @@ -317,7 +317,9 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
>> >        }
>> >
>> >        if (sr->autocomp_active) {
>> > -               sr_class->disable(sr->voltdm, 1);
>> > +               sr_class->disable(sr->voltdm,
>> > +                               omap_voltage_get_nom_volt(sr->voltdm),
>> > +                               1);
>> >                if (sr_class->class_deinit &&
>> >                    sr_class->class_deinit(sr->voltdm,
>> >                            sr_class->class_priv_data)) {
>> > @@ -471,6 +473,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
>> >  /* Public Functions */
>> >
>> >  /**
>> > + * is_sr_enabled() - is Smart reflex enabled for this domain?
>> > + * @voltdm: voltage domain to check
>> > + *
>> > + * Returns 0 if SR is enabled for this domain, else returns err
>> > + */
>> > +bool is_sr_enabled(struct voltagedomain *voltdm)
>> > +{
>> > +       struct omap_sr *sr;
>> > +       if (IS_ERR_OR_NULL(voltdm)) {
>> > +               pr_warning("%s: invalid param voltdm\n", __func__);
>> > +               return false;
>> > +       }
>> > +       sr = _sr_lookup(voltdm);
>> > +       if (IS_ERR(sr)) {
>> > +               pr_warning("%s: omap_sr struct for sr_%s not found\n",
>> > +                       __func__, voltdm->name);
>> > +               return false;
>> > +       }
>> > +       return sr->autocomp_active;
>> > +}
>> > +
>> > +/**
>> >  * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
>> >  *                      error generator module.
>> >  * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
>> > @@ -839,6 +863,7 @@ void omap_sr_enable(struct voltagedomain *voltdm,
>> >  * omap_sr_disable() - API to disable SR without resetting the voltage
>> >  *                     processor voltage
>> >  * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
>> > + * @volt_data: Voltage data to go to
>> >  *
>> >  * This API is to be called from the kernel in order to disable
>> >  * a particular smartreflex module. This API will in turn call
>> > @@ -846,7 +871,8 @@ void omap_sr_enable(struct voltagedomain *voltdm,
>> >  * the smartreflex class disable not to reset the VP voltage after
>> >  * disabling smartreflex.
>> >  */
>> > -void omap_sr_disable(struct voltagedomain *voltdm)
>> > +void omap_sr_disable(struct voltagedomain *voltdm,
>> > +               struct omap_volt_data *vdata)
>> >  {
>> >        struct omap_sr *sr = _sr_lookup(voltdm);
>> >
>> > @@ -865,7 +891,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
>> >                return;
>> >        }
>> >
>> > -       sr_class->disable(voltdm, 0);
>> > +       sr_class->disable(voltdm, vdata, 0);
>> >  }
>> >
>> >  /**
>> > @@ -898,7 +924,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
>> >                return;
>> >        }
>> >
>> > -       sr_class->disable(voltdm, 1);
>> > +       sr_class->disable(voltdm, omap_voltage_get_nom_volt(voltdm), 1);
>> >  }
>> >
>> >  /**
>> > diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
>> > index 77cb0cd..c451835 100644
>> > --- a/arch/arm/mach-omap2/voltage.c
>> > +++ b/arch/arm/mach-omap2/voltage.c
>> > @@ -374,9 +374,45 @@ static int nom_volt_debug_get(void *data, u64 *val)
>> >        return 0;
>> >  }
>> >
>> > +static int dyn_volt_debug_get(void *data, u64 *val)
>> > +{
>> > +       struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
>> > +       struct omap_volt_data *volt_data;
>> > +
>> > +       if (!vdd) {
>> > +               pr_warning("Wrong paramater passed\n");
>> > +               return -EINVAL;
>> > +       }
>> > +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
>> > +
>> > +       *val = volt_data->volt_dynamic_nominal;
>> > +
>> > +       return 0;
>> > +}
>> > +
>> > +static int calib_volt_debug_get(void *data, u64 *val)
>> > +{
>> > +       struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
>> > +       struct omap_volt_data *volt_data;
>> > +
>> > +       if (!vdd) {
>> > +               pr_warning("Wrong paramater passed\n");
>> > +               return -EINVAL;
>> > +       }
>> > +       volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
>> > +
>> > +       *val = volt_data->volt_calibrated;
>> > +
>> > +       return 0;
>> > +}
>> > +
>> >  DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");
>> >  DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
>> >                                                                "%llu\n");
>> > +DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL,
>> > +                                                               "%llu\n");
>> > +DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL,
>> > +                                                               "%llu\n");
>> >  static void vp_latch_vsel(struct omap_vdd_info *vdd)
>> >  {
>> >        u32 vpconfig;
>> > @@ -504,6 +540,12 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
>> >        (void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
>> >                                vdd->debug_dir, (void *) vdd,
>> >                                &nom_volt_debug_fops);
>> > +       (void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO,
>> > +                               vdd->debug_dir, (void *) vdd,
>> > +                               &dyn_volt_debug_fops);
>> > +       (void) debugfs_create_file("curr_calibrated_volt", S_IRUGO,
>> > +                               vdd->debug_dir, (void *) vdd,
>> > +                               &calib_volt_debug_fops);
>> >  }
>> >
>> >  /* Voltage scale and accessory APIs */
>> > @@ -1132,6 +1174,33 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
>> >  }
>> >
>> >  /**
>> > + * omap_voltage_calib_reset() - reset the calibrated voltage entries
>> > + * @voltdm: voltage domain to reset the entries for
>> > + *
>> > + * when the calibrated entries are no longer valid, this api allows
>> > + * the calibrated voltages to be reset.
>> > + */
>> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm)
>> > +{
>> > +       struct omap_vdd_info *vdd;
>> > +       struct omap_volt_data *volt_data;
>> > +
>> > +       if (IS_ERR_OR_NULL(voltdm)) {
>> > +               pr_warning("%s: VDD specified does not exist!\n", __func__);
>> > +               return -EINVAL;
>> > +       }
>> > +
>> > +       vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
>> > +       volt_data = vdd->volt_data;
>> > +       /* reset the calibrated voltages as 0 */
>> > +       while (volt_data->volt_nominal) {
>> > +               volt_data->volt_calibrated = 0;
>> > +               volt_data++;
>> > +       }
>> > +       return 0;
>> > +}
>> > +
>> > +/**
>> >  * omap_vp_get_curr_volt() - API to get the current vp voltage.
>> >  * @voltdm:    pointer to the VDD.
>> >  *
>> > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
>> > index b6333ae..dba7939 100644
>> > --- a/arch/arm/plat-omap/Kconfig
>> > +++ b/arch/arm/plat-omap/Kconfig
>> > @@ -67,6 +67,23 @@ config OMAP_SMARTREFLEX_CLASS3
>> >          Class 3 implementation of Smartreflex employs continuous hardware
>> >          voltage calibration.
>> >
>> > +config OMAP_SMARTREFLEX_CLASS1P5
>> > +       bool "Class 1.5 mode of Smartreflex Implementation"
>> > +       depends on OMAP_SMARTREFLEX && TWL4030_CORE
>> > +       help
>> > +         Say Y to enable Class 1.5 implementation of Smartreflex
>> > +         Class 1.5 implementation of Smartreflex employs software controlled
>> > +         hardware voltage calibration.
>> > +
>> > +config OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
>> > +       int "Class 1.5 mode recalibration recalibration delay(ms)"
>> > +       depends on OMAP_SMARTREFLEX_CLASS1P5
>> > +       default 86400000
>> > +       help
>> > +         Setup the recalibration delay in milliseconds. Use 0 for never doing
>> > +         a recalibration. Defaults to recommended recalibration every 24hrs.
>> > +         If you do not understand this, use the default.
>> > +
>> >  config OMAP_RESET_CLOCKS
>> >        bool "Reset unused clocks during boot"
>> >        depends on ARCH_OMAP
>> > diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
>> > index 07f35b2..ee5c58f 100644
>> > --- a/arch/arm/plat-omap/include/plat/smartreflex.h
>> > +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
>> > @@ -167,6 +167,7 @@ struct omap_sr_pmic_data {
>> >  #define SR_CLASS1      0x1
>> >  #define SR_CLASS2      0x2
>> >  #define SR_CLASS3      0x3
>> > +#define SR_CLASS1P5    0x4
>> >
>> >  /**
>> >  * struct omap_sr_class_data - Smartreflex class driver info
>> > @@ -187,7 +188,9 @@ struct omap_sr_pmic_data {
>> >  struct omap_sr_class_data {
>> >        int (*enable)(struct voltagedomain *voltdm,
>> >                        struct omap_volt_data *volt_data);
>> > -       int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
>> > +       int (*disable)(struct voltagedomain *voltdm,
>> > +                       struct omap_volt_data *volt_data,
>> > +                       int is_volt_reset);
>> >        int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
>> >        int (*class_deinit)(struct voltagedomain *voltdm,
>> >                        void *class_priv_data);
>> > @@ -235,7 +238,8 @@ struct omap_sr_data {
>> >  /* Smartreflex module enable/disable interface */
>> >  void omap_sr_enable(struct voltagedomain *voltdm,
>> >                        struct omap_volt_data *volt_data);
>> > -void omap_sr_disable(struct voltagedomain *voltdm);
>> > +void omap_sr_disable(struct voltagedomain *voltdm,
>> > +                       struct omap_volt_data *volt_data);
>> >  void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
>> >
>> >  /* API to register the pmic specific data with the smartreflex driver. */
>> > @@ -250,6 +254,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm);
>> >
>> >  /* API to register the smartreflex class driver with the smartreflex driver */
>> >  int sr_register_class(struct omap_sr_class_data *class_data);
>> > +bool is_sr_enabled(struct voltagedomain *voltdm);
>> >  #else
>> >  static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
>> >  static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
>> > @@ -264,5 +269,9 @@ static inline void omap_sr_disable_reset_volt(
>> >                struct voltagedomain *voltdm) {}
>> >  static inline void omap_sr_register_pmic(
>> >                struct omap_sr_pmic_data *pmic_data) {}
>> > +static inline bool is_sr_enabled(struct voltagedomain *voltdm)
>> > +{
>> > +       return false;
>> > +}
>> >  #endif
>> >  #endif
>> > diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
>> > index 332c581..54445f0 100644
>> > --- a/arch/arm/plat-omap/include/plat/voltage.h
>> > +++ b/arch/arm/plat-omap/include/plat/voltage.h
>> > @@ -58,6 +58,8 @@
>> >  #define OMAP4430_VDD_CORE_OPP50_UV             930000
>> >  #define OMAP4430_VDD_CORE_OPP100_UV            1100000
>> >
>> > +#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV    50000
>> > +
>> >  /**
>> >  * struct voltagedomain - omap voltage domain global structure.
>> >  * @name:      Name of the voltage domain which can be used as a unique
>> > @@ -81,6 +83,8 @@ struct voltagedomain {
>> >  */
>> >  struct omap_volt_data {
>> >        u32     volt_nominal;
>> > +       u32     volt_calibrated;
>> > +       u32     volt_dynamic_nominal;
>> >        u32     sr_efuse_offs;
>> >        u8      sr_errminlimit;
>> >        u8      vp_errgain;
>> > @@ -127,6 +131,7 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
>> >  bool omap_vp_is_transdone(struct voltagedomain *voltdm);
>> >  bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
>> >  struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
>> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm);
>> >  #ifdef CONFIG_PM
>> >  int omap_voltage_register_pmic(struct voltagedomain *voltdm,
>> >                struct omap_volt_pmic_info *pmic_info);
>> > @@ -160,7 +165,23 @@ static inline unsigned long omap_get_operation_voltage(
>> >  {
>> >        if (IS_ERR_OR_NULL(vdata))
>> >                return 0;
>> > -       return vdata->volt_nominal;
>> > +       return (vdata->volt_calibrated) ? vdata->volt_calibrated :
>> > +               (vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
>> > +                       vdata->volt_nominal;
>> >  }
>> >
>> > +/* what is my dynamic nominal? */
>> > +static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
>> > +{
>> > +       if (IS_ERR_OR_NULL(vdata))
>> > +               return 0;
>> > +       if (vdata->volt_calibrated) {
>> > +               unsigned long v = vdata->volt_calibrated +
>> > +                       OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
>> > +               if (v > vdata->volt_nominal)
>> > +                       return vdata->volt_nominal;
>> > +               return v;
>> > +       }
>> > +       return vdata->volt_nominal;
>> > +}
>> >  #endif
>> > --
>> > 1.7.1
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> >
>> I have tested this Patch Series on OMAP 3630 SDP,  for MPU and IVA Powerdomains
> Could you clarify on null pointer issue: on SDP3630? or OMAP4SDP? I
> see there is a risk with OMAP4 where there is a bug in the following
> scenario:
> bootloader setups the OPP frequency for an OPP(e.g. 1GHz) which is
> disabled by default on OPP table in kernel. this needs to be cleanly
> fixed in pm.c, at the same time, the exposed functions in class1p5
> needs parameter validation as well.
Sorry, it is reproduced on OMAP 4430 SDP.
>> it throws error log "Unable to refer to NULL pointer" if
>> curr_nominal_volt, curr_calibrated_volt
>> or curr_dynamical_volt is accessed through debugfs.
>> Could you please provide fix for this.
>
>
> Regards,
> Nishanth Menon
>



-- 
Thanks,
Regards,
Shweta
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 01/19] omap3: hwmod: add smartreflex irqs
  2011-02-19 12:01 ` [PATCH 01/19] omap3: hwmod: add smartreflex irqs Nishanth Menon
@ 2011-03-02 23:48   ` Kevin Hilman
  2011-03-03  0:43     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-02 23:48 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> OMAP3 smartreflex irqs in hwmod structures with the same naming as
> present in OMAP4. Without these IRQs being registered, SmartReflex
> driver will be unable to get the irq numbers to handle notifications
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

minor: IRQ is an acronym, please capitalize consistenly throughout.

I know we haven't been too consitent about this but OMAP is also an
acronym, please capitialize (c.f. $SUBJECT).  This goes for the whole
series.

Otherwise patch looks fine.

Kevin

> ---
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   17 +++++++++++++++++
>  1 files changed, 17 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> index 8d81813..ea1f49a 100644
> --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
> @@ -265,6 +265,15 @@ static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = {
>  	.user		= OCP_USER_MPU | OCP_USER_SDMA,
>  };
>  
> +
> +static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
> +	{.name = "sr1_irq", .irq = 18},
> +};
> +
> +static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
> +	{.name = "sr2_irq", .irq = 19},
> +};
> +
>  /* L4 CORE -> SR1 interface */
>  static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
>  	{
> @@ -1289,6 +1298,8 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
>  					CHIP_IS_OMAP3430ES3_0 |
>  					CHIP_IS_OMAP3430ES3_1),
>  	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
> +	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
> +	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_mpu_irqs),
>  };
>  
>  static struct omap_hwmod omap36xx_sr1_hwmod = {
> @@ -1308,6 +1319,8 @@ static struct omap_hwmod omap36xx_sr1_hwmod = {
>  	.slaves		= omap3_sr1_slaves,
>  	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
>  	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
> +	.mpu_irqs	= omap3_smartreflex_mpu_irqs,
> +	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_mpu_irqs),
>  };
>  
>  /* SR2 */
> @@ -1335,6 +1348,8 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
>  					CHIP_IS_OMAP3430ES3_0 |
>  					CHIP_IS_OMAP3430ES3_1),
>  	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
> +	.mpu_irqs	= omap3_smartreflex_core_irqs,
> +	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_core_irqs),
>  };
>  
>  static struct omap_hwmod omap36xx_sr2_hwmod = {
> @@ -1354,6 +1369,8 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
>  	.slaves		= omap3_sr2_slaves,
>  	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
>  	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
> +	.mpu_irqs	= omap3_smartreflex_core_irqs,
> +	.mpu_irqs_cnt	= ARRAY_SIZE(omap3_smartreflex_core_irqs),
>  };
>  
>  static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-02-23  9:08             ` Menon, Nishanth
@ 2011-03-02 23:52               ` Kevin Hilman
  2011-03-03  0:35                 ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-02 23:52 UTC (permalink / raw)
  To: Menon, Nishanth; +Cc: Vishwanath Sripathy, linux-omap, Tony Lindgren

"Menon, Nishanth" <nm@ti.com> writes:

> On Wed, Feb 23, 2011 at 14:29, Vishwanath Sripathy <vishwanath.bs@ti.com> wrote:
>>> -----Original Message-----
>>> From: Menon, Nishanth [mailto:nm@ti.com]
>>> Sent: Wednesday, February 23, 2011 1:48 PM
>>> To: Vishwanath Sripathy
>>> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>>> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>>>
>>>  Wed, Feb 23, 2011 at 12:24, Vishwanath Sripathy
>>> <vishwanath.bs@ti.com> wrote:
>>> >> -----Original Message-----
>>> >> From: Nishanth Menon [mailto:nm@ti.com]
>>> >> Sent: Sunday, February 20, 2011 10:42 AM
>>> >> To: Vishwanath Sripathy
>>> >> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>>> >> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>>> >>
>>> >> Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
>>> >> [..]
>>> >> >> omap2_set_init_voltage should setup the curr_volt based on
>>> which
>>> >> OPP
>>> >> >> the system is functioning at. Blindly setting a 1.2v setting in
>> the
>>> >> >> initial structure may not even match the default voltages stored
>>> in
>>> >> >> the voltage table which are supported for the domain.
>>> >> >>
>>> >> >> For example, OMAP3430 core domain does not use 1.2v and ends
>>> up
>>> >> >> generating a warning on the first transition.
>>> >> >>
>>> >> [..]
>>> >> >> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
>>> >> >> omap2/voltage.c
>>> >> >> index 12be525..280ee12 100644
>>> >> >> --- a/arch/arm/mach-omap2/voltage.c
>>> >> >> +++ b/arch/arm/mach-omap2/voltage.c
>>> >> [..]
>>> >> >>    /* Generic voltage parameters */
>>> >> >> -  vdd->curr_volt = 1200000;
>>> >> > Where do you update this parameter upon initialization? Shouldn't
>>> you
>>> >> read
>>> >> > the VP register and find the actual current voltage and update this
>>> >> param?
>>> >>
>>> >> The sequence is as follows:
>>> >> a) omapx_vdd_data configure is called as part of sr init sequence.
>>> >>       And the curr_volt with this patch is not updated at this stage.
>>> >> b) somewhere down in the boot sequence, pm.c's
>>> >> omap2_set_init_voltage
>>> >> starts up. This looks up the current clk frequency from clock layer
>> of
>>> >> the parent device for the domain, picks up the nominal voltages
>>> stored
>>> >> in the opp layer, then does a omap_voltage_scale_vdd to that
>>> voltage. In
>>> >> omap_voltage_scale_vdd, The current voltage is merely picked off
>>> the vp
>>> >> (in _pre_volt_scale). the last step it does is to setup
>> vdd->curr_volt.
>>> >> This can then be used by dvfs layer etc to make appropriate
>>> decisions.
>>> >>
>>> >> So, No, I dont think I need to update it here, it should happen as
>>> part
>>> >> of the pm init sequence.
>>> >>
>>> >> Could you explain what problem do you foresee by doing this?
>>> > What if omap_voltage_scale_vdd fails when called from
>>> > omap2_set_init_voltage? Or omap2_set_init_voltage returns error
>>> even
>>> > before calling omap_voltage_scale_vdd because it could not find the
>>> > matching voltage for the frequency set by bootloader?
>>> >
>>> > Your assumption that curr_volt is always set by
>>> omap2_set_init_voltage
>>> > need not be true always.
>>>
>>> set_init_voltage's job is to set the initial voltage. if it is
>>> incapable of doing it, I say fix that instead of hacking in some
>>> random number as curr_volt.
>> I never said to use random numbers. All I suggested was that instead of
>> relying on some others function's behavior, read the VP register to fill
>> in the right values. If set_init_voltage succeeds, it will anyway update
>> with right voltage.
> OK, lets take this argument for a moment.
> Q: which voltage to set as curr_volt?
> a) what if the update was done over vcbypass by bootloader? Cannot
> trust the vp register for the value.
> b) what if the voltage was updated over i2c1 to the PMIC by
> bootloader? cant trust vp register again.
> c) use some number like 1.2v - which we are aligned is wrong.
>
> in short, what should we do for a accurate curr_volt? vp register may
> not be correct, instead, the right steps to do:
> find my current freq, check the OPP table for the voltage needed,
> setup the voltage for it, update curr_volt for it. this is trust
> worthy, rest are not.
>
> This is what set_init_voltage does, replicating that logic in
> voltage.c makes no sense again to me.

Agreed.

Please update the changelog with a summary of how curr_volt is properly
updated so it's clear that you're not removing something that isn't
updated elsewhere.

Thanks,

Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 08/19] omap3+: sr: make notify independent of class
  2011-02-19 12:01 ` [PATCH 08/19] omap3+: sr: make notify independent of class Nishanth Menon
@ 2011-03-03  0:05   ` Kevin Hilman
  0 siblings, 0 replies; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:05 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> Interrupt notification mechanism of SmartReflex can be used by the
> choice of implementation of the class driver. For example, Class 2 and
> Class 1.5 of SmartReflex can both use the interrupt notification to
> identify the transition of voltage or other events.
>
> Hence, the actual class does not matter for notifier. Let the class
> driver's handling decide how it should be used. smartreflex driver
> should provide just the primitives.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

Thanks, queueing for 2.6.39 after capitalizing OMAP & SR in subject.

Kevin

> ---
>  arch/arm/mach-omap2/smartreflex.c |    6 ++----
>  1 files changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> index eba90a4..6f0c7d0 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -142,7 +142,7 @@ static irqreturn_t sr_interrupt(int irq, void *data)
>  		sr_write_reg(sr_info, IRQSTATUS, status);
>  	}
>  
> -	if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
> +	if (sr_class->notify)
>  		sr_class->notify(sr_info->voltdm, status);
>  
>  	return IRQ_HANDLED;
> @@ -257,9 +257,7 @@ static int sr_late_init(struct omap_sr *sr_info)
>  	struct resource *mem;
>  	int ret = 0;
>  
> -	if (sr_class->class_type == SR_CLASS2 &&
> -		sr_class->notify_flags && sr_info->irq) {
> -
> +	if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
>  		name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
>  		if (name == NULL) {
>  			ret = -ENOMEM;

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data
  2011-02-19 12:01 ` [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data Nishanth Menon
@ 2011-03-03  0:08   ` Kevin Hilman
  2011-03-03  0:41     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:08 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> Certain class drivers such as class 1.5 drivers, will need specific
> notification that they have to be started up or stopped independent
> of smart reflex operation. They also may need private data to be
> used for operations of their own, provide the same.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

Basic principle looks fine, but some naming comments below...

[...]

> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
> index 6568c88..8b6ecd9 100644
> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> @@ -167,6 +167,8 @@ struct omap_sr_pmic_data {
>   *
>   * @enable:		API to enable a particular class smaartreflex.
>   * @disable:		API to disable a particular class smartreflex.
> + * @class_init:		API to do class specific initialization (optional)
> + * @class_deinit:	API to do class specific initialization (optional)

The 'class_' prefix here is not needed.

The changelog uses 'start' and 'stop' instead of init & deinit.  I
prefer those names to [de]init.

Kevin

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 10/19] omap3+: sr: fix cosmetic indentation
  2011-02-19 12:01 ` [PATCH 10/19] omap3+: sr: fix cosmetic indentation Nishanth Menon
@ 2011-03-03  0:09   ` Kevin Hilman
  0 siblings, 0 replies; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:09 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> Error label case seems to have a 2 tab indentation when just 1 is
> necessary.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

Thanks, queueing for 2.6.39 after capitalizing OMAP and SR in subject.

Kevin

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 11/19] omap3+: sr: call handler with interrupt disabled
  2011-02-19 12:01 ` [PATCH 11/19] omap3+: sr: call handler with interrupt disabled Nishanth Menon
@ 2011-03-03  0:11   ` Kevin Hilman
  2011-03-03  0:46     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:11 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> Request the handler irq such that there is no nesting for calls.
> the notifiers are not expected to be nested, further the interrupt
> events for status change should be handled prior to the next event
> else there is a risk of loosing events.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

IRQs disabled interrupt handlers are soon to disappear in the kernel.

This kind of thing should be handled using locking, most likely IRQs
disabled spinlocks.

Kevin

> ---
>  arch/arm/mach-omap2/smartreflex.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> index 1fe8b95..7931fcd 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -278,7 +278,7 @@ static int sr_late_init(struct omap_sr *sr_info)
>  			goto error;
>  		}
>  		ret = request_irq(sr_info->irq, sr_interrupt,
> -				0, name, (void *)sr_info);
> +				IRQF_DISABLED, name, (void *)sr_info);
>  		if (ret)
>  			goto error;
>  	}

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 12/19] omap3+: sr: disable interrupt by default
  2011-02-19 12:01 ` [PATCH 12/19] omap3+: sr: disable interrupt by default Nishanth Menon
@ 2011-03-03  0:15   ` Kevin Hilman
  2011-03-03  0:26     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:15 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> We will enable and disable interrupt on a need basis in the class
> driver. we need to keep the irq disabled by default else the
> forceupdate or vcbypass events could trigger events that we dont
> need/expect to handle.

It's not clear from the patch where the IRQ is re-enabled.  For example,
without knowing better, I would expect a corresponding change to the
Class 3 driver to enable/disable the IRQ as needed.

Kevin


> Signed-off-by: Nishanth Menon <nm@ti.com>
> ---
>  arch/arm/mach-omap2/smartreflex.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> index 7931fcd..9c61ab0 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -281,6 +281,7 @@ static int sr_late_init(struct omap_sr *sr_info)
>  				IRQF_DISABLED, name, (void *)sr_info);
>  		if (ret)
>  			goto error;
> +		disable_irq(sr_info->irq);
>  	}
>  
>  	if (pdata && pdata->enable_on_init)

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 14/19] omap3+: sr: introduce notifiers flags
  2011-02-19 12:01 ` [PATCH 14/19] omap3+: sr: introduce notifiers flags Nishanth Menon
@ 2011-03-03  0:17   ` Kevin Hilman
  2011-03-03  0:47     ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:17 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> SmartReflex IP v1 and v2 have different registers and offsets.
> Currently, we pass the status as is to the class driver. However,
> since we dont pass the version of the underlying SR hardware
> to the Class driver, it will not be unable to make consistent
> sense of the status bits coming over to it.
>
> A class driver should be able to function without dependency
> on the exact IP version it is actually running on. We hence
> introduce our own translation in s/w level for a generic
> notification flag.
>
> As part of this change, we will now call the notifier iff we get
> a match with the notifier flags that the class driver requested.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

Looks fine, minor comment below...

[...]

> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
> index 8b6ecd9..ff07d1e 100644
> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> @@ -141,6 +141,12 @@
>  #define OMAP3430_SR_ERRWEIGHT		0x04
>  #define OMAP3430_SR_ERRMAXLIMIT		0x02
>  
> +/* Smart reflex notifiers for class drivers to use */
> +#define SR_NOTIFY_MCUACCUM     (0x1 << 0)
> +#define SR_NOTIFY_MCUVALID     (0x1 << 1)
> +#define SR_NOTIFY_MCUBOUND     (0x1 << 2)
> +#define SR_NOTIFY_MCUDISACK    (0x1 << 3)
> +

Please use BIT(x)

Kevin

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 16/19] omap3+: sr: disable spamming interrupts
  2011-02-19 12:01 ` [PATCH 16/19] omap3+: sr: disable spamming interrupts Nishanth Menon
@ 2011-03-03  0:21   ` Kevin Hilman
  0 siblings, 0 replies; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:21 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> At times with bad SR configurations especially during silicon bringups,
> we could get continuous spurious interrupts which end up hanging the
> platform in the form of an ISR call for status bits that are
> automatically enabled by the h/w without any s/w clearing option.
>
> If we detect scenarios where isr was called without the corresponding

minor: please capitalize ISR consistently throughout.

> notification bit being set, instead of hanging up the system,
> we will disable interrupt after noting the event in the system log
> to try and keep system sanity and allow developer to debug and fix
> the condition.
>
> Signed-off-by: Nishanth Menon <nm@ti.com>

otherwise, patch looks fine.

Kevin

> ---
>  arch/arm/mach-omap2/smartreflex.c |   12 ++++++++++--
>  1 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> index ad23b8d..0301186 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -209,8 +209,16 @@ static irqreturn_t sr_interrupt(int irq, void *data)
>  		value = irqstat_to_notifier_v2(status);
>  	}
>  
> -	if (sr_class->notify)
> -		sr_class->notify(sr_info->voltdm, value);
> +	/* Attempt some resemblence of recovery! */
> +	if (!value) {
> +		dev_err(&sr_info->pdev->dev, "%s: Spurious interrupt!"
> +			"status = 0x%08x. Disabling to prevent spamming!!\n",
> +			__func__, status);
> +		disable_irq_nosync(sr_info->irq);
> +	} else {
> +		if (sr_class->notify)
> +			sr_class->notify(sr_info->voltdm, value);
> +	}
>  
>  	return IRQ_HANDLED;
>  }

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 12/19] omap3+: sr: disable interrupt by default
  2011-03-03  0:15   ` Kevin Hilman
@ 2011-03-03  0:26     ` Nishanth Menon
  2011-03-03  0:59       ` Kevin Hilman
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:26 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 05:45 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>> We will enable and disable interrupt on a need basis in the class
>> driver. we need to keep the irq disabled by default else the
>> forceupdate or vcbypass events could trigger events that we dont
>> need/expect to handle.
>
> It's not clear from the patch where the IRQ is re-enabled.  For example,
> without knowing better, I would expect a corresponding change to the
> Class 3 driver to enable/disable the IRQ as needed.

Why would that be?
a) class 3 driver does not request for any notifiers
b) class 3 does'nt need interrupts.
c) each class driver can choose to enable when it needs it - class3 does'nt.

is it fine if I add a "this is a preperation for class drivers such as 
class 2 and class 1.5 which would need to use interrupts" in commit message?

>
> Kevin
>
>
>> Signed-off-by: Nishanth Menon<nm@ti.com>
>> ---
>>   arch/arm/mach-omap2/smartreflex.c |    1 +
>>   1 files changed, 1 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
>> index 7931fcd..9c61ab0 100644
>> --- a/arch/arm/mach-omap2/smartreflex.c
>> +++ b/arch/arm/mach-omap2/smartreflex.c
>> @@ -281,6 +281,7 @@ static int sr_late_init(struct omap_sr *sr_info)
>>   				IRQF_DISABLED, name, (void *)sr_info);
>>   		if (ret)
>>   			goto error;
>> +		disable_irq(sr_info->irq);
>>   	}
>>
>>   	if (pdata&&  pdata->enable_on_init)


-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 00/19] OMAP3+: introduce SR class 1.5
  2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
                   ` (18 preceding siblings ...)
  2011-02-19 12:01 ` [PATCH 19/19] omap3430: sr: class3: restrict cpu to run on Nishanth Menon
@ 2011-03-03  0:33 ` Kevin Hilman
  2011-03-03  0:37   ` Nishanth Menon
  19 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:33 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Hi Nishanth,

Nishanth Menon <nm@ti.com> writes:

> Hi,
> This series intends to introduce SmartReflex AVS Class 1.5 support which
> is now the recommended AVS class for usage in OMAP3630, OMAP4 an potentially
> in later generation of silicon as well. Smartreflex class 1.5 is a software
> controlled hardware calibration mechanism designed to improve dvfs latencies
> and system performance as well as helping bring in additional benefits to the
> system from h/w perspective. The corresponding patch has details on this class
> and the implementation as well.

In addition to some specific comments given on individual patches, I
a couple of general, nit-picky comments:

- Please capitalize acronyms throughout the
  subjects/comments/changelogs.  This series tends to mix lower-case and
  upper case acronyms

- Please Cc linux-arm-kernel for patches intended for mainline.  Because
  of this, I didn't (yet) queue the ones I said I would queue. 

- Please rebase this on top of my pm-core branch (or Paul's
  integration-2.6.39 branch if you prefer.)  There are some important
  voltage related re-organization happening there that affects your code.

Kevin

> The series eventually results in OMAP343x based platforms using class3 and
> OMAP3630, OMAP4 platforms using class1.5 automatically without modifications
> or additions to board files.
>
> This series is Based on:
> a) k.org 2.6.38-rc5 (b2.6.38-rc5)
> b) The following branches Kevin Hilman's tree: (pm-base)
>  'pm/for_2.6.38/pm-fixes', 'pm/for_2.6.39/pm-misc' and 'pm/pm-wip/cpufreq'
>  http://git.kernel.org/?p=linux/kernel/git/khilman/linux-omap-pm.git;a=summary
> c) sr-fixes: (sr-baseline)
> 	http://marc.info/?l=linux-omap&m=129783708019505&w=2
> 	http://marc.info/?l=linux-omap&m=129679846322563&w=2
>
> This series is also available at:
> 	git://gitorious.org/linux-omap-nm-sr/linux-omap-sr.git
> 	Branch: sr-1.5-v1
>
> Note: There is also a branch sr-dvfs-1.5 in my tree which contains the test
> version of code which is based off Vishwa's DVFS series which is currently
> being revamped. it may need few handtweaking for testing (esp selecting class
> at menuconfig level or by commenting out appropriate late_init).
>
> The series contains a bunch of bugfixes and improvements needed to introduce
> Smartreflex class 1.5.

> Nishanth Menon (19):
>   omap3: hwmod: add smartreflex irqs
>   omap3630: hwmod: sr: enable for higher ES
>   omap3+: voltage: remove initial voltage
>   omap3+: voltage: remove spurious pr_notice for debugfs
>   omap3+: voltage: use IS_ERR_OR_NULL
>   omap3+: voltage: use volt_data pointer instead values
>   omap3+: voltage: add transdone apis
>   omap3+: sr: make notify independent of class
>   omap3+: sr: introduce class init,deinit and priv data
>   omap3+: sr: fix cosmetic indentation
>   omap3+: sr: call handler with interrupt disabled
>   omap3+: sr: disable interrupt by default
>   omap3+: sr: enable/disable SR only on need
>   omap3+: sr: introduce notifiers flags
>   omap3+: sr: introduce notifier_control
>   omap3+: sr: disable spamming interrupts
>   omap3+: sr: make enable path use volt_data pointer
>   omap3630+: sr: add support for class 1.5
>   omap3430: sr: class3: restrict cpu to run on
>
>  arch/arm/mach-omap2/Makefile                  |    1 +
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c    |   25 +-
>  arch/arm/mach-omap2/pm.c                      |    3 +-
>  arch/arm/mach-omap2/smartreflex-class1p5.c    |  556 +++++++++++++++++++++++++
>  arch/arm/mach-omap2/smartreflex-class3.c      |   21 +-
>  arch/arm/mach-omap2/smartreflex.c             |  249 ++++++++++--
>  arch/arm/mach-omap2/voltage.c                 |  236 ++++++++---
>  arch/arm/plat-omap/Kconfig                    |   17 +
>  arch/arm/plat-omap/include/plat/smartreflex.h |   42 ++-
>  arch/arm/plat-omap/include/plat/voltage.h     |   36 ++-
>  10 files changed, 1062 insertions(+), 124 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/smartreflex-class1p5.c
>
> Testing performed:
> - basic boot tests on SDP3630 and SDP3430 - with bare series
> - Detailed dvfs tests with Viswha's series on SDP3430 and SDP3630
> - OMAP4 was'nt supported yet by dvfs series, so very restricted tests.
> - Build tests with and without each of SR classes, SMARTREFLEX enabled.
>
> Test Script: http://pastebin.mozilla.org/1080985
>
> I request any additional tests on Panda, BeagleXM, EVM platforms that folks
> may have. please feel free to comment and provide tested-by/Acked-by feedback
> before I take this ahead including l-a.
>
> Regards,
> Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-03-02 23:52               ` Kevin Hilman
@ 2011-03-03  0:35                 ` Nishanth Menon
  2011-03-03  0:53                   ` Kevin Hilman
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:35 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: Vishwanath Sripathy, linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 05:22 AM:
> "Menon, Nishanth"<nm@ti.com>  writes:
>
>> On Wed, Feb 23, 2011 at 14:29, Vishwanath Sripathy<vishwanath.bs@ti.com>  wrote:
>>>> -----Original Message-----
>>>> From: Menon, Nishanth [mailto:nm@ti.com]
>>>> Sent: Wednesday, February 23, 2011 1:48 PM
>>>> To: Vishwanath Sripathy
>>>> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>>>> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>>>>
>>>>   Wed, Feb 23, 2011 at 12:24, Vishwanath Sripathy
>>>> <vishwanath.bs@ti.com>  wrote:
>>>>>> -----Original Message-----
>>>>>> From: Nishanth Menon [mailto:nm@ti.com]
>>>>>> Sent: Sunday, February 20, 2011 10:42 AM
>>>>>> To: Vishwanath Sripathy
>>>>>> Cc: linux-omap; Tony Lindgren; Kevin Hilman
>>>>>> Subject: Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
>>>>>>
>>>>>> Vishwanath Sripathy wrote, on 02/19/2011 06:54 PM:
>>>>>> [..]
>>>>>>>> omap2_set_init_voltage should setup the curr_volt based on
>>>> which
>>>>>> OPP
>>>>>>>> the system is functioning at. Blindly setting a 1.2v setting in
>>> the
>>>>>>>> initial structure may not even match the default voltages stored
>>>> in
>>>>>>>> the voltage table which are supported for the domain.
>>>>>>>>
>>>>>>>> For example, OMAP3430 core domain does not use 1.2v and ends
>>>> up
>>>>>>>> generating a warning on the first transition.
>>>>>>>>
>>>>>> [..]
>>>>>>>> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
>>>>>>>> omap2/voltage.c
>>>>>>>> index 12be525..280ee12 100644
>>>>>>>> --- a/arch/arm/mach-omap2/voltage.c
>>>>>>>> +++ b/arch/arm/mach-omap2/voltage.c
>>>>>> [..]
>>>>>>>>     /* Generic voltage parameters */
>>>>>>>> -  vdd->curr_volt = 1200000;
>>>>>>> Where do you update this parameter upon initialization? Shouldn't
>>>> you
>>>>>> read
>>>>>>> the VP register and find the actual current voltage and update this
>>>>>> param?
>>>>>>
>>>>>> The sequence is as follows:
>>>>>> a) omapx_vdd_data configure is called as part of sr init sequence.
>>>>>>        And the curr_volt with this patch is not updated at this stage.
>>>>>> b) somewhere down in the boot sequence, pm.c's
>>>>>> omap2_set_init_voltage
>>>>>> starts up. This looks up the current clk frequency from clock layer
>>> of
>>>>>> the parent device for the domain, picks up the nominal voltages
>>>> stored
>>>>>> in the opp layer, then does a omap_voltage_scale_vdd to that
>>>> voltage. In
>>>>>> omap_voltage_scale_vdd, The current voltage is merely picked off
>>>> the vp
>>>>>> (in _pre_volt_scale). the last step it does is to setup
>>> vdd->curr_volt.
>>>>>> This can then be used by dvfs layer etc to make appropriate
>>>> decisions.
>>>>>>
>>>>>> So, No, I dont think I need to update it here, it should happen as
>>>> part
>>>>>> of the pm init sequence.
>>>>>>
>>>>>> Could you explain what problem do you foresee by doing this?
>>>>> What if omap_voltage_scale_vdd fails when called from
>>>>> omap2_set_init_voltage? Or omap2_set_init_voltage returns error
>>>> even
>>>>> before calling omap_voltage_scale_vdd because it could not find the
>>>>> matching voltage for the frequency set by bootloader?
>>>>>
>>>>> Your assumption that curr_volt is always set by
>>>> omap2_set_init_voltage
>>>>> need not be true always.
>>>>
>>>> set_init_voltage's job is to set the initial voltage. if it is
>>>> incapable of doing it, I say fix that instead of hacking in some
>>>> random number as curr_volt.
>>> I never said to use random numbers. All I suggested was that instead of
>>> relying on some others function's behavior, read the VP register to fill
>>> in the right values. If set_init_voltage succeeds, it will anyway update
>>> with right voltage.
>> OK, lets take this argument for a moment.
>> Q: which voltage to set as curr_volt?
>> a) what if the update was done over vcbypass by bootloader? Cannot
>> trust the vp register for the value.
>> b) what if the voltage was updated over i2c1 to the PMIC by
>> bootloader? cant trust vp register again.
>> c) use some number like 1.2v - which we are aligned is wrong.
>>
>> in short, what should we do for a accurate curr_volt? vp register may
>> not be correct, instead, the right steps to do:
>> find my current freq, check the OPP table for the voltage needed,
>> setup the voltage for it, update curr_volt for it. this is trust
>> worthy, rest are not.
>>
>> This is what set_init_voltage does, replicating that logic in
>> voltage.c makes no sense again to me.
>
> Agreed.
>
> Please update the changelog with a summary of how curr_volt is properly
> updated so it's clear that you're not removing something that isn't
> updated elsewhere.
>

Does the following sound any better?:
Blindly setting a 1.2v setting in the initial structure may not even 
match the default voltages stored in the voltage table which are 
supported for the domain. For example, OMAP3430 core domain does not use 
1.2v and ends up generating a warning on the first transition.

Further, since omap2_set_init_voltage is called as part of the pm 
framework's initialization sequence to configure the voltage required 
for the current OPP, the call does(and has to) setup the system 
voltage(curr_volt as a result) using the right mechanisms appropriate 
for the system at that point of time. This also overrides initialization 
we are currently doing in voltage.c  making it redundant. So remove the 
wrong and useless initialization.

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 00/19] OMAP3+: introduce SR class 1.5
  2011-03-03  0:33 ` [PATCH 00/19] OMAP3+: introduce SR class 1.5 Kevin Hilman
@ 2011-03-03  0:37   ` Nishanth Menon
  2011-03-03  1:00     ` Kevin Hilman
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:37 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 06:03 AM:
> - Please capitalize acronyms throughout the
>    subjects/comments/changelogs.  This series tends to mix lower-case and
>    upper case acronyms
Ack. thanks for catching it.

>
> - Please Cc linux-arm-kernel for patches intended for mainline.  Because
>    of this, I didn't (yet) queue the ones I said I would queue.
done that with v2 which I had happened to have posted yesterday :(:
http://marc.info/?l=linux-omap&m=129906334611444&w=2

>
> - Please rebase this on top of my pm-core branch (or Paul's
>    integration-2.6.39 branch if you prefer.)  There are some important
>    voltage related re-organization happening there that affects your code.
ok. will do that and integrate comments from v1 and v2 for v3..

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data
  2011-03-03  0:08   ` Kevin Hilman
@ 2011-03-03  0:41     ` Nishanth Menon
  2011-03-03  0:57       ` Kevin Hilman
  0 siblings, 1 reply; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:41 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 05:38 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>> Certain class drivers such as class 1.5 drivers, will need specific
>> notification that they have to be started up or stopped independent
>> of smart reflex operation. They also may need private data to be
>> used for operations of their own, provide the same.
>>
>> Signed-off-by: Nishanth Menon<nm@ti.com>
>
> Basic principle looks fine, but some naming comments below...
k, thx.

>
> [...]
>
>> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
>> index 6568c88..8b6ecd9 100644
>> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
>> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
>> @@ -167,6 +167,8 @@ struct omap_sr_pmic_data {
>>    *
>>    * @enable:		API to enable a particular class smaartreflex.
>>    * @disable:		API to disable a particular class smartreflex.
>> + * @class_init:		API to do class specific initialization (optional)
>> + * @class_deinit:	API to do class specific initialization (optional)
>
> The 'class_' prefix here is not needed.
ack.

>
> The changelog uses 'start' and 'stop' instead of init&  deinit.  I
> prefer those names to [de]init.

Would'nt start and stop cause confusion when mixed with existing 
enable/disable? does enable/start actually start the SR? intent here 
with init/deinit is to do class specific initialization or deinitialization.

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 01/19] omap3: hwmod: add smartreflex irqs
  2011-03-02 23:48   ` Kevin Hilman
@ 2011-03-03  0:43     ` Nishanth Menon
  0 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:43 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 05:18 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>> OMAP3 smartreflex irqs in hwmod structures with the same naming as
>> present in OMAP4. Without these IRQs being registered, SmartReflex
>> driver will be unable to get the irq numbers to handle notifications
>>
>> Signed-off-by: Nishanth Menon<nm@ti.com>
>
> minor: IRQ is an acronym, please capitalize consistenly throughout.
>
> I know we haven't been too consitent about this but OMAP is also an
> acronym, please capitialize (c.f. $SUBJECT).  This goes for the whole
> series.
here and elsewhere - will do with v3.. thanks for catching..

>
> Otherwise patch looks fine.

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 11/19] omap3+: sr: call handler with interrupt disabled
  2011-03-03  0:11   ` Kevin Hilman
@ 2011-03-03  0:46     ` Nishanth Menon
  0 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:46 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 05:41 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>> Request the handler irq such that there is no nesting for calls.
>> the notifiers are not expected to be nested, further the interrupt
>> events for status change should be handled prior to the next event
>> else there is a risk of loosing events.
>>
>> Signed-off-by: Nishanth Menon<nm@ti.com>
>
> IRQs disabled interrupt handlers are soon to disappear in the kernel.
>
> This kind of thing should be handled using locking, most likely IRQs
> disabled spinlocks.

http://marc.info/?t=129906354500012&r=1&w=2
Ack.. painfully made clear in l-a as well.. dropping this :(
>
> Kevin
>
>> ---
>>   arch/arm/mach-omap2/smartreflex.c |    2 +-
>>   1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
>> index 1fe8b95..7931fcd 100644
>> --- a/arch/arm/mach-omap2/smartreflex.c
>> +++ b/arch/arm/mach-omap2/smartreflex.c
>> @@ -278,7 +278,7 @@ static int sr_late_init(struct omap_sr *sr_info)
>>   			goto error;
>>   		}
>>   		ret = request_irq(sr_info->irq, sr_interrupt,
>> -				0, name, (void *)sr_info);
>> +				IRQF_DISABLED, name, (void *)sr_info);
>>   		if (ret)
>>   			goto error;
>>   	}


-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 14/19] omap3+: sr: introduce notifiers flags
  2011-03-03  0:17   ` Kevin Hilman
@ 2011-03-03  0:47     ` Nishanth Menon
  0 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  0:47 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 05:47 AM:
[..]
>
>> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
>> index 8b6ecd9..ff07d1e 100644
>> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
>> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
>> @@ -141,6 +141,12 @@
>>   #define OMAP3430_SR_ERRWEIGHT		0x04
>>   #define OMAP3430_SR_ERRMAXLIMIT		0x02
>>
>> +/* Smart reflex notifiers for class drivers to use */
>> +#define SR_NOTIFY_MCUACCUM     (0x1<<  0)
>> +#define SR_NOTIFY_MCUVALID     (0x1<<  1)
>> +#define SR_NOTIFY_MCUBOUND     (0x1<<  2)
>> +#define SR_NOTIFY_MCUDISACK    (0x1<<  3)
>> +
>
> Please use BIT(x)

Ack.

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 03/19] omap3+: voltage: remove initial voltage
  2011-03-03  0:35                 ` Nishanth Menon
@ 2011-03-03  0:53                   ` Kevin Hilman
  0 siblings, 0 replies; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:53 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: Vishwanath Sripathy, linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

[...]

>
> Does the following sound any better?:

Yes, thanks.

> Blindly setting a 1.2v setting in the initial structure may not even
> match the default voltages stored in the voltage table which are
> supported for the domain. For example, OMAP3430 core domain does not
> use 1.2v and ends up generating a warning on the first transition.
>
> Further, since omap2_set_init_voltage is called as part of the pm
> framework's initialization sequence to configure the voltage required
> for the current OPP, the call does(and has to) setup the system
> voltage(curr_volt as a result) using the right mechanisms appropriate
> for the system at that point of time. This also overrides
> initialization we are currently doing in voltage.c  making it
> redundant. So remove the wrong and useless initialization.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data
  2011-03-03  0:41     ` Nishanth Menon
@ 2011-03-03  0:57       ` Kevin Hilman
  2011-03-03  1:22         ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:57 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> Kevin Hilman wrote, on 03/03/2011 05:38 AM:
>> Nishanth Menon<nm@ti.com>  writes:
>>
>>> Certain class drivers such as class 1.5 drivers, will need specific
>>> notification that they have to be started up or stopped independent
>>> of smart reflex operation. They also may need private data to be
>>> used for operations of their own, provide the same.
>>>
>>> Signed-off-by: Nishanth Menon<nm@ti.com>
>>
>> Basic principle looks fine, but some naming comments below...
> k, thx.
>
>>
>> [...]
>>
>>> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
>>> index 6568c88..8b6ecd9 100644
>>> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
>>> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
>>> @@ -167,6 +167,8 @@ struct omap_sr_pmic_data {
>>>    *
>>>    * @enable:		API to enable a particular class smaartreflex.
>>>    * @disable:		API to disable a particular class smartreflex.
>>> + * @class_init:		API to do class specific initialization (optional)
>>> + * @class_deinit:	API to do class specific initialization (optional)
>>
>> The 'class_' prefix here is not needed.
> ack.
>
>>
>> The changelog uses 'start' and 'stop' instead of init&  deinit.  I
>> prefer those names to [de]init.
>
> Would'nt start and stop cause confusion when mixed with existing
> enable/disable? does enable/start actually start the SR? intent here
> with init/deinit is to do class specific initialization or
> deinitialization.

Well, one way or another, make the changelog consistent with the
function names.

To me though, start/stop has more meaning.  They are called from
sr_[start|stop]_vddautocomp, so using start/stop is consistent there.
Also, init is usually something done once (and doesn't have a de-init
counterpart) but here we're talking about something done for each 
sr_[start|stop]_vddautocomp()

Kevin



^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 12/19] omap3+: sr: disable interrupt by default
  2011-03-03  0:26     ` Nishanth Menon
@ 2011-03-03  0:59       ` Kevin Hilman
  2011-03-03  1:23         ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  0:59 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

> Kevin Hilman wrote, on 03/03/2011 05:45 AM:
>> Nishanth Menon<nm@ti.com>  writes:
>>
>>> We will enable and disable interrupt on a need basis in the class
>>> driver. we need to keep the irq disabled by default else the
>>> forceupdate or vcbypass events could trigger events that we dont
>>> need/expect to handle.
>>
>> It's not clear from the patch where the IRQ is re-enabled.  For example,
>> without knowing better, I would expect a corresponding change to the
>> Class 3 driver to enable/disable the IRQ as needed.
>
> Why would that be?
> a) class 3 driver does not request for any notifiers
> b) class 3 does'nt need interrupts.
> c) each class driver can choose to enable when it needs it - class3 does'nt.
>
> is it fine if I add a "this is a preperation for class drivers such as
> class 2 and class 1.5 which would need to use interrupts" in commit
> message?

Yes, also stating/summarizing that existing class driver (e.g. class 3)
does not use interrupts would be helpful.

Kevin

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 00/19] OMAP3+: introduce SR class 1.5
  2011-03-03  0:37   ` Nishanth Menon
@ 2011-03-03  1:00     ` Kevin Hilman
  2011-03-03  1:30       ` Nishanth Menon
  0 siblings, 1 reply; 64+ messages in thread
From: Kevin Hilman @ 2011-03-03  1:00 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: linux-omap, Tony Lindgren

Nishanth Menon <nm@ti.com> writes:

>>
>> - Please Cc linux-arm-kernel for patches intended for mainline.  Because
>>    of this, I didn't (yet) queue the ones I said I would queue.
> done that with v2 which I had happened to have posted yesterday :(:
> http://marc.info/?l=linux-omap&m=129906334611444&w=2

Doh, sorry.  

My backlog is deep enough that I hadn't seen your v2 yet. :/

Kevin

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data
  2011-03-03  0:57       ` Kevin Hilman
@ 2011-03-03  1:22         ` Nishanth Menon
  0 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  1:22 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 06:27 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>> Kevin Hilman wrote, on 03/03/2011 05:38 AM:
>>> Nishanth Menon<nm@ti.com>   writes:
>>>
>>>> Certain class drivers such as class 1.5 drivers, will need specific
>>>> notification that they have to be started up or stopped independent
>>>> of smart reflex operation. They also may need private data to be
>>>> used for operations of their own, provide the same.
>>>>
>>>> Signed-off-by: Nishanth Menon<nm@ti.com>
>>>
>>> Basic principle looks fine, but some naming comments below...
>> k, thx.
>>
>>>
>>> [...]
>>>
>>>> diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
>>>> index 6568c88..8b6ecd9 100644
>>>> --- a/arch/arm/plat-omap/include/plat/smartreflex.h
>>>> +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
>>>> @@ -167,6 +167,8 @@ struct omap_sr_pmic_data {
>>>>     *
>>>>     * @enable:		API to enable a particular class smaartreflex.
>>>>     * @disable:		API to disable a particular class smartreflex.
>>>> + * @class_init:		API to do class specific initialization (optional)
>>>> + * @class_deinit:	API to do class specific initialization (optional)
>>>
>>> The 'class_' prefix here is not needed.
>> ack.
>>
>>>
>>> The changelog uses 'start' and 'stop' instead of init&   deinit.  I
>>> prefer those names to [de]init.
>>
>> Would'nt start and stop cause confusion when mixed with existing
>> enable/disable? does enable/start actually start the SR? intent here
>> with init/deinit is to do class specific initialization or
>> deinitialization.
>
> Well, one way or another, make the changelog consistent with the
> function names.
>
> To me though, start/stop has more meaning.  They are called from
> sr_[start|stop]_vddautocomp, so using start/stop is consistent there.
> Also, init is usually something done once (and doesn't have a de-init
> counterpart) but here we're talking about something done for each
> sr_[start|stop]_vddautocomp()

fair enough - unless there are other dissenting voices, will switch to 
start/stop for the api name and add documentation in code to explain the 
need.

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 12/19] omap3+: sr: disable interrupt by default
  2011-03-03  0:59       ` Kevin Hilman
@ 2011-03-03  1:23         ` Nishanth Menon
  0 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  1:23 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 06:29 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>> Kevin Hilman wrote, on 03/03/2011 05:45 AM:
>>> Nishanth Menon<nm@ti.com>   writes:
>>>
>>>> We will enable and disable interrupt on a need basis in the class
>>>> driver. we need to keep the irq disabled by default else the
>>>> forceupdate or vcbypass events could trigger events that we dont
>>>> need/expect to handle.
>>>
>>> It's not clear from the patch where the IRQ is re-enabled.  For example,
>>> without knowing better, I would expect a corresponding change to the
>>> Class 3 driver to enable/disable the IRQ as needed.
>>
>> Why would that be?
>> a) class 3 driver does not request for any notifiers
>> b) class 3 does'nt need interrupts.
>> c) each class driver can choose to enable when it needs it - class3 does'nt.
>>
>> is it fine if I add a "this is a preperation for class drivers such as
>> class 2 and class 1.5 which would need to use interrupts" in commit
>> message?
>
> Yes, also stating/summarizing that existing class driver (e.g. class 3)
> does not use interrupts would be helpful.
Ack. will do in v3.

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 00/19] OMAP3+: introduce SR class 1.5
  2011-03-03  1:00     ` Kevin Hilman
@ 2011-03-03  1:30       ` Nishanth Menon
  0 siblings, 0 replies; 64+ messages in thread
From: Nishanth Menon @ 2011-03-03  1:30 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, Tony Lindgren

Kevin Hilman wrote, on 03/03/2011 06:30 AM:
> Nishanth Menon<nm@ti.com>  writes:
>
>>>
>>> - Please Cc linux-arm-kernel for patches intended for mainline.  Because
>>>     of this, I didn't (yet) queue the ones I said I would queue.
>> done that with v2 which I had happened to have posted yesterday :(:
>> http://marc.info/?l=linux-omap&m=129906334611444&w=2
>
> Doh, sorry.
>
> My backlog is deep enough that I hadn't seen your v2 yet. :/

nothing lost ;).. I guess we can skip it for the moment and look at v3 
later this week..

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 64+ messages in thread

end of thread, other threads:[~2011-03-03  1:30 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-19 12:01 [PATCH 00/19] OMAP3+: introduce SR class 1.5 Nishanth Menon
2011-02-19 12:01 ` [PATCH 01/19] omap3: hwmod: add smartreflex irqs Nishanth Menon
2011-03-02 23:48   ` Kevin Hilman
2011-03-03  0:43     ` Nishanth Menon
2011-02-19 12:01 ` [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES Nishanth Menon
2011-02-19 13:22   ` Vishwanath Sripathy
2011-02-20  5:26     ` Nishanth Menon
2011-02-20  5:38       ` do we need CHIP_GE_OMAP3630ES1in .oc? (was Re: [PATCH 02/19] omap3630: hwmod: sr: enable for higher ES) Nishanth Menon
2011-02-21  5:50         ` Anand Gadiyar
2011-02-19 12:01 ` [PATCH 03/19] omap3+: voltage: remove initial voltage Nishanth Menon
2011-02-19 13:24   ` Vishwanath Sripathy
2011-02-20  5:12     ` Nishanth Menon
2011-02-23  6:54       ` Vishwanath Sripathy
2011-02-23  8:18         ` Menon, Nishanth
2011-02-23  8:59           ` Vishwanath Sripathy
2011-02-23  9:08             ` Menon, Nishanth
2011-03-02 23:52               ` Kevin Hilman
2011-03-03  0:35                 ` Nishanth Menon
2011-03-03  0:53                   ` Kevin Hilman
2011-02-19 12:01 ` [PATCH 04/19] omap3+: voltage: remove spurious pr_notice for debugfs Nishanth Menon
2011-02-19 12:01 ` [PATCH 05/19] omap3+: voltage: use IS_ERR_OR_NULL Nishanth Menon
2011-02-19 12:01 ` [PATCH 06/19] omap3+: voltage: use volt_data pointer instead values Nishanth Menon
2011-02-24  5:28   ` Gulati, Shweta
2011-02-24  8:29     ` Gulati, Shweta
2011-02-24 17:22     ` Menon, Nishanth
2011-02-19 12:01 ` [PATCH 07/19] omap3+: voltage: add transdone apis Nishanth Menon
2011-02-19 12:01 ` [PATCH 08/19] omap3+: sr: make notify independent of class Nishanth Menon
2011-03-03  0:05   ` Kevin Hilman
2011-02-19 12:01 ` [PATCH 09/19] omap3+: sr: introduce class init,deinit and priv data Nishanth Menon
2011-03-03  0:08   ` Kevin Hilman
2011-03-03  0:41     ` Nishanth Menon
2011-03-03  0:57       ` Kevin Hilman
2011-03-03  1:22         ` Nishanth Menon
2011-02-19 12:01 ` [PATCH 10/19] omap3+: sr: fix cosmetic indentation Nishanth Menon
2011-03-03  0:09   ` Kevin Hilman
2011-02-19 12:01 ` [PATCH 11/19] omap3+: sr: call handler with interrupt disabled Nishanth Menon
2011-03-03  0:11   ` Kevin Hilman
2011-03-03  0:46     ` Nishanth Menon
2011-02-19 12:01 ` [PATCH 12/19] omap3+: sr: disable interrupt by default Nishanth Menon
2011-03-03  0:15   ` Kevin Hilman
2011-03-03  0:26     ` Nishanth Menon
2011-03-03  0:59       ` Kevin Hilman
2011-03-03  1:23         ` Nishanth Menon
2011-02-19 12:01 ` [PATCH 13/19] omap3+: sr: enable/disable SR only on need Nishanth Menon
2011-02-19 12:01 ` [PATCH 14/19] omap3+: sr: introduce notifiers flags Nishanth Menon
2011-03-03  0:17   ` Kevin Hilman
2011-03-03  0:47     ` Nishanth Menon
2011-02-19 12:01 ` [PATCH 15/19] omap3+: sr: introduce notifier_control Nishanth Menon
2011-02-19 13:40   ` Vishwanath Sripathy
2011-02-20  4:50     ` Nishanth Menon
2011-02-23  6:46       ` Vishwanath Sripathy
2011-02-23  8:14         ` Menon, Nishanth
2011-02-19 12:01 ` [PATCH 16/19] omap3+: sr: disable spamming interrupts Nishanth Menon
2011-03-03  0:21   ` Kevin Hilman
2011-02-19 12:01 ` [PATCH 17/19] omap3+: sr: make enable path use volt_data pointer Nishanth Menon
2011-02-19 12:01 ` [PATCH 18/19] omap3630+: sr: add support for class 1.5 Nishanth Menon
2011-03-01  9:53   ` Gulati, Shweta
2011-03-01 10:17     ` Menon, Nishanth
2011-03-01 12:20       ` Gulati, Shweta
2011-02-19 12:01 ` [PATCH 19/19] omap3430: sr: class3: restrict cpu to run on Nishanth Menon
2011-03-03  0:33 ` [PATCH 00/19] OMAP3+: introduce SR class 1.5 Kevin Hilman
2011-03-03  0:37   ` Nishanth Menon
2011-03-03  1:00     ` Kevin Hilman
2011-03-03  1:30       ` Nishanth Menon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox