linux-omap.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support
@ 2010-10-27 16:10 Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3 Thara Gopinath
                   ` (9 more replies)
  0 siblings, 10 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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 based against lo-master with the following additional
patches applied.
	https://patchwork.kernel.org/patch/266911/
	https://patchwork.kernel.org/patch/266921/
	https://patchwork.kernel.org/patch/266931/
	https://patchwork.kernel.org/patch/183712/
	https://patchwork.kernel.org/patch/285872/

The entire series with the dependencies are available at
        http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=summary
        head: thara-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

Thara Gopinath (9):
  OMAP3: PM: Adding voltage driver support for OMAP3
  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: Adding debug support to Voltage and Smartreflex drivers
  OMAP3: PM: Program correct init voltages for VDD1 and VDD2
  OMAP3: PM: Register TWL4030 pmic info with the voltage driver.

 arch/arm/mach-omap2/Makefile                  |    5 +-
 arch/arm/mach-omap2/control.h                 |   27 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c    |  249 +++++
 arch/arm/mach-omap2/pm.c                      |   68 ++
 arch/arm/mach-omap2/smartreflex-class3.c      |   59 ++
 arch/arm/mach-omap2/smartreflex.c             | 1005 ++++++++++++++++++
 arch/arm/mach-omap2/sr_device.c               |  177 ++++
 arch/arm/mach-omap2/voltage.c                 | 1369 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   45 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  271 +++++
 arch/arm/plat-omap/include/plat/voltage.h     |  142 +++
 arch/arm/plat-omap/opp_twl_tps.c              |   17 +
 drivers/mfd/twl-core.c                        |    7 +-
 drivers/mfd/twl4030-power.c                   |   29 +
 include/linux/i2c/twl.h                       |    1 +
 15 files changed, 3468 insertions(+), 3 deletions(-)
 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] 31+ messages in thread

* [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-11-10 18:59   ` Kevin Hilman
                     ` (2 more replies)
  2010-10-27 16:10 ` [PATCH v4 2/9] OMAP3: PM: Adding smartreflex driver support Thara Gopinath
                   ` (8 subsequent siblings)
  9 siblings, 3 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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 also 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
n-target value, errminlimit and voltage processor errorgain.
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.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/Makefile              |    3 +-
 arch/arm/mach-omap2/voltage.c             | 1158 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/voltage.h |  141 ++++
 3 files changed, 1301 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 0b6d9af..bfdabcc 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -51,7 +51,8 @@ obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
 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/voltage.c b/arch/arm/mach-omap2/voltage.c
new file mode 100644
index 0000000..5aa5109
--- /dev/null
+++ b/arch/arm/mach-omap2/voltage.c
@@ -0,0 +1,1158 @@
+/*
+ * 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"
+
+#define VP_IDLE_TIMEOUT		200
+#define VP_TRANXDONE_TIMEOUT	300
+#define VOLTAGE_DIR_SIZE	16
+
+static struct dentry *voltage_dir;
+/* PRM voltage module */
+static u32 volt_mod;
+
+/* 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 {
+	/* 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 */
+	u16 vlimitto_vddmin;
+	u16 vlimitto_vddmax;
+	u16 vlimitto_timeout;
+	u16 vlimitto_vddmin_shift;
+	u16 vlimitto_vddmax_shift;
+	u16 vlimitto_timeout_shift;
+	/* PRM_IRQSTATUS*/
+	u32 tranxdone_status;
+};
+
+/**
+ * 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.
+ * @vp_offs		: structure containing the offsets for various
+ *			  vp registers
+ * @vp_reg		: the register values, shifts, masks for various
+ *			  vp registers
+ * @voltdm		: pointer to the voltage domain structure
+ * @debug_dir		: debug directory for this voltage domain.
+ * @volt_data_count	: number of distinct voltages supported by this vdd.
+ * @nominal_volt	: nominal voltage for this vdd.
+ * @curr_volt		: current voltage for this vdd;
+ * cmdval_reg		: voltage controller cmdval register.
+ * @vdd_sr_reg		: the smartreflex register associated with this VDD.
+ */
+struct omap_vdd_info{
+	struct omap_volt_data *volt_data;
+	struct vp_reg_offs vp_offs;
+	struct vp_reg_val vp_reg;
+	struct voltagedomain voltdm;
+	struct dentry *debug_dir;
+	int volt_data_count;
+	u32 nominal_volt;
+	u32 curr_volt;
+	u8 cmdval_reg;
+	u8 vdd_sr_reg;
+};
+
+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)
+
+/* TODO: OMAP4 register offsets */
+
+/*
+ * Default voltage controller settings.
+ */
+static struct omap_volt_vc_data vc_config = {
+	.clksetup = 0xff,
+	.voltsetup_time1 = 0xfff,
+	.voltsetup_time2 = 0xfff,
+	.voltoffset = 0xff,
+	.voltsetup2 = 0xff,
+	.vdd0_on = 0x30,        /* 1.2v */
+	.vdd0_onlp = 0x20,      /* 1.0v */
+	.vdd0_ret = 0x1e,       /* 0.975v */
+	.vdd0_off = 0x00,       /* 0.6v */
+	.vdd1_on = 0x2c,        /* 1.15v */
+	.vdd1_onlp = 0x20,      /* 1.0v */
+	.vdd1_ret = 0x1e,       /* .975v */
+	.vdd1_off = 0x00,       /* 0.6v */
+};
+
+/*
+ * Default PMIC Data
+ */
+static struct omap_volt_pmic_info volt_pmic_info = {
+	.slew_rate = 4000,
+	.step_size = 12500,
+};
+
+/*
+ * Structures containing OMAP3430/OMAP3630 voltage supported and various
+ * data associated with it per voltage domain basis. Smartreflex Ntarget
+ * values are left as 0 as they have to be populated by smartreflex
+ * driver after reading the efuse.
+ */
+
+/* VDD1 */
+static struct omap_volt_data omap34xx_vdd1_volt_data[] = {
+	{.volt_nominal = 975000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
+	{.volt_nominal = 1075000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
+	{.volt_nominal = 1200000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
+	{.volt_nominal = 1270000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
+	{.volt_nominal = 1350000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
+};
+
+static struct omap_volt_data omap36xx_vdd1_volt_data[] = {
+	{.volt_nominal = 930000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
+	{.volt_nominal = 1100000, .sr_errminlimit = 0xF9, .vp_errgain = 0x16},
+	{.volt_nominal = 1260000, .sr_errminlimit = 0xFA, .vp_errgain = 0x23},
+	{.volt_nominal = 1350000, .sr_errminlimit = 0xFA, .vp_errgain = 0x27},
+};
+
+/* VDD2 */
+static struct omap_volt_data omap34xx_vdd2_volt_data[] = {
+	{.volt_nominal = 975000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
+	{.volt_nominal = 1050000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
+	{.volt_nominal = 1150000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
+};
+
+static struct omap_volt_data omap36xx_vdd2_volt_data[] = {
+	{.volt_nominal = 930000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
+	{.volt_nominal = 1137500, .sr_errminlimit = 0xF9, .vp_errgain = 0x16},
+};
+
+
+/* By default VPFORCEUPDATE is the chosen method of voltage scaling */
+static bool voltscale_vpforceupdate = true;
+
+static inline u32 voltage_read_reg(u8 offset)
+{
+	return prm_read_mod_reg(volt_mod, offset);
+}
+
+static inline void voltage_write_reg(u8 offset, u32 value)
+{
+	prm_write_mod_reg(value, volt_mod, offset);
+}
+
+static void vp_latch_vsel(struct omap_vdd_info *vdd)
+{
+	u32 vpconfig;
+	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 (!volt_pmic_info.uv_to_vsel) {
+		pr_warning("%s: PMIC function to convert voltage in uV to"
+			" vsel not registered\n", __func__);
+		return;
+	}
+
+	vsel = volt_pmic_info.uv_to_vsel(uvdc);
+
+	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+	vpconfig &= ~(vdd->vp_reg.vpconfig_initvoltage_mask |
+			vdd->vp_reg.vpconfig_initvdd);
+	vpconfig |= vsel << vdd->vp_reg.vpconfig_initvoltage_shift;
+
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	/* Trigger initVDD value copy to voltage processor */
+	voltage_write_reg(vdd->vp_offs.vpconfig,
+			(vpconfig | vdd->vp_reg.vpconfig_initvdd));
+
+	/* Clear initVDD copy trigger bit */
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+}
+
+/* OMAP3 specific voltage init functions */
+/*
+ * Intializes the voltage controller registers with the PMIC and board
+ * specific parameters and voltage setup times for OMAP3. If the board
+ * file does not populate the voltage controller parameters through
+ * omap3_pm_init_vc, default values specified in vc_config is used.
+ */
+static void __init omap3_init_voltagecontroller(void)
+{
+	voltage_write_reg(OMAP3_PRM_VC_SMPS_SA_OFFSET,
+			(OMAP3_SRI2C_SLAVE_ADDR <<
+			 OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT) |
+			(OMAP3_SRI2C_SLAVE_ADDR <<
+			 OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT));
+	voltage_write_reg(OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET,
+			(OMAP3_VDD2_SR_CONTROL_REG << OMAP3430_VOLRA1_SHIFT) |
+			(OMAP3_VDD1_SR_CONTROL_REG << OMAP3430_VOLRA0_SHIFT));
+	voltage_write_reg(OMAP3_PRM_VC_CMD_VAL_0_OFFSET,
+			(vc_config.vdd0_on << OMAP3430_VC_CMD_ON_SHIFT) |
+			(vc_config.vdd0_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
+			(vc_config.vdd0_ret << OMAP3430_VC_CMD_RET_SHIFT) |
+			(vc_config.vdd0_off << OMAP3430_VC_CMD_OFF_SHIFT));
+	voltage_write_reg(OMAP3_PRM_VC_CMD_VAL_1_OFFSET,
+			(vc_config.vdd1_on << OMAP3430_VC_CMD_ON_SHIFT) |
+			(vc_config.vdd1_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
+			(vc_config.vdd1_ret << OMAP3430_VC_CMD_RET_SHIFT) |
+			(vc_config.vdd1_off << OMAP3430_VC_CMD_OFF_SHIFT));
+	voltage_write_reg(OMAP3_PRM_VC_CH_CONF_OFFSET,
+			OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK);
+	voltage_write_reg(OMAP3_PRM_VC_I2C_CFG_OFFSET,
+			OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK);
+
+	/* Write setup times */
+	voltage_write_reg(OMAP3_PRM_CLKSETUP_OFFSET, vc_config.clksetup);
+	voltage_write_reg(OMAP3_PRM_VOLTSETUP1_OFFSET,
+			(vc_config.voltsetup_time2 <<
+			 OMAP3430_SETUP_TIME2_SHIFT) |
+			(vc_config.voltsetup_time1 <<
+			 OMAP3430_SETUP_TIME1_SHIFT));
+	voltage_write_reg(OMAP3_PRM_VOLTOFFSET_OFFSET, vc_config.voltoffset);
+	voltage_write_reg(OMAP3_PRM_VOLTSETUP2_OFFSET, vc_config.voltsetup2);
+}
+
+/* Sets up all the VDD related info for OMAP3 */
+static void __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
+{
+	struct clk *sys_ck;
+	u32 sys_clk_speed, timeout_val, waittime;
+
+	if (!strcmp(vdd->voltdm.name, "mpu")) {
+		if (cpu_is_omap3630()) {
+			vdd->vp_reg.vlimitto_vddmin =
+					OMAP3630_VP1_VLIMITTO_VDDMIN;
+			vdd->vp_reg.vlimitto_vddmax =
+					OMAP3630_VP1_VLIMITTO_VDDMAX;
+			vdd->volt_data = omap36xx_vdd1_volt_data;
+			vdd->volt_data_count =
+					ARRAY_SIZE(omap36xx_vdd1_volt_data);
+		} else {
+			vdd->vp_reg.vlimitto_vddmin =
+					OMAP3430_VP1_VLIMITTO_VDDMIN;
+			vdd->vp_reg.vlimitto_vddmax =
+					OMAP3430_VP1_VLIMITTO_VDDMAX;
+			vdd->volt_data = omap34xx_vdd1_volt_data;
+			vdd->volt_data_count =
+					ARRAY_SIZE(omap34xx_vdd1_volt_data);
+		}
+
+		vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK;
+		vdd->cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
+		vdd->vdd_sr_reg = OMAP3_VDD1_SR_CONTROL_REG;
+	} else if (!strcmp(vdd->voltdm.name, "core")) {
+		if (cpu_is_omap3630()) {
+			vdd->vp_reg.vlimitto_vddmin =
+					OMAP3630_VP2_VLIMITTO_VDDMIN;
+			vdd->vp_reg.vlimitto_vddmax =
+					OMAP3630_VP2_VLIMITTO_VDDMAX;
+			vdd->volt_data = omap36xx_vdd2_volt_data;
+			vdd->volt_data_count =
+					ARRAY_SIZE(omap36xx_vdd2_volt_data);
+		} else {
+			vdd->vp_reg.vlimitto_vddmin =
+					OMAP3430_VP2_VLIMITTO_VDDMIN;
+			vdd->vp_reg.vlimitto_vddmax =
+					OMAP3430_VP2_VLIMITTO_VDDMAX;
+			vdd->volt_data = omap34xx_vdd2_volt_data;
+			vdd->volt_data_count =
+					ARRAY_SIZE(omap34xx_vdd2_volt_data);
+		}
+
+		vdd->vp_reg.tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK;
+		vdd->cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
+		vdd->vdd_sr_reg = OMAP3_VDD2_SR_CONTROL_REG;
+	} else {
+		pr_warning("%s: vdd_%s does not exisit in OMAP3\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+
+	/*
+	 * 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;
+	}
+	sys_clk_speed = clk_get_rate(sys_ck);
+	clk_put(sys_ck);
+	/* Divide to avoid overflow */
+	sys_clk_speed /= 1000;
+
+	/* Nominal/Reset voltage of the VDD */
+	vdd->nominal_volt = vdd->curr_volt = 1200000;
+
+	/* VPCONFIG bit fields */
+	vdd->vp_reg.vpconfig_erroroffset = (OMAP3_VP_CONFIG_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 = ((volt_pmic_info.step_size / volt_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 = OMAP3_VP_VSTEPMIN_VSTEPMIN;
+	vdd->vp_reg.vstepmax_stepmax = OMAP3_VP_VSTEPMAX_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 * OMAP3_VP_VLIMITTO_TIMEOUT_US) / 1000;
+	vdd->vp_reg.vlimitto_timeout = timeout_val;
+	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;
+}
+
+/* Generic voltage init functions */
+static void __init init_voltageprocessor(struct omap_vdd_info *vdd)
+{
+	u32 vpconfig;
+
+	vpconfig = vdd->vp_reg.vpconfig_erroroffset |
+			(vdd->vp_reg.vpconfig_errorgain <<
+			vdd->vp_reg.vpconfig_errorgain_shift) |
+			vdd->vp_reg.vpconfig_timeouten;
+
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	voltage_write_reg(vdd->vp_offs.vstepmin,
+			(vdd->vp_reg.vstepmin_smpswaittimemin <<
+			vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
+			(vdd->vp_reg.vstepmin_stepmin <<
+			vdd->vp_reg.vstepmin_stepmin_shift));
+
+	voltage_write_reg(vdd->vp_offs.vstepmax,
+			(vdd->vp_reg.vstepmax_smpswaittimemax <<
+			vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
+			(vdd->vp_reg.vstepmax_stepmax <<
+			vdd->vp_reg.vstepmax_stepmax_shift));
+
+	voltage_write_reg(vdd->vp_offs.vlimitto,
+			(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));
+}
+
+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 memry 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;
+	}
+}
+
+/* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
+static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
+		unsigned long target_volt)
+{
+	struct omap_volt_data *volt_data;
+	u32 vc_bypass_value, vc_cmdval, vc_valid, vc_bypass_val_reg_offs;
+	u32 vp_errgain_val, vc_cmd_on_mask;
+	u32 loop_cnt = 0, retries_cnt = 0;
+	u32 smps_steps = 0, smps_delay = 0;
+	u8 vc_data_shift, vc_slaveaddr_shift, vc_regaddr_shift;
+	u8 vc_cmd_on_shift;
+	u8 target_vsel, current_vsel, sr_i2c_slave_addr;
+
+	if (cpu_is_omap34xx()) {
+		vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
+		vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
+		vc_data_shift = OMAP3430_DATA_SHIFT;
+		vc_slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
+		vc_regaddr_shift = OMAP3430_REGADDR_SHIFT;
+		vc_valid = OMAP3430_VALID_MASK;
+		vc_bypass_val_reg_offs = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
+		sr_i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR;
+	} else {
+		pr_warning("%s: Voltage scaling not yet enabled for"
+			"this chip\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Get volt_data corresponding to target_volt */
+	volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
+	if (IS_ERR(volt_data)) {
+		/*
+		 * If a match is not found but the target voltage is
+		 * is the nominal vdd voltage allow scaling
+		 */
+		if (target_volt != vdd->nominal_volt) {
+			pr_warning("%s: Unable to get volt table for vdd_%s"
+				"during voltage scaling. Some really Wrong!",
+				__func__, vdd->voltdm.name);
+			return -ENODATA;
+		}
+		volt_data = NULL;
+	}
+
+	if (!volt_pmic_info.uv_to_vsel) {
+		pr_warning("%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;
+	}
+
+	target_vsel = volt_pmic_info.uv_to_vsel(target_volt);
+	current_vsel = voltage_read_reg(vdd->vp_offs.voltage);
+	smps_steps = abs(target_vsel - current_vsel);
+
+	/* Setting the ON voltage to the new target voltage */
+	vc_cmdval = voltage_read_reg(vdd->cmdval_reg);
+	vc_cmdval &= ~vc_cmd_on_mask;
+	vc_cmdval |= (target_vsel << vc_cmd_on_shift);
+	voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
+
+	/* Setting vp errorgain based on the voltage */
+	if (volt_data) {
+		vp_errgain_val = voltage_read_reg(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;
+		voltage_write_reg(vdd->vp_offs.vpconfig, vp_errgain_val);
+	}
+
+	vc_bypass_value = (target_vsel << vc_data_shift) |
+			(vdd->vdd_sr_reg << vc_regaddr_shift) |
+			(sr_i2c_slave_addr << vc_slaveaddr_shift);
+
+	voltage_write_reg(vc_bypass_val_reg_offs, vc_bypass_value);
+
+	voltage_write_reg(vc_bypass_val_reg_offs, vc_bypass_value | vc_valid);
+	vc_bypass_value = voltage_read_reg(vc_bypass_val_reg_offs);
+
+	/*
+	 * 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 = voltage_read_reg(vc_bypass_val_reg_offs);
+	}
+
+	/* SMPS slew rate / step size. 2us added as buffer. */
+	smps_delay = ((smps_steps * volt_pmic_info.step_size) /
+			volt_pmic_info.slew_rate) + 2;
+	udelay(smps_delay);
+
+	vdd->curr_volt = target_volt;
+
+	return 0;
+}
+
+/* VP force update method of voltage scaling */
+static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
+		unsigned long target_volt)
+{
+	struct omap_volt_data *volt_data;
+	u32 vc_cmd_on_mask, vc_cmdval, vpconfig;
+	u32 smps_steps = 0, smps_delay = 0;
+	int timeout = 0;
+	u8 target_vsel, current_vsel;
+	u8 vc_cmd_on_shift;
+	u8 prm_irqst_reg_offs, ocp_mod;
+
+	if (cpu_is_omap34xx()) {
+		vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
+		vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
+		prm_irqst_reg_offs = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
+		ocp_mod = OCP_MOD;
+	} else {
+		pr_warning("%s: Voltage scaling not yet enabled for"
+			"this chip\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Get volt_data corresponding to the target_volt */
+	volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
+	if (IS_ERR(volt_data)) {
+		/*
+		 * If a match is not found but the target voltage is
+		 * is the nominal vdd voltage allow scaling
+		 */
+		if (target_volt != vdd->nominal_volt) {
+			pr_warning("%s: Unable to get voltage table for vdd_%s"
+				"during voltage scaling. Some really Wrong!",
+				__func__, vdd->voltdm.name);
+			return -ENODATA;
+		}
+		volt_data = NULL;
+	}
+
+	if (!volt_pmic_info.uv_to_vsel) {
+		pr_warning("%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;
+	}
+
+	target_vsel = volt_pmic_info.uv_to_vsel(target_volt);
+	current_vsel = voltage_read_reg(vdd->vp_offs.voltage);
+	smps_steps = abs(target_vsel - current_vsel);
+
+	/* Setting the ON voltage to the new target voltage */
+	vc_cmdval = voltage_read_reg(vdd->cmdval_reg);
+	vc_cmdval &= ~vc_cmd_on_mask;
+	vc_cmdval |= (target_vsel << vc_cmd_on_shift);
+	voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
+
+	/* Getting  vp errorgain based on the voltage */
+	if (volt_data)
+		vdd->vp_reg.vpconfig_errorgain =
+					volt_data->vp_errgain;
+
+	/*
+	 * Clear all pending TransactionDone interrupt/status. Typical latency
+	 * is <3us
+	 */
+	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
+		prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
+				ocp_mod, prm_irqst_reg_offs);
+		if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
+				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 = voltage_read_reg(vdd->vp_offs.vpconfig);
+	vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
+			vdd->vp_reg.vpconfig_forceupdate |
+			vdd->vp_reg.vpconfig_initvoltage_mask |
+			vdd->vp_reg.vpconfig_errorgain_mask);
+	vpconfig |= ((target_vsel <<
+			vdd->vp_reg.vpconfig_initvoltage_shift) |
+			(vdd->vp_reg.vpconfig_errorgain <<
+			 vdd->vp_reg.vpconfig_errorgain_shift));
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	/* Trigger initVDD value copy to voltage processor */
+	vpconfig |= vdd->vp_reg.vpconfig_initvdd;
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	/* Force update of voltage */
+	vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	/*
+	 * Wait for TransactionDone. Typical latency is <200us.
+	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
+	 */
+	timeout = 0;
+	omap_test_timeout((prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
+			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);
+
+	/*
+	 * Wait for voltage to settle with SW wait-loop.
+	 * SMPS slew rate / step size. 2us added as buffer.
+	 */
+	smps_delay = ((smps_steps * volt_pmic_info.step_size) /
+			volt_pmic_info.slew_rate) + 2;
+	udelay(smps_delay);
+
+	/*
+	 * Disable TransactionDone interrupt , clear all status, clear
+	 * control registers
+	 */
+	timeout = 0;
+	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
+		prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
+				ocp_mod, prm_irqst_reg_offs);
+		if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
+				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 = voltage_read_reg(vdd->vp_offs.vpconfig);
+	/* Clear initVDD copy trigger bit */
+	vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+	/* Clear force bit */
+	vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	vdd->curr_volt = target_volt;
+
+	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);
+
+	curr_vsel = voltage_read_reg(vdd->vp_offs.voltage);
+
+	if (!volt_pmic_info.vsel_to_uv) {
+		pr_warning("%s: PMIC function to convert vsel to voltage"
+			"in uV not registerd\n", __func__);
+		return 0;
+	}
+
+	return volt_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;
+
+	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 VP is already enabled, do nothing. Return */
+	if (voltage_read_reg(vdd->vp_offs.vpconfig) &
+				vdd->vp_reg.vpconfig_vpenable)
+		return;
+	/*
+	 * This latching is required only if VC bypass method is used for
+	 * voltage scaling during dvfs.
+	 */
+	if (!voltscale_vpforceupdate)
+		vp_latch_vsel(vdd);
+
+	/* Enable VP */
+	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+	voltage_write_reg(vdd->vp_offs.vpconfig,
+				vpconfig | vdd->vp_reg.vpconfig_vpenable);
+}
+
+/**
+ * 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;
+	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 VP is already disabled, do nothing. Return */
+	if (!(voltage_read_reg(vdd->vp_offs.vpconfig) &
+				vdd->vp_reg.vpconfig_vpenable)) {
+		pr_warning("%s: Trying to disable VP for vdd_%s when"
+			"it is already disabled\n", __func__, voltdm->name);
+		return;
+	}
+
+	/* Disable VP */
+	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+	vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+	/*
+	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
+	 */
+	omap_test_timeout((voltage_read_reg(vdd->vp_offs.vstatus)),
+				VP_IDLE_TIMEOUT, timeout);
+
+	if (timeout >= VP_IDLE_TIMEOUT)
+		pr_warning("%s: vdd_%s idle timedout\n",
+			__func__, voltdm->name);
+	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 (voltscale_vpforceupdate)
+		return vp_forceupdate_scale_voltage(vdd, target_volt);
+	else
+		return vc_bypass_scale_voltage(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_change_voltscale_method() - API to change the voltage scaling method.
+ * @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(int voltscale_method)
+{
+	switch (voltscale_method) {
+	case VOLTSCALE_VPFORCEUPDATE:
+		voltscale_vpforceupdate = true;
+		return;
+	case VOLTSCALE_VCBYPASS:
+		voltscale_vpforceupdate = false;
+		return;
+	default:
+		pr_warning("%s: Trying to change the method of voltage scaling"
+			"to an unsupported one!\n", __func__);
+	}
+}
+
+/**
+ * omap_voltage_init_vc() - polpulates vc_config with values specified in
+ *			  board file
+ * @setup_vc:	the structure with various vc parameters
+ *
+ * Updates vc_config with the voltage setup times and other parameters as
+ * specified in setup_vc. vc_config is later used in init_voltagecontroller
+ * to initialize the voltage controller registers. Board files should call
+ * this function with the correct volatge settings corresponding
+ * the particular PMIC and chip.
+ */
+void __init omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc)
+{
+	if (!setup_vc)
+		return;
+
+	vc_config.clksetup = setup_vc->clksetup;
+	vc_config.voltsetup_time1 = setup_vc->voltsetup_time1;
+	vc_config.voltsetup_time2 = setup_vc->voltsetup_time2;
+	vc_config.voltoffset = setup_vc->voltoffset;
+	vc_config.voltsetup2 = setup_vc->voltsetup2;
+	vc_config.vdd0_on = setup_vc->vdd0_on;
+	vc_config.vdd0_onlp = setup_vc->vdd0_onlp;
+	vc_config.vdd0_ret = setup_vc->vdd0_ret;
+	vc_config.vdd0_off = setup_vc->vdd0_off;
+	vc_config.vdd1_on = setup_vc->vdd1_on;
+	vc_config.vdd1_onlp = setup_vc->vdd1_onlp;
+	vc_config.vdd1_ret = setup_vc->vdd1_ret;
+	vc_config.vdd1_off = setup_vc->vdd1_off;
+}
+
+/**
+ * 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.
+ *
+ */
+int 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 0;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	*volt_data = vdd->volt_data;
+	return vdd->volt_data_count;
+}
+
+/**
+ * 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; i < vdd->volt_data_count; 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_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_voltage_register_pmic() - API to register PMIC specific data
+ * @pmic_info:	the structure containing pmic info
+ *
+ * This API is to be called by the borad file to specify the pmic specific
+ * info as present in omap_volt_pmic_info structure. A default pmic info
+ * table is maintained in the driver volt_pmic_info. If the board file do
+ * not override the default table using this API, the default values wiil
+ * be used in the driver.
+ */
+void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info)
+{
+	volt_pmic_info.slew_rate = pmic_info->slew_rate;
+	volt_pmic_info.step_size = pmic_info->step_size;
+	volt_pmic_info.vsel_to_uv = pmic_info->vsel_to_uv;
+	volt_pmic_info.uv_to_vsel = pmic_info->uv_to_vsel;
+}
+
+/**
+ * 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_init : Volatage init API which does VP and VC init.
+ */
+static int __init omap_voltage_init(void)
+{
+	void (*init_voltagecontroller) (void);
+	void (*vdd_data_configure) (struct omap_vdd_info *vdd);
+	int i;
+
+	if (cpu_is_omap34xx()) {
+		volt_mod = OMAP3430_GR_MOD;
+		vdd_info = omap3_vdd_info;
+		nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
+		init_voltagecontroller = omap3_init_voltagecontroller;
+		vdd_data_configure = omap3_vdd_data_configure;
+	} else {
+		pr_warning("%s: voltage driver support not added\n", __func__);
+		return 0;
+	}
+
+	voltage_dir = debugfs_create_dir("voltage", NULL);
+	if (IS_ERR(voltage_dir))
+		pr_err("%s: Unable to create voltage debugfs main dir\n",
+			__func__);
+
+	init_voltagecontroller();
+	for (i = 0; i < nr_scalable_vdd; i++) {
+		vdd_data_configure(&vdd_info[i]);
+		init_voltageprocessor(&vdd_info[i]);
+		vdd_debugfs_init(&vdd_info[i]);
+	}
+	return 0;
+}
+postcore_initcall(omap_voltage_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..ecd7352
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -0,0 +1,141 @@
+/*
+ * 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
+
+/* Voltage SR Parameters for OMAP3*/
+#define OMAP3_SRI2C_SLAVE_ADDR			0x12
+#define OMAP3_VDD1_SR_CONTROL_REG		0x00
+#define OMAP3_VDD2_SR_CONTROL_REG		0x01
+
+/*
+ * Omap3 VP register specific values. Maybe these need to come from
+ * board file or PMIC data structure
+ */
+#define OMAP3_VP_CONFIG_ERROROFFSET		0x00
+#define	OMAP3_VP_VSTEPMIN_SMPSWAITTIMEMIN	0x3C
+#define OMAP3_VP_VSTEPMIN_VSTEPMIN		0x1
+#define OMAP3_VP_VSTEPMAX_SMPSWAITTIMEMAX	0x3C
+#define OMAP3_VP_VSTEPMAX_VSTEPMAX		0x04
+#define OMAP3_VP_VLIMITTO_TIMEOUT_US		0x200
+
+/*
+ * Omap3430 specific VP register values. Maybe these need to come from
+ * board file or PMIC data structure
+ */
+#define OMAP3430_VP1_VLIMITTO_VDDMIN		0x14
+#define OMAP3430_VP1_VLIMITTO_VDDMAX		0x42
+#define OMAP3430_VP2_VLIMITTO_VDDMAX		0x2C
+#define OMAP3430_VP2_VLIMITTO_VDDMIN		0x18
+
+/*
+ * Omap3630 specific VP register values. Maybe these need to come from
+ * board file or PMIC data structure
+ */
+#define OMAP3630_VP1_VLIMITTO_VDDMIN		0x18
+#define OMAP3630_VP1_VLIMITTO_VDDMAX		0x3C
+#define OMAP3630_VP2_VLIMITTO_VDDMIN		0x18
+#define OMAP3630_VP2_VLIMITTO_VDDMAX		0x30
+
+/* TODO OMAP4 VP register values if the same file is used for OMAP4*/
+
+/**
+ * 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_nvalue:		Smartreflex N target value at voltage <voltage>
+ * @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_nvalue;
+	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;
+	unsigned long (*vsel_to_uv) (const u8 vsel);
+	u8 (*uv_to_vsel) (unsigned long uV);
+};
+
+/* Various voltage controller related info */
+struct omap_volt_vc_data {
+	u16 clksetup;
+	u16 voltsetup_time1;
+	u16 voltsetup_time2;
+	u16 voltoffset;
+	u16 voltsetup2;
+	/* PRM_VC_CMD_VAL_0 specific bits */
+	u16 vdd0_on;
+	u16 vdd0_onlp;
+	u16 vdd0_ret;
+	u16 vdd0_off;
+	/* PRM_VC_CMD_VAL_1 specific bits */
+	u16 vdd1_on;
+	u16 vdd1_onlp;
+	u16 vdd1_ret;
+	u16 vdd1_off;
+};
+
+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);
+int 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
+void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info);
+void omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc);
+void omap_change_voltscale_method(int voltscale_method);
+#else
+static inline void omap_voltage_register_pmic
+			(struct omap_volt_pmic_info *pmic_info) {}
+static inline void omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc) {}
+static inline  void omap_change_voltscale_method(int voltscale_method) {}
+#endif
+
+#endif
-- 
1.7.0.4


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

* [PATCH v4 2/9] OMAP3: PM: Adding smartreflex driver support.
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3 Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file Thara Gopinath
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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             |  975 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   36 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  271 +++++++
 4 files changed, 1283 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 bfdabcc..c97a1b5 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -55,6 +55,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..c24ae54
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -0,0 +1,975 @@
+/*
+ * 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/omap_device.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;
+	bool			autocomp_active;
+	int			ip_type;
+	u32			clk_length;
+	u32			err_weight;
+	u32			err_minlimit;
+	u32			err_maxlimit;
+	u32			accum_data;
+	u32			senn_avgweight;
+	u32			senp_avgweight;
+	unsigned int		irq;
+	void __iomem		*base;
+	struct platform_device	*pdev;
+	struct list_head	node;
+	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);
+}
+
+/* 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);
+	struct omap_sr_data *pdata;
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return -EINVAL;
+	}
+
+	pdata = sr->pdev->dev.platform_data;
+
+	if (!sr->clk_length)
+		sr_set_clk_length(sr);
+
+	if (pdata) {
+		senp_en = pdata->senp_mod;
+		senn_en = pdata->senn_mod;
+	} else {
+		dev_err(&sr->pdev->dev, "%s: Missing pdata\n", __func__);
+		return -EINVAL;
+	}
+
+	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);
+	struct omap_sr_data *pdata;
+
+	if (IS_ERR(sr)) {
+		pr_warning("%s: omap_sr struct for sr_%s not found\n",
+			__func__, voltdm->name);
+		return -EINVAL;
+	}
+
+	pdata = sr->pdev->dev.platform_data;
+
+	if (!sr->clk_length)
+		sr_set_clk_length(sr);
+
+	if (pdata) {
+		senp_en = pdata->senp_mod;
+		senn_en = pdata->senn_mod;
+	} else {
+		dev_err(&sr->pdev->dev, "%s: Missing pdata\n", __func__);
+		return -EINVAL;
+	}
+
+	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(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 = volt_data->sr_nvalue;
+
+	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_device *odev = to_omap_device(pdev);
+	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->autocomp_active = false;
+	sr_info->ip_type = odev->hwmods[0]->class->rev;
+	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..04b0bd2 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -35,6 +35,42 @@ 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_SMARTREFLEX_TESTING
+	bool "Smartreflex testing support"
+	depends on OMAP_SMARTREFLEX
+	default n
+	help
+	  Say Y if you want to enable SmartReflex testing with SW hardcoded
+	  NVALUES intead of E-fuse NVALUES set in factory silicon testing.
+
+	  In some devices the E-fuse values have not been set, even though
+	  SmartReflex modules are included. Using these hardcoded values set
+	  in software, one can test the SmartReflex features without E-fuse.
+
+	  WARNING: Enabling this option may cause your device to hang!
+
 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..e1ddbb0
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/smartreflex.h
@@ -0,0 +1,271 @@
+/*
+ * 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>
+
+#ifdef CONFIG_PM_DEBUG
+extern struct dentry *pm_dbg_main_dir;
+extern struct dentry *sr_dbg_dir;
+#endif
+
+/*
+ * 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_dev_data - Smartreflex device specific data
+ *
+ * @volts_supported:	Number of distinct voltages possible for the VDD
+ *			associated with this smartreflex module.
+ * @efuse_sr_control:	The regisrter offset of control_fuse_sr efuse
+ *			register from which sennenable and senpenable values
+ *			are obtained.
+ * @sennenable_shift:	The shift in the control_fuse_sr register for
+ *			obtaining the sennenable value for this smartreflex
+ *			module.
+ * @senpenable_shift:	The shift in the control_fuse_sr register for
+ *			obtaining the senpenable value for this smartreflex
+ *			module.
+ * @efuse_nvalues_offs:	Array of efuse offsets from which ntarget values can
+ *			be retrieved. Number of efuse offsets in this arrray
+ *			is equal to the volts_supported value ie one efuse
+ *			register per supported voltage.
+ * @test_sennenable:	SENNENABLE test value
+ * @test_senpenable:	SENPENABLE test value.
+ * @test_nvalues:	Array of test ntarget values.
+ * @vdd_name:		Name of the voltage domain associated with this
+ *			Smartreflex device.
+ * @volt_data:		Voltage table associated with this smartreflex module
+ */
+struct omap_sr_dev_data {
+	int volts_supported;
+	u32 efuse_sr_control;
+	u32 sennenable_shift;
+	u32 senpenable_shift;
+	u32 *efuse_nvalues_offs;
+	u32 test_sennenable;
+	u32 test_senpenable;
+	u32 *test_nvalues;
+	char *vdd_name;
+	struct omap_volt_data *volt_data;
+};
+
+/**
+ * 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_data - Smartreflex platform data.
+ *
+ * @senp_mod:		SENPENABLE value for the sr
+ * @senn_mod:		SENNENABLE value for sr
+ * @sr_nvalue:		array of n target values for sr
+ * @enable_on_init:	whether this sr module needs to enabled at
+ *			boot up or not.
+ * @voltdm:		Pointer to the voltage domain associated with the SR
+ */
+struct omap_sr_data {
+	u32				senp_mod;
+	u32				senn_mod;
+	bool				enable_on_init;
+	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] 31+ messages in thread

* [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3 Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 2/9] OMAP3: PM: Adding smartreflex driver support Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-28  5:38   ` Varadarajan, Charulatha
  2010-10-27 16:10 ` [PATCH v4 4/9] OMAP3: PM: Adding smartreflex hwmod data Thara Gopinath
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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 and test n-target vaules, module enable/disable
pointers and a parameter to indicate whether smartreflex
autocompensation needs to be enabled on init or not.
Currently auocompensation is enabled on init by default
for OMAP3430 ES3.1 chip.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/Makefile    |    2 +-
 arch/arm/mach-omap2/sr_device.c |  177 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 178 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 c97a1b5..42b0cc5 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -55,7 +55,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/sr_device.c b/arch/arm/mach-omap2/sr_device.c
new file mode 100644
index 0000000..b7e2d10
--- /dev/null
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -0,0 +1,177 @@
+/*
+ * 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 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
+	},
+};
+
+#ifdef OMAP_SMARTREFLEX_TESTING
+/*
+ * Hard coded nvalues for testing purposes for OMAP3430,
+ * may cause device to hang!
+ */
+static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
+				struct omap_sr_data *sr_data)
+{
+	int i;
+
+	if (!dev_data || !dev_data->volts_supported ||
+			!dev_data->volt_data || !dev_data->test_nvalues) {
+		pr_warning("%s: Bad parameters! dev_data = %x,"
+			"dev_data->volts_supported = %x,"
+			"dev_data->volt_data = %x,"
+			"dev_data->test_nvalues = %x\n", __func__,
+			(unsigned int)dev_data, dev_data->volts_supported,
+			(unsigned int)dev_data->volt_data,
+			(unsigned int)dev_data->test_nvalues);
+		return;
+	}
+
+	sr_data->senn_mod = dev_data->test_sennenable;
+	sr_data->senp_mod = dev_data->test_senpenable;
+	for (i = 0; i < dev_data->volts_supported; i++)
+		dev_data->volt_data[i].sr_nvalue = dev_data->test_nvalues[i];
+}
+#else
+/* Read EFUSE values from control registers for OMAP3430 */
+static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
+				struct omap_sr_data *sr_data)
+{
+	int i;
+
+	if (!dev_data || !dev_data->volts_supported || !dev_data->volt_data ||
+			!dev_data->efuse_nvalues_offs) {
+		pr_warning("%s: Bad parameters! dev_data = %x,"
+			"dev_data->volts_supported = %x,"
+			"dev_data->volt_data = %x,"
+			"dev_data->efuse_nvalues_offs = %x\n", __func__,
+			(unsigned int)dev_data, dev_data->volts_supported,
+			(unsigned int)dev_data->volt_data,
+			(unsigned int)dev_data->efuse_nvalues_offs);
+		return;
+	}
+
+	/*
+	 * From OMAP3630 onwards there are no efuse registers for senn_mod
+	 * and senp_mod. They have to be 0x1 by default.
+	 */
+	if (!dev_data->efuse_sr_control) {
+		sr_data->senn_mod = 0x1;
+		sr_data->senp_mod = 0x1;
+	} else {
+		u32 v, shift;
+
+		v = omap_ctrl_readl(dev_data->efuse_sr_control);
+
+		shift = dev_data->sennenable_shift;
+		sr_data->senn_mod = (v & (0x3 << shift)) >> shift;
+
+		shift = dev_data->senpenable_shift;
+		sr_data->senp_mod = (v & (0x3 << shift)) >> shift;
+	}
+
+	for (i = 0; i < dev_data->volts_supported; i++) {
+		u32 v = omap_ctrl_readl(dev_data->efuse_nvalues_offs[i]);
+
+		dev_data->volt_data[i].sr_nvalue = v;
+	}
+}
+#endif
+
+static int sr_dev_init(struct omap_hwmod *oh, void *user)
+{
+	struct omap_sr_data *sr_data;
+	struct omap_sr_dev_data *sr_dev_data;
+	struct omap_device *od;
+	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;
+	}
+
+	sr_dev_data = (struct omap_sr_dev_data *)oh->dev_attr;
+	if (unlikely(!sr_dev_data)) {
+		pr_err("%s: dev atrribute is NULL\n", __func__);
+		goto exit;
+	}
+
+	/*
+	 * OMAP3430 ES3.1 chips by default come with Efuse burnt
+	 * with parameters required for full functionality of
+	 * smartreflex AVS feature like ntarget values , sennenable
+	 * and senpenable. So enable the SR AVS feature during boot up
+	 * itself if it is a OMAP3430 ES3.1 chip.
+	 */
+	sr_data->enable_on_init = false;
+	if (cpu_is_omap343x())
+		if (omap_rev() == OMAP3430_REV_ES3_1)
+			sr_data->enable_on_init = true;
+
+	sr_data->voltdm = omap_voltage_domain_lookup(sr_dev_data->vdd_name);
+	if (IS_ERR(sr_data->voltdm)) {
+		pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
+			__func__, sr_dev_data->vdd_name);
+		goto exit;
+	}
+
+	sr_dev_data->volts_supported = omap_voltage_get_volttable(
+			sr_data->voltdm, &sr_dev_data->volt_data);
+	if (!sr_dev_data->volts_supported) {
+		pr_warning("%s: No Voltage table registerd fo VDD%d."
+			"Something really wrong\n\n", __func__, i + 1);
+		goto exit;
+	}
+
+	sr_set_nvalues(sr_dev_data, sr_data);
+
+	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;
+}
+
+static int __init omap_devinit_smartreflex(void)
+{
+	return omap_hwmod_for_each_by_class("smartreflex", sr_dev_init, NULL);
+}
+device_initcall(omap_devinit_smartreflex);
-- 
1.7.0.4


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

* [PATCH v4 4/9] OMAP3: PM: Adding smartreflex hwmod data
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (2 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 5/9] OMAP3: PM: Adding smartreflex class3 driver Thara Gopinath
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

This patch adds the smartreflex hwmod data for OMAP3430
and OMAP3630. A dev_attr is also added to the hwmod
structure for each smartreflex module which contains
SoC specific info like the efuse offsets, test n-values
etc.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/control.h              |   27 +++
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |  249 ++++++++++++++++++++++++++++
 2 files changed, 276 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index b6c6b7c..d9b5bed 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)
@@ -243,6 +260,16 @@
 #define OMAP2_SYSBOOT_1_MASK		(1 << 1)
 #define OMAP2_SYSBOOT_0_MASK		(1 << 0)
 
+/* CONTROL_FUSE_SR bits */
+#define OMAP343X_SR2_SENNENABLE_MASK    (0x3 << 10)
+#define OMAP343X_SR2_SENNENABLE_SHIFT   10
+#define OMAP343X_SR2_SENPENABLE_MASK    (0x3 << 8)
+#define OMAP343X_SR2_SENPENABLE_SHIFT   8
+#define OMAP343X_SR1_SENNENABLE_MASK    (0x3 << 2)
+#define OMAP343X_SR1_SENNENABLE_SHIFT   2
+#define OMAP343X_SR1_SENPENABLE_MASK    (0x3 << 0)
+#define OMAP343X_SR1_SENPENABLE_SHIFT   0
+
 /* CONTROL_PBIAS_LITE bits */
 #define OMAP343X_PBIASLITESUPPLY_HIGH1	(1 << 15)
 #define OMAP343X_PBIASLITEVMODEERROR1	(1 << 11)
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ed6bf4a..a6fbb6f 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -21,11 +21,13 @@
 #include <plat/l4_3xxx.h>
 #include <plat/i2c.h>
 #include <plat/omap34xx.h>
+#include <plat/smartreflex.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-34xx.h"
 #include "cm-regbits-34xx.h"
+#include "control.h"
 
 /*
  * OMAP3xxx hardware module integration data
@@ -45,6 +47,8 @@ static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
 static struct omap_hwmod omap3xxx_i2c1_hwmod;
 static struct omap_hwmod omap3xxx_i2c2_hwmod;
 static struct omap_hwmod omap3xxx_i2c3_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 = {
@@ -253,9 +257,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 */
@@ -736,6 +778,209 @@ static struct omap_hwmod omap3xxx_i2c3_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 u32 omap34xx_sr1_efuse_offs[] = {
+	OMAP343X_CONTROL_FUSE_OPP1_VDD1, OMAP343X_CONTROL_FUSE_OPP2_VDD1,
+	OMAP343X_CONTROL_FUSE_OPP3_VDD1, OMAP343X_CONTROL_FUSE_OPP4_VDD1,
+	OMAP343X_CONTROL_FUSE_OPP5_VDD1,
+};
+
+static u32 omap34xx_sr1_test_nvalues[] = {
+	0x9A90E6, 0xAABE9A, 0xBBF5C5, 0xBBB292, 0xBBF5C5,
+};
+
+static struct omap_sr_dev_data omap34xx_sr1_dev_attr = {
+	.efuse_sr_control	= OMAP343X_CONTROL_FUSE_SR,
+	.sennenable_shift	= OMAP343X_SR1_SENNENABLE_SHIFT,
+	.senpenable_shift	= OMAP343X_SR1_SENPENABLE_SHIFT,
+	.efuse_nvalues_offs	= omap34xx_sr1_efuse_offs,
+	.test_sennenable	= 0x3,
+	.test_senpenable	= 0x3,
+	.test_nvalues		= omap34xx_sr1_test_nvalues,
+	.vdd_name		= "mpu",
+};
+
+static struct omap_hwmod omap34xx_sr1_hwmod = {
+	.name		= "sr1_hwmod",
+	.class		= &omap34xx_smartreflex_hwmod_class,
+	.main_clk	= "sr1_fck",
+	.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),
+	.dev_attr	= &omap34xx_sr1_dev_attr,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2 |
+					CHIP_IS_OMAP3430ES3_0 |
+					CHIP_IS_OMAP3430ES3_1),
+	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+};
+
+static u32 omap36xx_sr1_efuse_offs[] = {
+	OMAP3630_CONTROL_FUSE_OPP50_VDD1, OMAP3630_CONTROL_FUSE_OPP100_VDD1,
+	OMAP3630_CONTROL_FUSE_OPP120_VDD1, OMAP3630_CONTROL_FUSE_OPP1G_VDD1,
+};
+
+static u32 omap36xx_sr1_test_nvalues[] = {
+	0x898beb, 0x999b83, 0xaac5a8, 0xaab197,
+};
+
+static struct omap_sr_dev_data omap36xx_sr1_dev_attr = {
+	.efuse_nvalues_offs	= omap36xx_sr1_efuse_offs,
+	.test_sennenable	= 0x1,
+	.test_senpenable	= 0x1,
+	.test_nvalues		= omap36xx_sr1_test_nvalues,
+	.vdd_name		= "mpu",
+};
+
+static struct omap_hwmod omap36xx_sr1_hwmod = {
+	.name		= "sr1_hwmod",
+	.class		= &omap36xx_smartreflex_hwmod_class,
+	.main_clk	= "sr1_fck",
+	.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),
+	.dev_attr	= &omap36xx_sr1_dev_attr,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
+/* SR2 */
+static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = {
+	&omap3_l4_core__sr2,
+};
+
+static u32 omap34xx_sr2_efuse_offs[] = {
+	OMAP343X_CONTROL_FUSE_OPP1_VDD2, OMAP343X_CONTROL_FUSE_OPP2_VDD2,
+	OMAP343X_CONTROL_FUSE_OPP3_VDD2,
+};
+
+static u32 omap34xx_sr2_test_nvalues[] = {
+	0x0, 0xAAC098, 0xAB89D9
+};
+
+static struct omap_sr_dev_data omap34xx_sr2_dev_attr = {
+	.efuse_sr_control	= OMAP343X_CONTROL_FUSE_SR,
+	.sennenable_shift	= OMAP343X_SR2_SENNENABLE_SHIFT,
+	.senpenable_shift	= OMAP343X_SR2_SENPENABLE_SHIFT,
+	.efuse_nvalues_offs	= omap34xx_sr2_efuse_offs,
+	.test_sennenable	= 0x3,
+	.test_senpenable	= 0x3,
+	.test_nvalues		= omap34xx_sr2_test_nvalues,
+	.vdd_name		= "core",
+};
+
+static struct omap_hwmod omap34xx_sr2_hwmod = {
+	.name		= "sr2_hwmod",
+	.class		= &omap34xx_smartreflex_hwmod_class,
+	.main_clk	= "sr2_fck",
+	.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),
+	.dev_attr	= &omap34xx_sr2_dev_attr,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2 |
+					CHIP_IS_OMAP3430ES3_0 |
+					CHIP_IS_OMAP3430ES3_1),
+	.flags		= HWMOD_SET_DEFAULT_CLOCKACT,
+};
+
+static u32 omap36xx_sr2_efuse_offs[] = {
+	OMAP3630_CONTROL_FUSE_OPP50_VDD2, OMAP3630_CONTROL_FUSE_OPP100_VDD2,
+};
+
+static u32 omap36xx_sr2_test_nvalues[] = {
+	0x898beb, 0x9a8cee,
+};
+
+static struct omap_sr_dev_data omap36xx_sr2_dev_attr = {
+	.efuse_nvalues_offs	= omap36xx_sr2_efuse_offs,
+	.test_sennenable	= 0x1,
+	.test_senpenable	= 0x1,
+	.test_nvalues		= omap36xx_sr2_test_nvalues,
+	.vdd_name		= "core",
+};
+
+static struct omap_hwmod omap36xx_sr2_hwmod = {
+	.name		= "sr2_hwmod",
+	.class		= &omap36xx_smartreflex_hwmod_class,
+	.main_clk	= "sr2_fck",
+	.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),
+	.dev_attr	= &omap36xx_sr2_dev_attr,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
 static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l3_main_hwmod,
 	&omap3xxx_l4_core_hwmod,
@@ -751,6 +996,10 @@ 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,
 	NULL,
 };
 
-- 
1.7.0.4


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

* [PATCH v4 5/9] OMAP3: PM: Adding smartreflex class3 driver
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (3 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 4/9] OMAP3: PM: Adding smartreflex hwmod data Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 6/9] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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 42b0cc5..e194830 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -56,6 +56,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 04b0bd2..7ba92c2 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -71,6 +71,15 @@ config OMAP_SMARTREFLEX_TESTING
 
 	  WARNING: Enabling this option may cause your device to hang!
 
+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] 31+ messages in thread

* [PATCH v4 6/9] OMAP3: PM: Adding T2 enabling of smartreflex support
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (4 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 5/9] OMAP3: PM: Adding smartreflex class3 driver Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

This patch adds support in the twl4030 driver to hook up
the API enabling smartreflex support on PMIC side with the
smartreflex driver. Without this the OMAP smartreflex modules
will not function.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 drivers/mfd/twl-core.c      |    7 +++++--
 drivers/mfd/twl4030-power.c |   29 +++++++++++++++++++++++++++++
 include/linux/i2c/twl.h     |    1 +
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 720e099..677b903 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -1009,8 +1009,11 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	clocks_init(&client->dev, pdata->clock);
 
 	/* load power event scripts */
-	if (twl_has_power() && pdata->power)
-		twl4030_power_init(pdata->power);
+	if (twl_has_power()) {
+		twl4030_power_sr_init();
+		 if (pdata->power)
+			twl4030_power_init(pdata->power);
+	}
 
 	/* Maybe init the T2 Interrupt subsystem */
 	if (client->irq
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 7efa878..0e897a7 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -31,6 +31,8 @@
 
 #include <asm/mach-types.h>
 
+#include <plat/smartreflex.h>
+
 static u8 twl4030_start_script_address = 0x2b;
 
 #define PWR_P1_SW_EVENTS	0x10
@@ -63,6 +65,10 @@ static u8 twl4030_start_script_address = 0x2b;
 #define R_MEMORY_ADDRESS	PHY_TO_OFF_PM_MASTER(0x59)
 #define R_MEMORY_DATA		PHY_TO_OFF_PM_MASTER(0x5a)
 
+/* Smartreflex Control */
+#define R_DCDC_GLOBAL_CFG	PHY_TO_OFF_PM_RECEIVER(0x61)
+#define CFG_ENABLE_SRFLX	0x08
+
 #define R_PROTECT_KEY		0x0E
 #define R_KEY_1			0xC0
 #define R_KEY_2			0x0C
@@ -511,6 +517,29 @@ int twl4030_remove_script(u8 flags)
 	return err;
 }
 
+/* API to enable smrtreflex on Triton side */
+static void twl4030_smartreflex_init(void)
+{
+	int ret = 0;
+	u8 read_val;
+
+	ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &read_val,
+			R_DCDC_GLOBAL_CFG);
+	read_val |= CFG_ENABLE_SRFLX;
+	ret |= twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, read_val,
+			R_DCDC_GLOBAL_CFG);
+}
+
+struct omap_sr_pmic_data twl4030_sr_data = {
+	.sr_pmic_init   = twl4030_smartreflex_init,
+};
+
+void __init twl4030_power_sr_init()
+{
+	/* Register the SR init API with the Smartreflex driver */
+	omap_sr_register_pmic(&twl4030_sr_data);
+}
+
 void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
 {
 	int err = 0;
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 6de90bf..b02011e 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -550,6 +550,7 @@ struct twl4030_power_data {
 };
 
 extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
+extern void twl4030_power_sr_init(void);
 extern int twl4030_remove_script(u8 flags);
 
 struct twl4030_codec_audio_data {
-- 
1.7.0.4


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

* [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (5 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 6/9] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-11-10 19:12   ` Kevin Hilman
  2010-10-27 16:10 ` [PATCH v4 8/9] OMAP3: PM: Program correct init voltages for VDD1 and VDD2 Thara Gopinath
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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/vdd_<x>/smartreflex/<parameter>

To enable overriding of these parameters from user side, write 1
into
	/debug/voltage/vdd_<x>/override_volt_params

where <x> is mpu or core for OMAP3.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/smartreflex.c         |   34 ++++-
 arch/arm/mach-omap2/voltage.c             |  219 ++++++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/voltage.h |    1 +
 3 files changed, 248 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index c24ae54..2669584 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -555,8 +555,13 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
 		return -ENODATA;
 	}
 
-	/* errminlimit is opp dependent and hence linked to voltage */
-	sr->err_minlimit = volt_data->sr_errminlimit;
+	/*
+	 * errminlimit is opp dependent and hence linked to voltage.
+	 * If the override option is enabled, the user might have over ridden
+	 * this parameter, so do not get it from voltage table.
+	 */
+	if (!omap_voltage_override_params(voltdm))
+		sr->err_minlimit = volt_data->sr_errminlimit;
 
 	pm_runtime_get_sync(&sr->pdev->dev);
 
@@ -804,9 +809,28 @@ static int omap_sr_autocomp_store(void *data, u64 val)
 	return 0;
 }
 
+static int omap_sr_params_show(void *data, u64 *val)
+{
+	u32 *param = data;
+
+	*val = *param;
+	return 0;
+}
+
+static int omap_sr_params_store(void *data, u64 val)
+{
+	u32 *option = data;
+
+	*option = val;
+	return 0;
+}
+
 DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
 		omap_sr_autocomp_store, "%llu\n");
 
+DEFINE_SIMPLE_ATTRIBUTE(sr_params_fops, omap_sr_params_show,
+		omap_sr_params_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);
@@ -889,6 +913,12 @@ 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_file("errweight", S_IRUGO | S_IWUGO, dbg_dir,
+			&sr_info->err_weight, &sr_params_fops);
+	(void) debugfs_create_file("errmaxlimit", S_IRUGO | S_IWUGO, dbg_dir,
+			&sr_info->err_maxlimit, &sr_params_fops);
+	(void) debugfs_create_file("errminlimit", S_IRUGO | S_IWUGO, dbg_dir,
+			&sr_info->err_minlimit, &sr_params_fops);
 
 	return ret;
 
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 5aa5109..ac81ace 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -110,6 +110,7 @@ struct omap_vdd_info{
 	u32 curr_volt;
 	u8 cmdval_reg;
 	u8 vdd_sr_reg;
+	bool user_override_params;
 };
 
 static struct omap_vdd_info *vdd_info;
@@ -228,6 +229,115 @@ static inline void voltage_write_reg(u8 offset, u32 value)
 	prm_write_mod_reg(value, volt_mod, offset);
 }
 
+/* Voltage debugfs support */
+static int vp_debug_get(void *data, u64 *val)
+{
+	u16 *option = data;
+
+	if (!option) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+
+	*val = *option;
+
+	return 0;
+}
+
+static int vp_debug_set(void *data, u64 val)
+{
+	u32 *option = data;
+
+	if (!option) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+
+	*option = val;
+
+	return 0;
+}
+
+static int volt_params_override_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 = vdd->user_override_params;
+
+	return 0;
+}
+
+static int volt_params_override_set(void *data, u64 val)
+{
+	struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
+
+	if (!vdd) {
+		pr_warning("Wrong paramater passed\n");
+		return -EINVAL;
+	}
+
+	 if (val && (val != 1)) {
+		pr_warning("Invalid argument %lld\n", val);
+		return -EINVAL;
+	 }
+
+	 if (!val)
+		vdd->user_override_params = false;
+	 else
+		vdd->user_override_params = true;
+
+	 return 0;
+}
+
+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 = voltage_read_reg(vdd->vp_offs.voltage);
+	pr_notice("curr_vsel = %x\n", vsel);
+
+	if (!volt_pmic_info.vsel_to_uv) {
+		pr_warning("PMIC function to convert vsel to voltage"
+			"in uV not registerd\n");
+		return -EINVAL;
+	}
+
+	*val = volt_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_debug_fops, vp_debug_get, vp_debug_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(volt_override_fops, volt_params_override_get,
+				volt_params_override_set, "%llu\n");
+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;
@@ -467,7 +577,49 @@ 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_file("vp_errorgain", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vpconfig_errorgain),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_smpswaittimemin", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vstepmin_smpswaittimemin),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_stepmin", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vstepmin_stepmin),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_smpswaittimemax", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vstepmax_smpswaittimemax),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_stepmax", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vstepmax_stepmax),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_vddmax", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vlimitto_vddmax),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_vddmin", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vlimitto_vddmin),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_timeout", S_IRUGO | S_IWUGO,
+				vdd->debug_dir,
+				&(vdd->vp_reg.vlimitto_timeout),
+				&vp_debug_fops);
+	(void) debugfs_create_file("override_volt_params", S_IRUGO | S_IWUGO,
+				vdd->debug_dir, (void *) vdd,
+				&volt_override_fops);
+	(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);
 }
 
 /* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
@@ -531,8 +683,11 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
 	vc_cmdval |= (target_vsel << vc_cmd_on_shift);
 	voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
 
-	/* Setting vp errorgain based on the voltage */
-	if (volt_data) {
+	/*
+	 * Setting vp errorgain based on the voltage If enabled allow
+	 * the override of errorgain from user side.
+	 */
+	if (!vdd->user_override_params && vdd->volt_data) {
 		vp_errgain_val = voltage_read_reg(vdd->vp_offs.vpconfig);
 		vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
 		vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
@@ -637,8 +792,11 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
 	vc_cmdval |= (target_vsel << vc_cmd_on_shift);
 	voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
 
-	/* Getting  vp errorgain based on the voltage */
-	if (volt_data)
+	/*
+	 * Getting vp errorgain based on the voltage If enabled allow
+	 * the override of errorgain from user side.
+	 */
+	if (!vdd->user_override_params && vdd->volt_data)
 		vdd->vp_reg.vpconfig_errorgain =
 					volt_data->vp_errgain;
 
@@ -813,6 +971,37 @@ void omap_vp_enable(struct voltagedomain *voltdm)
 	if (!voltscale_vpforceupdate)
 		vp_latch_vsel(vdd);
 
+	/*
+	 * If override option is enabled, it is likely that the
+	 * following parameters were set from user space so rewrite them.
+	 */
+	if (vdd->user_override_params) {
+		vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+		vpconfig |= (vdd->vp_reg.vpconfig_errorgain <<
+			vdd->vp_reg.vpconfig_errorgain_shift);
+		voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+
+		voltage_write_reg(vdd->vp_offs.vstepmin,
+			(vdd->vp_reg.vstepmin_smpswaittimemin <<
+			vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
+			(vdd->vp_reg.vstepmin_stepmin <<
+			vdd->vp_reg.vstepmin_stepmin_shift));
+
+		voltage_write_reg(vdd->vp_offs.vstepmax,
+			(vdd->vp_reg.vstepmax_smpswaittimemax <<
+			vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
+			(vdd->vp_reg.vstepmax_stepmax <<
+			vdd->vp_reg.vstepmax_stepmax_shift));
+
+		voltage_write_reg(vdd->vp_offs.vlimitto,
+			(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));
+	}
+
 	/* Enable VP */
 	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
 	voltage_write_reg(vdd->vp_offs.vpconfig,
@@ -1073,6 +1262,28 @@ struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm)
 }
 
 /**
+ * omap_voltage_override_params() - API to return whether user wants
+ *					to override voltage params or not.
+ * @voltdm:	pointer to the VDD
+ *
+ * This API returns back the value of the flag user_override_params for
+ * a particular voltage domain indicating whether user wants to over ride
+ * various voltage parameters from user-space or not.
+ */
+bool omap_voltage_override_params(struct voltagedomain *voltdm)
+{
+	struct omap_vdd_info *vdd;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return false;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+	return vdd->user_override_params;
+}
+
+/**
  * omap_voltage_register_pmic() - API to register PMIC specific data
  * @pmic_info:	the structure containing pmic info
  *
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index ecd7352..5677544 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -127,6 +127,7 @@ 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);
+bool omap_voltage_override_params(struct voltagedomain *voltdm);
 #ifdef CONFIG_PM
 void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info);
 void omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc);
-- 
1.7.0.4


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

* [PATCH v4 8/9] OMAP3: PM: Program correct init voltages for VDD1 and VDD2
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (6 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-27 16:10 ` [PATCH v4 9/9] OMAP3: PM: Register TWL4030 pmic info with the voltage driver Thara Gopinath
  2010-10-27 17:21 ` [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Nishanth Menon
  9 siblings, 0 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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 |   68 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 0fe905c..353e155 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>
@@ -20,6 +21,7 @@
 
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
+#include <plat/voltage.h>
 
 #include "pm.h"
 
@@ -138,6 +140,67 @@ 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 int __init omap2_common_pm_init(void)
 {
 	omap2_init_processor_devices();
@@ -145,6 +208,11 @@ static int __init omap2_common_pm_init(void)
 	if (cpu_is_omap34xx() || cpu_is_omap44xx())
 		omap_init_opp_table();
 
+	if (cpu_is_omap34xx()) {
+		omap2_set_init_voltage("mpu", "dpll1_ck", mpu_dev);
+		omap2_set_init_voltage("core", "l3_ick", l3_dev);
+	}
+
 	omap_pm_if_init();
 
 	return 0;
-- 
1.7.0.4


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

* [PATCH v4 9/9] OMAP3: PM: Register TWL4030 pmic info with the voltage driver.
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (7 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 8/9] OMAP3: PM: Program correct init voltages for VDD1 and VDD2 Thara Gopinath
@ 2010-10-27 16:10 ` Thara Gopinath
  2010-10-27 17:21 ` [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Nishanth Menon
  9 siblings, 0 replies; 31+ messages in thread
From: Thara Gopinath @ 2010-10-27 16:10 UTC (permalink / raw)
  To: linux-omap
  Cc: paul, khilman, b-cousson, vishwanath.bs, sawant, Thara Gopinath

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.

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

diff --git a/arch/arm/plat-omap/opp_twl_tps.c b/arch/arm/plat-omap/opp_twl_tps.c
index 112f106..4448fc5 100644
--- a/arch/arm/plat-omap/opp_twl_tps.c
+++ b/arch/arm/plat-omap/opp_twl_tps.c
@@ -13,7 +13,10 @@
  * XXX This code should be part of some other TWL/TPS code.
  */
 
+#include <linux/module.h>
+
 #include <plat/opp_twl_tps.h>
+#include <plat/voltage.h>
 
 /**
  * omap_twl_vsel_to_vdc - convert TWL/TPS VSEL value to microvolts DC
@@ -39,3 +42,17 @@ u8 omap_twl_uv_to_vsel(unsigned long uv)
 	/* Round up to higher voltage */
 	return DIV_ROUND_UP(uv - 600000, 12500);
 }
+
+static struct omap_volt_pmic_info twl_volt_info = {
+	.slew_rate	= 4000,
+	.step_size	= 12500,
+	.vsel_to_uv	= omap_twl_vsel_to_uv,
+	.uv_to_vsel	= omap_twl_uv_to_vsel,
+};
+
+static int __init omap_twl_init(void)
+{
+	omap_voltage_register_pmic(&twl_volt_info);
+	return 0;
+}
+arch_initcall(omap_twl_init);
-- 
1.7.0.4


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

* Re: [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support
  2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
                   ` (8 preceding siblings ...)
  2010-10-27 16:10 ` [PATCH v4 9/9] OMAP3: PM: Register TWL4030 pmic info with the voltage driver Thara Gopinath
@ 2010-10-27 17:21 ` Nishanth Menon
  2010-10-28 15:32   ` Gopinath, Thara
  9 siblings, 1 reply; 31+ messages in thread
From: Nishanth Menon @ 2010-10-27 17:21 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com,
	khilman@deeprootsystems.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand

Gopinath, Thara had written, on 10/27/2010 11:10 AM, the following:
> 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 for the revamped set
> 
> This patch series is based against lo-master with the following additional
> patches applied.
> 	https://patchwork.kernel.org/patch/266911/
> 	https://patchwork.kernel.org/patch/266921/
> 	https://patchwork.kernel.org/patch/266931/
> 	https://patchwork.kernel.org/patch/183712/
> 	https://patchwork.kernel.org/patch/285872/
> 
> The entire series with the dependencies are available at
>         http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=summary
>         head: thara-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
> 
Thanks for hosting the branch, Looking at:
http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=shortlog;h=refs/heads/thara-pm-sr
I am guessing DVFS is missing in this branch? Is it possible to give it 
a test drive?

Also curious should:
"OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code should probably be 
" dropped with "OMAP3: PM: Register TWL4030 pmic info with the voltage" ?

[...]

my 2cents: If that tree were organized based on branches which depend on 
each other it will be easier to identify the dependencies :)
probably:
kernel.org (now that l-o is merged - potential 2.6.37-rc1)
  |- clock patches  -\
  |- DVFS series    -|
  |- OMAP OPP series |
                     |-merged-based -
				 |-voltage layer & SR series perhaps
				 	|- twl optimization
						|- board changes
						*** final code ***
Just 2 cents to make it easier for folks who are not in PM mostly to see 
how everything falls together in place..

-- 
Regards,
Nishanth Menon

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

* RE: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
  2010-10-27 16:10 ` [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file Thara Gopinath
@ 2010-10-28  5:38   ` Varadarajan, Charulatha
  2010-10-28 15:26     ` Gopinath, Thara
  0 siblings, 1 reply; 31+ messages in thread
From: Varadarajan, Charulatha @ 2010-10-28  5:38 UTC (permalink / raw)
  To: Gopinath, Thara, linux-omap@vger.kernel.org
  Cc: paul@pwsan.com, khilman@deeprootsystems.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand

Thara, 

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org 
> [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Gopinath, Thara
> Sent: Wednesday, October 27, 2010 9:41 PM
> To: linux-omap@vger.kernel.org
> Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson, 
> Benoit; Sripathy, Vishwanath; Sawant, Anand; Gopinath, Thara
> Subject: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
> 
> 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 and test n-target vaules, module enable/disable
> pointers and a parameter to indicate whether smartreflex
> autocompensation needs to be enabled on init or not.
> Currently auocompensation is enabled on init by default
> for OMAP3430 ES3.1 chip.
> 
> Signed-off-by: Thara Gopinath <thara@ti.com>
> ---
>  arch/arm/mach-omap2/Makefile    |    2 +-
>  arch/arm/mach-omap2/sr_device.c |  177 
> +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 178 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/sr_device.c
> 

<<snip>>

> +
> +static int sr_dev_init(struct omap_hwmod *oh, void *user)

Since *user is unused, you may rename it to *unused

> +{
> +	struct omap_sr_data *sr_data;
> +	struct omap_sr_dev_data *sr_dev_data;
> +	struct omap_device *od;
> +	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;
> +	}
> +
> +	sr_dev_data = (struct omap_sr_dev_data *)oh->dev_attr;
> +	if (unlikely(!sr_dev_data)) {
> +		pr_err("%s: dev atrribute is NULL\n", __func__);
> +		goto exit;
> +	}
> +
> +	/*
> +	 * OMAP3430 ES3.1 chips by default come with Efuse burnt
> +	 * with parameters required for full functionality of
> +	 * smartreflex AVS feature like ntarget values , sennenable
> +	 * and senpenable. So enable the SR AVS feature during boot up
> +	 * itself if it is a OMAP3430 ES3.1 chip.
> +	 */
> +	sr_data->enable_on_init = false;
> +	if (cpu_is_omap343x())
> +		if (omap_rev() == OMAP3430_REV_ES3_1)
> +			sr_data->enable_on_init = true;
> +
> +	sr_data->voltdm = 
> omap_voltage_domain_lookup(sr_dev_data->vdd_name);
> +	if (IS_ERR(sr_data->voltdm)) {
> +		pr_err("%s: Unable to get voltage domain 
> pointer for VDD %s\n",
> +			__func__, sr_dev_data->vdd_name);
> +		goto exit;
> +	}
> +
> +	sr_dev_data->volts_supported = omap_voltage_get_volttable(
> +			sr_data->voltdm, &sr_dev_data->volt_data);
> +	if (!sr_dev_data->volts_supported) {
> +		pr_warning("%s: No Voltage table registerd fo VDD%d."
> +			"Something really wrong\n\n", __func__, i + 1);
> +		goto exit;
> +	}
> +
> +	sr_set_nvalues(sr_dev_data, sr_data);
> +
> +	od = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
> +			       omap_sr_latency,
> +			       ARRAY_SIZE(omap_sr_latency), 0);

Patch 4 should come before patch 3 in the series. Otherwise, this
would fail during a git-bisect.

> +	if (IS_ERR(od))
> +		pr_warning("%s: Could not build omap_device for 
> %s: %s.\n\n",
> +			__func__, name, oh->name);

Return error.

> +exit:
> +	i++;
> +	kfree(sr_data);
> +	return 0;
> +}
> +
> +static int __init omap_devinit_smartreflex(void)
> +{
> +	return omap_hwmod_for_each_by_class("smartreflex", 
> sr_dev_init, NULL);
> +}
> +device_initcall(omap_devinit_smartreflex);
> -- 
> 1.7.0.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* RE: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
  2010-10-28  5:38   ` Varadarajan, Charulatha
@ 2010-10-28 15:26     ` Gopinath, Thara
  2010-10-29  4:48       ` Varadarajan, Charulatha
  0 siblings, 1 reply; 31+ messages in thread
From: Gopinath, Thara @ 2010-10-28 15:26 UTC (permalink / raw)
  To: Varadarajan, Charulatha, linux-omap@vger.kernel.org
  Cc: paul@pwsan.com, khilman@deeprootsystems.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Varadarajan, Charulatha
>>Sent: Thursday, October 28, 2010 11:09 AM
>>To: Gopinath, Thara; linux-omap@vger.kernel.org
>>Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson, Benoit; Sripathy,
>>Vishwanath; Sawant, Anand
>>Subject: RE: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
>>
>>Thara,
>>
>>> -----Original Message-----
>>> From: linux-omap-owner@vger.kernel.org
>>> [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Gopinath, Thara
>>> Sent: Wednesday, October 27, 2010 9:41 PM
>>> To: linux-omap@vger.kernel.org
>>> Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson,
>>> Benoit; Sripathy, Vishwanath; Sawant, Anand; Gopinath, Thara
>>> Subject: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
>>>
>>> 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 and test n-target vaules, module enable/disable
>>> pointers and a parameter to indicate whether smartreflex
>>> autocompensation needs to be enabled on init or not.
>>> Currently auocompensation is enabled on init by default
>>> for OMAP3430 ES3.1 chip.
>>>
>>> Signed-off-by: Thara Gopinath <thara@ti.com>
>>> ---
>>>  arch/arm/mach-omap2/Makefile    |    2 +-
>>>  arch/arm/mach-omap2/sr_device.c |  177
>>> +++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 178 insertions(+), 1 deletions(-)
>>>  create mode 100644 arch/arm/mach-omap2/sr_device.c
>>>
>>
>><<snip>>
>>
>>> +
>>> +static int sr_dev_init(struct omap_hwmod *oh, void *user)
>>
>>Since *user is unused, you may rename it to *unused

Ok will do.

>>
>>> +{
>>> +	struct omap_sr_data *sr_data;
>>> +	struct omap_sr_dev_data *sr_dev_data;
>>> +	struct omap_device *od;
>>> +	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;
>>> +	}
>>> +
>>> +	sr_dev_data = (struct omap_sr_dev_data *)oh->dev_attr;
>>> +	if (unlikely(!sr_dev_data)) {
>>> +		pr_err("%s: dev atrribute is NULL\n", __func__);
>>> +		goto exit;
>>> +	}
>>> +
>>> +	/*
>>> +	 * OMAP3430 ES3.1 chips by default come with Efuse burnt
>>> +	 * with parameters required for full functionality of
>>> +	 * smartreflex AVS feature like ntarget values , sennenable
>>> +	 * and senpenable. So enable the SR AVS feature during boot up
>>> +	 * itself if it is a OMAP3430 ES3.1 chip.
>>> +	 */
>>> +	sr_data->enable_on_init = false;
>>> +	if (cpu_is_omap343x())
>>> +		if (omap_rev() == OMAP3430_REV_ES3_1)
>>> +			sr_data->enable_on_init = true;
>>> +
>>> +	sr_data->voltdm =
>>> omap_voltage_domain_lookup(sr_dev_data->vdd_name);
>>> +	if (IS_ERR(sr_data->voltdm)) {
>>> +		pr_err("%s: Unable to get voltage domain
>>> pointer for VDD %s\n",
>>> +			__func__, sr_dev_data->vdd_name);
>>> +		goto exit;
>>> +	}
>>> +
>>> +	sr_dev_data->volts_supported = omap_voltage_get_volttable(
>>> +			sr_data->voltdm, &sr_dev_data->volt_data);
>>> +	if (!sr_dev_data->volts_supported) {
>>> +		pr_warning("%s: No Voltage table registerd fo VDD%d."
>>> +			"Something really wrong\n\n", __func__, i + 1);
>>> +		goto exit;
>>> +	}
>>> +
>>> +	sr_set_nvalues(sr_dev_data, sr_data);
>>> +
>>> +	od = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
>>> +			       omap_sr_latency,
>>> +			       ARRAY_SIZE(omap_sr_latency), 0);
>>
>>Patch 4 should come before patch 3 in the series. Otherwise, this
>>would fail during a git-bisect.

Why?? All patches individually compile and boot.

>>
>>> +	if (IS_ERR(od))
>>> +		pr_warning("%s: Could not build omap_device for
>>> %s: %s.\n\n",
>>> +			__func__, name, oh->name);
>>
>>Return error.
>>
>>> +exit:
>>> +	i++;
>>> +	kfree(sr_data);
>>> +	return 0;
>>> +}
>>> +
>>> +static int __init omap_devinit_smartreflex(void)
>>> +{
>>> +	return omap_hwmod_for_each_by_class("smartreflex",
>>> sr_dev_init, NULL);
>>> +}
>>> +device_initcall(omap_devinit_smartreflex);
>>> --
>>> 1.7.0.4
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe
>>> linux-omap" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>

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

* RE: [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support
  2010-10-27 17:21 ` [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Nishanth Menon
@ 2010-10-28 15:32   ` Gopinath, Thara
  2010-11-10 19:03     ` Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Gopinath, Thara @ 2010-10-28 15:32 UTC (permalink / raw)
  To: Menon, Nishanth
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com,
	khilman@deeprootsystems.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Wednesday, October 27, 2010 10:51 PM
>>To: Gopinath, Thara
>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; khilman@deeprootsystems.com;
>>Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver
>>support
>>
>>Gopinath, Thara had written, on 10/27/2010 11:10 AM, the following:
>>> 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 for the revamped set

You are most welcome!!

>>>
>>> This patch series is based against lo-master with the following additional
>>> patches applied.
>>> 	https://patchwork.kernel.org/patch/266911/
>>> 	https://patchwork.kernel.org/patch/266921/
>>> 	https://patchwork.kernel.org/patch/266931/
>>> 	https://patchwork.kernel.org/patch/183712/
>>> 	https://patchwork.kernel.org/patch/285872/
>>>
>>> The entire series with the dependencies are available at
>>>         http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=summary
>>>         head: thara-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
>>>
>>Thanks for hosting the branch, Looking at:

Again glad tat u liked it:-)

>>http://dev.omapzoom.org/?p=thara/omap-dvfs.git;a=shortlog;h=refs/heads/thara-
>>pm-sr
>>I am guessing DVFS is missing in this branch? Is it possible to give it
>>a test drive?

Yes.. This is exactly what I am trying to do. Will keep you updated.

>>
>>Also curious should:
>>"OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code should probably be
>>" dropped with "OMAP3: PM: Register TWL4030 pmic info with the voltage" ?

Hmm.. Last time I suggested moving the contents of this patch to twl-core.c
Nobody seemed to much keen. Hence I retained the plat-omap/opp-twl-tpl.c file.
In fact "OMAP3: PM: Register TWL4030 pmic info with the voltage" registers the
params from plat-omap/opp-twl-tpl.c. But if we have a consensus I will just drop this patch and have the pmic params passed from twl-core.c.

>>
>>[...]
>>
>>my 2cents: If that tree were organized based on branches which depend on
>>each other it will be easier to identify the dependencies :)
>>probably:
>>kernel.org (now that l-o is merged - potential 2.6.37-rc1)
>>  |- clock patches  -\
>>  |- DVFS series    -|
>>  |- OMAP OPP series |
>>                     |-merged-based -
>>				 |-voltage layer & SR series perhaps
>>				 	|- twl optimization
>>						|- board changes
>>						*** final code ***
>>Just 2 cents to make it easier for folks who are not in PM mostly to see
>>how everything falls together in place..

I agree. But then I need some five patches on top of potential 2.6.37-rc1,
which are not present in any branch. Are you asking me to generate separate branches for all these patches?

Regards
Thara

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

* RE: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
  2010-10-28 15:26     ` Gopinath, Thara
@ 2010-10-29  4:48       ` Varadarajan, Charulatha
  0 siblings, 0 replies; 31+ messages in thread
From: Varadarajan, Charulatha @ 2010-10-29  4:48 UTC (permalink / raw)
  To: Gopinath, Thara, linux-omap@vger.kernel.org
  Cc: paul@pwsan.com, khilman@deeprootsystems.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand



> -----Original Message-----
> From: Gopinath, Thara
> Sent: Thursday, October 28, 2010 8:56 PM
> To: Varadarajan, Charulatha; linux-omap@vger.kernel.org
> Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson, Benoit; Sripathy,
> Vishwanath; Sawant, Anand
> Subject: RE: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
> 
> 
> 
> >>-----Original Message-----
> >>From: Varadarajan, Charulatha
> >>Sent: Thursday, October 28, 2010 11:09 AM
> >>To: Gopinath, Thara; linux-omap@vger.kernel.org
> >>Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson, Benoit;
> Sripathy,
> >>Vishwanath; Sawant, Anand
> >>Subject: RE: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
> >>
> >>Thara,
> >>
> >>> -----Original Message-----
> >>> From: linux-omap-owner@vger.kernel.org
> >>> [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Gopinath, Thara
> >>> Sent: Wednesday, October 27, 2010 9:41 PM
> >>> To: linux-omap@vger.kernel.org
> >>> Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson,
> >>> Benoit; Sripathy, Vishwanath; Sawant, Anand; Gopinath, Thara
> >>> Subject: [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file.
> >>>
> >>> 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 and test n-target vaules, module enable/disable
> >>> pointers and a parameter to indicate whether smartreflex
> >>> autocompensation needs to be enabled on init or not.
> >>> Currently auocompensation is enabled on init by default
> >>> for OMAP3430 ES3.1 chip.
> >>>
> >>> Signed-off-by: Thara Gopinath <thara@ti.com>
> >>> ---
> >>>  arch/arm/mach-omap2/Makefile    |    2 +-
> >>>  arch/arm/mach-omap2/sr_device.c |  177
> >>> +++++++++++++++++++++++++++++++++++++++
> >>>  2 files changed, 178 insertions(+), 1 deletions(-)
> >>>  create mode 100644 arch/arm/mach-omap2/sr_device.c
> >>>
> >>
> >><<snip>>
> >>
> >>> +
> >>> +static int sr_dev_init(struct omap_hwmod *oh, void *user)
> >>
> >>Since *user is unused, you may rename it to *unused
> 
> Ok will do.
> 
> >>
> >>> +{
> >>> +	struct omap_sr_data *sr_data;
> >>> +	struct omap_sr_dev_data *sr_dev_data;
> >>> +	struct omap_device *od;
> >>> +	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;
> >>> +	}
> >>> +
> >>> +	sr_dev_data = (struct omap_sr_dev_data *)oh->dev_attr;
> >>> +	if (unlikely(!sr_dev_data)) {
> >>> +		pr_err("%s: dev atrribute is NULL\n", __func__);
> >>> +		goto exit;
> >>> +	}
> >>> +
> >>> +	/*
> >>> +	 * OMAP3430 ES3.1 chips by default come with Efuse burnt
> >>> +	 * with parameters required for full functionality of
> >>> +	 * smartreflex AVS feature like ntarget values , sennenable
> >>> +	 * and senpenable. So enable the SR AVS feature during boot up
> >>> +	 * itself if it is a OMAP3430 ES3.1 chip.
> >>> +	 */
> >>> +	sr_data->enable_on_init = false;
> >>> +	if (cpu_is_omap343x())
> >>> +		if (omap_rev() == OMAP3430_REV_ES3_1)
> >>> +			sr_data->enable_on_init = true;
> >>> +
> >>> +	sr_data->voltdm =
> >>> omap_voltage_domain_lookup(sr_dev_data->vdd_name);
> >>> +	if (IS_ERR(sr_data->voltdm)) {
> >>> +		pr_err("%s: Unable to get voltage domain
> >>> pointer for VDD %s\n",
> >>> +			__func__, sr_dev_data->vdd_name);
> >>> +		goto exit;
> >>> +	}
> >>> +
> >>> +	sr_dev_data->volts_supported = omap_voltage_get_volttable(
> >>> +			sr_data->voltdm, &sr_dev_data->volt_data);
> >>> +	if (!sr_dev_data->volts_supported) {
> >>> +		pr_warning("%s: No Voltage table registerd fo VDD%d."
> >>> +			"Something really wrong\n\n", __func__, i + 1);
> >>> +		goto exit;
> >>> +	}
> >>> +
> >>> +	sr_set_nvalues(sr_dev_data, sr_data);
> >>> +
> >>> +	od = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
> >>> +			       omap_sr_latency,
> >>> +			       ARRAY_SIZE(omap_sr_latency), 0);
> >>
> >>Patch 4 should come before patch 3 in the series. Otherwise, this
> >>would fail during a git-bisect.
> 
> Why?? All patches individually compile and boot.

Oh data for SR is filled only in patch 4 but oh is being used here.
Wouldn't that create a problem?

> 
> >>
> >>> +	if (IS_ERR(od))
> >>> +		pr_warning("%s: Could not build omap_device for
> >>> %s: %s.\n\n",
> >>> +			__func__, name, oh->name);
> >>
> >>Return error.
> >>
> >>> +exit:
> >>> +	i++;
> >>> +	kfree(sr_data);
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int __init omap_devinit_smartreflex(void)
> >>> +{
> >>> +	return omap_hwmod_for_each_by_class("smartreflex",
> >>> sr_dev_init, NULL);
> >>> +}
> >>> +device_initcall(omap_devinit_smartreflex);
> >>> --
> >>> 1.7.0.4
> >>>
> >>> --
> >>> To unsubscribe from this list: send the line "unsubscribe
> >>> linux-omap" in
> >>> the body of a message to majordomo@vger.kernel.org
> >>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>>

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

* Re: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3
  2010-10-27 16:10 ` [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3 Thara Gopinath
@ 2010-11-10 18:59   ` Kevin Hilman
  2010-11-15 10:47     ` Gopinath, Thara
       [not found]   ` <FCCFB4CDC6E5564B9182F639FC356087034C012076@dbde02.ent.ti.com>
       [not found]   ` <87hbfp9gli.fsf@deeprootsystems.com>
  2 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2010-11-10 18:59 UTC (permalink / raw)
  To: Thara Gopinath; +Cc: linux-omap, paul, b-cousson, vishwanath.bs, sawant

[resend with thinned out response, since original reply was determined
 to be spam by vger.kernel.org.  wondering that tells me about my review
 style... ]

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 also 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
> n-target value, errminlimit and voltage processor errorgain.
> 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.
>
> Signed-off-by: Thara Gopinath <thara@ti.com>

All comments below are cut-and-paste from v3 review, and were not
addressed in this update.

[...]

> --- /dev/null
> +++ b/arch/arm/mach-omap2/voltage.c
> @@ -0,0 +1,1158 @@
> +/*
> + * 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"
> +
> +#define VP_IDLE_TIMEOUT		200
> +#define VP_TRANXDONE_TIMEOUT	300
> +#define VOLTAGE_DIR_SIZE	16
> +
> +static struct dentry *voltage_dir;
> +/* PRM voltage module */
> +static u32 volt_mod;

There's no need for this to be a global, this should be a member of
vdd_info (or the voltage domain.)  That means the read/write functions
will have to take an additional argument (vdd or voltdm) but that's
cleaner to me.

[...]

> +/* OMAP3 specific voltage init functions */
> +/*
> + * Intializes the voltage controller registers with the PMIC and board
> + * specific parameters and voltage setup times for OMAP3. If the board
> + * file does not populate the voltage controller parameters through
> + * omap3_pm_init_vc, default values specified in vc_config is used.
> + */
> +static void __init omap3_init_voltagecontroller(void)

I'd like to see consistent naming.  Elsewhere in the code, things are
named with either a vdd, vc or vp prefix.  Let's keep that here and call
this omap3_vc_init(), and for VP below, s/init_voltagecontroller/vp_init/

[...]

> +	/*
> +	 * 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;
> +	}
> +	sys_clk_speed = clk_get_rate(sys_ck);
> +	clk_put(sys_ck);
> +	/* Divide to avoid overflow */
> +	sys_clk_speed /= 1000;
> +
> +	/* Nominal/Reset voltage of the VDD */
> +	vdd->nominal_volt = vdd->curr_volt = 1200000;

This should be a #define someplace, something like OMAP3_VDDx_RESET_VOL
or similar.  Ideally with a TRM/doc reference to where it comes from.

I'm a little confused. Is this a hardware reset value? or a software
reset value which is part of this layer.

It's a little confusing, since if this is a hardware reset voltage why
does init_voltageprocessor() have to write it to the VP during init?

Even better, rather than hard code this, it would be even better if it
just picked one of the nominal voltages from the volt_data table.

[...]

> +/* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
> +static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
> +		unsigned long target_volt)
> +{
> +	struct omap_volt_data *volt_data;
> +	u32 vc_bypass_value, vc_cmdval, vc_valid, vc_bypass_val_reg_offs;
> +	u32 vp_errgain_val, vc_cmd_on_mask;
> +	u32 loop_cnt = 0, retries_cnt = 0;
> +	u32 smps_steps = 0, smps_delay = 0;
> +	u8 vc_data_shift, vc_slaveaddr_shift, vc_regaddr_shift;
> +	u8 vc_cmd_on_shift;
> +	u8 target_vsel, current_vsel, sr_i2c_slave_addr;
> +
> +	if (cpu_is_omap34xx()) {
> +		vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
> +		vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
> +		vc_data_shift = OMAP3430_DATA_SHIFT;
> +		vc_slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
> +		vc_regaddr_shift = OMAP3430_REGADDR_SHIFT;
> +		vc_valid = OMAP3430_VALID_MASK;
> +		vc_bypass_val_reg_offs = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
> +		sr_i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR;
> +	} else {
> +		pr_warning("%s: Voltage scaling not yet enabled for"
> +			"this chip\n", __func__);
> +		return -EINVAL;
> +	}

cpu_is_* checks are only acceptable at init time.  This one happens
during every scale.  These VC settings should be set at init time only.

Same issue with forceupdate_scale.

[...]

> +/* VP force update method of voltage scaling */
> +static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
> +		unsigned long target_volt)
> +{
> +	struct omap_volt_data *volt_data;
> +	u32 vc_cmd_on_mask, vc_cmdval, vpconfig;
> +	u32 smps_steps = 0, smps_delay = 0;
> +	int timeout = 0;
> +	u8 target_vsel, current_vsel;
> +	u8 vc_cmd_on_shift;
> +	u8 prm_irqst_reg_offs, ocp_mod;
> +
> +	if (cpu_is_omap34xx()) {
> +		vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
> +		vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
> +		prm_irqst_reg_offs = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
> +		ocp_mod = OCP_MOD;
> +	} else {
> +		pr_warning("%s: Voltage scaling not yet enabled for"
> +			"this chip\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* Get volt_data corresponding to the target_volt */
> +	volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
> +	if (IS_ERR(volt_data)) {
> +		/*
> +		 * If a match is not found but the target voltage is
> +		 * is the nominal vdd voltage allow scaling
> +		 */
> +		if (target_volt != vdd->nominal_volt) {
> +			pr_warning("%s: Unable to get voltage table for vdd_%s"
> +				"during voltage scaling. Some really Wrong!",
> +				__func__, vdd->voltdm.name);
> +			return -ENODATA;
> +		}
> +		volt_data = NULL;
> +	}
> +
> +	if (!volt_pmic_info.uv_to_vsel) {
> +		pr_warning("%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;
> +	}
> +
> +	target_vsel = volt_pmic_info.uv_to_vsel(target_volt);
> +	current_vsel = voltage_read_reg(vdd->vp_offs.voltage);
> +	smps_steps = abs(target_vsel - current_vsel);
> +
> +	/* Setting the ON voltage to the new target voltage */
> +	vc_cmdval = voltage_read_reg(vdd->cmdval_reg);
> +	vc_cmdval &= ~vc_cmd_on_mask;
> +	vc_cmdval |= (target_vsel << vc_cmd_on_shift);
> +	voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
> +

Up 'til here, this looks almost exactly like the vc_bypass version.
Maybe they can be combined into a common pre-scale function?

> +	/* Getting  vp errorgain based on the voltage */
> +	if (volt_data)
> +		vdd->vp_reg.vpconfig_errorgain =
> +					volt_data->vp_errgain;

This also looks similar to the vc_bypass version.

After the full-series is applied, the comments are identical, but the
code is different.  I suspect they should be the same though.   Possibly
a good reason to have a common pre-scale function.

> +
> +	/*
> +	 * Clear all pending TransactionDone interrupt/status. Typical latency
> +	 * is <3us
> +	 */
> +	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
> +		prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
> +				ocp_mod, prm_irqst_reg_offs);
> +		if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
> +				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 = voltage_read_reg(vdd->vp_offs.vpconfig);
> +	vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
> +			vdd->vp_reg.vpconfig_forceupdate |
> +			vdd->vp_reg.vpconfig_initvoltage_mask |
> +			vdd->vp_reg.vpconfig_errorgain_mask);
> +	vpconfig |= ((target_vsel <<
> +			vdd->vp_reg.vpconfig_initvoltage_shift) |
> +			(vdd->vp_reg.vpconfig_errorgain <<
> +			 vdd->vp_reg.vpconfig_errorgain_shift));
> +	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
> +
> +	/* Trigger initVDD value copy to voltage processor */
> +	vpconfig |= vdd->vp_reg.vpconfig_initvdd;
> +	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
> +
> +	/* Force update of voltage */
> +	vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
> +	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
> +
> +	/*
> +	 * Wait for TransactionDone. Typical latency is <200us.
> +	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
> +	 */
> +	timeout = 0;
> +	omap_test_timeout((prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
> +			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);
> +
> +	/*
> +	 * Wait for voltage to settle with SW wait-loop.
> +	 * SMPS slew rate / step size. 2us added as buffer.
> +	 */
> +	smps_delay = ((smps_steps * volt_pmic_info.step_size) /
> +			volt_pmic_info.slew_rate) + 2;
> +	udelay(smps_delay);
> +
> +	/*
> +	 * Disable TransactionDone interrupt , clear all status, clear
> +	 * control registers
> +	 */
> +	timeout = 0;
> +	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
> +		prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
> +				ocp_mod, prm_irqst_reg_offs);
> +		if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
> +				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 = voltage_read_reg(vdd->vp_offs.vpconfig);
> +	/* Clear initVDD copy trigger bit */
> +	vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
> +	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
> +	/* Clear force bit */
> +	vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
> +	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
> +
> +	vdd->curr_volt = target_volt;

The smps_delay part and updating ->curr_volt is common to the two scale
methods too.  Maybe can be combined into a post-scale common function.

> +
> +	return 0;
> +}

[...]

> +void omap_vp_enable(struct voltagedomain *voltdm)
> +{
> +	struct omap_vdd_info *vdd;
> +	u32 vpconfig;
> +
> +	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 VP is already enabled, do nothing. Return */
> +	if (voltage_read_reg(vdd->vp_offs.vpconfig) &
> +				vdd->vp_reg.vpconfig_vpenable)
> +		return;

Minor: is a register access here required?  Why not just keep an
'vp_enabled' flag as part of the vdd struct?

> +	/*
> +	 * This latching is required only if VC bypass method is used for
> +	 * voltage scaling during dvfs.
> +	 */
> +	if (!voltscale_vpforceupdate)
> +		vp_latch_vsel(vdd);
> +
> +	/* Enable VP */
> +	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
> +	voltage_write_reg(vdd->vp_offs.vpconfig,
> +				vpconfig | vdd->vp_reg.vpconfig_vpenable);
> +}
> +
> +/**
> + * 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;
> +	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 VP is already disabled, do nothing. Return */
> +	if (!(voltage_read_reg(vdd->vp_offs.vpconfig) &
> +				vdd->vp_reg.vpconfig_vpenable)) {
> +		pr_warning("%s: Trying to disable VP for vdd_%s when"
> +			"it is already disabled\n", __func__, voltdm->name);
> +		return;
> +	}

Same here... is a register read really needed if we can just check
vdd->vp_enabled?

> +
> +	/* Disable VP */
> +	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
> +	vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
> +	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
> +
> +	/*
> +	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
> +	 */
> +	omap_test_timeout((voltage_read_reg(vdd->vp_offs.vstatus)),
> +				VP_IDLE_TIMEOUT, timeout);
> +
> +	if (timeout >= VP_IDLE_TIMEOUT)
> +		pr_warning("%s: vdd_%s idle timedout\n",
> +			__func__, voltdm->name);
> +	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 (voltscale_vpforceupdate)
> +		return vp_forceupdate_scale_voltage(vdd, target_volt);
> +	else
> +		return vc_bypass_scale_voltage(vdd, target_volt);

Rather than the 'if' here, let's have a 'scale' function pointer
associated with the VDD which gets updated if the method changes.

Not sure if would ever be useful, but that would also allow the scale
method to be different across VDDs instead of having it global.

[...]

> +void omap_change_voltscale_method(int voltscale_method)
> +{
> +	switch (voltscale_method) {
> +	case VOLTSCALE_VPFORCEUPDATE:
> +		voltscale_vpforceupdate = true;
> +		return;
> +	case VOLTSCALE_VCBYPASS:
> +		voltscale_vpforceupdate = false;
> +		return;
> +	default:
> +		pr_warning("%s: Trying to change the method of voltage scaling"
> +			"to an unsupported one!\n", __func__);
> +	}
> +}

And this API should be changed to take a 'vdd' and just change the
'scale' function pointer.

[...]

Kevin

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

* Re: [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support
  2010-10-28 15:32   ` Gopinath, Thara
@ 2010-11-10 19:03     ` Kevin Hilman
  0 siblings, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2010-11-10 19:03 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: Menon, Nishanth, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand

"Gopinath, Thara" <thara@ti.com> writes:

[...]

>>>
>>>Also curious should:
>>>"OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code should probably be
>>>" dropped with "OMAP3: PM: Register TWL4030 pmic info with the voltage" ?
>
> Hmm.. Last time I suggested moving the contents of this patch to
> twl-core.c Nobody seemed to much keen. Hence I retained the
> plat-omap/opp-twl-tpl.c file.  In fact "OMAP3: PM: Register TWL4030
> pmic info with the voltage" registers the params from
> plat-omap/opp-twl-tpl.c. But if we have a consensus I will just drop
> this patch and have the pmic params passed from twl-core.c.

Sounds right to me.

Kevin


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

* Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-10-27 16:10 ` [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
@ 2010-11-10 19:12   ` Kevin Hilman
  2010-11-15 11:00     ` Gopinath, Thara
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2010-11-10 19:12 UTC (permalink / raw)
  To: Thara Gopinath; +Cc: linux-omap, paul, b-cousson, vishwanath.bs, sawant

Thara Gopinath <thara@ti.com> writes:

> 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/vdd_<x>/smartreflex/<parameter>
>
> To enable overriding of these parameters from user side, write 1
> into
> 	/debug/voltage/vdd_<x>/override_volt_params

Please just git rid of any sort of override parameter from sysfs.

Instead, you can detect in the sysfs code itself if any parameters were
changed and then set the vdd->user_override flag.

Kevin

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

* RE: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3
  2010-11-10 18:59   ` Kevin Hilman
@ 2010-11-15 10:47     ` Gopinath, Thara
  0 siblings, 0 replies; 31+ messages in thread
From: Gopinath, Thara @ 2010-11-15 10:47 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>Sent: Thursday, November 11, 2010 12:30 AM
>>To: Gopinath, Thara
>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; Cousson, Benoit; Sripathy,
>>Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for
>>OMAP3
>>
>>[resend with thinned out response, since original reply was determined
>> to be spam by vger.kernel.org.  wondering that tells me about my review
>> style... ]
>>
>>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 also 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
>>> n-target value, errminlimit and voltage processor errorgain.
>>> 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.
>>>
>>> Signed-off-by: Thara Gopinath <thara@ti.com>
>>
>>All comments below are cut-and-paste from v3 review, and were not
>>addressed in this update.

Hello Kevin,

Thanks for the review. I thought I had fixed most of the v3 comments
except the ones about the n-target values. Sorry if I had missed some.

>>
>>[...]
>>
>>> --- /dev/null
>>> +++ b/arch/arm/mach-omap2/voltage.c
>>> @@ -0,0 +1,1158 @@
>>> +/*
>>> + * 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"
>>> +
>>> +#define VP_IDLE_TIMEOUT            200
>>> +#define VP_TRANXDONE_TIMEOUT       300
>>> +#define VOLTAGE_DIR_SIZE   16
>>> +
>>> +static struct dentry *voltage_dir;
>>> +/* PRM voltage module */
>>> +static u32 volt_mod;
>>
>>There's no need for this to be a global, this should be a member of
>>vdd_info (or the voltage domain.)  That means the read/write functions
>>will have to take an additional argument (vdd or voltdm) but that's
>>cleaner to me.

Ok.

>>
>>[...]
>>
>>> +/* OMAP3 specific voltage init functions */
>>> +/*
>>> + * Intializes the voltage controller registers with the PMIC and board
>>> + * specific parameters and voltage setup times for OMAP3. If the board
>>> + * file does not populate the voltage controller parameters through
>>> + * omap3_pm_init_vc, default values specified in vc_config is used.
>>> + */
>>> +static void __init omap3_init_voltagecontroller(void)
>>
>>I'd like to see consistent naming.  Elsewhere in the code, things are
>>named with either a vdd, vc or vp prefix.  Let's keep that here and call
>>this omap3_vc_init(), and for VP below, s/init_voltagecontroller/vp_init/

Will rename

>>
>>[...]
>>
>>> +   /*
>>> +    * 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;
>>> +   }
>>> +   sys_clk_speed = clk_get_rate(sys_ck);
>>> +   clk_put(sys_ck);
>>> +   /* Divide to avoid overflow */
>>> +   sys_clk_speed /= 1000;
>>> +
>>> +   /* Nominal/Reset voltage of the VDD */
>>> +   vdd->nominal_volt = vdd->curr_volt = 1200000;
>>
>>This should be a #define someplace, something like OMAP3_VDDx_RESET_VOL
>>or similar.  Ideally with a TRM/doc reference to where it comes from.
>>
>>I'm a little confused. Is this a hardware reset value? or a software
>>reset value which is part of this layer.
>>
>>It's a little confusing, since if this is a hardware reset voltage why
>>does init_voltageprocessor() have to write it to the VP during init?
>>
>>Even better, rather than hard code this, it would be even better if it
>>just picked one of the nominal voltages from the volt_data table.

Yes this is the default voltage at which the hardware will boot up.
I had to add this since some errata workarounds requires the vdd to be put to
this level even though this level might not correspond to any opp. The voltage scaling APIs get the error gain from a table corresponding to voltage and might not find an entry for this voltage and hence will fail. I do a check in the scaling APIs if not errorgain is found, is the voltage equal to nominal voltage and if yes I go ahead with the voltage scaling. Maybe I will remove this variable and allow the scaling APIs to scale voltage even if the table does not contain the entry.

>>
>>[...]
>>
>>> +/* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
>>> +static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
>>> +           unsigned long target_volt)
>>> +{
>>> +   struct omap_volt_data *volt_data;
>>> +   u32 vc_bypass_value, vc_cmdval, vc_valid, vc_bypass_val_reg_offs;
>>> +   u32 vp_errgain_val, vc_cmd_on_mask;
>>> +   u32 loop_cnt = 0, retries_cnt = 0;
>>> +   u32 smps_steps = 0, smps_delay = 0;
>>> +   u8 vc_data_shift, vc_slaveaddr_shift, vc_regaddr_shift;
>>> +   u8 vc_cmd_on_shift;
>>> +   u8 target_vsel, current_vsel, sr_i2c_slave_addr;
>>> +
>>> +   if (cpu_is_omap34xx()) {
>>> +           vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
>>> +           vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
>>> +           vc_data_shift = OMAP3430_DATA_SHIFT;
>>> +           vc_slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
>>> +           vc_regaddr_shift = OMAP3430_REGADDR_SHIFT;
>>> +           vc_valid = OMAP3430_VALID_MASK;
>>> +           vc_bypass_val_reg_offs = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
>>> +           sr_i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR;
>>> +   } else {
>>> +           pr_warning("%s: Voltage scaling not yet enabled for"
>>> +                   "this chip\n", __func__);
>>> +           return -EINVAL;
>>> +   }
>>
>>cpu_is_* checks are only acceptable at init time.  This one happens
>>during every scale.  These VC settings should be set at init time only.
>>
>>Same issue with forceupdate_scale.

These masks are needed only in vc bypass voltage scaling API. I was thinking that for using in just one API I need not maintain these variables in the generic vdd structure. But yes this will add a cpu_is_* check in this API.
Is it preferred to have these variables defined in the common vdd structures and populated during init even if used only in one API?

>>
>>[...]
>>
>>> +/* VP force update method of voltage scaling */
>>> +static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
>>> +           unsigned long target_volt)
>>> +{
>>> +   struct omap_volt_data *volt_data;
>>> +   u32 vc_cmd_on_mask, vc_cmdval, vpconfig;
>>> +   u32 smps_steps = 0, smps_delay = 0;
>>> +   int timeout = 0;
>>> +   u8 target_vsel, current_vsel;
>>> +   u8 vc_cmd_on_shift;
>>> +   u8 prm_irqst_reg_offs, ocp_mod;
>>> +
>>> +   if (cpu_is_omap34xx()) {
>>> +           vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
>>> +           vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
>>> +           prm_irqst_reg_offs = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
>>> +           ocp_mod = OCP_MOD;
>>> +   } else {
>>> +           pr_warning("%s: Voltage scaling not yet enabled for"
>>> +                   "this chip\n", __func__);
>>> +           return -EINVAL;
>>> +   }
>>> +
>>> +   /* Get volt_data corresponding to the target_volt */
>>> +   volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
>>> +   if (IS_ERR(volt_data)) {
>>> +           /*
>>> +            * If a match is not found but the target voltage is
>>> +            * is the nominal vdd voltage allow scaling
>>> +            */
>>> +           if (target_volt != vdd->nominal_volt) {
>>> +                   pr_warning("%s: Unable to get voltage table for vdd_%s"
>>> +                           "during voltage scaling. Some really Wrong!",
>>> +                           __func__, vdd->voltdm.name);
>>> +                   return -ENODATA;
>>> +           }
>>> +           volt_data = NULL;
>>> +   }
>>> +
>>> +   if (!volt_pmic_info.uv_to_vsel) {
>>> +           pr_warning("%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;
>>> +   }
>>> +
>>> +   target_vsel = volt_pmic_info.uv_to_vsel(target_volt);
>>> +   current_vsel = voltage_read_reg(vdd->vp_offs.voltage);
>>> +   smps_steps = abs(target_vsel - current_vsel);
>>> +
>>> +   /* Setting the ON voltage to the new target voltage */
>>> +   vc_cmdval = voltage_read_reg(vdd->cmdval_reg);
>>> +   vc_cmdval &= ~vc_cmd_on_mask;
>>> +   vc_cmdval |= (target_vsel << vc_cmd_on_shift);
>>> +   voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
>>> +
>>
>>Up 'til here, this looks almost exactly like the vc_bypass version.
>>Maybe they can be combined into a common pre-scale function?
>>
>>> +   /* Getting  vp errorgain based on the voltage */
>>> +   if (volt_data)
>>> +           vdd->vp_reg.vpconfig_errorgain =
>>> +                                   volt_data->vp_errgain;
>>
>>This also looks similar to the vc_bypass version.
>>
>>After the full-series is applied, the comments are identical, but the
>>code is different.  I suspect they should be the same though.   Possibly
>>a good reason to have a common pre-scale function.

I will try combining into a common pre-scale fn. Not sure how many of these
steps are common but will give it a try for sure

>>
>>> +
>>> +   /*
>>> +    * Clear all pending TransactionDone interrupt/status. Typical latency
>>> +    * is <3us
>>> +    */
>>> +   while (timeout++ < VP_TRANXDONE_TIMEOUT) {
>>> +           prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
>>> +                           ocp_mod, prm_irqst_reg_offs);
>>> +           if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
>>> +                           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 = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
>>> +                   vdd->vp_reg.vpconfig_forceupdate |
>>> +                   vdd->vp_reg.vpconfig_initvoltage_mask |
>>> +                   vdd->vp_reg.vpconfig_errorgain_mask);
>>> +   vpconfig |= ((target_vsel <<
>>> +                   vdd->vp_reg.vpconfig_initvoltage_shift) |
>>> +                   (vdd->vp_reg.vpconfig_errorgain <<
>>> +                    vdd->vp_reg.vpconfig_errorgain_shift));
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /* Trigger initVDD value copy to voltage processor */
>>> +   vpconfig |= vdd->vp_reg.vpconfig_initvdd;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /* Force update of voltage */
>>> +   vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /*
>>> +    * Wait for TransactionDone. Typical latency is <200us.
>>> +    * Depends on SMPSWAITTIMEMIN/MAX and voltage change
>>> +    */
>>> +   timeout = 0;
>>> +   omap_test_timeout((prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
>>> +                   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);
>>> +
>>> +   /*
>>> +    * Wait for voltage to settle with SW wait-loop.
>>> +    * SMPS slew rate / step size. 2us added as buffer.
>>> +    */
>>> +   smps_delay = ((smps_steps * volt_pmic_info.step_size) /
>>> +                   volt_pmic_info.slew_rate) + 2;
>>> +   udelay(smps_delay);
>>> +
>>> +   /*
>>> +    * Disable TransactionDone interrupt , clear all status, clear
>>> +    * control registers
>>> +    */
>>> +   timeout = 0;
>>> +   while (timeout++ < VP_TRANXDONE_TIMEOUT) {
>>> +           prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
>>> +                           ocp_mod, prm_irqst_reg_offs);
>>> +           if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
>>> +                           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 = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   /* Clear initVDD copy trigger bit */
>>> +   vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +   /* Clear force bit */
>>> +   vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   vdd->curr_volt = target_volt;
>>
>>The smps_delay part and updating ->curr_volt is common to the two scale
>>methods too.  Maybe can be combined into a post-scale common function.

Will do this.

>>
>>> +
>>> +   return 0;
>>> +}
>>
>>[...]
>>
>>> +void omap_vp_enable(struct voltagedomain *voltdm)
>>> +{
>>> +   struct omap_vdd_info *vdd;
>>> +   u32 vpconfig;
>>> +
>>> +   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 VP is already enabled, do nothing. Return */
>>> +   if (voltage_read_reg(vdd->vp_offs.vpconfig) &
>>> +                           vdd->vp_reg.vpconfig_vpenable)
>>> +           return;
>>
>>Minor: is a register access here required?  Why not just keep an
>>'vp_enabled' flag as part of the vdd struct?

I do not want to have the complications of maintaining a flag and ensuring exclusivity. But do you think having a register read here is bad? Latency cannot be much as it is a single register read. If you really think we should have a flag, I can change it.

>>
>>> +   /*
>>> +    * This latching is required only if VC bypass method is used for
>>> +    * voltage scaling during dvfs.
>>> +    */
>>> +   if (!voltscale_vpforceupdate)
>>> +           vp_latch_vsel(vdd);
>>> +
>>> +   /* Enable VP */
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig,
>>> +                           vpconfig | vdd->vp_reg.vpconfig_vpenable);
>>> +}
>>> +
>>> +/**
>>> + * 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;
>>> +   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 VP is already disabled, do nothing. Return */
>>> +   if (!(voltage_read_reg(vdd->vp_offs.vpconfig) &
>>> +                           vdd->vp_reg.vpconfig_vpenable)) {
>>> +           pr_warning("%s: Trying to disable VP for vdd_%s when"
>>> +                   "it is already disabled\n", __func__, voltdm->name);
>>> +           return;
>>> +   }
>>
>>Same here... is a register read really needed if we can just check
>>vdd->vp_enabled?
>>
>>> +
>>> +   /* Disable VP */
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /*
>>> +    * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
>>> +    */
>>> +   omap_test_timeout((voltage_read_reg(vdd->vp_offs.vstatus)),
>>> +                           VP_IDLE_TIMEOUT, timeout);
>>> +
>>> +   if (timeout >= VP_IDLE_TIMEOUT)
>>> +           pr_warning("%s: vdd_%s idle timedout\n",
>>> +                   __func__, voltdm->name);
>>> +   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 (voltscale_vpforceupdate)
>>> +           return vp_forceupdate_scale_voltage(vdd, target_volt);
>>> +   else
>>> +           return vc_bypass_scale_voltage(vdd, target_volt);
>>
>>Rather than the 'if' here, let's have a 'scale' function pointer
>>associated with the VDD which gets updated if the method changes.
>>
>>Not sure if would ever be useful, but that would also allow the scale
>>method to be different across VDDs instead of having it global.

Sounds good to me. Only we will be maintaining a fn ptr per vdd basis
for scaling the vdd. But then it is ok.

>>
>>[...]
>>
>>> +void omap_change_voltscale_method(int voltscale_method)
>>> +{
>>> +   switch (voltscale_method) {
>>> +   case VOLTSCALE_VPFORCEUPDATE:
>>> +           voltscale_vpforceupdate = true;
>>> +           return;
>>> +   case VOLTSCALE_VCBYPASS:
>>> +           voltscale_vpforceupdate = false;
>>> +           return;
>>> +   default:
>>> +           pr_warning("%s: Trying to change the method of voltage scaling"
>>> +                   "to an unsupported one!\n", __func__);
>>> +   }
>>> +}
>>
>>And this API should be changed to take a 'vdd' and just change the
>>'scale' function pointer.

Ok.

Regards
Thara

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

* RE: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-11-10 19:12   ` Kevin Hilman
@ 2010-11-15 11:00     ` Gopinath, Thara
  2010-11-15 22:12       ` Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Gopinath, Thara @ 2010-11-15 11:00 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>Sent: Thursday, November 11, 2010 12:43 AM
>>To: Gopinath, Thara
>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; Cousson, Benoit; Sripathy,
>>Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>Smartreflex drivers
>>
>>Thara Gopinath <thara@ti.com> writes:
>>
>>> 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/vdd_<x>/smartreflex/<parameter>
>>>
>>> To enable overriding of these parameters from user side, write 1
>>> into
>>> 	/debug/voltage/vdd_<x>/override_volt_params
>>
>>Please just git rid of any sort of override parameter from sysfs.
>>
>>Instead, you can detect in the sysfs code itself if any parameters were
>>changed and then set the vdd->user_override flag.

But when will I unset this flag??

Regards
Thara

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

* RE: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3
       [not found]   ` <FCCFB4CDC6E5564B9182F639FC356087034C012076@dbde02.ent.ti.com>
@ 2010-11-15 14:55     ` Gopinath, Thara
  0 siblings, 0 replies; 31+ messages in thread
From: Gopinath, Thara @ 2010-11-15 14:55 UTC (permalink / raw)
  To: Sripathy, Vishwanath, linux-omap@vger.kernel.org
  Cc: paul@pwsan.com, khilman@deeprootsystems.com, Cousson, Benoit,
	Sawant, Anand



>>-----Original Message-----
>>From: Sripathy, Vishwanath
>>Sent: Thursday, November 11, 2010 11:30 AM
>>To: Gopinath, Thara; linux-omap@vger.kernel.org
>>Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson, Benoit; Sawant,
>>Anand
>>Subject: RE: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for
>>OMAP3
>>
>>Thara,
>>
>>> -----Original Message-----
>>> From: Gopinath, Thara
>>> Sent: Wednesday, October 27, 2010 9:41 PM
>>> To: linux-omap@vger.kernel.org
>>> Cc: paul@pwsan.com; khilman@deeprootsystems.com; Cousson, Benoit;
>>> Sripathy, Vishwanath; Sawant, Anand; Gopinath, Thara
>>> Subject: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for
>>> OMAP3
>>>
>>> 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 also 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
>>> n-target value, errminlimit and voltage processor errorgain.
>>> 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.
>>>
>>> Signed-off-by: Thara Gopinath <thara@ti.com>
>>> ---
>>>  arch/arm/mach-omap2/Makefile              |    3 +-
>>>  arch/arm/mach-omap2/voltage.c             | 1158
>>> +++++++++++++++++++++++++++++
>>>  arch/arm/plat-omap/include/plat/voltage.h |  141 ++++
>>>  3 files changed, 1301 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 0b6d9af..bfdabcc 100644
>>> --- a/arch/arm/mach-omap2/Makefile
>>> +++ b/arch/arm/mach-omap2/Makefile
>>> @@ -51,7 +51,8 @@ obj-$(CONFIG_ARCH_OMAP2)		+=
>>> sdrc2xxx.o
>>>  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/voltage.c b/arch/arm/mach-
>>> omap2/voltage.c
>>> new file mode 100644
>>> index 0000000..5aa5109
>>> --- /dev/null
>>> +++ b/arch/arm/mach-omap2/voltage.c
>>> @@ -0,0 +1,1158 @@
>>> +/*
>>> + * 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"
>>> +
>>> +#define VP_IDLE_TIMEOUT		200
>>> +#define VP_TRANXDONE_TIMEOUT	300
>>> +#define VOLTAGE_DIR_SIZE	16
>>> +
>>> +static struct dentry *voltage_dir;
>>> +/* PRM voltage module */
>>> +static u32 volt_mod;
>>> +
>>> +/* 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 {
>>> +	/* 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 */
>>> +	u16 vlimitto_vddmin;
>>> +	u16 vlimitto_vddmax;
>>> +	u16 vlimitto_timeout;
>>> +	u16 vlimitto_vddmin_shift;
>>> +	u16 vlimitto_vddmax_shift;
>>> +	u16 vlimitto_timeout_shift;
>>> +	/* PRM_IRQSTATUS*/
>>> +	u32 tranxdone_status;
>>> +};
>>> +
>>> +/**
>>> + * 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.
>>> + * @vp_offs		: structure containing the offsets for various
>>> + *			  vp registers
>>> + * @vp_reg		: the register values, shifts, masks for various
>>> + *			  vp registers
>>> + * @voltdm		: pointer to the voltage domain structure
>>> + * @debug_dir		: debug directory for this voltage domain.
>>> + * @volt_data_count	: number of distinct voltages supported by
>>> this vdd.
>>> + * @nominal_volt	: nominal voltage for this vdd.
>>> + * @curr_volt		: current voltage for this vdd;
>>> + * cmdval_reg		: voltage controller cmdval register.
>>> + * @vdd_sr_reg		: the smartreflex register associated with
>>> this VDD.
>>> + */
>>> +struct omap_vdd_info{
>>> +	struct omap_volt_data *volt_data;
>>> +	struct vp_reg_offs vp_offs;
>>> +	struct vp_reg_val vp_reg;
>>> +	struct voltagedomain voltdm;
>>> +	struct dentry *debug_dir;
>>> +	int volt_data_count;
>>> +	u32 nominal_volt;
>>> +	u32 curr_volt;
>>> +	u8 cmdval_reg;
>>> +	u8 vdd_sr_reg;
>>> +};
>>> +
>>> +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)
>>> +
>>> +/* TODO: OMAP4 register offsets */
>>> +
>>> +/*
>>> + * Default voltage controller settings.
>>> + */
>>> +static struct omap_volt_vc_data vc_config = {
>>> +	.clksetup = 0xff,
>>> +	.voltsetup_time1 = 0xfff,
>>> +	.voltsetup_time2 = 0xfff,
>>> +	.voltoffset = 0xff,
>>> +	.voltsetup2 = 0xff,
>>> +	.vdd0_on = 0x30,        /* 1.2v */
>>> +	.vdd0_onlp = 0x20,      /* 1.0v */
>>> +	.vdd0_ret = 0x1e,       /* 0.975v */
>>> +	.vdd0_off = 0x00,       /* 0.6v */
>>> +	.vdd1_on = 0x2c,        /* 1.15v */
>>> +	.vdd1_onlp = 0x20,      /* 1.0v */
>>> +	.vdd1_ret = 0x1e,       /* .975v */
>>> +	.vdd1_off = 0x00,       /* 0.6v */
>>> +};
>>> +
>>> +/*
>>> + * Default PMIC Data
>>> + */
>>> +static struct omap_volt_pmic_info volt_pmic_info = {
>>> +	.slew_rate = 4000,
>>> +	.step_size = 12500,
>>> +};
>>> +
>>> +/*
>>> + * Structures containing OMAP3430/OMAP3630 voltage supported and
>>> various
>>> + * data associated with it per voltage domain basis. Smartreflex Ntarget
>>> + * values are left as 0 as they have to be populated by smartreflex
>>> + * driver after reading the efuse.
>>> + */
>>> +
>>> +/* VDD1 */
>>> +static struct omap_volt_data omap34xx_vdd1_volt_data[] = {
>>> +	{.volt_nominal = 975000, .sr_errminlimit = 0xF4, .vp_errgain =
>>> 0x0C},
>>> +	{.volt_nominal = 1075000, .sr_errminlimit = 0xF4, .vp_errgain =
>>> 0x0C},
>>> +	{.volt_nominal = 1200000, .sr_errminlimit = 0xF9, .vp_errgain =
>>> 0x18},
>>> +	{.volt_nominal = 1270000, .sr_errminlimit = 0xF9, .vp_errgain =
>>> 0x18},
>>> +	{.volt_nominal = 1350000, .sr_errminlimit = 0xF9, .vp_errgain =
>>> 0x18},
>>> +};
>>> +
>>> +static struct omap_volt_data omap36xx_vdd1_volt_data[] = {
>>> +	{.volt_nominal = 930000, .sr_errminlimit = 0xF4, .vp_errgain =
>>> 0x0C},
>>> +	{.volt_nominal = 1100000, .sr_errminlimit = 0xF9, .vp_errgain =
>>> 0x16},
>>> +	{.volt_nominal = 1260000, .sr_errminlimit = 0xFA, .vp_errgain =
>>> 0x23},
>>> +	{.volt_nominal = 1350000, .sr_errminlimit = 0xFA, .vp_errgain =
>>> 0x27},
>>> +};
>>These 3630 voltage values do not mach with Values in OPP definition list
>>(omap36xx_opp_def_list). Because of this, it fails to boot on OMP3630.

Will look into this and do the correction in the next version

Regards
Thara

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

* Re: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3
       [not found]     ` <5A47E75E594F054BAF48C5E4FC4B92AB035EFF4E51@dbde02.ent.ti.com>
@ 2010-11-15 19:43       ` Kevin Hilman
  0 siblings, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2010-11-15 19:43 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand

"Gopinath, Thara" <thara@ti.com> writes:

>>>

[...]

>>>
>>>cpu_is_* checks are only acceptable at init time.  This one happens
>>>during every scale.  These VC settings should be set at init time only.
>>>
>>>Same issue with forceupdate_scale.
>
> These masks are needed only in vc bypass voltage scaling API. I was
> thinking that for using in just one API I need not maintain these
> variables in the generic vdd structure. But yes this will add a
> cpu_is_* check in this API.  Is it preferred to have these variables
> defined in the common vdd structures and populated during init even if
> used only in one API?

Yes.

[...]

>>>> +void omap_vp_enable(struct voltagedomain *voltdm)
>>>> +{
>>>> +   struct omap_vdd_info *vdd;
>>>> +   u32 vpconfig;
>>>> +
>>>> +   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 VP is already enabled, do nothing. Return */
>>>> +   if (voltage_read_reg(vdd->vp_offs.vpconfig) &
>>>> +                           vdd->vp_reg.vpconfig_vpenable)
>>>> +           return;
>>>
>>>Minor: is a register access here required?  Why not just keep an
>>>'vp_enabled' flag as part of the vdd struct?
>
> I do not want to have the complications of maintaining a flag and
> ensuring exclusivity. 

Whether you use a flag or a register access, the ability to ensure 
exclusivity does not change.

> But do you think having a register read here is bad? 

Yes.

s/bad/unnecessary/

> Latency cannot be much as it is a single register read. If you really
> think we should have a flag, I can change it.

The PRCM is on L4, so accesses to PRCM registers are all slow and should
be avoided if possible.  This is an easy case where a register access
can be prevented simply by caching.


Kevin

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

* Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-11-15 11:00     ` Gopinath, Thara
@ 2010-11-15 22:12       ` Kevin Hilman
  2010-12-08 16:18         ` Gopinath, Thara
  0 siblings, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2010-11-15 22:12 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand

"Gopinath, Thara" <thara@ti.com> writes:

>>>-----Original Message-----
>>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>>Sent: Thursday, November 11, 2010 12:43 AM
>>>To: Gopinath, Thara
>>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; Cousson, Benoit; Sripathy,
>>>Vishwanath; Sawant, Anand
>>>Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>>Smartreflex drivers
>>>
>>>Thara Gopinath <thara@ti.com> writes:
>>>
>>>> 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/vdd_<x>/smartreflex/<parameter>
>>>>
>>>> To enable overriding of these parameters from user side, write 1
>>>> into
>>>> 	/debug/voltage/vdd_<x>/override_volt_params
>>>
>>>Please just git rid of any sort of override parameter from sysfs.
>>>
>>>Instead, you can detect in the sysfs code itself if any parameters were
>>>changed and then set the vdd->user_override flag.
>
> But when will I unset this flag??

You can't.

And, AFAICT, it wasn't clear from the current code or docs whether this
could work or was expected to work either, e.g., if you set
override_volt_params back to zero, to the original values all get reused?

If you want to provide this feature, then it should be documented and
made clear that this is an intended goal.

Thinking about this more, the main thing I don't like about this
approach is that the active code paths (enable & disable) have to check
each time if any of these values have been overidden.

Rather than have several places in the active code paths where this
override value is checked, there the sysfs methods should simply update
the values that are used by the core code.  This way, the core would 
not need to know about where the values came from (defalts, volt_data,
user override, etc.)

If you want to provide a way to revert this, then maybe writing -1 will
should switch that value back to the HW default, or volt_data default.

Kevin

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

* RE: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3
       [not found]   ` <87hbfp9gli.fsf@deeprootsystems.com>
       [not found]     ` <5A47E75E594F054BAF48C5E4FC4B92AB035EFF4E51@dbde02.ent.ti.com>
@ 2010-12-02  6:13     ` Gopinath, Thara
  1 sibling, 0 replies; 31+ messages in thread
From: Gopinath, Thara @ 2010-12-02  6:13 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>Sent: Thursday, November 11, 2010 12:00 AM
>>To: Gopinath, Thara
>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; Cousson, Benoit; Sripathy,
>>Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for
>>OMAP3
>>
>>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 also 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
>>> n-target value, errminlimit and voltage processor errorgain.
>>> 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.
>>>
>>> Signed-off-by: Thara Gopinath <thara@ti.com>
>>
>>All comments below are cut-and-paste from v3 review, and were not
>>addressed in this update.
>>
>>> ---
>>>  arch/arm/mach-omap2/Makefile              |    3 +-
>>>  arch/arm/mach-omap2/voltage.c             | 1158
>>+++++++++++++++++++++++++++++
>>>  arch/arm/plat-omap/include/plat/voltage.h |  141 ++++
>>>  3 files changed, 1301 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 0b6d9af..bfdabcc 100644
>>> --- a/arch/arm/mach-omap2/Makefile
>>> +++ b/arch/arm/mach-omap2/Makefile
>>> @@ -51,7 +51,8 @@ obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
>>>  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/voltage.c b/arch/arm/mach-omap2/voltage.c
>>> new file mode 100644
>>> index 0000000..5aa5109
>>> --- /dev/null
>>> +++ b/arch/arm/mach-omap2/voltage.c
>>> @@ -0,0 +1,1158 @@
>>> +/*
>>> + * 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"
>>> +
>>> +#define VP_IDLE_TIMEOUT		200
>>> +#define VP_TRANXDONE_TIMEOUT	300
>>> +#define VOLTAGE_DIR_SIZE	16
>>> +
>>> +static struct dentry *voltage_dir;
>>> +/* PRM voltage module */
>>> +static u32 volt_mod;
>>
>>There's no need for this to be a global, this should be a member of
>>vdd_info (or the voltage domain.)  That means the read/write functions
>>will have to take an additional argument (vdd or voltdm) but that's
>>cleaner to me.

Kevin,

The voltage_read and voltage_write APIs are used not only for the per vdd registers. We also access the vc registers through them and passing vdd or voltdm is not an option. Two options we have are 
	1. Keep the existing implementation
	2. Have volt_mod/prm_mod per vdd basis in the omap_vdd_info struct. Introduce a new struct for storing vc parameters per SoC basis and have a prm_mod there also. Scrap voltage_read and voltage_write APIs and use prm_read and prm_write instead. The last step is because we do not want a voltage_read / voltage_write which looks exactly similar to prm_read/prm_write and do nothing but call into prm_read/prm_write.

Do let me know your thoughts as I m in the midst of the rework. I am assuming you would prefer option 2 and proceeding :-)! 

Regards
Thara

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

* RE: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-11-15 22:12       ` Kevin Hilman
@ 2010-12-08 16:18         ` Gopinath, Thara
  2010-12-08 16:34           ` Nishanth Menon
  0 siblings, 1 reply; 31+ messages in thread
From: Gopinath, Thara @ 2010-12-08 16:18 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: linux-omap@vger.kernel.org, paul@pwsan.com, Cousson, Benoit,
	Sripathy, Vishwanath, Sawant, Anand, Menon, Nishanth



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>Sent: Tuesday, November 16, 2010 3:43 AM
>>To: Gopinath, Thara
>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; Cousson, Benoit; Sripathy,
>>Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>Smartreflex drivers
>>
>>"Gopinath, Thara" <thara@ti.com> writes:
>>
>>>>>-----Original Message-----
>>>>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>>>>Sent: Thursday, November 11, 2010 12:43 AM
>>>>>To: Gopinath, Thara
>>>>>Cc: linux-omap@vger.kernel.org; paul@pwsan.com; Cousson, Benoit; Sripathy,
>>>>>Vishwanath; Sawant, Anand
>>>>>Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>>>>Smartreflex drivers
>>>>>
>>>>>Thara Gopinath <thara@ti.com> writes:
>>>>>
>>>>>> 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/vdd_<x>/smartreflex/<parameter>
>>>>>>
>>>>>> To enable overriding of these parameters from user side, write 1
>>>>>> into
>>>>>> 	/debug/voltage/vdd_<x>/override_volt_params
>>>>>
>>>>>Please just git rid of any sort of override parameter from sysfs.
>>>>>
>>>>>Instead, you can detect in the sysfs code itself if any parameters were
>>>>>changed and then set the vdd->user_override flag.

But in the sys-fs code I do not have access to vdd. How do I then set this flag?

>>>
>>> But when will I unset this flag??
>>
>>You can't.
>>
>>And, AFAICT, it wasn't clear from the current code or docs whether this
>>could work or was expected to work either, e.g., if you set
>>override_volt_params back to zero, to the original values all get reused?
>>
>>If you want to provide this feature, then it should be documented and
>>made clear that this is an intended goal.
>>
>>Thinking about this more, the main thing I don't like about this
>>approach is that the active code paths (enable & disable) have to check
>>each time if any of these values have been overidden.
>>
>>Rather than have several places in the active code paths where this
>>override value is checked, there the sysfs methods should simply update
>>the values that are used by the core code.  This way, the core would
>>not need to know about where the values came from (defalts, volt_data,
>>user override, etc.)
>>
>>If you want to provide a way to revert this, then maybe writing -1 will
>>should switch that value back to the HW default, or volt_data default.
Kevin, Benoit, Nishant et al,

Without this override flag today there is no direct way of
allowing user to write into these parameters. My question is,
is there a need for the parameters to be over-written
from the user-space? If yes, I need ideas on how to
implement it with using override_volt_params !

Regards
Thara

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

* Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-08 16:18         ` Gopinath, Thara
@ 2010-12-08 16:34           ` Nishanth Menon
  2010-12-09  9:43             ` Gopinath, Thara
  0 siblings, 1 reply; 31+ messages in thread
From: Nishanth Menon @ 2010-12-08 16:34 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: Kevin Hilman, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand

Gopinath, Thara had written, on 12/08/2010 10:18 AM, the following:
[..]
>>> And, AFAICT, it wasn't clear from the current code or docs whether this
>>> could work or was expected to work either, e.g., if you set
>>> override_volt_params back to zero, to the original values all get reused?
>>>
>>> If you want to provide this feature, then it should be documented and
>>> made clear that this is an intended goal.
>>>
>>> Thinking about this more, the main thing I don't like about this
>>> approach is that the active code paths (enable & disable) have to check
>>> each time if any of these values have been overidden.
>>>
>>> Rather than have several places in the active code paths where this
>>> override value is checked, there the sysfs methods should simply update
>>> the values that are used by the core code.  This way, the core would
>>> not need to know about where the values came from (defalts, volt_data,
>>> user override, etc.)
>>>
>>> If you want to provide a way to revert this, then maybe writing -1 will
>>> should switch that value back to the HW default, or volt_data default.
> Kevin, Benoit, Nishant et al,
> 
> Without this override flag today there is no direct way of
> allowing user to write into these parameters. My question is,
Glancing at the debug entries being overidden, as developer (debug 
users) working for tweaking parameters for their platform - yes - we 
will need some mechanism to runtime tweak and see the behavior without 
needing to rebuild the kernel everytime.

On production system (OS users): they should'nt be using this.


> is there a need for the parameters to be over-written
> from the user-space? If yes, I need ideas on how to
> implement it with using override_volt_params !

Lets get the basics in kernel.org in some form! IMHO, all this double 
knobs are un-necessary overheads in codeflow for development only code- 
just provide the debugfs entries that reflect the data in their original 
structures, use the original structures everytime we go to a new 
transition (aka if you change the params in debugfs, they dont take 
effect till you do another transition).. but that is just my 2cents.

---
Regards,
Nishanth Menon

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

* RE: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-08 16:34           ` Nishanth Menon
@ 2010-12-09  9:43             ` Gopinath, Thara
  2010-12-09 11:23               ` Nishanth Menon
  2010-12-09 17:19               ` Kevin Hilman
  0 siblings, 2 replies; 31+ messages in thread
From: Gopinath, Thara @ 2010-12-09  9:43 UTC (permalink / raw)
  To: Menon, Nishanth
  Cc: Kevin Hilman, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Nishanth Menon [mailto:nm@ti.com]
>>Sent: Wednesday, December 08, 2010 10:05 PM
>>To: Gopinath, Thara
>>Cc: Kevin Hilman; linux-omap@vger.kernel.org; paul@pwsan.com; Cousson,
>>Benoit; Sripathy, Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>Smartreflex drivers
>>
>>Gopinath, Thara had written, on 12/08/2010 10:18 AM, the following:
>>[..]
>>>>> And, AFAICT, it wasn't clear from the current code or docs whether this
>>>>> could work or was expected to work either, e.g., if you set
>>>>> override_volt_params back to zero, to the original values all get reused?
>>>>>
>>>>> If you want to provide this feature, then it should be documented and
>>>>> made clear that this is an intended goal.
>>>>>
>>>>> Thinking about this more, the main thing I don't like about this
>>>>> approach is that the active code paths (enable & disable) have to check
>>>>> each time if any of these values have been overidden.
>>>>>
>>>>> Rather than have several places in the active code paths where this
>>>>> override value is checked, there the sysfs methods should simply update
>>>>> the values that are used by the core code.  This way, the core would
>>>>> not need to know about where the values came from (defalts, volt_data,
>>>>> user override, etc.)
>>>>>
>>>>> If you want to provide a way to revert this, then maybe writing -1 will
>>>>> should switch that value back to the HW default, or volt_data default.
>>> Kevin, Benoit, Nishant et al,
>>>
>>> Without this override flag today there is no direct way of
>>> allowing user to write into these parameters. My question is,
>>Glancing at the debug entries being overidden, as developer (debug
>>users) working for tweaking parameters for their platform - yes - we
>>will need some mechanism to runtime tweak and see the behavior without
>>needing to rebuild the kernel everytime.
>>
>>On production system (OS users): they should'nt be using this.
>>
>>
>>> is there a need for the parameters to be over-written
>>> from the user-space? If yes, I need ideas on how to
>>> implement it with using override_volt_params !
>>
>>Lets get the basics in kernel.org in some form! IMHO, all this double
>>knobs are un-necessary overheads in codeflow for development only code-
>>just provide the debugfs entries that reflect the data in their original
>>structures, use the original structures everytime we go to a new
>>transition (aka if you change the params in debugfs, they dont take
>>effect till you do another transition).. but that is just my 2cents.

Nishant, 
The issue here is most of these parameters are one time setting (during init) and need not be changed at all if the user does not wish to over-ride them for debug purpose. Hence the need for the checks (not double-hooks). But I agree with your point that let us get the basic in the kernel.org in some form. So for this first version that we plan to push to kernel.org, I plan to expose out these parameters to user space but not allow a write access to them. The write access part can be added later whenever required. 

Regards
Thara
>>
>>---
>>Regards,
>>Nishanth Menon

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

* Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-09  9:43             ` Gopinath, Thara
@ 2010-12-09 11:23               ` Nishanth Menon
  2010-12-09 14:13                 ` Gopinath, Thara
  2010-12-09 17:19               ` Kevin Hilman
  1 sibling, 1 reply; 31+ messages in thread
From: Nishanth Menon @ 2010-12-09 11:23 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: Kevin Hilman, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand

Gopinath, Thara wrote, on 12/09/2010 03:43 AM:
>
>
>>> -----Original Message-----
>>> From: Nishanth Menon [mailto:nm@ti.com]
>>> Sent: Wednesday, December 08, 2010 10:05 PM
>>> To: Gopinath, Thara
>>> Cc: Kevin Hilman; linux-omap@vger.kernel.org; paul@pwsan.com; Cousson,
>>> Benoit; Sripathy, Vishwanath; Sawant, Anand
>>> Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>> Smartreflex drivers
>>>
>>> Gopinath, Thara had written, on 12/08/2010 10:18 AM, the following:
>>> [..]
>>>>>> And, AFAICT, it wasn't clear from the current code or docs whether this
>>>>>> could work or was expected to work either, e.g., if you set
>>>>>> override_volt_params back to zero, to the original values all get reused?
>>>>>>
>>>>>> If you want to provide this feature, then it should be documented and
>>>>>> made clear that this is an intended goal.
>>>>>>
>>>>>> Thinking about this more, the main thing I don't like about this
>>>>>> approach is that the active code paths (enable&  disable) have to check
>>>>>> each time if any of these values have been overidden.
>>>>>>
>>>>>> Rather than have several places in the active code paths where this
>>>>>> override value is checked, there the sysfs methods should simply update
>>>>>> the values that are used by the core code.  This way, the core would
>>>>>> not need to know about where the values came from (defalts, volt_data,
>>>>>> user override, etc.)
>>>>>>
>>>>>> If you want to provide a way to revert this, then maybe writing -1 will
>>>>>> should switch that value back to the HW default, or volt_data default.
>>>> Kevin, Benoit, Nishant et al,
>>>>
>>>> Without this override flag today there is no direct way of
>>>> allowing user to write into these parameters. My question is,
>>> Glancing at the debug entries being overidden, as developer (debug
>>> users) working for tweaking parameters for their platform - yes - we
>>> will need some mechanism to runtime tweak and see the behavior without
>>> needing to rebuild the kernel everytime.
>>>
>>> On production system (OS users): they should'nt be using this.
>>>
>>>
>>>> is there a need for the parameters to be over-written
>>>> from the user-space? If yes, I need ideas on how to
>>>> implement it with using override_volt_params !
>>>
>>> Lets get the basics in kernel.org in some form! IMHO, all this double
>>> knobs are un-necessary overheads in codeflow for development only code-
>>> just provide the debugfs entries that reflect the data in their original
>>> structures, use the original structures everytime we go to a new
>>> transition (aka if you change the params in debugfs, they dont take
>>> effect till you do another transition).. but that is just my 2cents.
>
> Nishant,
> The issue here is most of these parameters are one time setting (during init)
 > and need not be changed at all if the user does not wish to over-ride 
them for
 > debug purpose. Hence the need for the checks (not double-hooks). But 
I agree
If they are init time thingy, then why not set it up so that when some 
one echo's to the debugfs, it writes to the register as well? That way 
you dont need to add runtime check and the debug developer does'nt need 
to worry about echo 1> magic_control_sys_fs_file (just kidding).

 > with your point that let us get the basic in the kernel.org in some 
form. So
 >for this first version that we plan to push to kernel.org, I plan to 
expose out
 > these parameters to user space but not allow a write access to them. 
The write
 >access part can be added later whenever required.
Sure.. at this point, anything that actually works is welcome :)

-- 
Regards,
Nishanth Menon

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

* RE: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-09 11:23               ` Nishanth Menon
@ 2010-12-09 14:13                 ` Gopinath, Thara
  0 siblings, 0 replies; 31+ messages in thread
From: Gopinath, Thara @ 2010-12-09 14:13 UTC (permalink / raw)
  To: Menon, Nishanth
  Cc: Kevin Hilman, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, December 09, 2010 4:54 PM
>>To: Gopinath, Thara
>>Cc: Kevin Hilman; linux-omap@vger.kernel.org; paul@pwsan.com; Cousson,
>>Benoit; Sripathy, Vishwanath; Sawant, Anand
>>Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and
>>Smartreflex drivers
>>
>>Gopinath, Thara wrote, on 12/09/2010 03:43 AM:
>>>
>>>
>>>>> -----Original Message-----
>>>>> From: Nishanth Menon [mailto:nm@ti.com]
>>>>> Sent: Wednesday, December 08, 2010 10:05 PM
>>>>> To: Gopinath, Thara
>>>>> Cc: Kevin Hilman; linux-omap@vger.kernel.org; paul@pwsan.com; Cousson,
>>>>> Benoit; Sripathy, Vishwanath; Sawant, Anand
>>>>> Subject: Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage
>>and
>>>>> Smartreflex drivers
>>>>>
>>>>> Gopinath, Thara had written, on 12/08/2010 10:18 AM, the following:
>>>>> [..]
>>>>>>>> And, AFAICT, it wasn't clear from the current code or docs whether
>>this
>>>>>>>> could work or was expected to work either, e.g., if you set
>>>>>>>> override_volt_params back to zero, to the original values all get
>>reused?
>>>>>>>>
>>>>>>>> If you want to provide this feature, then it should be documented and
>>>>>>>> made clear that this is an intended goal.
>>>>>>>>
>>>>>>>> Thinking about this more, the main thing I don't like about this
>>>>>>>> approach is that the active code paths (enable&  disable) have to
>>check
>>>>>>>> each time if any of these values have been overidden.
>>>>>>>>
>>>>>>>> Rather than have several places in the active code paths where this
>>>>>>>> override value is checked, there the sysfs methods should simply
>>update
>>>>>>>> the values that are used by the core code.  This way, the core would
>>>>>>>> not need to know about where the values came from (defalts, volt_data,
>>>>>>>> user override, etc.)
>>>>>>>>
>>>>>>>> If you want to provide a way to revert this, then maybe writing -1
>>will
>>>>>>>> should switch that value back to the HW default, or volt_data default.
>>>>>> Kevin, Benoit, Nishant et al,
>>>>>>
>>>>>> Without this override flag today there is no direct way of
>>>>>> allowing user to write into these parameters. My question is,
>>>>> Glancing at the debug entries being overidden, as developer (debug
>>>>> users) working for tweaking parameters for their platform - yes - we
>>>>> will need some mechanism to runtime tweak and see the behavior without
>>>>> needing to rebuild the kernel everytime.
>>>>>
>>>>> On production system (OS users): they should'nt be using this.
>>>>>
>>>>>
>>>>>> is there a need for the parameters to be over-written
>>>>>> from the user-space? If yes, I need ideas on how to
>>>>>> implement it with using override_volt_params !
>>>>>
>>>>> Lets get the basics in kernel.org in some form! IMHO, all this double
>>>>> knobs are un-necessary overheads in codeflow for development only code-
>>>>> just provide the debugfs entries that reflect the data in their original
>>>>> structures, use the original structures everytime we go to a new
>>>>> transition (aka if you change the params in debugfs, they dont take
>>>>> effect till you do another transition).. but that is just my 2cents.
>>>
>>> Nishant,
>>> The issue here is most of these parameters are one time setting (during
>>init)
>> > and need not be changed at all if the user does not wish to over-ride
>>them for
>> > debug purpose. Hence the need for the checks (not double-hooks). But
>>I agree
>>If they are init time thingy, then why not set it up so that when some
>>one echo's to the debugfs, it writes to the register as well? That way
>>you dont need to add runtime check and the debug developer does'nt need
>>to worry about echo 1> magic_control_sys_fs_file (just kidding).

Yes but then for it the debugfs set get APIs should have access to the data structures which stores the register offset etc. Today I am using a single API to set any parameter any vdd. This will have to change. Maybe one API per parameter. I cannot currently think of any better solution :-)! 
>>
>> > with your point that let us get the basic in the kernel.org in some
>>form. So
>> >for this first version that we plan to push to kernel.org, I plan to
>>expose out
>> > these parameters to user space but not allow a write access to them.
>>The write
>> >access part can be added later whenever required.
>>Sure.. at this point, anything that actually works is welcome :)
Ok :-) !

Regards
Thara

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

* Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-09  9:43             ` Gopinath, Thara
  2010-12-09 11:23               ` Nishanth Menon
@ 2010-12-09 17:19               ` Kevin Hilman
  2010-12-09 17:22                 ` Nishanth Menon
  1 sibling, 1 reply; 31+ messages in thread
From: Kevin Hilman @ 2010-12-09 17:19 UTC (permalink / raw)
  To: Gopinath, Thara
  Cc: Menon, Nishanth, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand

"Gopinath, Thara" <thara@ti.com> writes:

[...]

> So for this first version that we plan to push to kernel.org, I plan
> to expose out these parameters to user space but not allow a write
> access to them. The write access part can be added later whenever
> required.

OK with me.

Kevin

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

* Re: [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers
  2010-12-09 17:19               ` Kevin Hilman
@ 2010-12-09 17:22                 ` Nishanth Menon
  0 siblings, 0 replies; 31+ messages in thread
From: Nishanth Menon @ 2010-12-09 17:22 UTC (permalink / raw)
  To: Kevin Hilman
  Cc: Gopinath, Thara, linux-omap@vger.kernel.org, paul@pwsan.com,
	Cousson, Benoit, Sripathy, Vishwanath, Sawant, Anand

Kevin Hilman had written, on 12/09/2010 11:19 AM, the following:
> "Gopinath, Thara" <thara@ti.com> writes:
> 
> [...]
> 
>> So for this first version that we plan to push to kernel.org, I plan
>> to expose out these parameters to user space but not allow a write
>> access to them. The write access part can be added later whenever
>> required.
> 
> OK with me.
+1
Regards,
Nishanth Menon

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

end of thread, other threads:[~2010-12-09 17:22 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-27 16:10 [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Thara Gopinath
2010-10-27 16:10 ` [PATCH v4 1/9] OMAP3: PM: Adding voltage driver support for OMAP3 Thara Gopinath
2010-11-10 18:59   ` Kevin Hilman
2010-11-15 10:47     ` Gopinath, Thara
     [not found]   ` <FCCFB4CDC6E5564B9182F639FC356087034C012076@dbde02.ent.ti.com>
2010-11-15 14:55     ` Gopinath, Thara
     [not found]   ` <87hbfp9gli.fsf@deeprootsystems.com>
     [not found]     ` <5A47E75E594F054BAF48C5E4FC4B92AB035EFF4E51@dbde02.ent.ti.com>
2010-11-15 19:43       ` Kevin Hilman
2010-12-02  6:13     ` Gopinath, Thara
2010-10-27 16:10 ` [PATCH v4 2/9] OMAP3: PM: Adding smartreflex driver support Thara Gopinath
2010-10-27 16:10 ` [PATCH v4 3/9] OMAP3: PM: Adding smartreflex device file Thara Gopinath
2010-10-28  5:38   ` Varadarajan, Charulatha
2010-10-28 15:26     ` Gopinath, Thara
2010-10-29  4:48       ` Varadarajan, Charulatha
2010-10-27 16:10 ` [PATCH v4 4/9] OMAP3: PM: Adding smartreflex hwmod data Thara Gopinath
2010-10-27 16:10 ` [PATCH v4 5/9] OMAP3: PM: Adding smartreflex class3 driver Thara Gopinath
2010-10-27 16:10 ` [PATCH v4 6/9] OMAP3: PM: Adding T2 enabling of smartreflex support Thara Gopinath
2010-10-27 16:10 ` [PATCH v4 7/9] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers Thara Gopinath
2010-11-10 19:12   ` Kevin Hilman
2010-11-15 11:00     ` Gopinath, Thara
2010-11-15 22:12       ` Kevin Hilman
2010-12-08 16:18         ` Gopinath, Thara
2010-12-08 16:34           ` Nishanth Menon
2010-12-09  9:43             ` Gopinath, Thara
2010-12-09 11:23               ` Nishanth Menon
2010-12-09 14:13                 ` Gopinath, Thara
2010-12-09 17:19               ` Kevin Hilman
2010-12-09 17:22                 ` Nishanth Menon
2010-10-27 16:10 ` [PATCH v4 8/9] OMAP3: PM: Program correct init voltages for VDD1 and VDD2 Thara Gopinath
2010-10-27 16:10 ` [PATCH v4 9/9] OMAP3: PM: Register TWL4030 pmic info with the voltage driver Thara Gopinath
2010-10-27 17:21 ` [PATCH v4 0/9] OMAP3: Adding Smartreflex and Voltage driver support Nishanth Menon
2010-10-28 15:32   ` Gopinath, Thara
2010-11-10 19:03     ` Kevin Hilman

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).