linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support
@ 2010-12-20 16:59 Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 01/10] OMAP3: PM: Adding voltage " Thara Gopinath
                   ` (10 more replies)
  0 siblings, 11 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series introduces smartreflex and voltage driver support
for OMAP3430 and OMAP3630. SmartReflex modules do adaptive voltage
control for real-time voltage adjustments.

Originally all the functionalities introduced in this patch
were present in arch/arm/mach-omap2/smartreflex.c file in Kevin's
pm tree. This patch series does a major rewrite of this file
and introduces a separate voltage driver. Major contributors
to the original driver are

Eduardo Valentin (1):
      OMAP3: PM: SmartReflex: Fix scheduled while atomic problem

Kalle Jokiniemi (1):
      OMAP3: PM: SmartReflex driver integration

Kevin Hilman (2):
      temp: SR: IO_ADDRESS conversion
      OMAP: SR: OPP interfaces removed from OMAP PM layer

Nishanth Menon (1):
      omap3: pm: sr: replace get_opp with freq_to_opp

Paul Walmsley (2):
      OMAP SR: use opp_find_opp_by_opp_id()
      OMAP SR: use OPP API for OPP ID, remove direct access

Phil Carmody (2):
      OMAP3: PM: Don't do unnecessary searches in omap_sr_vdd*_autocomp_store
      OMAP3: PM: Early exit on invalid parameters

Rajendra Nayak (9):
      OMAP3: SR: Fix init voltage on OPP change
      OMAP3: SR: Update VDD1/2 voltages at boot
      OMAP3: SR: Use sysclk for SR CLKLENGTH calc
      OMAP3: SR: Reset voltage level on SR disable
      OMAP3: SR: Replace printk's with pr_* calls
      OMAP3: SR: Remove redundant defines
      OMAP3: SR: Fix SR driver to check for omap-pm return values
      OMAP3: PM: Put optimal SMPS stabilization delay
      OMAP3: SR: Wait for VP idle before a VP disable

Roger Quadros (4):
      OMAP3: PM: Fix Smartreflex when used with PM_NOOP layer
      OMAP3: PM: Make Smartreflex driver independent of SRF
      OMAP3: PM: Do not Enable SmartReflex if OPP tables not defined
      OMAP3: PM: Smartreflex: Fix VDD2 OPP determining logic

Romit Dasgupta (1):
      omap: pm: SR: use enum for OPP types

Teerth Reddy (1):
      OMAP3: SR: Replace SR_PASS/FAIL,SR_TRUE/FALSE

Tero Kristo (1):
      Smartreflex: Avoid unnecessary spam

This patch series is against pm-core branch of Kevin Hilman's 
OMAP PM tree with the following additional patch applied.
	https://patchwork.kernel.org/patch/421351/

The entire series with the dependencies are available at
        http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=summary
        head: kevin-pm-sr

This patch series has been tested on OMAP3430 SDP with omap2plus_defconfig
with the following menuconfig options enabled.
System type -> TI OMAP Implementations -> Smartreflex Support
System type -> TI OMAP Implementations ->
                Class 3 mode of Smartreflex Implementation

Major Changes in v6
	-Rebased to pm-core branch of Kevin Hilman's OMAP PM tree.

Major Changes in v5
	- Rebased to k.org 2.6.37-rc3
	- Rebased to Nishant Menon's latest opp patches
	- Voltage pmic info structure extended to include a
		vast set of PMIC dependent parameters.
	- Smartreflex software n-target values support
		removed from the kernel. Instead n-target
		values are exposed as debugfs entries which can
		be written into by the user if needed.
	- Introduced a new file arch/arm/mach-omap2/omap_twl.c
		for specifying OMAP and TWL related info for
		the voltage layer.
	- Remove default enabling of smartreflex autocompensation
		during boot on OMAP3430 ES3.1 chips. Instead
		an API is provided that can be called from
		board files in case autocompensation needs
		to be enabled during boot up itself.
	- Other review comments on v4

Thara Gopinath (10):
  OMAP3: PM: Adding voltage driver support.
  OMAP: Introduce voltage domain information in the hwmod structures
  OMAP3: PM: Adding smartreflex driver support.
  OMAP3: PM: Adding smartreflex device file.
  OMAP3: PM: Adding smartreflex hwmod data
  OMAP3: PM: Adding smartreflex class3 driver
  OMAP3: PM: Adding T2 enabling of smartreflex support
  OMAP3: PM: Register TWL4030 pmic info with the voltage driver.
  OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  OMAP3: PM: Program correct init voltages for VDD1 and VDD2

 arch/arm/mach-omap2/Makefile                  |    7 +-
 arch/arm/mach-omap2/control.h                 |   17 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c    |  176 ++++
 arch/arm/mach-omap2/omap_twl.c                |  111 +++
 arch/arm/mach-omap2/pm.c                      |   90 ++
 arch/arm/mach-omap2/pm.h                      |   23 +
 arch/arm/mach-omap2/smartreflex-class3.c      |   59 ++
 arch/arm/mach-omap2/smartreflex.c             | 1025 ++++++++++++++++++++
 arch/arm/mach-omap2/sr_device.c               |  131 +++
 arch/arm/mach-omap2/voltage.c                 | 1292 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   31 +
 arch/arm/plat-omap/include/plat/omap_hwmod.h  |    5 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  245 +++++
 arch/arm/plat-omap/include/plat/voltage.h     |  134 +++
 drivers/mfd/twl-core.c                        |   13 +
 include/linux/i2c/twl.h                       |   11 +
 16 files changed, 3369 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/omap_twl.c
 create mode 100644 arch/arm/mach-omap2/smartreflex-class3.c
 create mode 100644 arch/arm/mach-omap2/smartreflex.c
 create mode 100644 arch/arm/mach-omap2/sr_device.c
 create mode 100644 arch/arm/mach-omap2/voltage.c
 create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h
 create mode 100644 arch/arm/plat-omap/include/plat/voltage.h

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

* [PATCH v6 01/10] OMAP3: PM: Adding voltage driver support.
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-22 22:29   ` Kevin Hilman
  2010-12-28 16:17   ` Anand Sawant
  2010-12-20 16:59 ` [PATCH v6 02/10] OMAP: Introduce voltage domain information in the hwmod structures Thara Gopinath
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds voltage driver support for OMAP3. The driver
allows  configuring the voltage controller and voltage
processors during init and exports APIs to enable/disable
voltage processors, scale voltage and reset voltage.
The driver maintains the global voltage table on a per
VDD basis which contains the various voltages supported by the
VDD along with per voltage dependent data like smartreflex
efuse offset, errminlimit and voltage processor errorgain.
The driver also allows the voltage parameters dependent on the
PMIC to be passed from the PMIC file through an API.
The driver allows scaling of VDD voltages either through
"vc bypass method" or through "vp forceupdate method" the
choice being configurable through the board file.

This patch contains code originally in linux omap pm branch
smartreflex driver.  Major contributors to this driver are
Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley,
Nishant Menon, Kevin Hilman. The separation of PMIC parameters
into a separate structure which can be populated from
the PMIC file is based on the work of Lun Chang from Motorola
in an internal tree.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
This patch has 14 checkpatch.pl above 80-chars warnings for
the definitions of omap34xx_vddmpu_volt_data, omap36xx_vddmpu_volt_data,
omap34xx_vddcore_volt_data and omap36xx_vddcore_volt_data structures.
IMHO splitting of the entries in these structures affects
readability and looks very ugly. Hence they are left as is.

 arch/arm/mach-omap2/Makefile              |    3 +-
 arch/arm/mach-omap2/control.h             |   17 +
 arch/arm/mach-omap2/pm.c                  |    8 +
 arch/arm/mach-omap2/voltage.c             | 1226 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/voltage.h |  134 ++++
 5 files changed, 1387 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/voltage.c
 create mode 100644 arch/arm/plat-omap/include/plat/voltage.h

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 7c79683..5034797 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -57,7 +57,8 @@ endif
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o pm_bus.o
-obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o cpuidle34xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
+					   cpuidle34xx.o pm_bus.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o pm_bus.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index 5289461..9fe32dc 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -148,6 +148,15 @@
 #define OMAP343X_CONTROL_TEST_KEY_11	(OMAP2_CONTROL_GENERAL + 0x00f4)
 #define OMAP343X_CONTROL_TEST_KEY_12	(OMAP2_CONTROL_GENERAL + 0x00f8)
 #define OMAP343X_CONTROL_TEST_KEY_13	(OMAP2_CONTROL_GENERAL + 0x00fc)
+#define OMAP343X_CONTROL_FUSE_OPP1_VDD1 (OMAP2_CONTROL_GENERAL + 0x0110)
+#define OMAP343X_CONTROL_FUSE_OPP2_VDD1 (OMAP2_CONTROL_GENERAL + 0x0114)
+#define OMAP343X_CONTROL_FUSE_OPP3_VDD1 (OMAP2_CONTROL_GENERAL + 0x0118)
+#define OMAP343X_CONTROL_FUSE_OPP4_VDD1 (OMAP2_CONTROL_GENERAL + 0x011c)
+#define OMAP343X_CONTROL_FUSE_OPP5_VDD1 (OMAP2_CONTROL_GENERAL + 0x0120)
+#define OMAP343X_CONTROL_FUSE_OPP1_VDD2 (OMAP2_CONTROL_GENERAL + 0x0124)
+#define OMAP343X_CONTROL_FUSE_OPP2_VDD2 (OMAP2_CONTROL_GENERAL + 0x0128)
+#define OMAP343X_CONTROL_FUSE_OPP3_VDD2 (OMAP2_CONTROL_GENERAL + 0x012c)
+#define OMAP343X_CONTROL_FUSE_SR        (OMAP2_CONTROL_GENERAL + 0x0130)
 #define OMAP343X_CONTROL_IVA2_BOOTADDR	(OMAP2_CONTROL_GENERAL + 0x0190)
 #define OMAP343X_CONTROL_IVA2_BOOTMOD	(OMAP2_CONTROL_GENERAL + 0x0194)
 #define OMAP343X_CONTROL_DEBOBS(i)	(OMAP2_CONTROL_GENERAL + 0x01B0 \
@@ -164,6 +173,14 @@
 #define OMAP343X_CONTROL_SRAMLDO5	(OMAP2_CONTROL_GENERAL + 0x02C0)
 #define OMAP343X_CONTROL_CSI		(OMAP2_CONTROL_GENERAL + 0x02C4)
 
+/* OMAP3630 only CONTROL_GENERAL register offsets */
+#define OMAP3630_CONTROL_FUSE_OPP1G_VDD1        (OMAP2_CONTROL_GENERAL + 0x0110)
+#define OMAP3630_CONTROL_FUSE_OPP50_VDD1        (OMAP2_CONTROL_GENERAL + 0x0114)
+#define OMAP3630_CONTROL_FUSE_OPP100_VDD1       (OMAP2_CONTROL_GENERAL + 0x0118)
+#define OMAP3630_CONTROL_FUSE_OPP120_VDD1       (OMAP2_CONTROL_GENERAL + 0x0120)
+#define OMAP3630_CONTROL_FUSE_OPP50_VDD2        (OMAP2_CONTROL_GENERAL + 0x0128)
+#define OMAP3630_CONTROL_FUSE_OPP100_VDD2       (OMAP2_CONTROL_GENERAL + 0x012C)
+
 /* AM35XX only CONTROL_GENERAL register offsets */
 #define AM35XX_CONTROL_MSUSPENDMUX_6    (OMAP2_CONTROL_GENERAL + 0x0038)
 #define AM35XX_CONTROL_DEVCONF2         (OMAP2_CONTROL_GENERAL + 0x0310)
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 227a211..22adfb2 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -17,6 +17,7 @@
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
 #include <plat/common.h>
+#include <plat/voltage.h>
 
 #include "powerdomain.h"
 #include "clockdomain.h"
@@ -145,3 +146,10 @@ static int __init omap2_common_pm_init(void)
 }
 postcore_initcall(omap2_common_pm_init);
 
+static int __init omap2_common_pm_late_init(void)
+{
+	omap_voltage_late_init();
+
+	return 0;
+}
+late_initcall(omap2_common_pm_late_init);
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
new file mode 100644
index 0000000..875667f
--- /dev/null
+++ b/arch/arm/mach-omap2/voltage.c
@@ -0,0 +1,1226 @@
+/*
+ * OMAP3/OMAP4 Voltage Management Routines
+ *
+ * Author: Thara Gopinath	<thara@ti.com>
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * 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/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+
+#include <plat/common.h>
+#include <plat/voltage.h>
+
+#include "prm-regbits-34xx.h"
+#include "control.h"
+
+#define VP_IDLE_TIMEOUT		200
+#define VP_TRANXDONE_TIMEOUT	300
+#define VOLTAGE_DIR_SIZE	16
+
+/* Voltage processor register offsets */
+struct vp_reg_offs {
+	u8 vpconfig;
+	u8 vstepmin;
+	u8 vstepmax;
+	u8 vlimitto;
+	u8 vstatus;
+	u8 voltage;
+};
+
+/* Voltage Processor bit field values, shifts and masks */
+struct vp_reg_val {
+	/* PRM module */
+	u16 prm_mod;
+	/* VPx_VPCONFIG */
+	u32 vpconfig_erroroffset;
+	u16 vpconfig_errorgain;
+	u32 vpconfig_errorgain_mask;
+	u8 vpconfig_errorgain_shift;
+	u32 vpconfig_initvoltage_mask;
+	u8 vpconfig_initvoltage_shift;
+	u32 vpconfig_timeouten;
+	u32 vpconfig_initvdd;
+	u32 vpconfig_forceupdate;
+	u32 vpconfig_vpenable;
+	/* VPx_VSTEPMIN */
+	u8 vstepmin_stepmin;
+	u16 vstepmin_smpswaittimemin;
+	u8 vstepmin_stepmin_shift;
+	u8 vstepmin_smpswaittimemin_shift;
+	/* VPx_VSTEPMAX */
+	u8 vstepmax_stepmax;
+	u16 vstepmax_smpswaittimemax;
+	u8 vstepmax_stepmax_shift;
+	u8 vstepmax_smpswaittimemax_shift;
+	/* VPx_VLIMITTO */
+	u8 vlimitto_vddmin;
+	u8 vlimitto_vddmax;
+	u16 vlimitto_timeout;
+	u8 vlimitto_vddmin_shift;
+	u8 vlimitto_vddmax_shift;
+	u8 vlimitto_timeout_shift;
+	/* PRM_IRQSTATUS*/
+	u32 tranxdone_status;
+};
+
+/* Voltage controller registers and offsets */
+struct vc_reg_info {
+	/* PRM module */
+	u16 prm_mod;
+	/* VC register offsets */
+	u8 smps_sa_reg;
+	u8 smps_volra_reg;
+	u8 bypass_val_reg;
+	u8 cmdval_reg;
+	u8 voltsetup_reg;
+	/*VC_SMPS_SA*/
+	u8 smps_sa_shift;
+	u32 smps_sa_mask;
+	/* VC_SMPS_VOL_RA */
+	u8 smps_volra_shift;
+	u32 smps_volra_mask;
+	/* VC_BYPASS_VAL */
+	u8 data_shift;
+	u8 slaveaddr_shift;
+	u8 regaddr_shift;
+	u32 valid;
+	/* VC_CMD_VAL */
+	u8 cmd_on_shift;
+	u8 cmd_onlp_shift;
+	u8 cmd_ret_shift;
+	u8 cmd_off_shift;
+	u32 cmd_on_mask;
+	/* PRM_VOLTSETUP */
+	u8 voltsetup_shift;
+	u32 voltsetup_mask;
+};
+
+/**
+ * omap_vdd_info - Per Voltage Domain info
+ *
+ * @volt_data		: voltage table having the distinct voltages supported
+ *			  by the domain and other associated per voltage data.
+ * @pmic_info		: pmic specific parameters which should be populted by
+ *			  the pmic drivers.
+ * @vp_offs		: structure containing the offsets for various
+ *			  vp registers
+ * @vp_reg		: the register values, shifts, masks for various
+ *			  vp registers
+ * @vc_reg		: structure containing various various vc registers,
+ *			  shifts, masks etc.
+ * @voltdm		: pointer to the voltage domain structure
+ * @debug_dir		: debug directory for this voltage domain.
+ * @curr_volt		: current voltage for this vdd.
+ * @ocp_mod		: The prm module for accessing the prm irqstatus reg.
+ * @prm_irqst_reg	: prm irqstatus register.
+ * @vp_enabled		: flag to keep track of whether vp is enabled or not
+ * @volt_scale		: API to scale the voltage of the vdd.
+ */
+struct omap_vdd_info {
+	struct omap_volt_data *volt_data;
+	struct omap_volt_pmic_info *pmic_info;
+	struct vp_reg_offs vp_offs;
+	struct vp_reg_val vp_reg;
+	struct vc_reg_info vc_reg;
+	struct voltagedomain voltdm;
+	struct dentry *debug_dir;
+	u32 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);
+};
+
+static struct omap_vdd_info *vdd_info;
+/*
+ * Number of scalable voltage domains.
+ */
+static int nr_scalable_vdd;
+
+/* OMAP3 VDD sturctures */
+static struct omap_vdd_info omap3_vdd_info[] = {
+	{
+		.vp_offs = {
+			.vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET,
+			.vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
+			.vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
+			.vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
+			.vstatus = OMAP3_PRM_VP1_STATUS_OFFSET,
+			.voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
+		},
+		.voltdm = {
+			.name = "mpu",
+		},
+	},
+	{
+		.vp_offs = {
+			.vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET,
+			.vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
+			.vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
+			.vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
+			.vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
+			.voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
+		},
+		.voltdm = {
+			.name = "core",
+		},
+	},
+};
+
+#define OMAP3_NR_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)
+
+/*
+ * Structures containing OMAP3430/OMAP3630 voltage supported and various
+ * voltage dependent data for each VDD.
+ */
+#define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain)	\
+{									\
+	.volt_nominal	= _v_nom,					\
+	.sr_efuse_offs	= _efuse_offs,					\
+	.sr_errminlimit	= _errminlimit,					\
+	.vp_errgain	= _errgain					\
+}
+
+/* VDD1 */
+static struct omap_volt_data omap34xx_vddmpu_volt_data[] = {
+	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c),
+	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c),
+	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18),
+	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV, OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18),
+	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV, OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18),
+	VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+static struct omap_volt_data omap36xx_vddmpu_volt_data[] = {
+	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c),
+	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16),
+	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV, OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23),
+	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV, OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27),
+	VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+/* VDD2 */
+static struct omap_volt_data omap34xx_vddcore_volt_data[] = {
+	VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c),
+	VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c),
+	VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18),
+	VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+static struct omap_volt_data omap36xx_vddcore_volt_data[] = {
+	VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c),
+	VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16),
+	VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+static struct dentry *voltage_dir;
+
+/* Init function pointers */
+static void (*vc_init) (struct omap_vdd_info *vdd);
+static int (*vdd_data_configure) (struct omap_vdd_info *vdd);
+
+static u32 omap3_voltage_read_reg(u16 mod, u8 offset)
+{
+	return omap2_prm_read_mod_reg(mod, offset);
+}
+
+static void omap3_voltage_write_reg(u32 val, u16 mod, u8 offset)
+{
+	omap2_prm_write_mod_reg(val, mod, offset);
+}
+
+static void vp_latch_vsel(struct omap_vdd_info *vdd)
+{
+	u32 vpconfig;
+	u16 mod;
+	unsigned long uvdc;
+	char vsel;
+
+	uvdc = 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);
+		return;
+	}
+
+	if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
+		pr_warning("%s: PMIC function to convert voltage in uV to"
+			" vsel not registered\n", __func__);
+		return;
+	}
+
+	mod = vdd->vp_reg.prm_mod;
+
+	vsel = vdd->pmic_info->uv_to_vsel(uvdc);
+
+	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
+	vpconfig &= ~(vdd->vp_reg.vpconfig_initvoltage_mask |
+			vdd->vp_reg.vpconfig_initvdd);
+	vpconfig |= vsel << vdd->vp_reg.vpconfig_initvoltage_shift;
+
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+
+	/* Trigger initVDD value copy to voltage processor */
+	vdd->write_reg((vpconfig | vdd->vp_reg.vpconfig_initvdd), mod,
+			vdd->vp_offs.vpconfig);
+
+	/* Clear initVDD copy trigger bit */
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+}
+
+/* Generic voltage init functions */
+static void __init vp_init(struct omap_vdd_info *vdd)
+{
+	u32 vp_val;
+	u16 mod;
+
+	if (!vdd->read_reg || !vdd->write_reg) {
+		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+
+	mod = vdd->vp_reg.prm_mod;
+
+	vp_val = vdd->vp_reg.vpconfig_erroroffset |
+		(vdd->vp_reg.vpconfig_errorgain <<
+		vdd->vp_reg.vpconfig_errorgain_shift) |
+		vdd->vp_reg.vpconfig_timeouten;
+	vdd->write_reg(vp_val, mod, vdd->vp_offs.vpconfig);
+
+	vp_val = ((vdd->vp_reg.vstepmin_smpswaittimemin <<
+		vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
+		(vdd->vp_reg.vstepmin_stepmin <<
+		vdd->vp_reg.vstepmin_stepmin_shift));
+	vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmin);
+
+	vp_val = ((vdd->vp_reg.vstepmax_smpswaittimemax <<
+		vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
+		(vdd->vp_reg.vstepmax_stepmax <<
+		vdd->vp_reg.vstepmax_stepmax_shift));
+	vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmax);
+
+	vp_val = ((vdd->vp_reg.vlimitto_vddmax <<
+		vdd->vp_reg.vlimitto_vddmax_shift) |
+		(vdd->vp_reg.vlimitto_vddmin <<
+		vdd->vp_reg.vlimitto_vddmin_shift) |
+		(vdd->vp_reg.vlimitto_timeout <<
+		vdd->vp_reg.vlimitto_timeout_shift));
+	vdd->write_reg(vp_val, mod, vdd->vp_offs.vlimitto);
+}
+
+static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
+{
+	char *name;
+
+	name = kzalloc(VOLTAGE_DIR_SIZE, GFP_KERNEL);
+	if (!name) {
+		pr_warning("%s: Unable to allocate memory for debugfs"
+			" directory name for vdd_%s",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+	strcpy(name, "vdd_");
+	strcat(name, vdd->voltdm.name);
+
+	vdd->debug_dir = debugfs_create_dir(name, voltage_dir);
+	if (IS_ERR(vdd->debug_dir)) {
+		pr_warning("%s: Unable to create debugfs directory for"
+			" vdd_%s\n", __func__, vdd->voltdm.name);
+		vdd->debug_dir = NULL;
+	}
+}
+
+/* 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 *volt_data;
+	u32 vc_cmdval, vp_errgain_val;
+	u16 vp_mod, vc_mod;
+
+	/* 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",
+			__func__, vdd->voltdm.name);
+		return -EINVAL;
+	}
+
+	if (!vdd->pmic_info->uv_to_vsel) {
+		pr_err("%s: PMIC function to convert voltage in uV to"
+			"vsel not registered. Hence unable to scale voltage"
+			"for vdd_%s\n", __func__, vdd->voltdm.name);
+		return -ENODATA;
+	}
+
+	if (!vdd->read_reg || !vdd->write_reg) {
+		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
+			__func__, vdd->voltdm.name);
+		return -EINVAL;
+	}
+
+	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);
+	*current_vsel = vdd->read_reg(vp_mod, vdd->vp_offs.voltage);
+
+	/* Setting the ON voltage to the new target voltage */
+	vc_cmdval = vdd->read_reg(vc_mod, vdd->vc_reg.cmdval_reg);
+	vc_cmdval &= ~vdd->vc_reg.cmd_on_mask;
+	vc_cmdval |= (*target_vsel << vdd->vc_reg.cmd_on_shift);
+	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);
+	}
+
+	return 0;
+}
+
+static void _post_volt_scale(struct omap_vdd_info *vdd,
+		unsigned long target_volt, u8 target_vsel, u8 current_vsel)
+{
+	u32 smps_steps = 0, smps_delay = 0;
+
+	smps_steps = abs(target_vsel - current_vsel);
+	/* SMPS slew rate / step size. 2us added as buffer. */
+	smps_delay = ((smps_steps * vdd->pmic_info->step_size) /
+			vdd->pmic_info->slew_rate) + 2;
+	udelay(smps_delay);
+
+	vdd->curr_volt = target_volt;
+}
+
+/* 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)
+{
+	u32 loop_cnt = 0, retries_cnt = 0;
+	u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
+	u16 mod;
+	u8 target_vsel, current_vsel;
+	int ret;
+
+	ret = _pre_volt_scale(vdd, target_volt, &target_vsel, &current_vsel);
+	if (ret)
+		return ret;
+
+	mod = vdd->vc_reg.prm_mod;
+
+	vc_valid = vdd->vc_reg.valid;
+	vc_bypass_val_reg = vdd->vc_reg.bypass_val_reg;
+	vc_bypass_value = (target_vsel << vdd->vc_reg.data_shift) |
+			(vdd->pmic_info->pmic_reg <<
+			vdd->vc_reg.regaddr_shift) |
+			(vdd->pmic_info->i2c_slave_addr <<
+			vdd->vc_reg.slaveaddr_shift);
+
+	vdd->write_reg(vc_bypass_value, mod, vc_bypass_val_reg);
+	vdd->write_reg(vc_bypass_value | vc_valid, mod, vc_bypass_val_reg);
+
+	vc_bypass_value = vdd->read_reg(mod, vc_bypass_val_reg);
+	/*
+	 * Loop till the bypass command is acknowledged from the SMPS.
+	 * NOTE: This is legacy code. The loop count and retry count needs
+	 * to be revisited.
+	 */
+	while (!(vc_bypass_value & vc_valid)) {
+		loop_cnt++;
+
+		if (retries_cnt > 10) {
+			pr_warning("%s: Retry count exceeded\n", __func__);
+			return -ETIMEDOUT;
+		}
+
+		if (loop_cnt > 50) {
+			retries_cnt++;
+			loop_cnt = 0;
+			udelay(10);
+		}
+		vc_bypass_value = vdd->read_reg(mod, vc_bypass_val_reg);
+	}
+
+	_post_volt_scale(vdd, target_volt, target_vsel, current_vsel);
+	return 0;
+}
+
+/* VP force update method of voltage scaling */
+static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
+		unsigned long target_volt)
+{
+	u32 vpconfig;
+	u16 mod, ocp_mod;
+	u8 target_vsel, current_vsel, prm_irqst_reg;
+	int ret, timeout = 0;
+
+	ret = _pre_volt_scale(vdd, target_volt, &target_vsel, &current_vsel);
+	if (ret)
+		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))
+				break;
+		udelay(1);
+	}
+	if (timeout >= VP_TRANXDONE_TIMEOUT) {
+		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
+			"Voltage change aborted", __func__, vdd->voltdm.name);
+		return -ETIMEDOUT;
+	}
+
+	/* Configure for VP-Force Update */
+	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
+	vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
+			vdd->vp_reg.vpconfig_forceupdate |
+			vdd->vp_reg.vpconfig_initvoltage_mask);
+	vpconfig |= ((target_vsel <<
+			vdd->vp_reg.vpconfig_initvoltage_shift));
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+
+	/* Trigger initVDD value copy to voltage processor */
+	vpconfig |= vdd->vp_reg.vpconfig_initvdd;
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+
+	/* Force update of voltage */
+	vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+
+	/*
+	 * Wait for TransactionDone. Typical latency is <200us.
+	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
+	 */
+	timeout = 0;
+	omap_test_timeout((vdd->read_reg(ocp_mod, prm_irqst_reg) &
+			vdd->vp_reg.tranxdone_status),
+			VP_TRANXDONE_TIMEOUT, timeout);
+	if (timeout >= VP_TRANXDONE_TIMEOUT)
+		pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
+			"TRANXDONE never got set after the voltage update\n",
+			__func__, vdd->voltdm.name);
+
+	_post_volt_scale(vdd, target_volt, target_vsel, current_vsel);
+
+	/*
+	 * Disable TransactionDone interrupt , clear all status, clear
+	 * control registers
+	 */
+	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;
+		udelay(1);
+	}
+
+	if (timeout >= VP_TRANXDONE_TIMEOUT)
+		pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying"
+			"to clear the TRANXDONE status\n",
+			__func__, vdd->voltdm.name);
+
+	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
+	/* Clear initVDD copy trigger bit */
+	vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+	/* Clear force bit */
+	vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+
+	return 0;
+}
+
+/* OMAP3 specific voltage init functions */
+
+/*
+ * Intializes the voltage controller registers with the PMIC and board
+ * specific parameters and voltage setup times for OMAP3.
+ */
+static void __init omap3_vc_init(struct omap_vdd_info *vdd)
+{
+	u32 vc_val;
+	u16 mod;
+	u8 on_vsel, onlp_vsel, ret_vsel, off_vsel;
+	static bool is_initialized;
+
+	if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
+		pr_err("%s: PMIC info requried to configure vc for"
+			"vdd_%s not populated.Hence cannot initialize vc\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+
+	if (!vdd->read_reg || !vdd->write_reg) {
+		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+
+	mod = vdd->vc_reg.prm_mod;
+
+	/* Set up the SMPS_SA(i2c slave address in VC */
+	vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_sa_reg);
+	vc_val &= ~vdd->vc_reg.smps_sa_mask;
+	vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_reg.smps_sa_shift;
+	vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_sa_reg);
+
+	/* Setup the VOLRA(pmic reg addr) in VC */
+	vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_volra_reg);
+	vc_val &= ~vdd->vc_reg.smps_volra_mask;
+	vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_reg.smps_volra_shift;
+	vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_volra_reg);
+
+	/*Configure the setup times */
+	vc_val = vdd->read_reg(mod, vdd->vc_reg.voltsetup_reg);
+	vc_val &= ~vdd->vc_reg.voltsetup_mask;
+	vc_val |= vdd->pmic_info->volt_setup_time <<
+			vdd->vc_reg.voltsetup_shift;
+	vdd->write_reg(vc_val, mod, vdd->vc_reg.voltsetup_reg);
+
+	/* Set up the on, inactive, retention and off voltage */
+	on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt);
+	onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt);
+	ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt);
+	off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt);
+	vc_val	= ((on_vsel << vdd->vc_reg.cmd_on_shift) |
+		(onlp_vsel << vdd->vc_reg.cmd_onlp_shift) |
+		(ret_vsel << vdd->vc_reg.cmd_ret_shift) |
+		(off_vsel << vdd->vc_reg.cmd_off_shift));
+	vdd->write_reg(vc_val, mod, vdd->vc_reg.cmdval_reg);
+
+	if (is_initialized)
+		return;
+
+	/* Generic VC parameters init */
+	vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, mod,
+			OMAP3_PRM_VC_CH_CONF_OFFSET);
+	vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, mod,
+			OMAP3_PRM_VC_I2C_CFG_OFFSET);
+	vdd->write_reg(OMAP3_CLKSETUP, mod, OMAP3_PRM_CLKSETUP_OFFSET);
+	vdd->write_reg(OMAP3_VOLTOFFSET, mod, OMAP3_PRM_VOLTOFFSET_OFFSET);
+	vdd->write_reg(OMAP3_VOLTSETUP2, mod, OMAP3_PRM_VOLTSETUP2_OFFSET);
+	is_initialized = true;
+}
+
+/* Sets up all the VDD related info for OMAP3 */
+static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
+{
+	struct clk *sys_ck;
+	u32 sys_clk_speed, timeout_val, waittime;
+
+	if (!vdd->pmic_info) {
+		pr_err("%s: PMIC info requried to configure vdd_%s not"
+			"populated.Hence cannot initialize vdd_%s\n",
+			__func__, vdd->voltdm.name, vdd->voltdm.name);
+		return -EINVAL;
+	}
+
+	if (!strcmp(vdd->voltdm.name, "mpu")) {
+		if (cpu_is_omap3630())
+			vdd->volt_data = omap36xx_vddmpu_volt_data;
+		else
+			vdd->volt_data = omap34xx_vddmpu_volt_data;
+
+		vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK;
+		vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
+		vdd->vc_reg.smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT;
+		vdd->vc_reg.smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK;
+		vdd->vc_reg.smps_volra_shift = OMAP3430_VOLRA0_SHIFT;
+		vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA0_MASK;
+		vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME1_SHIFT;
+		vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME1_MASK;
+	} else if (!strcmp(vdd->voltdm.name, "core")) {
+		if (cpu_is_omap3630())
+			vdd->volt_data = omap36xx_vddcore_volt_data;
+		else
+			vdd->volt_data = omap34xx_vddcore_volt_data;
+
+		vdd->vp_reg.tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK;
+		vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
+		vdd->vc_reg.smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT;
+		vdd->vc_reg.smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK;
+		vdd->vc_reg.smps_volra_shift = OMAP3430_VOLRA1_SHIFT;
+		vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA1_MASK;
+		vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME2_SHIFT;
+		vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME2_MASK;
+	} else {
+		pr_warning("%s: vdd_%s does not exisit in OMAP3\n",
+			__func__, vdd->voltdm.name);
+		return -EINVAL;
+	}
+
+	/*
+	 * Sys clk rate is require to calculate vp timeout value and
+	 * smpswaittimemin and smpswaittimemax.
+	 */
+	sys_ck = clk_get(NULL, "sys_ck");
+	if (IS_ERR(sys_ck)) {
+		pr_warning("%s: Could not get the sys clk to calculate"
+			"various vdd_%s params\n", __func__, vdd->voltdm.name);
+		return -EINVAL;
+	}
+	sys_clk_speed = clk_get_rate(sys_ck);
+	clk_put(sys_ck);
+	/* Divide to avoid overflow */
+	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;
+	vdd->write_reg = omap3_voltage_write_reg;
+	vdd->volt_scale = vp_forceupdate_scale_voltage;
+	vdd->vp_enabled = false;
+
+	/* VC parameters */
+	vdd->vc_reg.prm_mod = OMAP3430_GR_MOD;
+	vdd->vc_reg.smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET;
+	vdd->vc_reg.smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET;
+	vdd->vc_reg.bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
+	vdd->vc_reg.voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET;
+	vdd->vc_reg.data_shift = OMAP3430_DATA_SHIFT;
+	vdd->vc_reg.slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
+	vdd->vc_reg.regaddr_shift = OMAP3430_REGADDR_SHIFT;
+	vdd->vc_reg.valid = OMAP3430_VALID_MASK;
+	vdd->vc_reg.cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
+	vdd->vc_reg.cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
+	vdd->vc_reg.cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT;
+	vdd->vc_reg.cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT;
+	vdd->vc_reg.cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT;
+
+	vdd->vp_reg.prm_mod = OMAP3430_GR_MOD;
+
+	/* VPCONFIG bit fields */
+	vdd->vp_reg.vpconfig_erroroffset = (vdd->pmic_info->vp_erroroffset <<
+				 OMAP3430_ERROROFFSET_SHIFT);
+	vdd->vp_reg.vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK;
+	vdd->vp_reg.vpconfig_errorgain_shift = OMAP3430_ERRORGAIN_SHIFT;
+	vdd->vp_reg.vpconfig_initvoltage_shift = OMAP3430_INITVOLTAGE_SHIFT;
+	vdd->vp_reg.vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK;
+	vdd->vp_reg.vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK;
+	vdd->vp_reg.vpconfig_initvdd = OMAP3430_INITVDD_MASK;
+	vdd->vp_reg.vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK;
+	vdd->vp_reg.vpconfig_vpenable = OMAP3430_VPENABLE_MASK;
+
+	/* VSTEPMIN VSTEPMAX bit fields */
+	waittime = ((vdd->pmic_info->step_size / vdd->pmic_info->slew_rate) *
+				sys_clk_speed) / 1000;
+	vdd->vp_reg.vstepmin_smpswaittimemin = waittime;
+	vdd->vp_reg.vstepmax_smpswaittimemax = waittime;
+	vdd->vp_reg.vstepmin_stepmin = vdd->pmic_info->vp_vstepmin;
+	vdd->vp_reg.vstepmax_stepmax = vdd->pmic_info->vp_vstepmax;
+	vdd->vp_reg.vstepmin_smpswaittimemin_shift =
+				OMAP3430_SMPSWAITTIMEMIN_SHIFT;
+	vdd->vp_reg.vstepmax_smpswaittimemax_shift =
+				OMAP3430_SMPSWAITTIMEMAX_SHIFT;
+	vdd->vp_reg.vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT;
+	vdd->vp_reg.vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT;
+
+	/* VLIMITTO bit fields */
+	timeout_val = (sys_clk_speed * vdd->pmic_info->vp_timeout_us) / 1000;
+	vdd->vp_reg.vlimitto_timeout = timeout_val;
+	vdd->vp_reg.vlimitto_vddmin = vdd->pmic_info->vp_vddmin;
+	vdd->vp_reg.vlimitto_vddmax = vdd->pmic_info->vp_vddmax;
+	vdd->vp_reg.vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT;
+	vdd->vp_reg.vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT;
+	vdd->vp_reg.vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT;
+
+	return 0;
+}
+
+/* Public functions */
+/**
+ * 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.
+ */
+unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return 0;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	return vdd->curr_volt;
+}
+
+/**
+ * omap_vp_get_curr_volt() - API to get the current vp voltage.
+ * @voltdm:	pointer to the VDD.
+ *
+ * This API returns the current voltage for the specified voltage processor
+ */
+unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+	u8 curr_vsel;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return 0;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	if (!vdd->read_reg) {
+		pr_err("%s: No read API for reading vdd_%s regs\n",
+			__func__, voltdm->name);
+		return 0;
+	}
+
+	curr_vsel = vdd->read_reg(vdd->vp_reg.prm_mod,
+			vdd->vp_offs.voltage);
+
+	if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) {
+		pr_warning("%s: PMIC function to convert vsel to voltage"
+			"in uV not registerd\n", __func__);
+		return 0;
+	}
+
+	return vdd->pmic_info->vsel_to_uv(curr_vsel);
+}
+
+/**
+ * omap_vp_enable() - API to enable a particular VP
+ * @voltdm:	pointer to the VDD whose VP is to be enabled.
+ *
+ * This API enables a particular voltage processor. Needed by the smartreflex
+ * class drivers.
+ */
+void omap_vp_enable(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+	u32 vpconfig;
+	u16 mod;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	if (!vdd->read_reg || !vdd->write_reg) {
+		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	mod = vdd->vp_reg.prm_mod;
+
+	/* If VP is already enabled, do nothing. Return */
+	if (vdd->vp_enabled)
+		return;
+
+	vp_latch_vsel(vdd);
+
+	/* Enable VP */
+	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
+	vpconfig |= vdd->vp_reg.vpconfig_vpenable;
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+	vdd->vp_enabled = true;
+}
+
+/**
+ * omap_vp_disable() - API to disable a particular VP
+ * @voltdm:	pointer to the VDD whose VP is to be disabled.
+ *
+ * This API disables a particular voltage processor. Needed by the smartreflex
+ * class drivers.
+ */
+void omap_vp_disable(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+	u32 vpconfig;
+	u16 mod;
+	int timeout;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	if (!vdd->read_reg || !vdd->write_reg) {
+		pr_err("%s: No read/write API for accessing vdd_%s regs\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	mod = vdd->vp_reg.prm_mod;
+
+	/* If VP is already disabled, do nothing. Return */
+	if (!vdd->vp_enabled) {
+		pr_warning("%s: Trying to disable VP for vdd_%s when"
+			"it is already disabled\n", __func__, voltdm->name);
+		return;
+	}
+
+	/* Disable VP */
+	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
+	vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
+	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+
+	/*
+	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
+	 */
+	omap_test_timeout((vdd->read_reg(mod, vdd->vp_offs.vstatus)),
+				VP_IDLE_TIMEOUT, timeout);
+
+	if (timeout >= VP_IDLE_TIMEOUT)
+		pr_warning("%s: vdd_%s idle timedout\n",
+			__func__, voltdm->name);
+
+	vdd->vp_enabled = false;
+
+	return;
+}
+
+/**
+ * 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
+ *
+ * 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_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return -EINVAL;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	if (!vdd->volt_scale) {
+		pr_err("%s: No voltage scale API registered for vdd_%s\n",
+			__func__, voltdm->name);
+		return -ENODATA;
+	}
+
+	return vdd->volt_scale(vdd, target_volt);
+}
+
+/**
+ * omap_voltage_reset() - Resets the voltage of a particular voltage domain
+ *			to that of the current OPP.
+ * @voltdm:	pointer to the VDD whose voltage is to be reset.
+ *
+ * This API finds out the correct voltage the voltage domain is supposed
+ * to be at and resets the voltage to that level. Should be used expecially
+ * while disabling any voltage compensation modules.
+ */
+void omap_voltage_reset(struct voltagedomain *voltdm)
+{
+	unsigned long target_uvdc;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return;
+	}
+
+	target_uvdc = omap_voltage_get_nom_volt(voltdm);
+	if (!target_uvdc) {
+		pr_err("%s: unable to find current voltage for vdd_%s\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	omap_voltage_scale_vdd(voltdm, target_uvdc);
+}
+
+/**
+ * omap_voltage_get_volttable() - API to get the voltage table associated with a
+ *				particular voltage domain.
+ * @voltdm:	pointer to the VDD for which the voltage table is required
+ * @volt_data:	the voltage table for the particular vdd which is to be
+ *		populated by this API
+ *
+ * This API populates the voltage table associated with a VDD into the
+ * passed parameter pointer. Returns the count of distinct voltages
+ * supported by this vdd.
+ *
+ */
+void omap_voltage_get_volttable(struct voltagedomain *voltdm,
+		struct omap_volt_data **volt_data)
+{
+	struct omap_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	*volt_data = vdd->volt_data;
+}
+
+/**
+ * omap_voltage_get_voltdata() - API to get the voltage table entry for a
+ *				particular voltage
+ * @voltdm:	pointer to the VDD whose voltage table has to be searched
+ * @volt:	the voltage to be searched in the voltage table
+ *
+ * This API searches through the voltage table for the required voltage
+ * domain and tries to find a matching entry for the passed voltage volt.
+ * If a matching entry is found volt_data is populated with that entry.
+ * This API searches only through the non-compensated voltages int the
+ * voltage table.
+ * Returns pointer to the voltage table entry corresponding to volt on
+ * sucess. Returns -ENODATA if no voltage table exisits for the passed voltage
+ * domain or if there is no matching entry.
+ */
+struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
+		unsigned long volt)
+{
+	struct omap_vdd_info *vdd;
+	int i;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	if (!vdd->volt_data) {
+		pr_warning("%s: voltage table does not exist for vdd_%s\n",
+			__func__, voltdm->name);
+		return ERR_PTR(-ENODATA);
+	}
+
+	for (i = 0; vdd->volt_data[i].volt_nominal != 0; i++) {
+		if (vdd->volt_data[i].volt_nominal == volt)
+			return &vdd->volt_data[i];
+	}
+
+	pr_notice("%s: Unable to match the current voltage with the voltage"
+		"table for vdd_%s\n", __func__, voltdm->name);
+
+	return ERR_PTR(-ENODATA);
+}
+
+/**
+ * omap_voltage_register_pmic() - API to register PMIC specific data
+ * @voltdm:	pointer to the VDD for which the PMIC specific data is
+ *		to be registered
+ * @pmic_info:	the structure containing pmic info
+ *
+ * This API is to be called by the SOC/PMIC file to specify the
+ * pmic specific info as present in omap_volt_pmic_info structure.
+ */
+int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+		struct omap_volt_pmic_info *pmic_info)
+{
+	struct omap_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return -EINVAL;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	vdd->pmic_info = pmic_info;
+
+	return 0;
+}
+
+/**
+ * omap_voltage_get_dbgdir() - API to get pointer to the debugfs directory
+ *				corresponding to a voltage domain.
+ *
+ * @voltdm:	pointer to the VDD whose debug directory is required.
+ *
+ * This API returns pointer to the debugfs directory corresponding
+ * to the voltage domain. Should be used by drivers requiring to
+ * add any debug entry for a particular voltage domain. Returns NULL
+ * in case of error.
+ */
+struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return NULL;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	return vdd->debug_dir;
+}
+
+/**
+ * omap_change_voltscale_method() - API to change the voltage scaling method.
+ * @voltdm:	pointer to the VDD whose voltage scaling method
+ *		has to be changed.
+ * @voltscale_method:	the method to be used for voltage scaling.
+ *
+ * This API can be used by the board files to change the method of voltage
+ * scaling between vpforceupdate and vcbypass. The parameter values are
+ * defined in voltage.h
+ */
+void omap_change_voltscale_method(struct voltagedomain *voltdm,
+		int voltscale_method)
+{
+	struct omap_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	switch (voltscale_method) {
+	case VOLTSCALE_VPFORCEUPDATE:
+		vdd->volt_scale = vp_forceupdate_scale_voltage;
+		return;
+	case VOLTSCALE_VCBYPASS:
+		vdd->volt_scale = vc_bypass_scale_voltage;
+		return;
+	default:
+		pr_warning("%s: Trying to change the method of voltage scaling"
+			"to an unsupported one!\n", __func__);
+	}
+}
+
+/**
+ * omap_voltage_domain_lookup() - API to get the voltage domain pointer
+ * @name:	Name of the voltage domain
+ *
+ * This API looks up in the global vdd_info struct for the
+ * existence of voltage domain <name>. If it exists, the API returns
+ * a pointer to the voltage domain structure corresponding to the
+ * VDD<name>. Else retuns error pointer.
+ */
+struct voltagedomain *omap_voltage_domain_lookup(char *name)
+{
+	int i;
+
+	if (!vdd_info) {
+		pr_err("%s: Voltage driver init not yet happened.Faulting!\n",
+			__func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (!name) {
+		pr_err("%s: No name to get the votage domain!\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	for (i = 0; i < nr_scalable_vdd; i++) {
+		if (!(strcmp(name, vdd_info[i].voltdm.name)))
+			return &vdd_info[i].voltdm;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+/**
+ * omap_voltage_late_init() - Init the various voltage parameters
+ *
+ * This API is to be called in the later stages of the
+ * system boot to init the voltage controller and
+ * voltage processors.
+ */
+int __init omap_voltage_late_init(void)
+{
+	int i;
+
+	if (!vdd_info) {
+		pr_err("%s: Voltage driver support not added\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	voltage_dir = debugfs_create_dir("voltage", NULL);
+	if (IS_ERR(voltage_dir))
+		pr_err("%s: Unable to create voltage debugfs main dir\n",
+			__func__);
+	for (i = 0; i < nr_scalable_vdd; i++) {
+		if (vdd_data_configure(&vdd_info[i]))
+			continue;
+		vc_init(&vdd_info[i]);
+		vp_init(&vdd_info[i]);
+		vdd_debugfs_init(&vdd_info[i]);
+	}
+
+	return 0;
+}
+
+/**
+ * omap_voltage_early_init()- Volatage driver early init
+ */
+static int __init omap_voltage_early_init(void)
+{
+	if (cpu_is_omap34xx()) {
+		vdd_info = omap3_vdd_info;
+		nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
+		vc_init = omap3_vc_init;
+		vdd_data_configure = omap3_vdd_data_configure;
+	} else {
+		pr_warning("%s: voltage driver support not added\n", __func__);
+	}
+
+	return 0;
+}
+core_initcall(omap_voltage_early_init);
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
new file mode 100644
index 0000000..2f4f59a
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -0,0 +1,134 @@
+/*
+ * OMAP Voltage Management Routines
+ *
+ * Author: Thara Gopinath	<thara@ti.com>
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * 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.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
+#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
+
+#define VOLTSCALE_VPFORCEUPDATE		1
+#define VOLTSCALE_VCBYPASS		2
+
+/*
+ * OMAP3 GENERIC setup times. Revisit to see if these needs to be
+ * passed from board or PMIC file
+ */
+#define OMAP3_CLKSETUP		0xff
+#define OMAP3_VOLTOFFSET	0xff
+#define OMAP3_VOLTSETUP2	0xff
+
+/* Voltage value defines */
+#define OMAP3430_VDD_MPU_OPP1_UV		975000
+#define OMAP3430_VDD_MPU_OPP2_UV		1075000
+#define OMAP3430_VDD_MPU_OPP3_UV		1200000
+#define OMAP3430_VDD_MPU_OPP4_UV		1270000
+#define OMAP3430_VDD_MPU_OPP5_UV		1350000
+
+#define OMAP3430_VDD_CORE_OPP1_UV		975000
+#define OMAP3430_VDD_CORE_OPP2_UV		1050000
+#define OMAP3430_VDD_CORE_OPP3_UV		1150000
+
+#define OMAP3630_VDD_MPU_OPP50_UV		1012500
+#define OMAP3630_VDD_MPU_OPP100_UV		1200000
+#define OMAP3630_VDD_MPU_OPP120_UV		1325000
+#define OMAP3630_VDD_MPU_OPP1G_UV		1375000
+
+#define OMAP3630_VDD_CORE_OPP50_UV		1000000
+#define OMAP3630_VDD_CORE_OPP100_UV		1200000
+
+/**
+ * struct voltagedomain - omap voltage domain global structure.
+ * @name:	Name of the voltage domain which can be used as a unique
+ *		identifier.
+ */
+struct voltagedomain {
+	char *name;
+};
+
+/* API to get the voltagedomain pointer */
+struct voltagedomain *omap_voltage_domain_lookup(char *name);
+
+/**
+ * struct omap_volt_data - Omap voltage specific data.
+ * @voltage_nominal:	The possible voltage value in uV
+ * @sr_efuse_offs:	The offset of the efuse register(from system
+ *			control module base address) from where to read
+ *			the n-target value for the smartreflex module.
+ * @sr_errminlimit:	Error min limit value for smartreflex. This value
+ *			differs at differnet opp and thus is linked
+ *			with voltage.
+ * @vp_errorgain:	Error gain value for the voltage processor. This
+ *			field also differs according to the voltage/opp.
+ */
+struct omap_volt_data {
+	u32	volt_nominal;
+	u32	sr_efuse_offs;
+	u8	sr_errminlimit;
+	u8	vp_errgain;
+};
+
+/**
+ * struct omap_volt_pmic_info - PMIC specific data required by voltage driver.
+ * @slew_rate:	PMIC slew rate (in uv/us)
+ * @step_size:	PMIC voltage step size (in uv)
+ * @vsel_to_uv:	PMIC API to convert vsel value to actual voltage in uV.
+ * @uv_to_vsel:	PMIC API to convert voltage in uV to vsel value.
+ */
+struct omap_volt_pmic_info {
+	int slew_rate;
+	int step_size;
+	u32 on_volt;
+	u32 onlp_volt;
+	u32 ret_volt;
+	u32 off_volt;
+	u16 volt_setup_time;
+	u8 vp_erroroffset;
+	u8 vp_vstepmin;
+	u8 vp_vstepmax;
+	u8 vp_vddmin;
+	u8 vp_vddmax;
+	u8 vp_timeout_us;
+	u8 i2c_slave_addr;
+	u8 pmic_reg;
+	unsigned long (*vsel_to_uv) (const u8 vsel);
+	u8 (*uv_to_vsel) (unsigned long uV);
+};
+
+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);
+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 dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
+#ifdef CONFIG_PM
+int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+		struct omap_volt_pmic_info *pmic_info);
+void omap_change_voltscale_method(struct voltagedomain *voltdm,
+		int voltscale_method);
+int omap_voltage_late_init(void);
+#else
+static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+		struct omap_volt_pmic_info *pmic_info) {}
+static inline  void omap_change_voltscale_method(struct voltagedomain *voltdm,
+		int voltscale_method) {}
+static inline int omap_voltage_late_init(void)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif
-- 
1.7.0.4

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

* [PATCH v6 02/10] OMAP: Introduce voltage domain information in the hwmod structures
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 01/10] OMAP3: PM: Adding voltage " Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 03/10] OMAP3: PM: Adding smartreflex driver support Thara Gopinath
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch extends the device hwmod structure to contain
info about the voltage domain to which the device belongs to.
This is needed to support a device based DVFS where the
device knows which voltage domain it belongs to.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 62bdb23..09c46c1 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -34,6 +34,7 @@
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <plat/cpu.h>
+#include <plat/voltage.h>
 
 struct omap_device;
 
@@ -449,6 +450,8 @@ struct omap_hwmod_class {
  * @main_clk: main clock: OMAP clock name
  * @_clk: pointer to the main struct clk (filled in at runtime)
  * @opt_clks: other device clocks that drivers can request (0..*)
+ * @vdd_name: voltage domain name
+ * @voltdm: pointer to voltage domain (filled in at runtime)
  * @masters: ptr to array of OCP ifs that this hwmod can initiate on
  * @slaves: ptr to array of OCP ifs that this hwmod can respond on
  * @dev_attr: arbitrary device attributes that can be passed to the driver
@@ -491,6 +494,8 @@ struct omap_hwmod {
 	const char			*main_clk;
 	struct clk			*_clk;
 	struct omap_hwmod_opt_clk	*opt_clks;
+	char				*vdd_name;
+	struct voltagedomain		*voltdm;
 	struct omap_hwmod_ocp_if	**masters; /* connect to *_IA */
 	struct omap_hwmod_ocp_if	**slaves;  /* connect to *_TA */
 	void				*dev_attr;
-- 
1.7.0.4

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

* [PATCH v6 03/10] OMAP3: PM: Adding smartreflex driver support.
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 01/10] OMAP3: PM: Adding voltage " Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 02/10] OMAP: Introduce voltage domain information in the hwmod structures Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 04/10] OMAP3: PM: Adding smartreflex device file Thara Gopinath
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

SmartReflex modules do adaptive voltage control for real-time
voltage adjustments. With Smartreflex the power supply voltage
can be adapted to the silicon performance(manufacturing process,
temperature induced performance, age induced performance etc).

There are differnet classes of smartreflex implementation.
	Class-0: Manufacturing Test Calibration
	Class-1: Boot-Time Software Calibration
	Class-2: Continuous Software Calibration
	Class-3: Continuous Hardware Calibration
	Class-4: Fully Integrated Power Management

OMAP3 has two smartreflex modules one associated with VDD MPU and the
other associated with VDD CORE.
This patch adds support for  smartreflex driver. The driver is designed
for Class-1 , Class-2 and Class-3 support and is  a platform driver.
Smartreflex driver can be enabled through a Kconfig option
"SmartReflex support" under "System type"->"TI OMAP implementations" menu.

Smartreflex autocompensation feature can be enabled runtime through
a debug fs option.
To enable smartreflex autocompensation feature
	echo 1 > /debug/voltage/vdd_<X>/smartreflex/autocomp
To disable smartreflex autocompensation feature
	echo 0 > /debug/voltage/vdd_<X>/smartreflex/autocomp

where X can be mpu, core , iva etc.

This patch contains code originally in linux omap pm branch.
Major contributors to this driver are
Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley,
Nishant Menon, Kevin Hilman.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/Makefile                  |    1 +
 arch/arm/mach-omap2/smartreflex.c             |  983 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   22 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  245 ++++++
 4 files changed, 1251 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex.c
 create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 5034797..b1bead0 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o pm_bus.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o pm_bus.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
+obj-$(CONFIG_OMAP_SMARTREFLEX)          += smartreflex.o
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
new file mode 100644
index 0000000..eee23d0
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -0,0 +1,983 @@
+/*
+ * OMAP SmartReflex Voltage Control
+ *
+ * Author: Thara Gopinath	<thara@ti.com>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * 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/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include <plat/common.h>
+#include <plat/smartreflex.h>
+
+#include "pm.h"
+
+#define SMARTREFLEX_NAME_LEN	16
+#define SR_DISABLE_TIMEOUT	200
+
+struct omap_sr {
+	int				srid;
+	int				ip_type;
+	int				nvalue_count;
+	bool				autocomp_active;
+	u32				clk_length;
+	u32				err_weight;
+	u32				err_minlimit;
+	u32				err_maxlimit;
+	u32				accum_data;
+	u32				senn_avgweight;
+	u32				senp_avgweight;
+	u32				senp_mod;
+	u32				senn_mod;
+	unsigned int			irq;
+	void __iomem			*base;
+	struct platform_device		*pdev;
+	struct list_head		node;
+	struct omap_sr_nvalue_table	*nvalue_table;
+	struct voltagedomain		*voltdm;
+};
+
+/* sr_list contains all the instances of smartreflex module */
+static LIST_HEAD(sr_list);
+
+static struct omap_sr_class_data *sr_class;
+static struct omap_sr_pmic_data *sr_pmic_data;
+
+static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
+{
+	__raw_writel(value, (sr->base + offset));
+}
+
+static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
+					u32 value)
+{
+	u32 reg_val;
+	u32 errconfig_offs = 0, errconfig_mask = 0;
+
+	reg_val = __raw_readl(sr->base + offset);
+	reg_val &= ~mask;
+
+	/*
+	 * Smartreflex error config register is special as it contains
+	 * certain status bits which if written a 1 into means a clear
+	 * of those bits. So in order to make sure no accidental write of
+	 * 1 happens to those status bits, do a clear of them in the read
+	 * value. This mean this API doesn't rewrite values in these bits
+	 * if they are currently set, but does allow the caller to write
+	 * those bits.
+	 */
+	if (sr->ip_type == SR_TYPE_V1) {
+		errconfig_offs = ERRCONFIG_V1;
+		errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
+	} else if (sr->ip_type == SR_TYPE_V2) {
+		errconfig_offs = ERRCONFIG_V2;
+		errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2;
+	}
+
+	if (offset == errconfig_offs)
+		reg_val &= ~errconfig_mask;
+
+	reg_val |= value;
+
+	__raw_writel(reg_val, (sr->base + offset));
+}
+
+static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
+{
+	return __raw_readl(sr->base + offset);
+}
+
+static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
+{
+	struct omap_sr *sr_info;
+
+	if (!voltdm) {
+		pr_err("%s: Null voltage domain passed!\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	list_for_each_entry(sr_info, &sr_list, node) {
+		if (voltdm == sr_info->voltdm)
+			return sr_info;
+	}
+
+	return ERR_PTR(-ENODATA);
+}
+
+static irqreturn_t sr_interrupt(int irq, void *data)
+{
+	struct omap_sr *sr_info = (struct omap_sr *)data;
+	u32 status = 0;
+
+	if (sr_info->ip_type == SR_TYPE_V1) {
+		/* Read the status bits */
+		status = sr_read_reg(sr_info, ERRCONFIG_V1);
+
+		/* Clear them by writing back */
+		sr_write_reg(sr_info, ERRCONFIG_V1, status);
+	} else if (sr_info->ip_type == SR_TYPE_V2) {
+		/* Read the status bits */
+		sr_read_reg(sr_info, IRQSTATUS);
+
+		/* Clear them by writing back */
+		sr_write_reg(sr_info, IRQSTATUS, status);
+	}
+
+	if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
+		sr_class->notify(sr_info->voltdm, status);
+
+	return IRQ_HANDLED;
+}
+
+static void sr_set_clk_length(struct omap_sr *sr)
+{
+	struct clk *sys_ck;
+	u32 sys_clk_speed;
+
+	sys_ck = clk_get(NULL, "sys_ck");
+	if (IS_ERR(sys_ck)) {
+		dev_err(&sr->pdev->dev, "%s: unable to get sys clk\n",
+			__func__);
+		return;
+	}
+	sys_clk_speed = clk_get_rate(sys_ck);
+	clk_put(sys_ck);
+
+	switch (sys_clk_speed) {
+	case 12000000:
+		sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
+		break;
+	case 13000000:
+		sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
+		break;
+	case 19200000:
+		sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
+		break;
+	case 26000000:
+		sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
+		break;
+	case 38400000:
+		sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
+		break;
+	default:
+		dev_err(&sr->pdev->dev, "%s: Invalid sysclk value: %d\n",
+			__func__, sys_clk_speed);
+		break;
+	}
+}
+
+static void sr_set_regfields(struct omap_sr *sr)
+{
+	/*
+	 * For time being these values are defined in smartreflex.h
+	 * and populated during init. May be they can be moved to board
+	 * file or pmic specific data structure. In that case these structure
+	 * fields will have to be populated using the pdata or pmic structure.
+	 */
+	if (cpu_is_omap34xx()) {
+		sr->err_weight = OMAP3430_SR_ERRWEIGHT;
+		sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
+		sr->accum_data = OMAP3430_SR_ACCUMDATA;
+		if (!(strcmp(sr->voltdm->name, "mpu"))) {
+			sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
+			sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
+		} else {
+			sr->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT;
+			sr->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT;
+		}
+	}
+}
+
+static void sr_start_vddautocomp(struct omap_sr *sr)
+{
+	if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
+		dev_warn(&sr->pdev->dev,
+			"%s: smartreflex class driver not registered\n",
+			__func__);
+		return;
+	}
+
+	if (!sr_class->enable(sr->voltdm))
+		sr->autocomp_active = true;
+}
+
+static void sr_stop_vddautocomp(struct omap_sr *sr)
+{
+	if (!sr_class || !(sr_class->disable)) {
+		dev_warn(&sr->pdev->dev,
+			"%s: smartreflex class driver not registered\n",
+			__func__);
+		return;
+	}
+
+	if (sr->autocomp_active) {
+		sr_class->disable(sr->voltdm, 1);
+		sr->autocomp_active = false;
+	}
+}
+
+/*
+ * This function handles the intializations which have to be done
+ * only when both sr device and class driver regiter has
+ * completed. This will be attempted to be called from both sr class
+ * driver register and sr device intializtion API's. Only one call
+ * will ultimately succeed.
+ *
+ * Currenly this function registers interrrupt handler for a particular SR
+ * if smartreflex class driver is already registered and has
+ * requested for interrupts and the SR interrupt line in present.
+ */
+static int sr_late_init(struct omap_sr *sr_info)
+{
+	char *name;
+	struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
+	struct resource *mem;
+	int ret = 0;
+
+	if (sr_class->class_type == SR_CLASS2 &&
+		sr_class->notify_flags && sr_info->irq) {
+
+		name = kzalloc(SMARTREFLEX_NAME_LEN + 1, GFP_KERNEL);
+		strcpy(name, "sr_");
+		strcat(name, sr_info->voltdm->name);
+		ret = request_irq(sr_info->irq, sr_interrupt,
+				0, name, (void *)sr_info);
+		if (ret)
+			goto error;
+	}
+
+	if (pdata && pdata->enable_on_init)
+		sr_start_vddautocomp(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;
+}
+
+static void sr_v1_disable(struct omap_sr *sr)
+{
+	int timeout = 0;
+
+	/* Enable MCUDisableAcknowledge interrupt */
+	sr_modify_reg(sr, ERRCONFIG_V1,
+			ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN);
+
+	/* SRCONFIG - disable SR */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
+
+	/* Disable all other SR interrupts and clear the status */
+	sr_modify_reg(sr, ERRCONFIG_V1,
+			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
+			ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
+			(ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
+			ERRCONFIG_MCUBOUNDINTST |
+			ERRCONFIG_VPBOUNDINTST_V1));
+
+	/*
+	 * Wait for SR to be disabled.
+	 * wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
+	 */
+	omap_test_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
+			ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
+			timeout);
+
+	if (timeout >= SR_DISABLE_TIMEOUT)
+		dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
+			__func__);
+
+	/* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
+	sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN,
+			ERRCONFIG_MCUDISACKINTST);
+}
+
+static void sr_v2_disable(struct omap_sr *sr)
+{
+	int timeout = 0;
+
+	/* Enable MCUDisableAcknowledge interrupt */
+	sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT);
+
+	/* SRCONFIG - disable SR */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
+
+	/* Disable all other SR interrupts and clear the status */
+	sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+			ERRCONFIG_VPBOUNDINTST_V2);
+	sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
+			IRQENABLE_MCUVALIDINT |
+			IRQENABLE_MCUBOUNDSINT));
+	sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT |
+			IRQSTATUS_MCVALIDINT |
+			IRQSTATUS_MCBOUNDSINT));
+
+	/*
+	 * Wait for SR to be disabled.
+	 * wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
+	 */
+	omap_test_timeout((sr_read_reg(sr, IRQSTATUS) &
+			IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
+			timeout);
+
+	if (timeout >= SR_DISABLE_TIMEOUT)
+		dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
+			__func__);
+
+	/* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */
+	sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT);
+	sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
+}
+
+static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
+{
+	int i;
+
+	if (!sr->nvalue_table) {
+		dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
+			__func__);
+		return 0;
+	}
+
+	for (i = 0; i < sr->nvalue_count; i++) {
+		if (sr->nvalue_table[i].efuse_offs == efuse_offs)
+			return sr->nvalue_table[i].nvalue;
+	}
+
+	return 0;
+}
+
+/* Public Functions */
+
+/**
+ * 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.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * configure the error generator module inside the smartreflex module.
+ * SR settings if using the ERROR module inside Smartreflex.
+ * SR CLASS 3 by default uses only the ERROR module where as
+ * SR CLASS 2 can choose between ERROR module and MINMAXAVG
+ * module. Returns 0 on success and error value in case of failure.
+ */
+int sr_configure_errgen(struct voltagedomain *voltdm)
+{
+	u32 sr_config, sr_errconfig, errconfig_offs, vpboundint_en;
+	u32 vpboundint_st, senp_en = 0, senn_en = 0;
+	u8 senp_shift, senn_shift;
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return -EINVAL;
+	}
+
+	if (!sr->clk_length)
+		sr_set_clk_length(sr);
+
+	senp_en = sr->senp_mod;
+	senn_en = sr->senn_mod;
+
+	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+		SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
+
+	if (sr->ip_type == SR_TYPE_V1) {
+		sr_config |= SRCONFIG_DELAYCTRL;
+		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
+		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
+		errconfig_offs = ERRCONFIG_V1;
+		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
+		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
+	} else if (sr->ip_type == SR_TYPE_V2) {
+		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
+		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
+		errconfig_offs = ERRCONFIG_V2;
+		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
+		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
+	} else {
+		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+			"module without specifying the ip\n", __func__);
+		return -EINVAL;
+	}
+
+	sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
+	sr_write_reg(sr, SRCONFIG, sr_config);
+	sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) |
+		(sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) |
+		(sr->err_minlimit <<  ERRCONFIG_ERRMINLIMIT_SHIFT);
+	sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK |
+		SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+		sr_errconfig);
+
+	/* Enabling the interrupts if the ERROR module is used */
+	sr_modify_reg(sr, errconfig_offs,
+		vpboundint_en, (vpboundint_en | vpboundint_st));
+
+	return 0;
+}
+
+/**
+ * sr_configure_minmax() - Configures the smrtreflex to perform AVS using the
+ *			 minmaxavg module.
+ * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * configure the minmaxavg module inside the smartreflex module.
+ * SR settings if using the ERROR module inside Smartreflex.
+ * SR CLASS 3 by default uses only the ERROR module where as
+ * SR CLASS 2 can choose between ERROR module and MINMAXAVG
+ * module. Returns 0 on success and error value in case of failure.
+ */
+int sr_configure_minmax(struct voltagedomain *voltdm)
+{
+	u32 sr_config, sr_avgwt;
+	u32 senp_en = 0, senn_en = 0;
+	u8 senp_shift, senn_shift;
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return -EINVAL;
+	}
+
+	if (!sr->clk_length)
+		sr_set_clk_length(sr);
+
+	senp_en = sr->senp_mod;
+	senn_en = sr->senn_mod;
+
+	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+		SRCONFIG_SENENABLE |
+		(sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
+
+	if (sr->ip_type == SR_TYPE_V1) {
+		sr_config |= SRCONFIG_DELAYCTRL;
+		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
+		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
+	} else if (sr->ip_type == SR_TYPE_V2) {
+		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
+		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
+	} else {
+		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+			"module without specifying the ip\n", __func__);
+		return -EINVAL;
+	}
+
+	sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift));
+	sr_write_reg(sr, SRCONFIG, sr_config);
+	sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) |
+		(sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT);
+	sr_write_reg(sr, AVGWEIGHT, sr_avgwt);
+
+	/*
+	 * Enabling the interrupts if MINMAXAVG module is used.
+	 * TODO: check if all the interrupts are mandatory
+	 */
+	if (sr->ip_type == SR_TYPE_V1) {
+		sr_modify_reg(sr, ERRCONFIG_V1,
+			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
+			ERRCONFIG_MCUBOUNDINTEN),
+			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
+			 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
+			 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
+	} else if (sr->ip_type == SR_TYPE_V2) {
+		sr_write_reg(sr, IRQSTATUS,
+			IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
+			IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
+		sr_write_reg(sr, IRQENABLE_SET,
+			IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
+			IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
+	}
+
+	return 0;
+}
+
+/**
+ * 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
+ *		the smartreflex module is operating at.
+ *		This is required only to program the correct Ntarget value.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * 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)
+{
+	u32 nvalue_reciprocal;
+	struct omap_volt_data *volt_data;
+	struct omap_sr *sr = _sr_lookup(voltdm);
+	int ret;
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		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;
+	}
+
+	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);
+		return -ENODATA;
+	}
+
+	/* errminlimit is opp dependent and hence linked to voltage */
+	sr->err_minlimit = volt_data->sr_errminlimit;
+
+	pm_runtime_get_sync(&sr->pdev->dev);
+
+	/* Check if SR is already enabled. If yes do nothing */
+	if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE)
+		return 0;
+
+	/* Configure SR */
+	ret = sr_class->configure(voltdm);
+	if (ret)
+		return ret;
+
+	sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
+
+	/* SRCONFIG - enable SR */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
+	return 0;
+}
+
+/**
+ * sr_disable() - Disables the smartreflex module.
+ * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * disable a smartreflex module.
+ */
+void sr_disable(struct voltagedomain *voltdm)
+{
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	/* Check if SR clocks are already disabled. If yes do nothing */
+	if (pm_runtime_suspended(&sr->pdev->dev))
+		return;
+
+	/*
+	 * Disable SR if only it is indeed enabled. Else just
+	 * disable the clocks.
+	 */
+	if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
+		if (sr->ip_type == SR_TYPE_V1)
+			sr_v1_disable(sr);
+		else if (sr->ip_type == SR_TYPE_V2)
+			sr_v2_disable(sr);
+	}
+
+	pm_runtime_put_sync(&sr->pdev->dev);
+}
+
+/**
+ * sr_register_class() - API to register a smartreflex class parameters.
+ * @class_data:	The structure containing various sr class specific data.
+ *
+ * This API is to be called by the smartreflex class driver to register itself
+ * with the smartreflex driver during init. Returns 0 on success else the
+ * error value.
+ */
+int sr_register_class(struct omap_sr_class_data *class_data)
+{
+	struct omap_sr *sr_info;
+
+	if (!class_data) {
+		pr_warning("%s:, Smartreflex class data passed is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (sr_class) {
+		pr_warning("%s: Smartreflex class driver already registered\n",
+			__func__);
+		return -EBUSY;
+	}
+
+	sr_class = class_data;
+
+	/*
+	 * Call into late init to do intializations that require
+	 * both sr driver and sr class driver to be initiallized.
+	 */
+	list_for_each_entry(sr_info, &sr_list, node)
+		sr_late_init(sr_info);
+
+	return 0;
+}
+
+/**
+ * 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.
+ *
+ * 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)
+{
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	if (!sr->autocomp_active)
+		return;
+
+	if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
+		dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
+			"registered\n", __func__);
+		return;
+	}
+
+	sr_class->enable(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.
+ *
+ * This API is to be called from the kernel in order to disable
+ * a particular smartreflex module. This API will in turn call
+ * into the registered smartreflex class disable API. This API will tell
+ * the smartreflex class disable not to reset the VP voltage after
+ * disabling smartreflex.
+ */
+void omap_sr_disable(struct voltagedomain *voltdm)
+{
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	if (!sr->autocomp_active)
+		return;
+
+	if (!sr_class || !(sr_class->disable)) {
+		dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
+			"registered\n", __func__);
+		return;
+	}
+
+	sr_class->disable(voltdm, 0);
+}
+
+/**
+ * omap_sr_disable_reset_volt() - API to disable SR and reset the
+ *				voltage processor voltage
+ * @voltdm:	VDD pointer to which the SR module to be configured belongs to.
+ *
+ * This API is to be called from the kernel in order to disable
+ * a particular smartreflex module. This API will in turn call
+ * into the registered smartreflex class disable API. This API will tell
+ * the smartreflex class disable to reset the VP voltage after
+ * disabling smartreflex.
+ */
+void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
+{
+	struct omap_sr *sr = _sr_lookup(voltdm);
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return;
+	}
+
+	if (!sr->autocomp_active)
+		return;
+
+	if (!sr_class || !(sr_class->disable)) {
+		dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not"
+			"registered\n", __func__);
+		return;
+	}
+
+	sr_class->disable(voltdm, 1);
+}
+
+/**
+ * omap_sr_register_pmic() - API to register pmic specific info.
+ * @pmic_data:	The structure containing pmic specific data.
+ *
+ * This API is to be called from the PMIC specific code to register with
+ * smartreflex driver pmic specific info. Currently the only info required
+ * is the smartreflex init on the PMIC side.
+ */
+void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
+{
+	if (!pmic_data) {
+		pr_warning("%s: Trying to register NULL PMIC data structure"
+			"with smartreflex\n", __func__);
+		return;
+	}
+
+	sr_pmic_data = pmic_data;
+}
+
+/* PM Debug Fs enteries to enable disable smartreflex. */
+static int omap_sr_autocomp_show(void *data, u64 *val)
+{
+	struct omap_sr *sr_info = (struct omap_sr *) data;
+
+	if (!sr_info) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, sr_info->voltdm->name);
+		return -EINVAL;
+	}
+
+	*val = sr_info->autocomp_active;
+
+	return 0;
+}
+
+static int omap_sr_autocomp_store(void *data, u64 val)
+{
+	struct omap_sr *sr_info = (struct omap_sr *) data;
+
+	if (!sr_info) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, sr_info->voltdm->name);
+		return -EINVAL;
+	}
+
+	/* Sanity check */
+	if (val && (val != 1)) {
+		pr_warning("%s: Invalid argument %lld\n", __func__, val);
+		return -EINVAL;
+	}
+
+	if (!val)
+		sr_stop_vddautocomp(sr_info);
+	else
+		sr_start_vddautocomp(sr_info);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
+		omap_sr_autocomp_store, "%llu\n");
+
+static int __init omap_sr_probe(struct platform_device *pdev)
+{
+	struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
+	struct omap_sr_data *pdata = pdev->dev.platform_data;
+	struct resource *mem, *irq;
+	struct dentry *vdd_dbg_dir, *dbg_dir;
+	int ret = 0;
+
+	if (!sr_info) {
+		dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
+		return -EINVAL;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
+		ret = -ENODEV;
+		goto err_free_devinfo;
+	}
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+	pm_runtime_enable(&pdev->dev);
+
+	sr_info->pdev = pdev;
+	sr_info->srid = pdev->id;
+	sr_info->voltdm = pdata->voltdm;
+	sr_info->nvalue_table = pdata->nvalue_table;
+	sr_info->nvalue_count = pdata->nvalue_count;
+	sr_info->senn_mod = pdata->senn_mod;
+	sr_info->senp_mod = pdata->senp_mod;
+	sr_info->autocomp_active = false;
+	sr_info->ip_type = pdata->ip_type;
+	sr_info->base = ioremap(mem->start, resource_size(mem));
+	if (!sr_info->base) {
+		dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
+		ret = -ENOMEM;
+		goto err_release_region;
+	}
+
+	if (irq)
+		sr_info->irq = irq->start;
+
+	sr_set_clk_length(sr_info);
+	sr_set_regfields(sr_info);
+
+	list_add(&sr_info->node, &sr_list);
+
+	/*
+	 * Call into late init to do intializations that require
+	 * both sr driver and sr class driver to be initiallized.
+	 */
+	if (sr_class) {
+		ret = sr_late_init(sr_info);
+		if (ret) {
+			pr_warning("%s: Error in SR late init\n", __func__);
+			return ret;
+		}
+	}
+
+	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
+
+	/*
+	 * If the voltage domain debugfs directory is not created, do
+	 * not try to create rest of the debugfs entries.
+	 */
+	vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm);
+	if (!vdd_dbg_dir)
+		return -EINVAL;
+
+	dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
+	if (IS_ERR(dbg_dir)) {
+		dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
+			__func__);
+		return PTR_ERR(dbg_dir);
+	}
+
+	(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
+				(void *)sr_info, &pm_sr_fops);
+
+	return ret;
+
+err_release_region:
+	release_mem_region(mem->start, resource_size(mem));
+err_free_devinfo:
+	kfree(sr_info);
+
+	return ret;
+}
+
+static int __devexit omap_sr_remove(struct platform_device *pdev)
+{
+	struct omap_sr_data *pdata = pdev->dev.platform_data;
+	struct omap_sr *sr_info;
+	struct resource *mem;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
+		return -EINVAL;
+	}
+
+	sr_info = _sr_lookup(pdata->voltdm);
+	if (!sr_info) {
+		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (sr_info->autocomp_active)
+		sr_stop_vddautocomp(sr_info);
+
+	list_del(&sr_info->node);
+	iounmap(sr_info->base);
+	kfree(sr_info);
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	return 0;
+}
+
+static struct platform_driver smartreflex_driver = {
+	.remove         = omap_sr_remove,
+	.driver		= {
+		.name	= "smartreflex",
+	},
+};
+
+static int __init sr_init(void)
+{
+	int ret = 0;
+
+	/*
+	 * sr_init is a late init. If by then a pmic specific API is not
+	 * registered either there is no need for anything to be done on
+	 * the PMIC side or somebody has forgotten to register a PMIC
+	 * handler. Warn for the second condition.
+	 */
+	if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
+		sr_pmic_data->sr_pmic_init();
+	else
+		pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
+
+	ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe);
+	if (ret) {
+		pr_err("%s: platform driver register failed for SR\n",
+			__func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit sr_exit(void)
+{
+	platform_driver_unregister(&smartreflex_driver);
+}
+late_initcall(sr_init);
+module_exit(sr_exit);
+
+MODULE_DESCRIPTION("OMAP Smartreflex Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 92c5bb7..95ceca0 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -35,6 +35,28 @@ config OMAP_DEBUG_LEDS
 	depends on OMAP_DEBUG_DEVICES
 	default y if LEDS_CLASS
 
+config OMAP_SMARTREFLEX
+	bool "SmartReflex support"
+	depends on ARCH_OMAP3 && PM
+	help
+	  Say Y if you want to enable SmartReflex.
+
+	  SmartReflex can perform continuous dynamic voltage
+	  scaling around the nominal operating point voltage
+	  according to silicon characteristics and operating
+	  conditions. Enabling SmartReflex reduces power
+	  consumption.
+
+	  Please note, that by default SmartReflex is only
+	  initialized. To enable the automatic voltage
+	  compensation for vdd mpu  and vdd core from user space,
+	  user must write 1 to
+		/debug/voltage/vdd_<X>/smartreflex/autocomp,
+	  where X is mpu or core for OMAP3.
+	  Optionallly autocompensation can be enabled in the kernel
+	  by default during system init via the enable_on_init flag
+	  which an be passed as platform data to the smartreflex driver.
+
 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
new file mode 100644
index 0000000..6568c88
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -0,0 +1,245 @@
+/*
+ * OMAP Smartreflex Defines and Routines
+ *
+ * Author: Thara Gopinath	<thara@ti.com>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARM_OMAP_SMARTREFLEX_H
+#define __ASM_ARM_OMAP_SMARTREFLEX_H
+
+#include <linux/platform_device.h>
+#include <plat/voltage.h>
+
+/*
+ * Different Smartreflex IPs version. The v1 is the 65nm version used in
+ * OMAP3430. The v2 is the update for the 45nm version of the IP
+ * used in OMAP3630 and OMAP4430
+ */
+#define SR_TYPE_V1	1
+#define SR_TYPE_V2	2
+
+/* SMART REFLEX REG ADDRESS OFFSET */
+#define SRCONFIG		0x00
+#define SRSTATUS		0x04
+#define SENVAL			0x08
+#define SENMIN			0x0C
+#define SENMAX			0x10
+#define SENAVG			0x14
+#define AVGWEIGHT		0x18
+#define NVALUERECIPROCAL	0x1c
+#define SENERROR_V1		0x20
+#define ERRCONFIG_V1		0x24
+#define IRQ_EOI			0x20
+#define IRQSTATUS_RAW		0x24
+#define IRQSTATUS		0x28
+#define IRQENABLE_SET		0x2C
+#define IRQENABLE_CLR		0x30
+#define SENERROR_V2		0x34
+#define ERRCONFIG_V2		0x38
+
+/* Bit/Shift Positions */
+
+/* SRCONFIG */
+#define SRCONFIG_ACCUMDATA_SHIFT	22
+#define SRCONFIG_SRCLKLENGTH_SHIFT	12
+#define SRCONFIG_SENNENABLE_V1_SHIFT	5
+#define SRCONFIG_SENPENABLE_V1_SHIFT	3
+#define SRCONFIG_SENNENABLE_V2_SHIFT	1
+#define SRCONFIG_SENPENABLE_V2_SHIFT	0
+#define SRCONFIG_CLKCTRL_SHIFT		0
+
+#define SRCONFIG_ACCUMDATA_MASK		(0x3ff << 22)
+
+#define SRCONFIG_SRENABLE		BIT(11)
+#define SRCONFIG_SENENABLE		BIT(10)
+#define SRCONFIG_ERRGEN_EN		BIT(9)
+#define SRCONFIG_MINMAXAVG_EN		BIT(8)
+#define SRCONFIG_DELAYCTRL		BIT(2)
+
+/* AVGWEIGHT */
+#define AVGWEIGHT_SENPAVGWEIGHT_SHIFT	2
+#define AVGWEIGHT_SENNAVGWEIGHT_SHIFT	0
+
+/* NVALUERECIPROCAL */
+#define NVALUERECIPROCAL_SENPGAIN_SHIFT	20
+#define NVALUERECIPROCAL_SENNGAIN_SHIFT	16
+#define NVALUERECIPROCAL_RNSENP_SHIFT	8
+#define NVALUERECIPROCAL_RNSENN_SHIFT	0
+
+/* ERRCONFIG */
+#define ERRCONFIG_ERRWEIGHT_SHIFT	16
+#define ERRCONFIG_ERRMAXLIMIT_SHIFT	8
+#define ERRCONFIG_ERRMINLIMIT_SHIFT	0
+
+#define SR_ERRWEIGHT_MASK		(0x07 << 16)
+#define SR_ERRMAXLIMIT_MASK		(0xff << 8)
+#define SR_ERRMINLIMIT_MASK		(0xff << 0)
+
+#define ERRCONFIG_VPBOUNDINTEN_V1	BIT(31)
+#define ERRCONFIG_VPBOUNDINTST_V1	BIT(30)
+#define	ERRCONFIG_MCUACCUMINTEN		BIT(29)
+#define ERRCONFIG_MCUACCUMINTST		BIT(28)
+#define	ERRCONFIG_MCUVALIDINTEN		BIT(27)
+#define ERRCONFIG_MCUVALIDINTST		BIT(26)
+#define ERRCONFIG_MCUBOUNDINTEN		BIT(25)
+#define	ERRCONFIG_MCUBOUNDINTST		BIT(24)
+#define	ERRCONFIG_MCUDISACKINTEN	BIT(23)
+#define ERRCONFIG_VPBOUNDINTST_V2	BIT(23)
+#define ERRCONFIG_MCUDISACKINTST	BIT(22)
+#define ERRCONFIG_VPBOUNDINTEN_V2	BIT(22)
+
+#define ERRCONFIG_STATUS_V1_MASK	(ERRCONFIG_VPBOUNDINTST_V1 | \
+					ERRCONFIG_MCUACCUMINTST | \
+					ERRCONFIG_MCUVALIDINTST | \
+					ERRCONFIG_MCUBOUNDINTST | \
+					ERRCONFIG_MCUDISACKINTST)
+/* IRQSTATUS */
+#define IRQSTATUS_MCUACCUMINT		BIT(3)
+#define IRQSTATUS_MCVALIDINT		BIT(2)
+#define IRQSTATUS_MCBOUNDSINT		BIT(1)
+#define IRQSTATUS_MCUDISABLEACKINT	BIT(0)
+
+/* IRQENABLE_SET and IRQENABLE_CLEAR */
+#define IRQENABLE_MCUACCUMINT		BIT(3)
+#define IRQENABLE_MCUVALIDINT		BIT(2)
+#define IRQENABLE_MCUBOUNDSINT		BIT(1)
+#define IRQENABLE_MCUDISABLEACKINT	BIT(0)
+
+/* Common Bit values */
+
+#define SRCLKLENGTH_12MHZ_SYSCLK	0x3c
+#define SRCLKLENGTH_13MHZ_SYSCLK	0x41
+#define SRCLKLENGTH_19MHZ_SYSCLK	0x60
+#define SRCLKLENGTH_26MHZ_SYSCLK	0x82
+#define SRCLKLENGTH_38MHZ_SYSCLK	0xC0
+
+/*
+ * 3430 specific values. Maybe these should be passed from board file or
+ * pmic structures.
+ */
+#define OMAP3430_SR_ACCUMDATA		0x1f4
+
+#define OMAP3430_SR1_SENPAVGWEIGHT	0x03
+#define OMAP3430_SR1_SENNAVGWEIGHT	0x03
+
+#define OMAP3430_SR2_SENPAVGWEIGHT	0x01
+#define OMAP3430_SR2_SENNAVGWEIGHT	0x01
+
+#define OMAP3430_SR_ERRWEIGHT		0x04
+#define OMAP3430_SR_ERRMAXLIMIT		0x02
+
+/**
+ * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass
+ *				pmic specific info to smartreflex driver
+ *
+ * @sr_pmic_init:	API to initialize smartreflex on the PMIC side.
+ */
+struct omap_sr_pmic_data {
+	void (*sr_pmic_init) (void);
+};
+
+#ifdef CONFIG_OMAP_SMARTREFLEX
+/*
+ * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
+ * The smartreflex class driver should pass the class type.
+ * Should be used to populate the class_type field of the
+ * omap_smartreflex_class_data structure.
+ */
+#define SR_CLASS1	0x1
+#define SR_CLASS2	0x2
+#define SR_CLASS3	0x3
+
+/**
+ * struct omap_sr_class_data - Smartreflex class driver info
+ *
+ * @enable:		API to enable a particular class smaartreflex.
+ * @disable:		API to disable a particular class smartreflex.
+ * @configure:		API to configure a particular class smartreflex.
+ * @notify:		API to notify the class driver about an event in SR.
+ *			Not needed for class3.
+ * @notify_flags:	specify the events to be notified to the class driver
+ * @class_type:		specify which smartreflex class.
+ *			Can be used by the SR driver to take any class
+ *			based decisions.
+ */
+struct omap_sr_class_data {
+	int (*enable)(struct voltagedomain *voltdm);
+	int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
+	int (*configure)(struct voltagedomain *voltdm);
+	int (*notify)(struct voltagedomain *voltdm, u32 status);
+	u8 notify_flags;
+	u8 class_type;
+};
+
+/**
+ * struct omap_sr_nvalue_table	- Smartreflex n-target value info
+ *
+ * @efuse_offs:	The offset of the efuse where n-target values are stored.
+ * @nvalue:	The n-target value.
+ */
+struct omap_sr_nvalue_table {
+	u32 efuse_offs;
+	u32 nvalue;
+};
+
+/**
+ * struct omap_sr_data - Smartreflex platform data.
+ *
+ * @ip_type:		Smartreflex IP type.
+ * @senp_mod:		SENPENABLE value for the sr
+ * @senn_mod:		SENNENABLE value for sr
+ * @nvalue_count:	Number of distinct nvalues in the nvalue table
+ * @enable_on_init:	whether this sr module needs to enabled at
+ *			boot up or not.
+ * @nvalue_table:	table containing the  efuse offsets and nvalues
+ *			corresponding to them.
+ * @voltdm:		Pointer to the voltage domain associated with the SR
+ */
+struct omap_sr_data {
+	int				ip_type;
+	u32				senp_mod;
+	u32				senn_mod;
+	int				nvalue_count;
+	bool				enable_on_init;
+	struct omap_sr_nvalue_table	*nvalue_table;
+	struct voltagedomain		*voltdm;
+};
+
+/* Smartreflex module enable/disable interface */
+void omap_sr_enable(struct voltagedomain *voltdm);
+void omap_sr_disable(struct voltagedomain *voltdm);
+void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
+
+/* API to register the pmic specific data with the smartreflex driver. */
+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_configure_errgen(struct voltagedomain *voltdm);
+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);
+#else
+static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
+static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
+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) {}
+#endif
+#endif
-- 
1.7.0.4

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

* [PATCH v6 04/10] OMAP3: PM: Adding smartreflex device file.
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (2 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 03/10] OMAP3: PM: Adding smartreflex driver support Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 05/10] OMAP3: PM: Adding smartreflex hwmod data Thara Gopinath
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds support for device registration of various
smartreflex module present in the system. This patch introduces
the platform data for smartreflex devices which include
the efused n-target vaules, a parameter to indicate
whether smartreflex autocompensation needs to be
enabled on init or not. An API
omap_enable_smartreflex_on_init is provided for the
board files to enable smartreflex autocompensation during
system boot up.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/Makefile    |    2 +-
 arch/arm/mach-omap2/pm.c        |    2 +
 arch/arm/mach-omap2/pm.h        |   13 ++++
 arch/arm/mach-omap2/sr_device.c |  131 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/sr_device.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index b1bead0..4e6adbd 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -61,7 +61,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o pm_bus.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o pm_bus.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
-obj-$(CONFIG_OMAP_SMARTREFLEX)          += smartreflex.o
+obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 22adfb2..a05f590 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -21,6 +21,7 @@
 
 #include "powerdomain.h"
 #include "clockdomain.h"
+#include "pm.h"
 
 static struct omap_device_pm_latency *pm_lats;
 
@@ -149,6 +150,7 @@ postcore_initcall(omap2_common_pm_init);
 static int __init omap2_common_pm_late_init(void)
 {
 	omap_voltage_late_init();
+	omap_devinit_smartreflex();
 
 	return 0;
 }
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 419c9d4..77d3ec2 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -11,6 +11,8 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_PM_H
 #define __ARCH_ARM_MACH_OMAP2_PM_H
 
+#include <linux/err.h>
+
 #include "powerdomain.h"
 
 extern void *omap3_secure_ram_storage;
@@ -99,4 +101,15 @@ extern unsigned int save_secure_ram_context_sz;
 extern unsigned int omap24xx_cpu_suspend_sz;
 extern unsigned int omap34xx_cpu_suspend_sz;
 
+#ifdef CONFIG_OMAP_SMARTREFLEX
+extern int omap_devinit_smartreflex(void);
+extern void omap_enable_smartreflex_on_init(void);
+#else
+static inline int omap_devinit_smartreflex(void)
+{
+	return -EINVAL;
+}
+
+static inline void omap_enable_smartreflex_on_init(void) {}
+#endif
 #endif
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
new file mode 100644
index 0000000..9a3538f
--- /dev/null
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -0,0 +1,131 @@
+/*
+ * OMAP3/OMAP4 smartreflex device file
+ *
+ * Author: Thara Gopinath	<thara@ti.com>
+ *
+ * Based originally on code from smartreflex.c
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * 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/err.h>
+#include <linux/slab.h>
+
+#include <plat/omap_device.h>
+#include <plat/smartreflex.h>
+#include <plat/voltage.h>
+
+#include "control.h"
+
+static bool sr_enable_on_init;
+
+static struct omap_device_pm_latency omap_sr_latency[] = {
+	{
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_func	 = omap_device_enable_hwmods,
+		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST
+	},
+};
+
+/* Read EFUSE values from control registers for OMAP3430 */
+static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
+				struct omap_sr_data *sr_data)
+{
+	struct omap_sr_nvalue_table *nvalue_table;
+	int i, count = 0;
+
+	while (volt_data[count].volt_nominal)
+		count++;
+
+	nvalue_table = kzalloc(sizeof(struct omap_sr_nvalue_table)*count,
+			GFP_KERNEL);
+
+	for (i = 0; i < count; i++) {
+		u32 v = omap_ctrl_readl(volt_data[i].sr_efuse_offs);
+
+		nvalue_table[i].efuse_offs = volt_data[i].sr_efuse_offs;
+		nvalue_table[i].nvalue = v;
+	}
+
+	sr_data->nvalue_table = nvalue_table;
+	sr_data->nvalue_count = count;
+}
+
+static int sr_dev_init(struct omap_hwmod *oh, void *user)
+{
+	struct omap_sr_data *sr_data;
+	struct omap_device *od;
+	struct omap_volt_data *volt_data;
+	char *name = "smartreflex";
+	static int i;
+
+	sr_data = kzalloc(sizeof(struct omap_sr_data), GFP_KERNEL);
+	if (!sr_data) {
+		pr_err("%s: Unable to allocate memory for %s sr_data.Error!\n",
+			__func__, oh->name);
+		return -ENOMEM;
+	}
+
+	if (!oh->vdd_name) {
+		pr_err("%s: No voltage domain specified for %s."
+			"Cannot initialize\n", __func__, oh->name);
+		goto exit;
+	}
+
+	sr_data->ip_type = oh->class->rev;
+	sr_data->senn_mod = 0x1;
+	sr_data->senp_mod = 0x1;
+
+	sr_data->voltdm = omap_voltage_domain_lookup(oh->vdd_name);
+	if (IS_ERR(sr_data->voltdm)) {
+		pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
+			__func__, oh->vdd_name);
+		goto exit;
+	}
+
+	omap_voltage_get_volttable(sr_data->voltdm, &volt_data);
+	if (!volt_data) {
+		pr_warning("%s: No Voltage table registerd fo VDD%d."
+			"Something really wrong\n\n", __func__, i + 1);
+		goto exit;
+	}
+
+	sr_set_nvalues(volt_data, sr_data);
+
+	sr_data->enable_on_init = sr_enable_on_init;
+
+	od = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
+			       omap_sr_latency,
+			       ARRAY_SIZE(omap_sr_latency), 0);
+	if (IS_ERR(od))
+		pr_warning("%s: Could not build omap_device for %s: %s.\n\n",
+			__func__, name, oh->name);
+exit:
+	i++;
+	kfree(sr_data);
+	return 0;
+}
+
+/*
+ * API to be called from board files to enable smartreflex
+ * autocompensation at init.
+ */
+void __init omap_enable_smartreflex_on_init(void)
+{
+	sr_enable_on_init = true;
+}
+
+int __init omap_devinit_smartreflex(void)
+{
+	return omap_hwmod_for_each_by_class("smartreflex", sr_dev_init, NULL);
+}
-- 
1.7.0.4

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

* [PATCH v6 05/10] OMAP3: PM: Adding smartreflex hwmod data
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (3 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 04/10] OMAP3: PM: Adding smartreflex device file Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 06/10] OMAP3: PM: Adding smartreflex class3 driver Thara Gopinath
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the smartreflex hwmod data for OMAP3430
and OMAP3630.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |  176 ++++++++++++++++++++++++++++
 1 files changed, 176 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 8eb81b4..c98cfc0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -21,6 +21,8 @@
 #include <plat/l4_3xxx.h>
 #include <plat/i2c.h>
 #include <plat/gpio.h>
+#include <plat/smartreflex.h>
+#include <plat/smartreflex.h>
 
 #include "omap_hwmod_common_data.h"
 
@@ -52,6 +54,8 @@ static struct omap_hwmod omap3xxx_gpio3_hwmod;
 static struct omap_hwmod omap3xxx_gpio4_hwmod;
 static struct omap_hwmod omap3xxx_gpio5_hwmod;
 static struct omap_hwmod omap3xxx_gpio6_hwmod;
+static struct omap_hwmod omap34xx_sr1_hwmod;
+static struct omap_hwmod omap34xx_sr2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -260,9 +264,47 @@ static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = {
 	.user		= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> SR1 interface */
+static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
+	{
+		.pa_start	= OMAP34XX_SR1_BASE,
+		.pa_end		= OMAP34XX_SR1_BASE + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__sr1 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap34xx_sr1_hwmod,
+	.clk		= "sr_l4_ick",
+	.addr		= omap3_sr1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3_sr1_addr_space),
+	.user		= OCP_USER_MPU,
+};
+
+/* L4 CORE -> SR1 interface */
+static struct omap_hwmod_addr_space omap3_sr2_addr_space[] = {
+	{
+		.pa_start	= OMAP34XX_SR2_BASE,
+		.pa_end		= OMAP34XX_SR2_BASE + SZ_1K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__sr2 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap34xx_sr2_hwmod,
+	.clk		= "sr_l4_ick",
+	.addr		= omap3_sr2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3_sr2_addr_space),
+	.user		= OCP_USER_MPU,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
 	&omap3xxx_l3_main__l4_core,
+	&omap3_l4_core__sr1,
+	&omap3_l4_core__sr2,
 };
 
 /* Master interfaces on the L4_CORE interconnect */
@@ -1092,6 +1134,135 @@ static struct omap_hwmod omap3xxx_gpio6_hwmod = {
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
 
+/* SR common */
+static struct omap_hwmod_sysc_fields omap34xx_sr_sysc_fields = {
+	.clkact_shift	= 20,
+};
+
+static struct omap_hwmod_class_sysconfig omap34xx_sr_sysc = {
+	.sysc_offs	= 0x24,
+	.sysc_flags	= (SYSC_HAS_CLOCKACTIVITY | SYSC_NO_CACHE),
+	.clockact	= CLOCKACT_TEST_ICLK,
+	.sysc_fields	= &omap34xx_sr_sysc_fields,
+};
+
+static struct omap_hwmod_class omap34xx_smartreflex_hwmod_class = {
+	.name = "smartreflex",
+	.sysc = &omap34xx_sr_sysc,
+	.rev  = 1,
+};
+
+static struct omap_hwmod_sysc_fields omap36xx_sr_sysc_fields = {
+	.sidle_shift	= 24,
+	.enwkup_shift	= 26
+};
+
+static struct omap_hwmod_class_sysconfig omap36xx_sr_sysc = {
+	.sysc_offs	= 0x38,
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
+			SYSC_NO_CACHE),
+	.sysc_fields	= &omap36xx_sr_sysc_fields,
+};
+
+static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = {
+	.name = "smartreflex",
+	.sysc = &omap36xx_sr_sysc,
+	.rev  = 2,
+};
+
+/* SR1 */
+static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = {
+	&omap3_l4_core__sr1,
+};
+
+static struct omap_hwmod omap34xx_sr1_hwmod = {
+	.name		= "sr1_hwmod",
+	.class		= &omap34xx_smartreflex_hwmod_class,
+	.main_clk	= "sr1_fck",
+	.vdd_name	= "mpu",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
+		},
+	},
+	.slaves		= omap3_sr1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2 |
+					CHIP_IS_OMAP3430ES3_0 |
+					CHIP_IS_OMAP3430ES3_1),
+	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+};
+
+static struct omap_hwmod omap36xx_sr1_hwmod = {
+	.name		= "sr1_hwmod",
+	.class		= &omap36xx_smartreflex_hwmod_class,
+	.main_clk	= "sr1_fck",
+	.vdd_name	= "mpu",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR1_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
+		},
+	},
+	.slaves		= omap3_sr1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3_sr1_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
+/* SR2 */
+static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = {
+	&omap3_l4_core__sr2,
+};
+
+static struct omap_hwmod omap34xx_sr2_hwmod = {
+	.name		= "sr2_hwmod",
+	.class		= &omap34xx_smartreflex_hwmod_class,
+	.main_clk	= "sr2_fck",
+	.vdd_name	= "core",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
+		},
+	},
+	.slaves		= omap3_sr2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2 |
+					CHIP_IS_OMAP3430ES3_0 |
+					CHIP_IS_OMAP3430ES3_1),
+	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+};
+
+static struct omap_hwmod omap36xx_sr2_hwmod = {
+	.name		= "sr2_hwmod",
+	.class		= &omap36xx_smartreflex_hwmod_class,
+	.main_clk	= "sr2_fck",
+	.vdd_name	= "core",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_SR2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
+		},
+	},
+	.slaves		= omap3_sr2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3_sr2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
 static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l3_main_hwmod,
 	&omap3xxx_l4_core_hwmod,
@@ -1107,6 +1278,11 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_i2c1_hwmod,
 	&omap3xxx_i2c2_hwmod,
 	&omap3xxx_i2c3_hwmod,
+	&omap34xx_sr1_hwmod,
+	&omap34xx_sr2_hwmod,
+	&omap36xx_sr1_hwmod,
+	&omap36xx_sr2_hwmod,
+
 
 	/* gpio class */
 	&omap3xxx_gpio1_hwmod,
-- 
1.7.0.4

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

* [PATCH v6 06/10] OMAP3: PM: Adding smartreflex class3 driver
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (4 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 05/10] OMAP3: PM: Adding smartreflex hwmod data Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

Smartreflex Class3 implementation continuously monitors
silicon performance  and instructs the Voltage Processors
to increase or decrease the voltage.
This patch adds smartreflex class 3 driver. This driver hooks
up with the generic smartreflex driver smartreflex.c to abstract
out class specific implementations out of the generic driver.

Class3 driver is chosen as the default class driver for smartreflex.
If any other class driver needs to be implemented, the init of that
driver should be called from the board file. That way the new class driver
will over-ride the Class3 driver.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/Makefile             |    1 +
 arch/arm/mach-omap2/smartreflex-class3.c |   59 ++++++++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig               |    9 +++++
 3 files changed, 69 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex-class3.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 4e6adbd..1963f9e 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
new file mode 100644
index 0000000..60e7055
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -0,0 +1,59 @@
+/*
+ * Smart reflex Class 3 specific implementations
+ *
+ * Author: Thara Gopinath       <thara@ti.com>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * 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 <plat/smartreflex.h>
+
+static int sr_class3_enable(struct voltagedomain *voltdm)
+{
+	unsigned long volt = 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);
+}
+
+static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
+{
+	omap_vp_disable(voltdm);
+	sr_disable(voltdm);
+	if (is_volt_reset)
+		omap_voltage_reset(voltdm);
+
+	return 0;
+}
+
+static int sr_class3_configure(struct voltagedomain *voltdm)
+{
+	return sr_configure_errgen(voltdm);
+}
+
+/* SR class3 structure */
+static struct omap_sr_class_data class3_data = {
+	.enable = sr_class3_enable,
+	.disable = sr_class3_disable,
+	.configure = sr_class3_configure,
+	.class_type = SR_CLASS3,
+};
+
+/* Smartreflex Class3 init API to be called from board file */
+static int __init sr_class3_init(void)
+{
+	pr_info("SmartReflex Class3 initialized\n");
+	return sr_register_class(&class3_data);
+}
+late_initcall(sr_class3_init);
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 95ceca0..4029e6a 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -57,6 +57,15 @@ config OMAP_SMARTREFLEX
 	  by default during system init via the enable_on_init flag
 	  which an be passed as platform data to the smartreflex driver.
 
+config OMAP_SMARTREFLEX_CLASS3
+	bool "Class 3 mode of Smartreflex Implementation"
+	depends on OMAP_SMARTREFLEX && TWL4030_CORE
+	help
+	  Say Y to enable Class 3 implementation of Smartreflex
+
+	  Class 3 implementation of Smartreflex employs continuous hardware
+	  voltage calibration.
+
 config OMAP_RESET_CLOCKS
 	bool "Reset unused clocks during boot"
 	depends on ARCH_OMAP
-- 
1.7.0.4

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

* [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (5 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 06/10] OMAP3: PM: Adding smartreflex class3 driver Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-22 20:30   ` Kevin Hilman
  2010-12-20 16:59 ` [PATCH v6 08/10] OMAP3: PM: Register TWL4030 pmic info with the voltage driver Thara Gopinath
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds support in the twl4030 driver to enable smartreflex.
The smartreflex bit on twl4030 needs to be enabled by default irrespective
of whether smartreflex module is enabled on the OMAP side or not.
This is because without this bit enabled the voltage scaling through
vp forceupdate does not function properly.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 drivers/mfd/twl-core.c  |   13 +++++++++++++
 include/linux/i2c/twl.h |   11 +++++++++++
 2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 35275ba..b895ceb 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -1046,6 +1046,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
 	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
 	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
+	 * Also enable the smartreflex I2S bit.
 	 */
 
 	if (twl_class_is_4030()) {
@@ -1053,6 +1054,18 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
 		I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
 		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
+
+		/* The smartreflex bit on twl4030 needs to be enabled by
+		 * default irrespective of whether smartreflex module is
+		 * enabled on the OMAP side or not. This is because without
+		 * this bit enabled the voltage scaling through
+		 * vp forceupdate does not function properly.
+		 */
+		twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp,
+			TWL4030_PM_RECEIVER_DCDC_GLOBAL_CFG);
+		temp |= SMARTREFLEX_ENABLE;
+		twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp,
+			TWL4030_PM_RECEIVER_DCDC_GLOBAL_CFG);
 	}
 
 	status = add_children(pdata, id->driver_data);
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index c760991..d392f06 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -434,6 +434,17 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
 
 /*----------------------------------------------------------------------*/
 
+/*
+ * PM Receiver module register offsets (use TWL4030_MODULE_PM_RECEIVER)
+ */
+
+#define TWL4030_PM_RECEIVER_DCDC_GLOBAL_CFG	0x06
+
+/* Smartreflex I2S bus enable/ vmode enable bit */
+#define SMARTREFLEX_ENABLE			BIT(3)
+
+/*----------------------------------------------------------------------*/
+
 /* Power bus message definitions */
 
 /* The TWL4030/5030 splits its power-management resources (the various
-- 
1.7.0.4

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

* [PATCH v6 08/10] OMAP3: PM: Register TWL4030 pmic info with the voltage driver.
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (6 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-20 16:59 ` [PATCH v6 09/10] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch registers the TWL4030 PMIC specific informtion
with the voltage driver. Failing this patch the voltage driver
is unware of the formula to use for vsel to voltage and vice versa
conversion and lot of other PMIC dependent parameters.

This file is based on the arch/arm/plat-omap opp_twl_tpl.c file
by Paul Walmsley. The original file is replaced by this file.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/Makefile   |    2 +
 arch/arm/mach-omap2/omap_twl.c |  111 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.c       |    4 ++
 arch/arm/mach-omap2/pm.h       |   10 ++++
 4 files changed, 127 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/omap_twl.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 1963f9e..ae29a00 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
+obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
+
 # SMP support ONLY available for OMAP4
 obj-$(CONFIG_SMP)			+= omap-smp.o omap-headsmp.o
 obj-$(CONFIG_LOCAL_TIMERS)		+= timer-mpu.o
diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c
new file mode 100644
index 0000000..b8f0874
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_twl.c
@@ -0,0 +1,111 @@
+/**
+ * OMAP and TWL PMIC specific intializations.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated.
+ * Thara Gopinath
+ * Copyright (C) 2009 Texas Instruments Incorporated.
+ * Nishanth Menon
+ * Copyright (C) 2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include <plat/voltage.h>
+
+#define OMAP3_SRI2C_SLAVE_ADDR		0x12
+#define OMAP3_VDD_MPU_SR_CONTROL_REG	0x00
+#define OMAP3_VDD_CORE_SR_CONTROL_REG	0x01
+#define OMAP3_VP_CONFIG_ERROROFFSET	0x00
+#define OMAP3_VP_VSTEPMIN_VSTEPMIN	0x1
+#define OMAP3_VP_VSTEPMAX_VSTEPMAX	0x04
+#define OMAP3_VP_VLIMITTO_TIMEOUT_US	200
+
+#define OMAP3430_VP1_VLIMITTO_VDDMIN	0x14
+#define OMAP3430_VP1_VLIMITTO_VDDMAX	0x42
+#define OMAP3430_VP2_VLIMITTO_VDDMIN	0x18
+#define OMAP3430_VP2_VLIMITTO_VDDMAX	0x2c
+
+#define OMAP3630_VP1_VLIMITTO_VDDMIN	0x18
+#define OMAP3630_VP1_VLIMITTO_VDDMAX	0x3c
+#define OMAP3630_VP2_VLIMITTO_VDDMIN	0x18
+#define OMAP3630_VP2_VLIMITTO_VDDMAX	0x30
+
+unsigned long twl4030_vsel_to_uv(const u8 vsel)
+{
+	return (((vsel * 125) + 6000)) * 100;
+}
+
+u8 twl4030_uv_to_vsel(unsigned long uv)
+{
+	return DIV_ROUND_UP(uv - 600000, 12500);
+}
+
+static struct omap_volt_pmic_info omap3_mpu_volt_info = {
+	.slew_rate		= 4000,
+	.step_size		= 12500,
+	.on_volt		= 1200000,
+	.onlp_volt		= 1000000,
+	.ret_volt		= 975000,
+	.off_volt		= 600000,
+	.volt_setup_time	= 0xfff,
+	.vp_erroroffset		= OMAP3_VP_CONFIG_ERROROFFSET,
+	.vp_vstepmin		= OMAP3_VP_VSTEPMIN_VSTEPMIN,
+	.vp_vstepmax		= OMAP3_VP_VSTEPMAX_VSTEPMAX,
+	.vp_vddmin		= OMAP3430_VP1_VLIMITTO_VDDMIN,
+	.vp_vddmax		= OMAP3430_VP1_VLIMITTO_VDDMAX,
+	.vp_timeout_us		= OMAP3_VP_VLIMITTO_TIMEOUT_US,
+	.i2c_slave_addr		= OMAP3_SRI2C_SLAVE_ADDR,
+	.pmic_reg		= OMAP3_VDD_MPU_SR_CONTROL_REG,
+	.vsel_to_uv		= twl4030_vsel_to_uv,
+	.uv_to_vsel		= twl4030_uv_to_vsel,
+};
+
+static struct omap_volt_pmic_info omap3_core_volt_info = {
+	.slew_rate		= 4000,
+	.step_size		= 12500,
+	.on_volt                = 1200000,
+	.onlp_volt              = 1000000,
+	.ret_volt               = 975000,
+	.off_volt               = 600000,
+	.volt_setup_time        = 0xfff,
+	.vp_erroroffset		= OMAP3_VP_CONFIG_ERROROFFSET,
+	.vp_vstepmin		= OMAP3_VP_VSTEPMIN_VSTEPMIN,
+	.vp_vstepmax		= OMAP3_VP_VSTEPMAX_VSTEPMAX,
+	.vp_vddmin		= OMAP3430_VP2_VLIMITTO_VDDMIN,
+	.vp_vddmax		= OMAP3430_VP2_VLIMITTO_VDDMAX,
+	.vp_timeout_us		= OMAP3_VP_VLIMITTO_TIMEOUT_US,
+	.i2c_slave_addr		= OMAP3_SRI2C_SLAVE_ADDR,
+	.pmic_reg		= OMAP3_VDD_CORE_SR_CONTROL_REG,
+	.vsel_to_uv		= twl4030_vsel_to_uv,
+	.uv_to_vsel		= twl4030_uv_to_vsel,
+};
+
+int __init omap3_twl_init(void)
+{
+	struct voltagedomain *voltdm;
+
+	if (!cpu_is_omap34xx())
+		return -ENODEV;
+
+	if (cpu_is_omap3630()) {
+		omap3_mpu_volt_info.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN;
+		omap3_mpu_volt_info.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX;
+		omap3_core_volt_info.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN;
+		omap3_core_volt_info.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX;
+	}
+
+	voltdm = omap_voltage_domain_lookup("mpu");
+	omap_voltage_register_pmic(voltdm, &omap3_mpu_volt_info);
+
+	voltdm = omap_voltage_domain_lookup("core");
+	omap_voltage_register_pmic(voltdm, &omap3_core_volt_info);
+
+	return 0;
+}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index a05f590..e84f46b 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -149,7 +149,11 @@ postcore_initcall(omap2_common_pm_init);
 
 static int __init omap2_common_pm_late_init(void)
 {
+	/* Init the OMAP TWL parameters */
+	omap3_twl_init();
+	/* Init the voltage layer */
 	omap_voltage_late_init();
+	/* Smartreflex device init */
 	omap_devinit_smartreflex();
 
 	return 0;
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 77d3ec2..619db1b 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -112,4 +112,14 @@ static inline int omap_devinit_smartreflex(void)
 
 static inline void omap_enable_smartreflex_on_init(void) {}
 #endif
+
+#ifdef CONFIG_TWL4030_CORE
+extern int omap3_twl_init(void);
+#else
+static inline int omap3_twl_init(void)
+{
+	return -EINVAL;
+}
+#endif
+
 #endif
-- 
1.7.0.4

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

* [PATCH v6 09/10] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (7 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 08/10] OMAP3: PM: Register TWL4030 pmic info with the voltage driver Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-28 17:07   ` Anand Sawant
  2010-12-20 16:59 ` [PATCH v6 10/10] OMAP3: PM: Program correct init voltages for VDD1 and VDD2 Thara Gopinath
  2010-12-21  1:05 ` [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Kevin Hilman
  10 siblings, 1 reply; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds debug support to the voltage and smartreflex drivers.
This means a whole bunch of voltage processor and smartreflex
parameters are now visible through the pm debugfs.
The voltage parameters can be viewed at
        /debug/voltage/vdd_<x>/<parameter>
and the smartreflex parameters can be viewed at
        /debug/voltage/vdd_<x>/smartreflex/<parameter>

Also smartreflex n-target values are now exposed out at
	/debug/voltage/vdd_<x>/smartreflex/nvalue/<voltage>

The interface to access smartreflex n-target values is a
read-write interface which means user has the flexibility
to change the n-target values for any opp.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c |   46 ++++++++++++++++++++++++-
 arch/arm/mach-omap2/voltage.c     |   66 +++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index eee23d0..52a05b3 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -31,6 +31,7 @@
 #include "pm.h"
 
 #define SMARTREFLEX_NAME_LEN	16
+#define NVALUE_NAME_LEN		40
 #define SR_DISABLE_TIMEOUT	200
 
 struct omap_sr {
@@ -817,8 +818,9 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 	struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
 	struct omap_sr_data *pdata = pdev->dev.platform_data;
 	struct resource *mem, *irq;
-	struct dentry *vdd_dbg_dir, *dbg_dir;
-	int ret = 0;
+	struct dentry *vdd_dbg_dir, *dbg_dir, *nvalue_dir;
+	struct omap_volt_data *volt_data;
+	int i, ret = 0;
 
 	if (!sr_info) {
 		dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
@@ -897,6 +899,46 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
 	(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
 				(void *)sr_info, &pm_sr_fops);
+	(void) debugfs_create_x32("errweight", S_IRUGO, dbg_dir,
+			&sr_info->err_weight);
+	(void) debugfs_create_x32("errmaxlimit", S_IRUGO, dbg_dir,
+			&sr_info->err_maxlimit);
+	(void) debugfs_create_x32("errminlimit", S_IRUGO, dbg_dir,
+			&sr_info->err_minlimit);
+
+	nvalue_dir = debugfs_create_dir("nvalue", dbg_dir);
+	if (IS_ERR(nvalue_dir)) {
+		dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
+			"for n-values\n", __func__);
+		return PTR_ERR(nvalue_dir);
+	}
+
+	omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
+	if (!volt_data) {
+		dev_warn(&pdev->dev, "%s: No Voltage table for the"
+			" corresponding vdd vdd_%s. Cannot create debugfs"
+			"entries for n-values\n",
+			__func__, sr_info->voltdm->name);
+		return -ENODATA;
+	}
+
+	for (i = 0; i < sr_info->nvalue_count; i++) {
+		char *name;
+		char volt_name[32];
+
+		name = kzalloc(NVALUE_NAME_LEN + 1, GFP_KERNEL);
+		if (!name) {
+			dev_err(&pdev->dev, "%s: Unable to allocate memory"
+				" for n-value directory name\n",  __func__);
+			return -ENOMEM;
+		}
+
+		strcpy(name, "volt_");
+		sprintf(volt_name, "%d", volt_data[i].volt_nominal);
+		strcat(name, volt_name);
+		(void) debugfs_create_x32(name, S_IRUGO | S_IWUGO, nvalue_dir,
+				&(sr_info->nvalue_table[i].nvalue));
+	}
 
 	return ret;
 
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 875667f..b27fa4f 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -250,6 +250,47 @@ static void omap3_voltage_write_reg(u32 val, u16 mod, u8 offset)
 	omap2_prm_write_mod_reg(val, mod, offset);
 }
 
+/* Voltage debugfs support */
+static int vp_volt_debug_get(void *data, u64 *val)
+{
+	struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
+	u8 vsel;
+
+	if (!vdd) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+
+	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"
+			"in uV not registerd\n");
+		return -EINVAL;
+	}
+
+	*val = vdd->pmic_info->vsel_to_uv(vsel);
+	return 0;
+}
+
+static int nom_volt_debug_get(void *data, u64 *val)
+{
+	struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
+
+	if (!vdd) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+
+	*val = omap_voltage_get_nom_volt(&vdd->voltdm);
+
+	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");
 static void vp_latch_vsel(struct omap_vdd_info *vdd)
 {
 	u32 vpconfig;
@@ -349,7 +390,32 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
 		pr_warning("%s: Unable to create debugfs directory for"
 			" vdd_%s\n", __func__, vdd->voltdm.name);
 		vdd->debug_dir = NULL;
+		return;
 	}
+
+	(void) debugfs_create_x16("vp_errorgain", S_IRUGO, vdd->debug_dir,
+				&(vdd->vp_reg.vpconfig_errorgain));
+	(void) debugfs_create_x16("vp_smpswaittimemin", S_IRUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vstepmin_smpswaittimemin));
+	(void) debugfs_create_x8("vp_stepmin", S_IRUGO, vdd->debug_dir,
+				&(vdd->vp_reg.vstepmin_stepmin));
+	(void) debugfs_create_x16("vp_smpswaittimemax", S_IRUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vstepmax_smpswaittimemax));
+	(void) debugfs_create_x8("vp_stepmax", S_IRUGO, vdd->debug_dir,
+				&(vdd->vp_reg.vstepmax_stepmax));
+	(void) debugfs_create_x8("vp_vddmax", S_IRUGO, vdd->debug_dir,
+				&(vdd->vp_reg.vlimitto_vddmax));
+	(void) debugfs_create_x8("vp_vddmin", S_IRUGO, vdd->debug_dir,
+				&(vdd->vp_reg.vlimitto_vddmin));
+	(void) debugfs_create_x16("vp_timeout", S_IRUGO, vdd->debug_dir,
+				&(vdd->vp_reg.vlimitto_timeout));
+	(void) debugfs_create_file("curr_vp_volt", S_IRUGO, vdd->debug_dir,
+				(void *) vdd, &vp_volt_debug_fops);
+	(void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
+				vdd->debug_dir, (void *) vdd,
+				&nom_volt_debug_fops);
 }
 
 /* Voltage scale and accessory APIs */
-- 
1.7.0.4

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

* [PATCH v6 10/10] OMAP3: PM: Program correct init voltages for VDD1 and VDD2
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (8 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 09/10] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
@ 2010-12-20 16:59 ` Thara Gopinath
  2010-12-21  1:05 ` [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Kevin Hilman
  10 siblings, 0 replies; 22+ messages in thread
From: Thara Gopinath @ 2010-12-20 16:59 UTC (permalink / raw)
  To: linux-arm-kernel

By default the system boots up at nominal voltage for every
voltage domain in the system. This patch puts VDD1 and VDD2
to the correct boot up voltage as per the opp tables specified.
This patch implements this by matching the rate of the main clock
of the voltage domain with the opp table and picking up the correct
voltage.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/pm.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index e84f46b..cee86a5 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/opp.h>
 
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
@@ -138,6 +139,76 @@ err:
 	return ret;
 }
 
+/*
+ * This API is to be called during init to put the various voltage
+ * domains to the voltage as per the opp table. Typically we boot up
+ * at the nominal voltage. So this function finds out the rate of
+ * the clock associated with the voltage domain, finds out the correct
+ * opp entry and puts the voltage domain to the voltage specifies
+ * in the opp entry
+ */
+static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
+						struct device *dev)
+{
+	struct voltagedomain *voltdm;
+	struct clk *clk;
+	struct opp *opp;
+	unsigned long freq, bootup_volt;
+
+	if (!vdd_name || !clk_name || !dev) {
+		printk(KERN_ERR "%s: Invalid parameters!\n", __func__);
+		goto exit;
+	}
+
+	voltdm = omap_voltage_domain_lookup(vdd_name);
+	if (IS_ERR(voltdm)) {
+		printk(KERN_ERR "%s: Unable to get vdd pointer for vdd_%s\n",
+			__func__, vdd_name);
+		goto exit;
+	}
+
+	clk =  clk_get(NULL, clk_name);
+	if (IS_ERR(clk)) {
+		printk(KERN_ERR "%s: unable to get clk %s\n",
+			__func__, clk_name);
+		goto exit;
+	}
+
+	freq = clk->rate;
+	clk_put(clk);
+
+	opp = opp_find_freq_ceil(dev, &freq);
+	if (IS_ERR(opp)) {
+		printk(KERN_ERR "%s: unable to find boot up OPP for vdd_%s\n",
+			__func__, vdd_name);
+		goto exit;
+	}
+
+	bootup_volt = opp_get_voltage(opp);
+	if (!bootup_volt) {
+		printk(KERN_ERR "%s: unable to find voltage corresponding"
+			"to the bootup OPP for vdd_%s\n", __func__, vdd_name);
+		goto exit;
+	}
+
+	omap_voltage_scale_vdd(voltdm, bootup_volt);
+	return 0;
+
+exit:
+	printk(KERN_ERR "%s: Unable to put vdd_%s to its init voltage\n\n",
+		__func__, vdd_name);
+	return -EINVAL;
+}
+
+static void __init omap3_init_voltages(void)
+{
+	if (!cpu_is_omap34xx())
+		return;
+
+	omap2_set_init_voltage("mpu", "dpll1_ck", mpu_dev);
+	omap2_set_init_voltage("core", "l3_ick", l3_dev);
+}
+
 static int __init omap2_common_pm_init(void)
 {
 	omap2_init_processor_devices();
@@ -151,8 +222,13 @@ static int __init omap2_common_pm_late_init(void)
 {
 	/* Init the OMAP TWL parameters */
 	omap3_twl_init();
+
 	/* Init the voltage layer */
 	omap_voltage_late_init();
+
+	/* Initialize the voltages */
+	omap3_init_voltages();
+
 	/* Smartreflex device init */
 	omap_devinit_smartreflex();
 
-- 
1.7.0.4

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

* [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support
  2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (9 preceding siblings ...)
  2010-12-20 16:59 ` [PATCH v6 10/10] OMAP3: PM: Program correct init voltages for VDD1 and VDD2 Thara Gopinath
@ 2010-12-21  1:05 ` Kevin Hilman
  2010-12-21  2:23   ` Tony Lindgren
  10 siblings, 1 reply; 22+ messages in thread
From: Kevin Hilman @ 2010-12-21  1:05 UTC (permalink / raw)
  To: linux-arm-kernel

Thara Gopinath <thara@ti.com> writes:

> This patch series introduces smartreflex and voltage driver support
> for OMAP3430 and OMAP3630. SmartReflex modules do adaptive voltage
> control for real-time voltage adjustments.

Thanks Thara, these are looking good for 2.6.38.

Tony, unless there are major objections, I'll be queuing these two SR
series for 2.6.38.  They have dependencies on Paul's integration branch
so will wait 'til that stabilizies before sending pull request.

Kevin


> Originally all the functionalities introduced in this patch
> were present in arch/arm/mach-omap2/smartreflex.c file in Kevin's
> pm tree. This patch series does a major rewrite of this file
> and introduces a separate voltage driver. Major contributors
> to the original driver are
>
> Eduardo Valentin (1):
>       OMAP3: PM: SmartReflex: Fix scheduled while atomic problem
>
> Kalle Jokiniemi (1):
>       OMAP3: PM: SmartReflex driver integration
>
> Kevin Hilman (2):
>       temp: SR: IO_ADDRESS conversion
>       OMAP: SR: OPP interfaces removed from OMAP PM layer
>
> Nishanth Menon (1):
>       omap3: pm: sr: replace get_opp with freq_to_opp
>
> Paul Walmsley (2):
>       OMAP SR: use opp_find_opp_by_opp_id()
>       OMAP SR: use OPP API for OPP ID, remove direct access
>
> Phil Carmody (2):
>       OMAP3: PM: Don't do unnecessary searches in omap_sr_vdd*_autocomp_store
>       OMAP3: PM: Early exit on invalid parameters
>
> Rajendra Nayak (9):
>       OMAP3: SR: Fix init voltage on OPP change
>       OMAP3: SR: Update VDD1/2 voltages at boot
>       OMAP3: SR: Use sysclk for SR CLKLENGTH calc
>       OMAP3: SR: Reset voltage level on SR disable
>       OMAP3: SR: Replace printk's with pr_* calls
>       OMAP3: SR: Remove redundant defines
>       OMAP3: SR: Fix SR driver to check for omap-pm return values
>       OMAP3: PM: Put optimal SMPS stabilization delay
>       OMAP3: SR: Wait for VP idle before a VP disable
>
> Roger Quadros (4):
>       OMAP3: PM: Fix Smartreflex when used with PM_NOOP layer
>       OMAP3: PM: Make Smartreflex driver independent of SRF
>       OMAP3: PM: Do not Enable SmartReflex if OPP tables not defined
>       OMAP3: PM: Smartreflex: Fix VDD2 OPP determining logic
>
> Romit Dasgupta (1):
>       omap: pm: SR: use enum for OPP types
>
> Teerth Reddy (1):
>       OMAP3: SR: Replace SR_PASS/FAIL,SR_TRUE/FALSE
>
> Tero Kristo (1):
>       Smartreflex: Avoid unnecessary spam
>
> This patch series is against pm-core branch of Kevin Hilman's 
> OMAP PM tree with the following additional patch applied.
> 	https://patchwork.kernel.org/patch/421351/
>
> The entire series with the dependencies are available at
>         http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=summary
>         head: kevin-pm-sr
>
> This patch series has been tested on OMAP3430 SDP with omap2plus_defconfig
> with the following menuconfig options enabled.
> System type -> TI OMAP Implementations -> Smartreflex Support
> System type -> TI OMAP Implementations ->
>                 Class 3 mode of Smartreflex Implementation
>
> Major Changes in v6
> 	-Rebased to pm-core branch of Kevin Hilman's OMAP PM tree.
>
> Major Changes in v5
> 	- Rebased to k.org 2.6.37-rc3
> 	- Rebased to Nishant Menon's latest opp patches
> 	- Voltage pmic info structure extended to include a
> 		vast set of PMIC dependent parameters.
> 	- Smartreflex software n-target values support
> 		removed from the kernel. Instead n-target
> 		values are exposed as debugfs entries which can
> 		be written into by the user if needed.
> 	- Introduced a new file arch/arm/mach-omap2/omap_twl.c
> 		for specifying OMAP and TWL related info for
> 		the voltage layer.
> 	- Remove default enabling of smartreflex autocompensation
> 		during boot on OMAP3430 ES3.1 chips. Instead
> 		an API is provided that can be called from
> 		board files in case autocompensation needs
> 		to be enabled during boot up itself.
> 	- Other review comments on v4
>
> Thara Gopinath (10):
>   OMAP3: PM: Adding voltage driver support.
>   OMAP: Introduce voltage domain information in the hwmod structures
>   OMAP3: PM: Adding smartreflex driver support.
>   OMAP3: PM: Adding smartreflex device file.
>   OMAP3: PM: Adding smartreflex hwmod data
>   OMAP3: PM: Adding smartreflex class3 driver
>   OMAP3: PM: Adding T2 enabling of smartreflex support
>   OMAP3: PM: Register TWL4030 pmic info with the voltage driver.
>   OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
>   OMAP3: PM: Program correct init voltages for VDD1 and VDD2
>
>  arch/arm/mach-omap2/Makefile                  |    7 +-
>  arch/arm/mach-omap2/control.h                 |   17 +
>  arch/arm/mach-omap2/omap_hwmod_3xxx_data.c    |  176 ++++
>  arch/arm/mach-omap2/omap_twl.c                |  111 +++
>  arch/arm/mach-omap2/pm.c                      |   90 ++
>  arch/arm/mach-omap2/pm.h                      |   23 +
>  arch/arm/mach-omap2/smartreflex-class3.c      |   59 ++
>  arch/arm/mach-omap2/smartreflex.c             | 1025 ++++++++++++++++++++
>  arch/arm/mach-omap2/sr_device.c               |  131 +++
>  arch/arm/mach-omap2/voltage.c                 | 1292 +++++++++++++++++++++++++
>  arch/arm/plat-omap/Kconfig                    |   31 +
>  arch/arm/plat-omap/include/plat/omap_hwmod.h  |    5 +
>  arch/arm/plat-omap/include/plat/smartreflex.h |  245 +++++
>  arch/arm/plat-omap/include/plat/voltage.h     |  134 +++
>  drivers/mfd/twl-core.c                        |   13 +
>  include/linux/i2c/twl.h                       |   11 +
>  16 files changed, 3369 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/omap_twl.c
>  create mode 100644 arch/arm/mach-omap2/smartreflex-class3.c
>  create mode 100644 arch/arm/mach-omap2/smartreflex.c
>  create mode 100644 arch/arm/mach-omap2/sr_device.c
>  create mode 100644 arch/arm/mach-omap2/voltage.c
>  create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h
>  create mode 100644 arch/arm/plat-omap/include/plat/voltage.h

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

* [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support
  2010-12-21  1:05 ` [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Kevin Hilman
@ 2010-12-21  2:23   ` Tony Lindgren
  2010-12-21  3:18     ` Tony Lindgren
  2010-12-21 16:17     ` Kevin Hilman
  0 siblings, 2 replies; 22+ messages in thread
From: Tony Lindgren @ 2010-12-21  2:23 UTC (permalink / raw)
  To: linux-arm-kernel

* Kevin Hilman <khilman@deeprootsystems.com> [101220 17:05]:
> Thara Gopinath <thara@ti.com> writes:
> 
> > This patch series introduces smartreflex and voltage driver support
> > for OMAP3430 and OMAP3630. SmartReflex modules do adaptive voltage
> > control for real-time voltage adjustments.
> 
> Thanks Thara, these are looking good for 2.6.38.
> 
> Tony, unless there are major objections, I'll be queuing these two SR
> series for 2.6.38.  They have dependencies on Paul's integration branch

Well looking at patch 3/6 I think it should live under drivers somewhere
and mostly be compiled as a module. Probably the only change needed
for that is to not call cpu_is_omapxxxx but instead use some flags
passed in the platform_data. Otherwise the whole series looks OK to me.

Regards,

Tony

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

* [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support
  2010-12-21  2:23   ` Tony Lindgren
@ 2010-12-21  3:18     ` Tony Lindgren
  2010-12-21 16:17     ` Kevin Hilman
  1 sibling, 0 replies; 22+ messages in thread
From: Tony Lindgren @ 2010-12-21  3:18 UTC (permalink / raw)
  To: linux-arm-kernel

* Tony Lindgren <tony@atomide.com> [101220 18:31]:
> * Kevin Hilman <khilman@deeprootsystems.com> [101220 17:05]:
> > Thara Gopinath <thara@ti.com> writes:
> > 
> > > This patch series introduces smartreflex and voltage driver support
> > > for OMAP3430 and OMAP3630. SmartReflex modules do adaptive voltage
> > > control for real-time voltage adjustments.
> > 
> > Thanks Thara, these are looking good for 2.6.38.
> > 
> > Tony, unless there are major objections, I'll be queuing these two SR
> > series for 2.6.38.  They have dependencies on Paul's integration branch
> 
> Well looking at patch 3/6 I think it should live under drivers somewhere
> and mostly be compiled as a module. Probably the only change needed
> for that is to not call cpu_is_omapxxxx but instead use some flags
> passed in the platform_data. Otherwise the whole series looks OK to me.

Considering the short time left, maybe you can leave out the driver
part for now and merge all the platform related part for smartreflex?

Sorry I really should have made that driver comment way earlier..

Regards,

Tony

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

* [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support
  2010-12-21  2:23   ` Tony Lindgren
  2010-12-21  3:18     ` Tony Lindgren
@ 2010-12-21 16:17     ` Kevin Hilman
  2010-12-21 18:55       ` Tony Lindgren
  1 sibling, 1 reply; 22+ messages in thread
From: Kevin Hilman @ 2010-12-21 16:17 UTC (permalink / raw)
  To: linux-arm-kernel

Tony Lindgren <tony@atomide.com> writes:

> * Kevin Hilman <khilman@deeprootsystems.com> [101220 17:05]:
>> Thara Gopinath <thara@ti.com> writes:
>> 
>> > This patch series introduces smartreflex and voltage driver support
>> > for OMAP3430 and OMAP3630. SmartReflex modules do adaptive voltage
>> > control for real-time voltage adjustments.
>> 
>> Thanks Thara, these are looking good for 2.6.38.
>> 
>> Tony, unless there are major objections, I'll be queuing these two SR
>> series for 2.6.38.  They have dependencies on Paul's integration branch
>
> Well looking at patch 3/6 I think it should live under drivers somewhere
> and mostly be compiled as a module. Probably the only change needed
> for that is to not call cpu_is_omapxxxx but instead use some flags
> passed in the platform_data. Otherwise the whole series looks OK to me.

Moving this to be a regulator driver is part of the medium-term plan,
and is already under development.  For this phase, we just split up the
current driver into device and driver code and left under mach-omap2.
We are investigating (and making) changes to the regulator core so that
SmartReflex can be converted into a real regulator driver, but that is
still under development.

So, in the mean time, I'd like to merge this version so that other
development that depends on this (the regulator work mentioned above,
the DVFS work, etc.) can have a stable starting point.

Kevin

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

* [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support
  2010-12-21 16:17     ` Kevin Hilman
@ 2010-12-21 18:55       ` Tony Lindgren
  0 siblings, 0 replies; 22+ messages in thread
From: Tony Lindgren @ 2010-12-21 18:55 UTC (permalink / raw)
  To: linux-arm-kernel

* Kevin Hilman <khilman@deeprootsystems.com> [101221 08:17]:
> Tony Lindgren <tony@atomide.com> writes:
> 
> > * Kevin Hilman <khilman@deeprootsystems.com> [101220 17:05]:
> >> Thara Gopinath <thara@ti.com> writes:
> >> 
> >> > This patch series introduces smartreflex and voltage driver support
> >> > for OMAP3430 and OMAP3630. SmartReflex modules do adaptive voltage
> >> > control for real-time voltage adjustments.
> >> 
> >> Thanks Thara, these are looking good for 2.6.38.
> >> 
> >> Tony, unless there are major objections, I'll be queuing these two SR
> >> series for 2.6.38.  They have dependencies on Paul's integration branch
> >
> > Well looking at patch 3/6 I think it should live under drivers somewhere
> > and mostly be compiled as a module. Probably the only change needed
> > for that is to not call cpu_is_omapxxxx but instead use some flags
> > passed in the platform_data. Otherwise the whole series looks OK to me.
> 
> Moving this to be a regulator driver is part of the medium-term plan,
> and is already under development.  For this phase, we just split up the
> current driver into device and driver code and left under mach-omap2.
> We are investigating (and making) changes to the regulator core so that
> SmartReflex can be converted into a real regulator driver, but that is
> still under development.
> 
> So, in the mean time, I'd like to merge this version so that other
> development that depends on this (the regulator work mentioned above,
> the DVFS work, etc.) can have a stable starting point.

OK up to you.

Tony

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

* [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support
  2010-12-20 16:59 ` [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
@ 2010-12-22 20:30   ` Kevin Hilman
  2010-12-31  8:01     ` Gopinath, Thara
  0 siblings, 1 reply; 22+ messages in thread
From: Kevin Hilman @ 2010-12-22 20:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Thara,

Thara Gopinath <thara@ti.com> writes:

> This patch adds support in the twl4030 driver to enable smartreflex.
> The smartreflex bit on twl4030 needs to be enabled by default irrespective
> of whether smartreflex module is enabled on the OMAP side or not.
> This is because without this bit enabled the voltage scaling through
> vp forceupdate does not function properly.

Is this true for OMAP2 as well?  

This patch actually hangs the boot on 2430SDP.  

For now, I'll be dropping this patch from my pull request.  Also, this patch
will also need an Ack from the MFD maintainers, or possibly even merge 
through their tree.  Please also Cc the MFD list on the fix.

While fixing this issue, another CodingStyle comment below...

> Signed-off-by: Thara Gopinath <thara@ti.com>
> ---
>  drivers/mfd/twl-core.c  |   13 +++++++++++++
>  include/linux/i2c/twl.h |   11 +++++++++++
>  2 files changed, 24 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
> index 35275ba..b895ceb 100644
> --- a/drivers/mfd/twl-core.c
> +++ b/drivers/mfd/twl-core.c
> @@ -1046,6 +1046,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  	/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
>  	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
>  	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
> +	 * Also enable the smartreflex I2S bit.
>  	 */
>  
>  	if (twl_class_is_4030()) {
> @@ -1053,6 +1054,18 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
>  		I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
>  		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
> +
> +		/* The smartreflex bit on twl4030 needs to be enabled by
> +		 * default irrespective of whether smartreflex module is
> +		 * enabled on the OMAP side or not. This is because without
> +		 * this bit enabled the voltage scaling through
> +		 * vp forceupdate does not function properly.
> +		 */

please update multi-line coding style.

Kevin

> +		twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp,
> +			TWL4030_PM_RECEIVER_DCDC_GLOBAL_CFG);
> +		temp |= SMARTREFLEX_ENABLE;
> +		twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp,
> +			TWL4030_PM_RECEIVER_DCDC_GLOBAL_CFG);
>  	}
>  
>  	status = add_children(pdata, id->driver_data);
> diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
> index c760991..d392f06 100644
> --- a/include/linux/i2c/twl.h
> +++ b/include/linux/i2c/twl.h
> @@ -434,6 +434,17 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
>  
>  /*----------------------------------------------------------------------*/
>  
> +/*
> + * PM Receiver module register offsets (use TWL4030_MODULE_PM_RECEIVER)
> + */
> +
> +#define TWL4030_PM_RECEIVER_DCDC_GLOBAL_CFG	0x06
> +
> +/* Smartreflex I2S bus enable/ vmode enable bit */
> +#define SMARTREFLEX_ENABLE			BIT(3)
> +
> +/*----------------------------------------------------------------------*/
> +
>  /* Power bus message definitions */
>  
>  /* The TWL4030/5030 splits its power-management resources (the various

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

* [PATCH v6 01/10] OMAP3: PM: Adding voltage driver support.
  2010-12-20 16:59 ` [PATCH v6 01/10] OMAP3: PM: Adding voltage " Thara Gopinath
@ 2010-12-22 22:29   ` Kevin Hilman
  2010-12-28 16:17   ` Anand Sawant
  1 sibling, 0 replies; 22+ messages in thread
From: Kevin Hilman @ 2010-12-22 22:29 UTC (permalink / raw)
  To: linux-arm-kernel

Thara Gopinath <thara@ti.com> writes:

> This patch adds voltage driver support for OMAP3. The driver
> allows  configuring the voltage controller and voltage
> processors during init and exports APIs to enable/disable
> voltage processors, scale voltage and reset voltage.
> The driver maintains the global voltage table on a per
> VDD basis which contains the various voltages supported by the
> VDD along with per voltage dependent data like smartreflex
> efuse offset, errminlimit and voltage processor errorgain.
> The driver also allows the voltage parameters dependent on the
> PMIC to be passed from the PMIC file through an API.
> The driver allows scaling of VDD voltages either through
> "vc bypass method" or through "vp forceupdate method" the
> choice being configurable through the board file.
>
> This patch contains code originally in linux omap pm branch
> smartreflex driver.  Major contributors to this driver are
> Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley,
> Nishant Menon, Kevin Hilman. The separation of PMIC parameters
> into a separate structure which can be populated from
> the PMIC file is based on the work of Lun Chang from Motorola
> in an internal tree.
>
> Signed-off-by: Thara Gopinath <thara@ti.com>
> ---
> This patch has 14 checkpatch.pl above 80-chars warnings for
> the definitions of omap34xx_vddmpu_volt_data, omap36xx_vddmpu_volt_data,
> omap34xx_vddcore_volt_data and omap36xx_vddcore_volt_data structures.
> IMHO splitting of the entries in these structures affects
> readability and looks very ugly. Hence they are left as is.
>
>  arch/arm/mach-omap2/Makefile              |    3 +-
>  arch/arm/mach-omap2/control.h             |   17 +
>  arch/arm/mach-omap2/pm.c                  |    8 +
>  arch/arm/mach-omap2/voltage.c             | 1226 +++++++++++++++++++++++++++++
>  arch/arm/plat-omap/include/plat/voltage.h |  134 ++++
>  5 files changed, 1387 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/voltage.c
>  create mode 100644 arch/arm/plat-omap/include/plat/voltage.h
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 7c79683..5034797 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -57,7 +57,8 @@ endif
>  ifeq ($(CONFIG_PM),y)
>  obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
>  obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o pm_bus.o
> -obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o cpuidle34xx.o pm_bus.o
> +obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
> +					   cpuidle34xx.o pm_bus.o

This will not link when building OMAP2 only (common for n8x0 testing due
to kernel size limitation.)  In this config, voltage.o is not compiled,
but its functions are still called from the common pm.c.

Will fold the following diff into this patch.

Kevin


diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 91c9b60..4ab82f6 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -59,7 +59,7 @@ endif
 # Power Management
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o pm_bus.o voltage.o
 obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o pm_bus.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o voltage.o pm_bus.o

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

* [PATCH v6 01/10] OMAP3: PM: Adding voltage driver support.
  2010-12-20 16:59 ` [PATCH v6 01/10] OMAP3: PM: Adding voltage " Thara Gopinath
  2010-12-22 22:29   ` Kevin Hilman
@ 2010-12-28 16:17   ` Anand Sawant
  1 sibling, 0 replies; 22+ messages in thread
From: Anand Sawant @ 2010-12-28 16:17 UTC (permalink / raw)
  To: linux-arm-kernel

Thara,

Here are some comments on the voltage layer; many of them are
cosmetic in nature.

> -----Original Message-----
> From: Thara Gopinath [mailto:thara at ti.com]
> Sent: Monday, December 20, 2010 10:29 PM
> To: linux-omap at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org
> Cc: khilman at deeprootsystems.com; paul at pwsan.com; b-
> cousson at ti.com; vishwanath.bs at ti.com; sawant at ti.com;
> nm at ti.com; Thara Gopinath
> Subject: [PATCH v6 01/10] OMAP3: PM: Adding voltage driver
> support.
>
> This patch adds voltage driver support for OMAP3. The driver
> allows  configuring the voltage controller and voltage
> processors during init and exports APIs to enable/disable
> voltage processors, scale voltage and reset voltage.
> The driver maintains the global voltage table on a per
> VDD basis which contains the various voltages supported by
> the
> VDD along with per voltage dependent data like smartreflex
> efuse offset, errminlimit and voltage processor errorgain.
> The driver also allows the voltage parameters dependent on
> the
> PMIC to be passed from the PMIC file through an API.
> The driver allows scaling of VDD voltages either through
> "vc bypass method" or through "vp forceupdate method" the
> choice being configurable through the board file.
>
> This patch contains code originally in linux omap pm branch
> smartreflex driver.  Major contributors to this driver are
> Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley,
> Nishant Menon, Kevin Hilman. The separation of PMIC
> parameters
> into a separate structure which can be populated from
> the PMIC file is based on the work of Lun Chang from
> Motorola
> in an internal tree.
>
> Signed-off-by: Thara Gopinath <thara@ti.com>
> ---
> This patch has 14 checkpatch.pl above 80-chars warnings for
> the definitions of omap34xx_vddmpu_volt_data,
> omap36xx_vddmpu_volt_data,
> omap34xx_vddcore_volt_data and omap36xx_vddcore_volt_data
> structures.
> IMHO splitting of the entries in these structures affects
> readability and looks very ugly. Hence they are left as is.
>
>  arch/arm/mach-omap2/Makefile              |    3 +-
>  arch/arm/mach-omap2/control.h             |   17 +
>  arch/arm/mach-omap2/pm.c                  |    8 +
>  arch/arm/mach-omap2/voltage.c             | 1226
> +++++++++++++++++++++++++++++
>  arch/arm/plat-omap/include/plat/voltage.h |  134 ++++
>  5 files changed, 1387 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/voltage.c
>  create mode 100644 arch/arm/plat-
> omap/include/plat/voltage.h
>
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-
> omap2/Makefile
> index 7c79683..5034797 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -57,7 +57,8 @@ endif
>  ifeq ($(CONFIG_PM),y)
>  obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
>  obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o pm_bus.o
> -obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
> cpuidle34xx.o pm_bus.o
> +obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
> voltage.o \
> +					   cpuidle34xx.o pm_bus.o
>  obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o pm_bus.o
>  obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
>
> diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-
> omap2/control.h
> index 5289461..9fe32dc 100644
> --- a/arch/arm/mach-omap2/control.h
> +++ b/arch/arm/mach-omap2/control.h
> @@ -148,6 +148,15 @@
>  #define OMAP343X_CONTROL_TEST_KEY_11
> 	(OMAP2_CONTROL_GENERAL + 0x00f4)
>  #define OMAP343X_CONTROL_TEST_KEY_12
> 	(OMAP2_CONTROL_GENERAL + 0x00f8)
>  #define OMAP343X_CONTROL_TEST_KEY_13
> 	(OMAP2_CONTROL_GENERAL + 0x00fc)
> +#define OMAP343X_CONTROL_FUSE_OPP1_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0110)
> +#define OMAP343X_CONTROL_FUSE_OPP2_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0114)
> +#define OMAP343X_CONTROL_FUSE_OPP3_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0118)
> +#define OMAP343X_CONTROL_FUSE_OPP4_VDD1
> (OMAP2_CONTROL_GENERAL + 0x011c)
> +#define OMAP343X_CONTROL_FUSE_OPP5_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0120)
> +#define OMAP343X_CONTROL_FUSE_OPP1_VDD2
> (OMAP2_CONTROL_GENERAL + 0x0124)
> +#define OMAP343X_CONTROL_FUSE_OPP2_VDD2
> (OMAP2_CONTROL_GENERAL + 0x0128)
> +#define OMAP343X_CONTROL_FUSE_OPP3_VDD2
> (OMAP2_CONTROL_GENERAL + 0x012c)
> +#define OMAP343X_CONTROL_FUSE_SR
> (OMAP2_CONTROL_GENERAL + 0x0130)
>  #define OMAP343X_CONTROL_IVA2_BOOTADDR
> 	(OMAP2_CONTROL_GENERAL + 0x0190)
>  #define OMAP343X_CONTROL_IVA2_BOOTMOD
> 	(OMAP2_CONTROL_GENERAL + 0x0194)
>  #define OMAP343X_CONTROL_DEBOBS(i)	(OMAP2_CONTROL_GENERAL +
> 0x01B0 \
> @@ -164,6 +173,14 @@
>  #define OMAP343X_CONTROL_SRAMLDO5	(OMAP2_CONTROL_GENERAL +
> 0x02C0)
>  #define OMAP343X_CONTROL_CSI		(OMAP2_CONTROL_GENERAL +
> 0x02C4)
>
> +/* OMAP3630 only CONTROL_GENERAL register offsets */
> +#define OMAP3630_CONTROL_FUSE_OPP1G_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0110)
> +#define OMAP3630_CONTROL_FUSE_OPP50_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0114)
> +#define OMAP3630_CONTROL_FUSE_OPP100_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0118)
> +#define OMAP3630_CONTROL_FUSE_OPP120_VDD1
> (OMAP2_CONTROL_GENERAL + 0x0120)
> +#define OMAP3630_CONTROL_FUSE_OPP50_VDD2
> (OMAP2_CONTROL_GENERAL + 0x0128)
> +#define OMAP3630_CONTROL_FUSE_OPP100_VDD2
> (OMAP2_CONTROL_GENERAL + 0x012C)
> +
>  /* AM35XX only CONTROL_GENERAL register offsets */
>  #define AM35XX_CONTROL_MSUSPENDMUX_6
> (OMAP2_CONTROL_GENERAL + 0x0038)
>  #define AM35XX_CONTROL_DEVCONF2
> (OMAP2_CONTROL_GENERAL + 0x0310)
> diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-
> omap2/pm.c
> index 227a211..22adfb2 100644
> --- a/arch/arm/mach-omap2/pm.c
> +++ b/arch/arm/mach-omap2/pm.c
> @@ -17,6 +17,7 @@
>  #include <plat/omap-pm.h>
>  #include <plat/omap_device.h>
>  #include <plat/common.h>
> +#include <plat/voltage.h>
>
>  #include "powerdomain.h"
>  #include "clockdomain.h"
> @@ -145,3 +146,10 @@ static int __init
> omap2_common_pm_init(void)
>  }
>  postcore_initcall(omap2_common_pm_init);
>
> +static int __init omap2_common_pm_late_init(void)
> +{
> +	omap_voltage_late_init();
> +
> +	return 0;
> +}
> +late_initcall(omap2_common_pm_late_init);
> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
> omap2/voltage.c
> new file mode 100644
> index 0000000..875667f
> --- /dev/null
> +++ b/arch/arm/mach-omap2/voltage.c
> @@ -0,0 +1,1226 @@
> +/*
> + * OMAP3/OMAP4 Voltage Management Routines
> + *
> + * Author: Thara Gopinath	<thara@ti.com>
> + *
> + * Copyright (C) 2007 Texas Instruments, Inc.
> + * Rajendra Nayak <rnayak@ti.com>
> + * Lesly A M <x0080970@ti.com>
> + *
> + * Copyright (C) 2008 Nokia Corporation
> + * Kalle Jokiniemi
> + *
> + * Copyright (C) 2010 Texas Instruments, Inc.
> + * Thara Gopinath <thara@ti.com>
> + *
> + * 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/delay.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/debugfs.h>
> +#include <linux/slab.h>
> +
> +#include <plat/common.h>
> +#include <plat/voltage.h>
> +
> +#include "prm-regbits-34xx.h"
> +#include "control.h"
> +
> +#define VP_IDLE_TIMEOUT		200
> +#define VP_TRANXDONE_TIMEOUT	300
> +#define VOLTAGE_DIR_SIZE	16

Add comments for the above #defines.

> +
> +/* Voltage processor register offsets */

Add comments for the data members.

> +struct vp_reg_offs {
> +	u8 vpconfig;
> +	u8 vstepmin;
> +	u8 vstepmax;
> +	u8 vlimitto;
> +	u8 vstatus;
> +	u8 voltage;
> +};
> +
> +/* Voltage Processor bit field values, shifts and masks */

Add comments for the data members.

> +struct vp_reg_val {
> +	/* PRM module */
> +	u16 prm_mod;
> +	/* VPx_VPCONFIG */
> +	u32 vpconfig_erroroffset;
> +	u16 vpconfig_errorgain;
> +	u32 vpconfig_errorgain_mask;
> +	u8 vpconfig_errorgain_shift;
> +	u32 vpconfig_initvoltage_mask;
> +	u8 vpconfig_initvoltage_shift;
> +	u32 vpconfig_timeouten;
> +	u32 vpconfig_initvdd;
> +	u32 vpconfig_forceupdate;
> +	u32 vpconfig_vpenable;
> +	/* VPx_VSTEPMIN */
> +	u8 vstepmin_stepmin;
> +	u16 vstepmin_smpswaittimemin;
> +	u8 vstepmin_stepmin_shift;
> +	u8 vstepmin_smpswaittimemin_shift;
> +	/* VPx_VSTEPMAX */
> +	u8 vstepmax_stepmax;
> +	u16 vstepmax_smpswaittimemax;
> +	u8 vstepmax_stepmax_shift;
> +	u8 vstepmax_smpswaittimemax_shift;
> +	/* VPx_VLIMITTO */
> +	u8 vlimitto_vddmin;
> +	u8 vlimitto_vddmax;
> +	u16 vlimitto_timeout;
> +	u8 vlimitto_vddmin_shift;
> +	u8 vlimitto_vddmax_shift;
> +	u8 vlimitto_timeout_shift;
> +	/* PRM_IRQSTATUS*/
> +	u32 tranxdone_status;
> +};
> +
> +/* Voltage controller registers and offsets */

Add comments for the data members.

> +struct vc_reg_info {
> +	/* PRM module */
> +	u16 prm_mod;
> +	/* VC register offsets */
> +	u8 smps_sa_reg;
> +	u8 smps_volra_reg;
> +	u8 bypass_val_reg;
> +	u8 cmdval_reg;
> +	u8 voltsetup_reg;
> +	/*VC_SMPS_SA*/
> +	u8 smps_sa_shift;
> +	u32 smps_sa_mask;
> +	/* VC_SMPS_VOL_RA */
> +	u8 smps_volra_shift;
> +	u32 smps_volra_mask;
> +	/* VC_BYPASS_VAL */
> +	u8 data_shift;
> +	u8 slaveaddr_shift;
> +	u8 regaddr_shift;
> +	u32 valid;
> +	/* VC_CMD_VAL */
> +	u8 cmd_on_shift;
> +	u8 cmd_onlp_shift;
> +	u8 cmd_ret_shift;
> +	u8 cmd_off_shift;
> +	u32 cmd_on_mask;
> +	/* PRM_VOLTSETUP */
> +	u8 voltsetup_shift;
> +	u32 voltsetup_mask;
> +};
> +
> +/**
> + * omap_vdd_info - Per Voltage Domain info
> + *
> + * @volt_data		: voltage table having the distinct
> voltages supported
> + *			  by the domain and other associated per
> voltage data.
> + * @pmic_info		: pmic specific parameters which
> should be populted by
> + *			  the pmic drivers.
> + * @vp_offs		: structure containing the offsets
> for various
> + *			  vp registers
> + * @vp_reg		: the register values, shifts, masks for
> various
> + *			  vp registers
> + * @vc_reg		: structure containing various various vc
> registers,
> + *			  shifts, masks etc.
> + * @voltdm		: pointer to the voltage domain structure
> + * @debug_dir		: debug directory for this voltage
> domain.
> + * @curr_volt		: current voltage for this vdd.
> + * @ocp_mod		: The prm module for accessing the
> prm irqstatus reg.
> + * @prm_irqst_reg	: prm irqstatus register.
> + * @vp_enabled		: flag to keep track of whether vp
> is enabled or not

Add comments for read_reg & write_reg.

> + * @volt_scale		: API to scale the voltage of the
> vdd.

Add more explanation about the structure - like its
significance, how it is populated and used etc.

> + */
> +struct omap_vdd_info {
> +	struct omap_volt_data *volt_data;
> +	struct omap_volt_pmic_info *pmic_info;
> +	struct vp_reg_offs vp_offs;
> +	struct vp_reg_val vp_reg;
> +	struct vc_reg_info vc_reg;
> +	struct voltagedomain voltdm;

Make voltdm the first member of the structure as it's a key identifier.

> +	struct dentry *debug_dir;
> +	u32 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);
> +};
> +
> +static struct omap_vdd_info *vdd_info;

Add comment. It's an important pointer.

> +/*
> + * Number of scalable voltage domains.
> + */
> +static int nr_scalable_vdd;
> +
> +/* OMAP3 VDD sturctures */

Add comment to mention that partial initialization is
done here & the rest is done in omap3_vdd_data_configure()
function.

> +static struct omap_vdd_info omap3_vdd_info[] = {
> +	{
> +		.vp_offs = {
> +			.vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET,
> +			.vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
> +			.vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
> +			.vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
> +			.vstatus = OMAP3_PRM_VP1_STATUS_OFFSET,
> +			.voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
> +		},

Recommend to use DEFINE_VP_REG_OFFS macro similar to
VOLT_DATA_DEFINE to make it more readable.

> +		.voltdm = {
> +			.name = "mpu",
> +		},

Make this initialization the first initialization.

> +	},
> +	{
> +		.vp_offs = {
> +			.vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET,
> +			.vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
> +			.vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
> +			.vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
> +			.vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
> +			.voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
> +		},
> +		.voltdm = {
> +			.name = "core",
> +		},
> +	},
> +};
> +
> +#define OMAP3_NR_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)
> +
> +/*
> + * Structures containing OMAP3430/OMAP3630 voltage
> supported and various
> + * voltage dependent data for each VDD.
> + */
> +#define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit,
> _errgain)	\
> +{									\
> +	.volt_nominal	= _v_nom,
> 	\
> +	.sr_efuse_offs	= _efuse_offs,
> 	\
> +	.sr_errminlimit	= _errminlimit,
> 	\
> +	.vp_errgain	= _errgain					\
> +}
> +
> +/* VDD1 */

Add a comment stressing the need to keep
VOLT_DATA_DEFINE(0, 0, 0, 0) as always the last member.
Otherwise, the loop in omap_voltage_get_voltdata() will
not function properly.

> +static struct omap_volt_data omap34xx_vddmpu_volt_data[] =
> {
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV,
> OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c),
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV,
> OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c),
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV,
> OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18),
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV,
> OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18),
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV,
> OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18),
> +	VOLT_DATA_DEFINE(0, 0, 0, 0),
> +};
> +
> +static struct omap_volt_data omap36xx_vddmpu_volt_data[] =
> {
> +	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV,
> OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c),
> +	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV,
> OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16),
> +	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV,
> OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23),
> +	VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV,
> OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27),
> +	VOLT_DATA_DEFINE(0, 0, 0, 0),
> +};
> +
> +/* VDD2 */
> +static struct omap_volt_data omap34xx_vddcore_volt_data[] =
> {
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV,
> OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c),
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV,
> OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c),
> +	VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV,
> OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18),
> +	VOLT_DATA_DEFINE(0, 0, 0, 0),
> +};
> +
> +static struct omap_volt_data omap36xx_vddcore_volt_data[] =
> {
> +	VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV,
> OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c),
> +	VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV,
> OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16),
> +	VOLT_DATA_DEFINE(0, 0, 0, 0),
> +};
> +
> +static struct dentry *voltage_dir;

Add comment.

> +
> +/* Init function pointers */

Add comment mentioning how they are populated.

> +static void (*vc_init) (struct omap_vdd_info *vdd);
> +static int (*vdd_data_configure) (struct omap_vdd_info
> *vdd);

Recommend to define a similar init function pointer for
vp initialization. At present, it will be initialized with
the generic vp_init(). But it will allow easy migration
in case vp initialization is different for future OMAPs.

Also, highlight the difference between init (actually writes
to module registers) and data_configure (populates data
structures; no writing to registers) for clarity.

> +
> +static u32 omap3_voltage_read_reg(u16 mod, u8 offset)
> +{
> +	return omap2_prm_read_mod_reg(mod, offset);
> +}
> +
> +static void omap3_voltage_write_reg(u32 val, u16 mod, u8
> offset)
> +{
> +	omap2_prm_write_mod_reg(val, mod, offset);
> +}
> +

Add comment for vp_latch_vsel.

> +static void vp_latch_vsel(struct omap_vdd_info *vdd)
> +{
> +	u32 vpconfig;
> +	u16 mod;
> +	unsigned long uvdc;
> +	char vsel;
> +
> +	uvdc = 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);
> +		return;
> +	}
> +
> +	if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
> +		pr_warning("%s: PMIC function to convert voltage
> in uV to"
> +			" vsel not registered\n", __func__);
> +		return;
> +	}
> +
> +	mod = vdd->vp_reg.prm_mod;
> +
> +	vsel = vdd->pmic_info->uv_to_vsel(uvdc);
> +
> +	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
> +	vpconfig &= ~(vdd->vp_reg.vpconfig_initvoltage_mask |
> +			vdd->vp_reg.vpconfig_initvdd);
> +	vpconfig |= vsel << vdd-
> >vp_reg.vpconfig_initvoltage_shift;
> +
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +
> +	/* Trigger initVDD value copy to voltage processor */
> +	vdd->write_reg((vpconfig | vdd-
> >vp_reg.vpconfig_initvdd), mod,
> +			vdd->vp_offs.vpconfig);
> +

Check if any delay is needed between triggering initVDD copy
& clearing initVDD copy. Check if the two need to be atomic.

> +	/* Clear initVDD copy trigger bit */
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +}
> +
> +/* Generic voltage init functions */
> +static void __init vp_init(struct omap_vdd_info *vdd)

Recommend to change the return type to int to allow for
better error handling & diagnostic messages.

> +{
> +	u32 vp_val;
> +	u16 mod;
> +
> +	if (!vdd->read_reg || !vdd->write_reg) {
> +		pr_err("%s: No read/write API for accessing
> vdd_%s regs\n",
> +			__func__, vdd->voltdm.name);
> +		return;
> +	}
> +
> +	mod = vdd->vp_reg.prm_mod;
> +
> +	vp_val = vdd->vp_reg.vpconfig_erroroffset |
> +		(vdd->vp_reg.vpconfig_errorgain <<
> +		vdd->vp_reg.vpconfig_errorgain_shift) |
> +		vdd->vp_reg.vpconfig_timeouten;
> +	vdd->write_reg(vp_val, mod, vdd->vp_offs.vpconfig);
> +
> +	vp_val = ((vdd->vp_reg.vstepmin_smpswaittimemin <<
> +		vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
> +		(vdd->vp_reg.vstepmin_stepmin <<
> +		vdd->vp_reg.vstepmin_stepmin_shift));
> +	vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmin);
> +
> +	vp_val = ((vdd->vp_reg.vstepmax_smpswaittimemax <<
> +		vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
> +		(vdd->vp_reg.vstepmax_stepmax <<
> +		vdd->vp_reg.vstepmax_stepmax_shift));
> +	vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmax);
> +
> +	vp_val = ((vdd->vp_reg.vlimitto_vddmax <<
> +		vdd->vp_reg.vlimitto_vddmax_shift) |
> +		(vdd->vp_reg.vlimitto_vddmin <<
> +		vdd->vp_reg.vlimitto_vddmin_shift) |
> +		(vdd->vp_reg.vlimitto_timeout <<
> +		vdd->vp_reg.vlimitto_timeout_shift));
> +	vdd->write_reg(vp_val, mod, vdd->vp_offs.vlimitto);
> +}
> +

Add comment for vdd_debugfs_init.

> +static void __init vdd_debugfs_init(struct omap_vdd_info
> *vdd)
> +{
> +	char *name;
> +
> +	name = kzalloc(VOLTAGE_DIR_SIZE, GFP_KERNEL);
> +	if (!name) {
> +		pr_warning("%s: Unable to allocate memory for
> debugfs"
> +			" directory name for vdd_%s",
> +			__func__, vdd->voltdm.name);
> +		return;
> +	}
> +	strcpy(name, "vdd_");
> +	strcat(name, vdd->voltdm.name);
> +
> +	vdd->debug_dir = debugfs_create_dir(name,
> voltage_dir);
> +	if (IS_ERR(vdd->debug_dir)) {
> +		pr_warning("%s: Unable to create debugfs
> directory for"
> +			" vdd_%s\n", __func__, vdd->voltdm.name);
> +		vdd->debug_dir = NULL;
> +	}
> +}
> +
> +/* Voltage scale and accessory APIs */

Add comment for _pre_volt_scale.

> +static int _pre_volt_scale(struct omap_vdd_info *vdd,
> +		unsigned long 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;
> +
> +	/* 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",
> +			__func__, vdd->voltdm.name);
> +		return -EINVAL;
> +	}
> +
> +	if (!vdd->pmic_info->uv_to_vsel) {
> +		pr_err("%s: PMIC function to convert voltage in
> uV to"
> +			"vsel not registered. Hence unable to
> scale voltage"
> +			"for vdd_%s\n", __func__, vdd-
> >voltdm.name);
> +		return -ENODATA;
> +	}
> +
> +	if (!vdd->read_reg || !vdd->write_reg) {
> +		pr_err("%s: No read/write API for accessing
> vdd_%s regs\n",
> +			__func__, vdd->voltdm.name);
> +		return -EINVAL;
> +	}
> +
> +	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;

If there is an error on volt_data; return an error code.
No need to continue with the rest of the processing.

> +
> +	*target_vsel = vdd->pmic_info-
> >uv_to_vsel(target_volt);
> +	*current_vsel = vdd->read_reg(vp_mod, vdd-
> >vp_offs.voltage);
> +
> +	/* Setting the ON voltage to the new target voltage */
> +	vc_cmdval = vdd->read_reg(vc_mod, vdd-
> >vc_reg.cmdval_reg);
> +	vc_cmdval &= ~vdd->vc_reg.cmd_on_mask;
> +	vc_cmdval |= (*target_vsel << vdd-
> >vc_reg.cmd_on_shift);
> +	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);
> +	}

Recommend to take a snapshot of current vsel,
cmdval_reg & errgain before setting the new values. Think of
a mechanism to restore them in case the scaling function
(called after _pre_volt_scale()) fails midway.

Check related comments in vp_forceupdate_scale_voltage()
& vc_bypass_scale_voltage().

> +
> +	return 0;
> +}
> +

Add comment for _post_volt_scale.

> +static void _post_volt_scale(struct omap_vdd_info *vdd,
> +		unsigned long target_volt, u8 target_vsel, u8
> current_vsel)
> +{
> +	u32 smps_steps = 0, smps_delay = 0;
> +
> +	smps_steps = abs(target_vsel - current_vsel);
> +	/* SMPS slew rate / step size. 2us added as buffer. */
> +	smps_delay = ((smps_steps * vdd->pmic_info->step_size)
> /
> +			vdd->pmic_info->slew_rate) + 2;
> +	udelay(smps_delay);
> +
> +	vdd->curr_volt = target_volt;
> +}
> +
> +/* 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)
> +{
> +	u32 loop_cnt = 0, retries_cnt = 0;
> +	u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
> +	u16 mod;
> +	u8 target_vsel, current_vsel;
> +	int ret;
> +
> +	ret = _pre_volt_scale(vdd, target_volt, &target_vsel,
> &current_vsel);
> +	if (ret)
> +		return ret;

This check is ineffective to handle error in case volt_data
corresponding to the target voltage is not found as it
returns 0.

> +
> +	mod = vdd->vc_reg.prm_mod;
> +
> +	vc_valid = vdd->vc_reg.valid;
> +	vc_bypass_val_reg = vdd->vc_reg.bypass_val_reg;
> +	vc_bypass_value = (target_vsel << vdd-
> >vc_reg.data_shift) |
> +			(vdd->pmic_info->pmic_reg <<
> +			vdd->vc_reg.regaddr_shift) |
> +			(vdd->pmic_info->i2c_slave_addr <<
> +			vdd->vc_reg.slaveaddr_shift);
> +
> +	vdd->write_reg(vc_bypass_value, mod,
> vc_bypass_val_reg);
> +	vdd->write_reg(vc_bypass_value | vc_valid, mod,
> vc_bypass_val_reg);
> +
> +	vc_bypass_value = vdd->read_reg(mod,
> vc_bypass_val_reg);
> +	/*
> +	 * Loop till the bypass command is acknowledged from
> the SMPS.
> +	 * NOTE: This is legacy code. The loop count and retry
> count needs
> +	 * to be revisited.
> +	 */
> +	while (!(vc_bypass_value & vc_valid)) {
> +		loop_cnt++;
> +
> +		if (retries_cnt > 10) {
> +			pr_warning("%s: Retry count exceeded\n",
> __func__);

Recommend to restore the snapshot of vsel, cmdval_reg &
errgain in _pre_volt_scale before returning an error.

This can be bit complicated as HW's exact state is not
known.

> +			return -ETIMEDOUT;
> +		}
> +
> +		if (loop_cnt > 50) {
> +			retries_cnt++;
> +			loop_cnt = 0;
> +			udelay(10);
> +		}
> +		vc_bypass_value = vdd->read_reg(mod,
> vc_bypass_val_reg);
> +	}
> +
> +	_post_volt_scale(vdd, target_volt, target_vsel,
> current_vsel);
> +	return 0;
> +}
> +
> +/* VP force update method of voltage scaling */
> +static int vp_forceupdate_scale_voltage(struct
> omap_vdd_info *vdd,
> +		unsigned long target_volt)
> +{
> +	u32 vpconfig;
> +	u16 mod, ocp_mod;
> +	u8 target_vsel, current_vsel, prm_irqst_reg;
> +	int ret, timeout = 0;
> +
> +	ret = _pre_volt_scale(vdd, target_volt, &target_vsel,
> &current_vsel);
> +	if (ret)
> +		return ret;

This check is ineffective to handle error in case volt_data
corresponding to the target voltage is not found as it
returns 0.

> +
> +	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))
> +				break;
> +		udelay(1);
> +	}
> +	if (timeout >= VP_TRANXDONE_TIMEOUT) {
> +		pr_warning("%s: vdd_%s TRANXDONE timeout
> exceeded."
> +			"Voltage change aborted", __func__, vdd-
> >voltdm.name);

Recommend to restore the snapshot of vsel, cmdval_reg &
errgain in _pre_volt_scale before returning an error.

This can be bit complicated as HW's exact state is not
known.

> +		return -ETIMEDOUT;
> +	}
> +
> +	/* Configure for VP-Force Update */
> +	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
> +	vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
> +			vdd->vp_reg.vpconfig_forceupdate |
> +			vdd->vp_reg.vpconfig_initvoltage_mask);
> +	vpconfig |= ((target_vsel <<
> +			vdd->vp_reg.vpconfig_initvoltage_shift));
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +
> +	/* Trigger initVDD value copy to voltage processor */
> +	vpconfig |= vdd->vp_reg.vpconfig_initvdd;
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +
> +	/* Force update of voltage */
> +	vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +
> +	/*
> +	 * Wait for TransactionDone. Typical latency is
> <200us.
> +	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
> +	 */
> +	timeout = 0;
> +	omap_test_timeout((vdd->read_reg(ocp_mod,
> prm_irqst_reg) &
> +			vdd->vp_reg.tranxdone_status),
> +			VP_TRANXDONE_TIMEOUT, timeout);
> +	if (timeout >= VP_TRANXDONE_TIMEOUT)
> +		pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
> +			"TRANXDONE never got set after the voltage
> update\n",
> +			__func__, vdd->voltdm.name);
> +
> +	_post_volt_scale(vdd, target_volt, target_vsel,
> current_vsel);

It is risky to assume voltage change has been successful in
case TRANXDONE never got set after voltage update. Recommend
to do a read of SMPS voltage for confirmation before
proceeding further.

> +
> +	/*
> +	 * Disable TransactionDone interrupt , clear all
> status, clear
> +	 * control registers
> +	 */

Check whether it is safe to disable TRANXDONE interrupt even
if it didn't get set.

> +	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;
> +		udelay(1);
> +	}
> +
> +	if (timeout >= VP_TRANXDONE_TIMEOUT)
> +		pr_warning("%s: vdd_%s TRANXDONE timeout
> exceeded while trying"
> +			"to clear the TRANXDONE status\n",
> +			__func__, vdd->voltdm.name);
> +
> +	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
> +	/* Clear initVDD copy trigger bit */
> +	vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +	/* Clear force bit */
> +	vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +
> +	return 0;
> +}
> +
> +/* OMAP3 specific voltage init functions */
> +
> +/*
> + * Intializes the voltage controller registers with the
> PMIC and board
> + * specific parameters and voltage setup times for OMAP3.
> + */
> +static void __init omap3_vc_init(struct omap_vdd_info *vdd)
> +{
> +	u32 vc_val;
> +	u16 mod;
> +	u8 on_vsel, onlp_vsel, ret_vsel, off_vsel;
> +	static bool is_initialized;
> +
> +	if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
> +		pr_err("%s: PMIC info requried to configure vc
> for"
> +			"vdd_%s not populated.Hence cannot
> initialize vc\n",
> +			__func__, vdd->voltdm.name);
> +		return;
> +	}
> +
> +	if (!vdd->read_reg || !vdd->write_reg) {
> +		pr_err("%s: No read/write API for accessing
> vdd_%s regs\n",
> +			__func__, vdd->voltdm.name);
> +		return;
> +	}
> +
> +	mod = vdd->vc_reg.prm_mod;
> +
> +	/* Set up the SMPS_SA(i2c slave address in VC */
> +	vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_sa_reg);
> +	vc_val &= ~vdd->vc_reg.smps_sa_mask;
> +	vc_val |= vdd->pmic_info->i2c_slave_addr << vdd-
> >vc_reg.smps_sa_shift;
> +	vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_sa_reg);
> +
> +	/* Setup the VOLRA(pmic reg addr) in VC */
> +	vc_val = vdd->read_reg(mod, vdd-
> >vc_reg.smps_volra_reg);
> +	vc_val &= ~vdd->vc_reg.smps_volra_mask;
> +	vc_val |= vdd->pmic_info->pmic_reg << vdd-
> >vc_reg.smps_volra_shift;
> +	vdd->write_reg(vc_val, mod, vdd-
> >vc_reg.smps_volra_reg);
> +
> +	/*Configure the setup times */
> +	vc_val = vdd->read_reg(mod, vdd-
> >vc_reg.voltsetup_reg);
> +	vc_val &= ~vdd->vc_reg.voltsetup_mask;
> +	vc_val |= vdd->pmic_info->volt_setup_time <<
> +			vdd->vc_reg.voltsetup_shift;
> +	vdd->write_reg(vc_val, mod, vdd-
> >vc_reg.voltsetup_reg);
> +
> +	/* Set up the on, inactive, retention and off voltage
> */
> +	on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info-
> >on_volt);
> +	onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info-
> >onlp_volt);
> +	ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info-
> >ret_volt);
> +	off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info-
> >off_volt);
> +	vc_val	= ((on_vsel << vdd->vc_reg.cmd_on_shift) |
> +		(onlp_vsel << vdd->vc_reg.cmd_onlp_shift) |
> +		(ret_vsel << vdd->vc_reg.cmd_ret_shift) |
> +		(off_vsel << vdd->vc_reg.cmd_off_shift));
> +	vdd->write_reg(vc_val, mod, vdd->vc_reg.cmdval_reg);
> +
> +	if (is_initialized)
> +		return;
> +
> +	/* Generic VC parameters init */
> +	vdd->write_reg(OMAP3430_CMD1_MASK |
> OMAP3430_RAV1_MASK, mod,
> +			OMAP3_PRM_VC_CH_CONF_OFFSET);
> +	vdd->write_reg(OMAP3430_MCODE_SHIFT |
> OMAP3430_HSEN_MASK, mod,
> +			OMAP3_PRM_VC_I2C_CFG_OFFSET);
> +	vdd->write_reg(OMAP3_CLKSETUP, mod,
> OMAP3_PRM_CLKSETUP_OFFSET);
> +	vdd->write_reg(OMAP3_VOLTOFFSET, mod,
> OMAP3_PRM_VOLTOFFSET_OFFSET);
> +	vdd->write_reg(OMAP3_VOLTSETUP2, mod,
> OMAP3_PRM_VOLTSETUP2_OFFSET);
> +	is_initialized = true;
> +}
> +
> +/* Sets up all the VDD related info for OMAP3 */
> +static int __init omap3_vdd_data_configure(struct
> omap_vdd_info *vdd)
> +{
> +	struct clk *sys_ck;
> +	u32 sys_clk_speed, timeout_val, waittime;
> +
> +	if (!vdd->pmic_info) {
> +		pr_err("%s: PMIC info requried to configure
> vdd_%s not"
> +			"populated.Hence cannot initialize
> vdd_%s\n",
> +			__func__, vdd->voltdm.name, vdd-
> >voltdm.name);
> +		return -EINVAL;
> +	}
> +
> +	if (!strcmp(vdd->voltdm.name, "mpu")) {
> +		if (cpu_is_omap3630())
> +			vdd->volt_data =
> omap36xx_vddmpu_volt_data;
> +		else
> +			vdd->volt_data =
> omap34xx_vddmpu_volt_data;
> +
> +		vdd->vp_reg.tranxdone_status =
> OMAP3430_VP1_TRANXDONE_ST_MASK;
> +		vdd->vc_reg.cmdval_reg =
> OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
> +		vdd->vc_reg.smps_sa_shift =
> OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT;
> +		vdd->vc_reg.smps_sa_mask =
> OMAP3430_PRM_VC_SMPS_SA_SA0_MASK;
> +		vdd->vc_reg.smps_volra_shift =
> OMAP3430_VOLRA0_SHIFT;
> +		vdd->vc_reg.smps_volra_mask =
> OMAP3430_VOLRA0_MASK;
> +		vdd->vc_reg.voltsetup_shift =
> OMAP3430_SETUP_TIME1_SHIFT;
> +		vdd->vc_reg.voltsetup_mask =
> OMAP3430_SETUP_TIME1_MASK;
> +	} else if (!strcmp(vdd->voltdm.name, "core")) {
> +		if (cpu_is_omap3630())
> +			vdd->volt_data =
> omap36xx_vddcore_volt_data;
> +		else
> +			vdd->volt_data =
> omap34xx_vddcore_volt_data;
> +
> +		vdd->vp_reg.tranxdone_status =
> OMAP3430_VP2_TRANXDONE_ST_MASK;
> +		vdd->vc_reg.cmdval_reg =
> OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
> +		vdd->vc_reg.smps_sa_shift =
> OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT;
> +		vdd->vc_reg.smps_sa_mask =
> OMAP3430_PRM_VC_SMPS_SA_SA1_MASK;
> +		vdd->vc_reg.smps_volra_shift =
> OMAP3430_VOLRA1_SHIFT;
> +		vdd->vc_reg.smps_volra_mask =
> OMAP3430_VOLRA1_MASK;
> +		vdd->vc_reg.voltsetup_shift =
> OMAP3430_SETUP_TIME2_SHIFT;
> +		vdd->vc_reg.voltsetup_mask =
> OMAP3430_SETUP_TIME2_MASK;
> +	} else {
> +		pr_warning("%s: vdd_%s does not exisit in
> OMAP3\n",
> +			__func__, vdd->voltdm.name);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Sys clk rate is require to calculate vp timeout
> value and
> +	 * smpswaittimemin and smpswaittimemax.
> +	 */
> +	sys_ck = clk_get(NULL, "sys_ck");
> +	if (IS_ERR(sys_ck)) {
> +		pr_warning("%s: Could not get the sys clk to
> calculate"
> +			"various vdd_%s params\n", __func__, vdd-
> >voltdm.name);
> +		return -EINVAL;
> +	}
> +	sys_clk_speed = clk_get_rate(sys_ck);
> +	clk_put(sys_ck);
> +	/* Divide to avoid overflow */
> +	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;
> +	vdd->write_reg = omap3_voltage_write_reg;
> +	vdd->volt_scale = vp_forceupdate_scale_voltage;
> +	vdd->vp_enabled = false;
> +
> +	/* VC parameters */
> +	vdd->vc_reg.prm_mod = OMAP3430_GR_MOD;
> +	vdd->vc_reg.smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET;
> +	vdd->vc_reg.smps_volra_reg =
> OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET;
> +	vdd->vc_reg.bypass_val_reg =
> OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
> +	vdd->vc_reg.voltsetup_reg =
> OMAP3_PRM_VOLTSETUP1_OFFSET;
> +	vdd->vc_reg.data_shift = OMAP3430_DATA_SHIFT;
> +	vdd->vc_reg.slaveaddr_shift =
> OMAP3430_SLAVEADDR_SHIFT;
> +	vdd->vc_reg.regaddr_shift = OMAP3430_REGADDR_SHIFT;
> +	vdd->vc_reg.valid = OMAP3430_VALID_MASK;
> +	vdd->vc_reg.cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
> +	vdd->vc_reg.cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
> +	vdd->vc_reg.cmd_onlp_shift =
> OMAP3430_VC_CMD_ONLP_SHIFT;
> +	vdd->vc_reg.cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT;
> +	vdd->vc_reg.cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT;
> +
> +	vdd->vp_reg.prm_mod = OMAP3430_GR_MOD;
> +
> +	/* VPCONFIG bit fields */
> +	vdd->vp_reg.vpconfig_erroroffset = (vdd->pmic_info-
> >vp_erroroffset <<
> +				 OMAP3430_ERROROFFSET_SHIFT);
> +	vdd->vp_reg.vpconfig_errorgain_mask =
> OMAP3430_ERRORGAIN_MASK;
> +	vdd->vp_reg.vpconfig_errorgain_shift =
> OMAP3430_ERRORGAIN_SHIFT;
> +	vdd->vp_reg.vpconfig_initvoltage_shift =
> OMAP3430_INITVOLTAGE_SHIFT;
> +	vdd->vp_reg.vpconfig_initvoltage_mask =
> OMAP3430_INITVOLTAGE_MASK;
> +	vdd->vp_reg.vpconfig_timeouten =
> OMAP3430_TIMEOUTEN_MASK;
> +	vdd->vp_reg.vpconfig_initvdd = OMAP3430_INITVDD_MASK;
> +	vdd->vp_reg.vpconfig_forceupdate =
> OMAP3430_FORCEUPDATE_MASK;
> +	vdd->vp_reg.vpconfig_vpenable =
> OMAP3430_VPENABLE_MASK;
> +
> +	/* VSTEPMIN VSTEPMAX bit fields */
> +	waittime = ((vdd->pmic_info->step_size / vdd-
> >pmic_info->slew_rate) *
> +				sys_clk_speed) / 1000;
> +	vdd->vp_reg.vstepmin_smpswaittimemin = waittime;
> +	vdd->vp_reg.vstepmax_smpswaittimemax = waittime;
> +	vdd->vp_reg.vstepmin_stepmin = vdd->pmic_info-
> >vp_vstepmin;
> +	vdd->vp_reg.vstepmax_stepmax = vdd->pmic_info-
> >vp_vstepmax;
> +	vdd->vp_reg.vstepmin_smpswaittimemin_shift =
> +				OMAP3430_SMPSWAITTIMEMIN_SHIFT;
> +	vdd->vp_reg.vstepmax_smpswaittimemax_shift =
> +				OMAP3430_SMPSWAITTIMEMAX_SHIFT;
> +	vdd->vp_reg.vstepmin_stepmin_shift =
> OMAP3430_VSTEPMIN_SHIFT;
> +	vdd->vp_reg.vstepmax_stepmax_shift =
> OMAP3430_VSTEPMAX_SHIFT;
> +
> +	/* VLIMITTO bit fields */
> +	timeout_val = (sys_clk_speed * vdd->pmic_info-
> >vp_timeout_us) / 1000;
> +	vdd->vp_reg.vlimitto_timeout = timeout_val;
> +	vdd->vp_reg.vlimitto_vddmin = vdd->pmic_info-
> >vp_vddmin;
> +	vdd->vp_reg.vlimitto_vddmax = vdd->pmic_info-
> >vp_vddmax;
> +	vdd->vp_reg.vlimitto_vddmin_shift =
> OMAP3430_VDDMIN_SHIFT;
> +	vdd->vp_reg.vlimitto_vddmax_shift =
> OMAP3430_VDDMAX_SHIFT;
> +	vdd->vp_reg.vlimitto_timeout_shift =
> OMAP3430_TIMEOUT_SHIFT;
> +
> +	return 0;
> +}

Big function. Recommend to simplify it by creating two data
configure functions, one for vp and one for vc. And call them
from omap3_vdd_data_configure().

> +
> +/* Public functions */
> +/**
> + * 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.
> + */
> +unsigned long omap_voltage_get_nom_volt(struct
> voltagedomain *voltdm)
> +{
> +	struct omap_vdd_info *vdd;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return 0;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	return vdd->curr_volt;
> +}
> +
> +/**
> + * omap_vp_get_curr_volt() - API to get the current vp
> voltage.
> + * @voltdm:	pointer to the VDD.
> + *
> + * This API returns the current voltage for the specified
> voltage processor
> + */
> +unsigned long omap_vp_get_curr_volt(struct voltagedomain
> *voltdm)
> +{
> +	struct omap_vdd_info *vdd;
> +	u8 curr_vsel;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return 0;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +	if (!vdd->read_reg) {
> +		pr_err("%s: No read API for reading vdd_%s
> regs\n",
> +			__func__, voltdm->name);
> +		return 0;
> +	}
> +
> +	curr_vsel = vdd->read_reg(vdd->vp_reg.prm_mod,
> +			vdd->vp_offs.voltage);
> +
> +	if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) {
> +		pr_warning("%s: PMIC function to convert vsel to
> voltage"
> +			"in uV not registerd\n", __func__);
> +		return 0;
> +	}
> +
> +	return vdd->pmic_info->vsel_to_uv(curr_vsel);
> +}
> +
> +/**
> + * omap_vp_enable() - API to enable a particular VP
> + * @voltdm:	pointer to the VDD whose VP is to be
> enabled.
> + *
> + * This API enables a particular voltage processor. Needed
> by the smartreflex
> + * class drivers.
> + */
> +void omap_vp_enable(struct voltagedomain *voltdm)
> +{
> +	struct omap_vdd_info *vdd;
> +	u32 vpconfig;
> +	u16 mod;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +	if (!vdd->read_reg || !vdd->write_reg) {
> +		pr_err("%s: No read/write API for accessing
> vdd_%s regs\n",
> +			__func__, voltdm->name);
> +		return;
> +	}
> +
> +	mod = vdd->vp_reg.prm_mod;
> +
> +	/* If VP is already enabled, do nothing. Return */
> +	if (vdd->vp_enabled)
> +		return;
> +
> +	vp_latch_vsel(vdd);
> +
> +	/* Enable VP */
> +	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
> +	vpconfig |= vdd->vp_reg.vpconfig_vpenable;
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);

Check if there is a need for delay or status check (similar to
omap_vp_disable) before flipping the status to true.

> +	vdd->vp_enabled = true;
> +}
> +
> +/**
> + * omap_vp_disable() - API to disable a particular VP
> + * @voltdm:	pointer to the VDD whose VP is to be
> disabled.
> + *
> + * This API disables a particular voltage processor. Needed
> by the smartreflex
> + * class drivers.
> + */
> +void omap_vp_disable(struct voltagedomain *voltdm)
> +{
> +	struct omap_vdd_info *vdd;
> +	u32 vpconfig;
> +	u16 mod;
> +	int timeout;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +	if (!vdd->read_reg || !vdd->write_reg) {
> +		pr_err("%s: No read/write API for accessing
> vdd_%s regs\n",
> +			__func__, voltdm->name);
> +		return;
> +	}
> +
> +	mod = vdd->vp_reg.prm_mod;
> +
> +	/* If VP is already disabled, do nothing. Return */
> +	if (!vdd->vp_enabled) {
> +		pr_warning("%s: Trying to disable VP for vdd_%s
> when"
> +			"it is already disabled\n", __func__,
> voltdm->name);
> +		return;
> +	}
> +
> +	/* Disable VP */
> +	vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
> +	vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
> +	vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
> +
> +	/*
> +	 * Wait for VP idle Typical latency is <2us. Maximum
> latency is ~100us
> +	 */
> +	omap_test_timeout((vdd->read_reg(mod, vdd-
> >vp_offs.vstatus)),
> +				VP_IDLE_TIMEOUT, timeout);
> +
> +	if (timeout >= VP_IDLE_TIMEOUT)
> +		pr_warning("%s: vdd_%s idle timedout\n",
> +			__func__, voltdm->name);
> +
> +	vdd->vp_enabled = false;
> +
> +	return;
> +}
> +
> +/**
> + * 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
> + *
> + * 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_vdd_info *vdd;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	if (!vdd->volt_scale) {
> +		pr_err("%s: No voltage scale API registered for
> vdd_%s\n",
> +			__func__, voltdm->name);
> +		return -ENODATA;
> +	}
> +
> +	return vdd->volt_scale(vdd, target_volt);
> +}
> +
> +/**
> + * omap_voltage_reset() - Resets the voltage of a
> particular voltage domain
> + *			to that of the current OPP.
> + * @voltdm:	pointer to the VDD whose voltage is to be
> reset.
> + *
> + * This API finds out the correct voltage the voltage
> domain is supposed
> + * to be at and resets the voltage to that level. Should be
> used expecially
> + * while disabling any voltage compensation modules.
> + */
> +void omap_voltage_reset(struct voltagedomain *voltdm)
> +{
> +	unsigned long target_uvdc;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return;
> +	}
> +
> +	target_uvdc = omap_voltage_get_nom_volt(voltdm);
> +	if (!target_uvdc) {
> +		pr_err("%s: unable to find current voltage for
> vdd_%s\n",
> +			__func__, voltdm->name);
> +		return;
> +	}
> +
> +	omap_voltage_scale_vdd(voltdm, target_uvdc);
> +}
> +
> +/**
> + * omap_voltage_get_volttable() - API to get the voltage
> table associated with a
> + *				particular voltage domain.
> + * @voltdm:	pointer to the VDD for which the voltage
> table is required
> + * @volt_data:	the voltage table for the particular vdd
> which is to be
> + *		populated by this API
> + *
> + * This API populates the voltage table associated with a
> VDD into the
> + * passed parameter pointer. Returns the count of distinct
> voltages
> + * supported by this vdd.
> + *
> + */
> +void omap_voltage_get_volttable(struct voltagedomain
> *voltdm,
> +		struct omap_volt_data **volt_data)
> +{
> +	struct omap_vdd_info *vdd;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	*volt_data = vdd->volt_data;
> +}
> +
> +/**
> + * omap_voltage_get_voltdata() - API to get the voltage
> table entry for a
> + *				particular voltage
> + * @voltdm:	pointer to the VDD whose voltage table has
> to be searched
> + * @volt:	the voltage to be searched in the voltage table
> + *
> + * This API searches through the voltage table for the
> required voltage
> + * domain and tries to find a matching entry for the passed
> voltage volt.
> + * If a matching entry is found volt_data is populated with
> that entry.
> + * This API searches only through the non-compensated
> voltages int the
> + * voltage table.
> + * Returns pointer to the voltage table entry corresponding
> to volt on
> + * sucess. Returns -ENODATA if no voltage table exisits for
> the passed voltage
> + * domain or if there is no matching entry.
> + */
> +struct omap_volt_data *omap_voltage_get_voltdata(struct
> voltagedomain *voltdm,
> +		unsigned long volt)
> +{
> +	struct omap_vdd_info *vdd;
> +	int i;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	if (!vdd->volt_data) {
> +		pr_warning("%s: voltage table does not exist for
> vdd_%s\n",
> +			__func__, voltdm->name);
> +		return ERR_PTR(-ENODATA);
> +	}
> +
> +	for (i = 0; vdd->volt_data[i].volt_nominal != 0; i++)
> {
> +		if (vdd->volt_data[i].volt_nominal == volt)
> +			return &vdd->volt_data[i];
> +	}
> +
> +	pr_notice("%s: Unable to match the current voltage
> with the voltage"
> +		"table for vdd_%s\n", __func__, voltdm->name);
> +
> +	return ERR_PTR(-ENODATA);
> +}
> +
> +/**
> + * omap_voltage_register_pmic() - API to register PMIC
> specific data
> + * @voltdm:	pointer to the VDD for which the PMIC
> specific data is
> + *		to be registered
> + * @pmic_info:	the structure containing pmic info
> + *
> + * This API is to be called by the SOC/PMIC file to specify
> the
> + * pmic specific info as present in omap_volt_pmic_info
> structure.
> + */
> +int omap_voltage_register_pmic(struct voltagedomain
> *voltdm,
> +		struct omap_volt_pmic_info *pmic_info)
> +{
> +	struct omap_vdd_info *vdd;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	vdd->pmic_info = pmic_info;
> +
> +	return 0;
> +}
> +
> +/**
> + * omap_voltage_get_dbgdir() - API to get pointer to the
> debugfs directory
> + *				corresponding to a voltage domain.
> + *
> + * @voltdm:	pointer to the VDD whose debug directory
> is required.
> + *
> + * This API returns pointer to the debugfs directory
> corresponding
> + * to the voltage domain. Should be used by drivers
> requiring to
> + * add any debug entry for a particular voltage domain.
> Returns NULL
> + * in case of error.
> + */
> +struct dentry *omap_voltage_get_dbgdir(struct voltagedomain
> *voltdm)
> +{
> +	struct omap_vdd_info *vdd;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return NULL;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	return vdd->debug_dir;
> +}
> +
> +/**
> + * omap_change_voltscale_method() - API to change the
> voltage scaling method.
> + * @voltdm:	pointer to the VDD whose voltage scaling
> method
> + *		has to be changed.
> + * @voltscale_method:	the method to be used for voltage
> scaling.
> + *
> + * This API can be used by the board files to change the
> method of voltage
> + * scaling between vpforceupdate and vcbypass. The
> parameter values are
> + * defined in voltage.h
> + */
> +void omap_change_voltscale_method(struct voltagedomain
> *voltdm,
> +		int voltscale_method)

Recommend to change the return type to int for better error
handling.

> +{
> +	struct omap_vdd_info *vdd;
> +
> +	if (!voltdm || IS_ERR(voltdm)) {
> +		pr_warning("%s: VDD specified does not
> exist!\n", __func__);
> +		return;
> +	}
> +
> +	vdd = container_of(voltdm, struct omap_vdd_info,
> voltdm);
> +
> +	switch (voltscale_method) {
> +	case VOLTSCALE_VPFORCEUPDATE:
> +		vdd->volt_scale = vp_forceupdate_scale_voltage;
> +		return;
> +	case VOLTSCALE_VCBYPASS:
> +		vdd->volt_scale = vc_bypass_scale_voltage;
> +		return;
> +	default:
> +		pr_warning("%s: Trying to change the method of
> voltage scaling"
> +			"to an unsupported one!\n", __func__);
> +	}
> +}
> +
> +/**
> + * omap_voltage_domain_lookup() - API to get the voltage
> domain pointer
> + * @name:	Name of the voltage domain
> + *
> + * This API looks up in the global vdd_info struct for the
> + * existence of voltage domain <name>. If it exists, the
> API returns
> + * a pointer to the voltage domain structure corresponding
> to the
> + * VDD<name>. Else retuns error pointer.
> + */
> +struct voltagedomain *omap_voltage_domain_lookup(char
> *name)
> +{
> +	int i;
> +
> +	if (!vdd_info) {
> +		pr_err("%s: Voltage driver init not yet
> happened.Faulting!\n",
> +			__func__);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	if (!name) {
> +		pr_err("%s: No name to get the votage
> domain!\n", __func__);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	for (i = 0; i < nr_scalable_vdd; i++) {
> +		if (!(strcmp(name, vdd_info[i].voltdm.name)))
> +			return &vdd_info[i].voltdm;
> +	}

Print an error before returning.

> +
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +/**
> + * omap_voltage_late_init() - Init the various voltage
> parameters
> + *
> + * This API is to be called in the later stages of the
> + * system boot to init the voltage controller and
> + * voltage processors.
> + */
> +int __init omap_voltage_late_init(void)
> +{
> +	int i;
> +
> +	if (!vdd_info) {
> +		pr_err("%s: Voltage driver support not added\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	voltage_dir = debugfs_create_dir("voltage", NULL);
> +	if (IS_ERR(voltage_dir))
> +		pr_err("%s: Unable to create voltage debugfs
> main dir\n",
> +			__func__);
> +	for (i = 0; i < nr_scalable_vdd; i++) {
> +		if (vdd_data_configure(&vdd_info[i]))
> +			continue;

Do error checking and print success/ fail message (especially
fail) for each of vc_init, vp_init & vdd_debugfs_init.
May need to change the return types of those functions.

A failure should stop further initialization.

> +		vc_init(&vdd_info[i]);
> +		vp_init(&vdd_info[i]);
> +		vdd_debugfs_init(&vdd_info[i]);
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * omap_voltage_early_init()- Volatage driver early init
> + */
> +static int __init omap_voltage_early_init(void)
> +{
> +	if (cpu_is_omap34xx()) {
> +		vdd_info = omap3_vdd_info;
> +		nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
> +		vc_init = omap3_vc_init;
> +		vdd_data_configure = omap3_vdd_data_configure;
> +	} else {
> +		pr_warning("%s: voltage driver support not
> added\n", __func__);
> +	}
> +
> +	return 0;
> +}

Recommend to reorder the functions based on logical grouping
of related functionalities e.g. all init/ configure functions
can be listed together. A comment explaining these different
groups and their constituent functions (located near the
beginning) will be useful.

> +core_initcall(omap_voltage_early_init);
> diff --git a/arch/arm/plat-omap/include/plat/voltage.h
> b/arch/arm/plat-omap/include/plat/voltage.h
> new file mode 100644
> index 0000000..2f4f59a
> --- /dev/null
> +++ b/arch/arm/plat-omap/include/plat/voltage.h
> @@ -0,0 +1,134 @@
> +/*
> + * OMAP Voltage Management Routines
> + *
> + * Author: Thara Gopinath	<thara@ti.com>
> + *
> + * Copyright (C) 2009 Texas Instruments, Inc.
> + * Thara Gopinath <thara@ti.com>
> + *
> + * 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.
> + */
> +
> +#ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
> +#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
> +
> +#define VOLTSCALE_VPFORCEUPDATE		1
> +#define VOLTSCALE_VCBYPASS		2

Add comment explaining the above #defines

> +
> +/*
> + * OMAP3 GENERIC setup times. Revisit to see if these needs
> to be
> + * passed from board or PMIC file
> + */
> +#define OMAP3_CLKSETUP		0xff
> +#define OMAP3_VOLTOFFSET	0xff
> +#define OMAP3_VOLTSETUP2	0xff
> +
> +/* Voltage value defines */
> +#define OMAP3430_VDD_MPU_OPP1_UV		975000
> +#define OMAP3430_VDD_MPU_OPP2_UV		1075000
> +#define OMAP3430_VDD_MPU_OPP3_UV		1200000
> +#define OMAP3430_VDD_MPU_OPP4_UV		1270000
> +#define OMAP3430_VDD_MPU_OPP5_UV		1350000
> +
> +#define OMAP3430_VDD_CORE_OPP1_UV		975000
> +#define OMAP3430_VDD_CORE_OPP2_UV		1050000
> +#define OMAP3430_VDD_CORE_OPP3_UV		1150000
> +
> +#define OMAP3630_VDD_MPU_OPP50_UV		1012500
> +#define OMAP3630_VDD_MPU_OPP100_UV		1200000
> +#define OMAP3630_VDD_MPU_OPP120_UV		1325000
> +#define OMAP3630_VDD_MPU_OPP1G_UV		1375000
> +
> +#define OMAP3630_VDD_CORE_OPP50_UV		1000000
> +#define OMAP3630_VDD_CORE_OPP100_UV		1200000
> +
> +/**
> + * struct voltagedomain - omap voltage domain global
> structure.
> + * @name:	Name of the voltage domain which can be used as
> a unique
> + *		identifier.
> + */
> +struct voltagedomain {
> +	char *name;
> +};
> +
> +/* API to get the voltagedomain pointer */
> +struct voltagedomain *omap_voltage_domain_lookup(char
> *name);
> +
> +/**
> + * struct omap_volt_data - Omap voltage specific data.
> + * @voltage_nominal:	The possible voltage value in uV
> + * @sr_efuse_offs:	The offset of the efuse
> register(from system
> + *			control module base address) from where to
> read
> + *			the n-target value for the smartreflex
> module.
> + * @sr_errminlimit:	Error min limit value for
> smartreflex. This value
> + *			differs at differnet opp and thus is
> linked
> + *			with voltage.
> + * @vp_errorgain:	Error gain value for the voltage
> processor. This
> + *			field also differs according to the
> voltage/opp.
> + */
> +struct omap_volt_data {
> +	u32	volt_nominal;
> +	u32	sr_efuse_offs;
> +	u8	sr_errminlimit;
> +	u8	vp_errgain;
> +};
> +
> +/**
> + * struct omap_volt_pmic_info - PMIC specific data required
> by voltage driver.
> + * @slew_rate:	PMIC slew rate (in uv/us)
> + * @step_size:	PMIC voltage step size (in uv)
> + * @vsel_to_uv:	PMIC API to convert vsel value to actual
> voltage in uV.
> + * @uv_to_vsel:	PMIC API to convert voltage in uV to vsel
> value.

Add comments for the remaining data members.

Best Regards,

Anand Sawant

> + */
> +struct omap_volt_pmic_info {
> +	int slew_rate;
> +	int step_size;
> +	u32 on_volt;
> +	u32 onlp_volt;
> +	u32 ret_volt;
> +	u32 off_volt;
> +	u16 volt_setup_time;
> +	u8 vp_erroroffset;
> +	u8 vp_vstepmin;
> +	u8 vp_vstepmax;
> +	u8 vp_vddmin;
> +	u8 vp_vddmax;
> +	u8 vp_timeout_us;
> +	u8 i2c_slave_addr;
> +	u8 pmic_reg;
> +	unsigned long (*vsel_to_uv) (const u8 vsel);
> +	u8 (*uv_to_vsel) (unsigned long uV);
> +};
> +
> +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);
> +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 dentry *omap_voltage_get_dbgdir(struct voltagedomain
> *voltdm);
> +#ifdef CONFIG_PM
> +int omap_voltage_register_pmic(struct voltagedomain
> *voltdm,
> +		struct omap_volt_pmic_info *pmic_info);
> +void omap_change_voltscale_method(struct voltagedomain
> *voltdm,
> +		int voltscale_method);
> +int omap_voltage_late_init(void);
> +#else
> +static inline int omap_voltage_register_pmic(struct
> voltagedomain *voltdm,
> +		struct omap_volt_pmic_info *pmic_info) {}
> +static inline  void omap_change_voltscale_method(struct
> voltagedomain *voltdm,
> +		int voltscale_method) {}
> +static inline int omap_voltage_late_init(void)
> +{
> +	return -EINVAL;
> +}
> +#endif
> +
> +#endif
> --
> 1.7.0.4

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

* [PATCH v6 09/10] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-20 16:59 ` [PATCH v6 09/10] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
@ 2010-12-28 17:07   ` Anand Sawant
  0 siblings, 0 replies; 22+ messages in thread
From: Anand Sawant @ 2010-12-28 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

Thara,

Few comments on the changes in voltage layer ...

> -----Original Message-----
> From: Thara Gopinath [mailto:thara at ti.com]
> Sent: Monday, December 20, 2010 10:29 PM
> To: linux-omap at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org
> Cc: khilman at deeprootsystems.com; paul at pwsan.com; b-
> cousson at ti.com; vishwanath.bs at ti.com; sawant at ti.com;
> nm at ti.com; Thara Gopinath
> Subject: [PATCH v6 09/10] OMAP3: PM: Adding debug support to
> Voltage and Smartreflex drivers
>
> This patch adds debug support to the voltage and smartreflex
> drivers.
> This means a whole bunch of voltage processor and
> smartreflex
> parameters are now visible through the pm debugfs.
> The voltage parameters can be viewed at
>         /debug/voltage/vdd_<x>/<parameter>
> and the smartreflex parameters can be viewed at
>         /debug/voltage/vdd_<x>/smartreflex/<parameter>
>
> Also smartreflex n-target values are now exposed out at
> 	/debug/voltage/vdd_<x>/smartreflex/nvalue/<voltage>
>
> The interface to access smartreflex n-target values is a
> read-write interface which means user has the flexibility
> to change the n-target values for any opp.
>
> Signed-off-by: Thara Gopinath <thara@ti.com>
> ---
>  arch/arm/mach-omap2/smartreflex.c |   46
> ++++++++++++++++++++++++-
>  arch/arm/mach-omap2/voltage.c     |   66
> +++++++++++++++++++++++++++++++++++++
>  2 files changed, 110 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/smartreflex.c
> b/arch/arm/mach-omap2/smartreflex.c
> index eee23d0..52a05b3 100644
> --- a/arch/arm/mach-omap2/smartreflex.c
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -31,6 +31,7 @@
>  #include "pm.h"
>
>  #define SMARTREFLEX_NAME_LEN	16
> +#define NVALUE_NAME_LEN		40
>  #define SR_DISABLE_TIMEOUT	200
>
>  struct omap_sr {
> @@ -817,8 +818,9 @@ static int __init omap_sr_probe(struct
> platform_device *pdev)
>  	struct omap_sr *sr_info = kzalloc(sizeof(struct
> omap_sr), GFP_KERNEL);
>  	struct omap_sr_data *pdata = pdev->dev.platform_data;
>  	struct resource *mem, *irq;
> -	struct dentry *vdd_dbg_dir, *dbg_dir;
> -	int ret = 0;
> +	struct dentry *vdd_dbg_dir, *dbg_dir, *nvalue_dir;
> +	struct omap_volt_data *volt_data;
> +	int i, ret = 0;
>
>  	if (!sr_info) {
>  		dev_err(&pdev->dev, "%s: unable to allocate
> sr_info\n",
> @@ -897,6 +899,46 @@ static int __init omap_sr_probe(struct
> platform_device *pdev)
>
>  	(void) debugfs_create_file("autocomp", S_IRUGO |
> S_IWUGO, dbg_dir,
>  				(void *)sr_info, &pm_sr_fops);
> +	(void) debugfs_create_x32("errweight", S_IRUGO,
> dbg_dir,
> +			&sr_info->err_weight);
> +	(void) debugfs_create_x32("errmaxlimit", S_IRUGO,
> dbg_dir,
> +			&sr_info->err_maxlimit);
> +	(void) debugfs_create_x32("errminlimit", S_IRUGO,
> dbg_dir,
> +			&sr_info->err_minlimit);
> +
> +	nvalue_dir = debugfs_create_dir("nvalue", dbg_dir);
> +	if (IS_ERR(nvalue_dir)) {
> +		dev_err(&pdev->dev, "%s: Unable to create
> debugfs directory"
> +			"for n-values\n", __func__);
> +		return PTR_ERR(nvalue_dir);
> +	}
> +
> +	omap_voltage_get_volttable(sr_info->voltdm,
> &volt_data);
> +	if (!volt_data) {
> +		dev_warn(&pdev->dev, "%s: No Voltage table for
> the"
> +			" corresponding vdd vdd_%s. Cannot create
> debugfs"
> +			"entries for n-values\n",
> +			__func__, sr_info->voltdm->name);
> +		return -ENODATA;
> +	}
> +
> +	for (i = 0; i < sr_info->nvalue_count; i++) {
> +		char *name;
> +		char volt_name[32];
> +
> +		name = kzalloc(NVALUE_NAME_LEN + 1, GFP_KERNEL);
> +		if (!name) {
> +			dev_err(&pdev->dev, "%s: Unable to
> allocate memory"
> +				" for n-value directory name\n",
> __func__);
> +			return -ENOMEM;
> +		}
> +
> +		strcpy(name, "volt_");
> +		sprintf(volt_name, "%d",
> volt_data[i].volt_nominal);
> +		strcat(name, volt_name);
> +		(void) debugfs_create_x32(name, S_IRUGO |
> S_IWUGO, nvalue_dir,
> +				&(sr_info->nvalue_table[i].nvalue));
> +	}
>
>  	return ret;
>
> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-
> omap2/voltage.c
> index 875667f..b27fa4f 100644
> --- a/arch/arm/mach-omap2/voltage.c
> +++ b/arch/arm/mach-omap2/voltage.c
> @@ -250,6 +250,47 @@ static void omap3_voltage_write_reg(u32
> val, u16 mod, u8 offset)
>  	omap2_prm_write_mod_reg(val, mod, offset);
>  }
>
> +/* Voltage debugfs support */

Add comment for the function.

> +static int vp_volt_debug_get(void *data, u64 *val)
> +{
> +	struct omap_vdd_info *vdd = (struct omap_vdd_info *)
> data;
> +	u8 vsel;
> +
> +	if (!vdd) {
> +		pr_warning("Wrong paramater passed\n");
> +		return -EINVAL;
> +	}
> +
> +	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"
> +			"in uV not registerd\n");
> +		return -EINVAL;
> +	}
> +
> +	*val = vdd->pmic_info->vsel_to_uv(vsel);
> +	return 0;
> +}
> +

Add comment for the function.

> +static int nom_volt_debug_get(void *data, u64 *val)
> +{
> +	struct omap_vdd_info *vdd = (struct omap_vdd_info *)
> data;
> +
> +	if (!vdd) {
> +		pr_warning("Wrong paramater passed\n");
> +		return -EINVAL;
> +	}
> +
> +	*val = omap_voltage_get_nom_volt(&vdd->voltdm);
> +
> +	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");
>  static void vp_latch_vsel(struct omap_vdd_info *vdd)
>  {
>  	u32 vpconfig;
> @@ -349,7 +390,32 @@ static void __init
> vdd_debugfs_init(struct omap_vdd_info *vdd)
>  		pr_warning("%s: Unable to create debugfs
> directory for"
>  			" vdd_%s\n", __func__, vdd->voltdm.name);
>  		vdd->debug_dir = NULL;
> +		return;
>  	}
> +
> +	(void) debugfs_create_x16("vp_errorgain", S_IRUGO,
> vdd->debug_dir,
> +				&(vdd->vp_reg.vpconfig_errorgain));
> +	(void) debugfs_create_x16("vp_smpswaittimemin",
> S_IRUGO,
> +				vdd->debug_dir,
> +				&(vdd-
> >vp_reg.vstepmin_smpswaittimemin));
> +	(void) debugfs_create_x8("vp_stepmin", S_IRUGO, vdd-
> >debug_dir,
> +				&(vdd->vp_reg.vstepmin_stepmin));
> +	(void) debugfs_create_x16("vp_smpswaittimemax",
> S_IRUGO,
> +				vdd->debug_dir,
> +				&(vdd-
> >vp_reg.vstepmax_smpswaittimemax));
> +	(void) debugfs_create_x8("vp_stepmax", S_IRUGO, vdd-
> >debug_dir,
> +				&(vdd->vp_reg.vstepmax_stepmax));
> +	(void) debugfs_create_x8("vp_vddmax", S_IRUGO, vdd-
> >debug_dir,
> +				&(vdd->vp_reg.vlimitto_vddmax));
> +	(void) debugfs_create_x8("vp_vddmin", S_IRUGO, vdd-
> >debug_dir,
> +				&(vdd->vp_reg.vlimitto_vddmin));
> +	(void) debugfs_create_x16("vp_timeout", S_IRUGO, vdd-
> >debug_dir,
> +				&(vdd->vp_reg.vlimitto_timeout));
> +	(void) debugfs_create_file("curr_vp_volt", S_IRUGO,
> vdd->debug_dir,
> +				(void *) vdd, &vp_volt_debug_fops);
> +	(void) debugfs_create_file("curr_nominal_volt",
> S_IRUGO,
> +				vdd->debug_dir, (void *) vdd,
> +				&nom_volt_debug_fops);

Recommend to add support for vc cmdval & vc bypass_val.

Best Regards,

Anand Sawant
>  }
>
>  /* Voltage scale and accessory APIs */
> --
> 1.7.0.4

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

* [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support
  2010-12-22 20:30   ` Kevin Hilman
@ 2010-12-31  8:01     ` Gopinath, Thara
  2011-01-02 14:28       ` Woodruff, Richard
  0 siblings, 1 reply; 22+ messages in thread
From: Gopinath, Thara @ 2010-12-31  8:01 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman at deeprootsystems.com]
>>Sent: Thursday, December 23, 2010 2:01 AM
>>To: Gopinath, Thara
>>Cc: linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
>>paul at pwsan.com; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand;
>>Menon, Nishanth
>>Subject: Re: [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex
>>support
>>
>>Hi Thara,
>>
>>Thara Gopinath <thara@ti.com> writes:
>>
>>> This patch adds support in the twl4030 driver to enable smartreflex.
>>> The smartreflex bit on twl4030 needs to be enabled by default
>>irrespective
>>> of whether smartreflex module is enabled on the OMAP side or not.
>>> This is because without this bit enabled the voltage scaling through
>>> vp forceupdate does not function properly.
>>
>>Is this true for OMAP2 as well?
>>
>>This patch actually hangs the boot on 2430SDP.

Hello Kevin,

I tried the latest lo master with smartreflex module compiled in using
omap2plus_defconfig and this patch on OMAP2430 SDP and it boots
fine for me. Your pm-core branch does not boot for me with or without this
patch on OMAP2430 SDP. But then I am not sure if this is needed for OMAP2
also. Considering this might be a omap and twl4030 dependent setting, my idea is to move this code to mach-omap2/omap_twl.c. I will post a patch for the same shortly.

Regards
Thara

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

* [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support
  2010-12-31  8:01     ` Gopinath, Thara
@ 2011-01-02 14:28       ` Woodruff, Richard
  0 siblings, 0 replies; 22+ messages in thread
From: Woodruff, Richard @ 2011-01-02 14:28 UTC (permalink / raw)
  To: linux-arm-kernel


> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
> owner at vger.kernel.org] On Behalf Of Gopinath, Thara
> Sent: Friday, December 31, 2010 2:02 AM

> >>Is this true for OMAP2 as well?

OMAP2 used VSEL for direct and VMODE for voltage control not SR path methods. I don't recall OMAP2 ever need to enable this as that path is not hooked up.  I've not double checked details but that is recollection.

> >>This patch actually hangs the boot on 2430SDP.

There were a lot of versions of 2430SDP boards PMIC-boards which created a variety of issues of someone is really watching the details.

Issues which stopped booting as I recall in the past were:
        - Initial state of interrupts not good allowing boot to livelock
        - Old boards had poor power routing and min voltages needed to be higher.
        - General i2c service thread issues.

I'd guess Thara has some random board with issues and Kevin's system is newer.  Probably Kevin is seeing patch issue as SR doesn't seem to follow for OMAP2.

Regards,
Richard W.

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

end of thread, other threads:[~2011-01-02 14:28 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-20 16:59 [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 01/10] OMAP3: PM: Adding voltage " Thara Gopinath
2010-12-22 22:29   ` Kevin Hilman
2010-12-28 16:17   ` Anand Sawant
2010-12-20 16:59 ` [PATCH v6 02/10] OMAP: Introduce voltage domain information in the hwmod structures Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 03/10] OMAP3: PM: Adding smartreflex driver support Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 04/10] OMAP3: PM: Adding smartreflex device file Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 05/10] OMAP3: PM: Adding smartreflex hwmod data Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 06/10] OMAP3: PM: Adding smartreflex class3 driver Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 07/10] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
2010-12-22 20:30   ` Kevin Hilman
2010-12-31  8:01     ` Gopinath, Thara
2011-01-02 14:28       ` Woodruff, Richard
2010-12-20 16:59 ` [PATCH v6 08/10] OMAP3: PM: Register TWL4030 pmic info with the voltage driver Thara Gopinath
2010-12-20 16:59 ` [PATCH v6 09/10] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
2010-12-28 17:07   ` Anand Sawant
2010-12-20 16:59 ` [PATCH v6 10/10] OMAP3: PM: Program correct init voltages for VDD1 and VDD2 Thara Gopinath
2010-12-21  1:05 ` [PATCH v6 00/10] OMAP: Adding Smartreflex and Voltage driver support Kevin Hilman
2010-12-21  2:23   ` Tony Lindgren
2010-12-21  3:18     ` Tony Lindgren
2010-12-21 16:17     ` Kevin Hilman
2010-12-21 18:55       ` Tony Lindgren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).