Skip to contentSkip to conversation

OMAP3: Adding Smartreflex and Voltage driver support

PATCH Superseded Thara Gopinath 2 participants 29 messages Aug 13, 2010 – Sep 15, 2010

Subsystems (6)

v2 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v2 cover OMAP3: Adding Smartreflex and Voltage driver support

From: thara gopinath <[email protected]>

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 origin/opp branch off Kevin's pm tree which in turn is based off lo-master. This series will apply against lo-master also but will break compilation due to lack of opp framework support on lo-master.

This patch series has been tested on OMAP3430 SDP with the extra five patches from origin/cpufreq branch off Kevin's pm tree applied. This series has been tested with with omap3_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 (8):
OMAP: PM: Allowing an early init of pm debugfs driver.
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

 arch/arm/mach-omap2/Makefile                  |    5 +-
 arch/arm/mach-omap2/board-3430sdp.c           |    2 +
 arch/arm/mach-omap2/board-3630sdp.c           |    2 +
 arch/arm/mach-omap2/board-zoom3.c             |    2 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c    |  249 +++++
 arch/arm/mach-omap2/pm-debug.c                |   18 +-
 arch/arm/mach-omap2/smartreflex-class3.c      |   61 ++
 arch/arm/mach-omap2/smartreflex-class3.h      |   23 +
 arch/arm/mach-omap2/smartreflex.c             | 1009 +++++++++++++++++++
 arch/arm/mach-omap2/sr_device.c               |  185 ++++
 arch/arm/mach-omap2/voltage.c                 | 1275 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   41 +
 arch/arm/plat-omap/include/plat/control.h     |   27 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  285 ++++++
 arch/arm/plat-omap/include/plat/voltage.h     |  137 +++
 drivers/mfd/twl-core.c                        |    7 +-
 drivers/mfd/twl4030-power.c                   |   29 +
 include/linux/i2c/twl.h                       |    1 +
 18 files changed, 3353 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex-class3.c
 create mode 100644 arch/arm/mach-omap2/smartreflex-class3.h
 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
Signature · 1 line
1.7.1.GIT
#1 lore raw

PATCH v2 1/8 OMAP: PM: Allowing an early init of pm debugfs driver.

This patch changes the pm_db_init from arch initcall to a postcore initcall. With arch initcall, it is impossible for pm driver that gets initialized prior to this driver to use one of the pm debug fs entries during its init. Making it a postcore initcall ensures that this drver gets initialized early on before any pm drivers. Also now the generir pm_debug directory is made global so that other drivers can include it and use it.

---
 arch/arm/mach-omap2/pm-debug.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/pm-debug.c +3 -2
index 723b44e..fed8da1 100644
@@ -162,7 +162,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us)
 
 static void pm_dbg_regset_store(u32 *ptr);
 
-struct dentry *pm_dbg_dir;
+struct dentry *pm_dbg_dir, *pm_dbg_main_dir;
 
 static int pm_dbg_init_done;
 
@@ -609,10 +609,11 @@ static int __init pm_dbg_init(void)
 				   &sleep_while_idle, &pm_dbg_option_fops);
 	(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
 				   &wakeup_timer_seconds, &pm_dbg_option_fops);
+	pm_dbg_main_dir = d;
 	pm_dbg_init_done = 1;
 
 	return 0;
 }
-arch_initcall(pm_dbg_init);
+postcore_initcall(pm_dbg_init);
 
 #endif
Signature · 1 line
1.7.1.GIT
#2 lore raw

Re: [PATCHv2 1/8] OMAP: PM: Allowing an early init of pm debugfs driver.

Quoted 6 lines · Thara Gopinath

This patch changes the pm_db_init from arch initcall to a postcore initcall. With arch initcall, it is impossible for pm driver that gets initialized prior to this driver to use one of the pm debug fs entries during its init. Making it a postcore initcall ensures that this drver gets initialized early on before any pm drivers.

Instead of tinkering with initcall ordering, how about calling the pm debug init from pm.c

Quoted 2 lines

Also now the generir pm_debug directory is made global so that other drivers can include it and use it.

include it from where?

Kevin

Quoted 31 lines
---
 arch/arm/mach-omap2/pm-debug.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/pm-debug.c +3 -2
index 723b44e..fed8da1 100644
@@ -162,7 +162,7 @@ void omap2_pm_dump(int mode, int resume, unsigned int us)
 
 static void pm_dbg_regset_store(u32 *ptr);
 
-struct dentry *pm_dbg_dir;
+struct dentry *pm_dbg_dir, *pm_dbg_main_dir;
 
 static int pm_dbg_init_done;
 
@@ -609,10 +609,11 @@ static int __init pm_dbg_init(void)
 				   &sleep_while_idle, &pm_dbg_option_fops);
 	(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
 				   &wakeup_timer_seconds, &pm_dbg_option_fops);
+	pm_dbg_main_dir = d;
 	pm_dbg_init_done = 1;
 
 	return 0;
 }
-arch_initcall(pm_dbg_init);
+postcore_initcall(pm_dbg_init);
 
 #endif
#3 lore raw

Re: [PATCHv2 1/8] OMAP: PM: Allowing an early init of pm debugfs driver.

Quoted 11 lines · Kevin Hilman
Quoted 6 lines · Thara Gopinath

This patch changes the pm_db_init from arch initcall to a postcore initcall. With arch initcall, it is impossible for pm driver that gets initialized prior to this driver to use one of the pm debug fs entries during its init. Making it a postcore initcall ensures that this drver gets initialized early on before any pm drivers.

Instead of tinkering with initcall ordering, how about calling the pm debug init from pm.c

ignore this comment, pm.c is a device_initcall, so wont solve your problem.

But I'd still like to know what PM drivers are being initialized so early they need this to be a postcore_initcall.

Kevin

#4 lore raw

RE: [PATCHv2 1/8] OMAP: PM: Allowing an early init of pm debugfs driver.

Quoted 20 lines
Quoted 20 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Wednesday, August 25, 2010 3:52 AM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 1/8] OMAP: PM: Allowing an early init of pm debugfs driver.

Quoted 9 lines · Kevin Hilman
Quoted 6 lines · Thara Gopinath

This patch changes the pm_db_init from arch initcall to a postcore initcall. With arch initcall, it is impossible for pm driver that gets initialized prior to this driver to use one of the pm debug fs entries during its init. Making it a postcore initcall ensures that this drver gets initialized early on before any pm drivers.

Quoted 8 lines
Quoted 8 lines
Quoted 2 lines

Instead of tinkering with initcall ordering, how about calling the pm debug init from pm.c

ignore this comment, pm.c is a device_initcall, so wont solve your problem.

But I'd still like to know what PM drivers are being initialized so early they need this to be a postcore_initcall.

It is needed from voltage and smartreflex layers for adding the debugfs entries. But considering these inits have been moved to device_initcall or late_initcall may be This change is no longer relevant. Thanks for catching this.

Regards
Thara

Quoted 3 lines
Quoted 3 lines

Kevin

#5 lore raw

PATCH v2 2/8 OMAP3: PM: Adding voltage driver support for OMAP3

In reply to 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.

---
 arch/arm/mach-omap2/Makefile              |    3 +-
 arch/arm/mach-omap2/voltage.c             | 1119 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/voltage.h |  132 ++++
 3 files changed, 1253 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/voltage.c
 create mode 100644 arch/arm/plat-omap/include/plat/voltage.h
arch/arm/mach-omap2/Makefile +2 -1
index 63b2d88..1c095cf 100644
@@ -49,7 +49,8 @@ obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
+					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 
arch/arm/mach-omap2/voltage.c new file +1119 -0

1,119 lines not on this page · raw message

arch/arm/plat-omap/include/plat/voltage.h new file +132 -0

132 lines not on this page · raw message

Signature · 1 line
1.7.1.GIT
#6 lore raw

Re: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3

Quoted 12 lines · 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.

Quoted 6 lines

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.

This is looking pretty good. Mostly minor style issues left to correct.

Quoted 169 lines
---
 arch/arm/mach-omap2/Makefile              |    3 +-
 arch/arm/mach-omap2/voltage.c             | 1119 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/voltage.h |  132 ++++
 3 files changed, 1253 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/voltage.c
 create mode 100644 arch/arm/plat-omap/include/plat/voltage.h
arch/arm/mach-omap2/Makefile +2 -1
index 63b2d88..1c095cf 100644
@@ -49,7 +49,8 @@ obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
+					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 
arch/arm/mach-omap2/voltage.c new file +141 -0
new file mode 100644
index 0000000..cb0fcac
@@ -0,0 +1,1119 @@
+/*
+ * OMAP3/OMAP4 Voltage Management Routines
+ *
+ * Author: Thara Gopinath	<[email protected]>
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Rajendra Nayak <[email protected]>
+ * Lesly A M <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * 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/pm.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <plat/omap-pm.h>
+#include <plat/omap34xx.h>
+#include <plat/opp.h>
+#include <plat/opp_twl_tps.h>
+#include <plat/clock.h>
+#include <plat/common.h>
+#include <plat/voltage.h>
+
+#include "prm-regbits-34xx.h"
+
+#define VP_IDLE_TIMEOUT		200
+#define VP_TRANXDONE_TIMEOUT	300
+
+/* 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
+ * @volt_clk		: the clock associated with the vdd.
+ * @opp_dev		: the 'struct device' associated with this vdd.
+ * @volt_data_count	: Number of distinct voltages supported by this vdd.
+ * @nominal_volt	: Nominal voltaged 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 clk *volt_clk;
+	struct device *opp_dev;
+	struct voltagedomain voltdm;
+	int volt_data_count;
+	unsigned long nominal_volt;
+	u8 cmdval_reg;
+	u8 vdd_sr_reg;
+};
+static struct omap_vdd_info *vdd_info;
+/*
+ * Number of scalable voltage domains.
+ */
+static int no_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,

arch/arm/mach-omap2/voltage.c line 151

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+			.vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
+			.voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
+		},
+		.voltdm = {
+			.name = "core",
+		},
+	},
+};
+
+#define OMAP3_NO_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)

Use of 'NO' here has already been commented on in earlier versions. Please use the _NUM or _NR suffix which is common.

Same issue with the name of the variable that this is assigned to.

Quoted 127 lines
arch/arm/mach-omap2/voltage.c new file +127 -0
+/* 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;
+	}
+	vsel = omap_twl_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) |

arch/arm/mach-omap2/voltage.c line 289

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+			(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);

insert blank line when starting a new logical section, especially when its separated by a comment. There a lots of these to fixup.

Quoted 217 lines
arch/arm/mach-omap2/voltage.c new file +217 -0
+	/* 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)
+{
+	unsigned long curr_volt;
+	struct omap_volt_data *volt_data;
+	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->volt_clk = clk_get(NULL, "dpll1_ck");
+		vdd->opp_dev = omap2_get_mpuss_device();
+		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->volt_clk = clk_get(NULL, "l3_ick");
+		vdd->opp_dev = omap2_get_l3_device();
+		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;
+	}
+
+	if (IS_ERR(vdd->volt_clk)) {
+		pr_warning("%s: unable to get clk for vdd_%s\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+	if (!vdd->opp_dev) {
+		pr_warning("%s: unable to get the opp device for vdd_%s\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+
+	curr_volt = omap_voltage_get_nom_volt(&vdd->voltdm);
+	if (!curr_volt) {
+		pr_warning("%s: unable to find current voltage for vdd_%s\n",
+			__func__, vdd->voltdm.name);
+		return;
+	}
+
+	volt_data = omap_voltage_get_voltdata(&vdd->voltdm, curr_volt);
+	if (IS_ERR(volt_data)) {
+		pr_warning("%s: Unable to get volt table for vdd_%s at init",
+			__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 = 1200000;
+
+	/* VPCONFIG bit fields */
+	vdd->vp_reg.vpconfig_erroroffset = (OMAP3_VP_CONFIG_ERROROFFSET <<
+				 OMAP3430_ERROROFFSET_SHIFT);
+	vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
+	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));
+
+	/* Set the init voltage */
+	vp_latch_vsel(vdd);
+
+	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+	/* Force update of voltage */
+	voltage_write_reg(vdd->vp_offs.vpconfig,
+			(vpconfig | vdd->vp_reg.vpconfig_forceupdate));
+	/* Clear force bit */
+	voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+}
+
+static void __init vdd_data_configure(struct omap_vdd_info *vdd)
+{
+	if (cpu_is_omap34xx())
+		omap3_vdd_data_configure(vdd);
+}
+static void __init init_voltagecontroller(void)
+{
+	if (cpu_is_omap34xx())
+		omap3_init_voltagecontroller();
+}
+
+/*
+ * 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;
+

arch/arm/mach-omap2/voltage.c line 516

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+	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 ?

Quoted 36 lines
arch/arm/mach-omap2/voltage.c new file +36 -0
+	/* 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;
+	}
+
+	target_vsel = omap_twl_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);
+	}
+

arch/arm/mach-omap2/voltage.c line 563

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+	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);
+
+	while ((vc_bypass_value & vc_valid) != 0x0) {

the '!= 0x0' is redundant

arch/arm/mach-omap2/voltage.c line 567

Quoted 4 lines
arch/arm/mach-omap2/voltage.c new file +4 -0
+		loop_cnt++;
+		if (retries_cnt > 10) {
+			pr_warning("%s: Loop count exceeded in check SR I2C"
+				"write during voltgae scaling\n", __func__);

string is confusing

arch/arm/mach-omap2/voltage.c line 576

Quoted 9 lines
arch/arm/mach-omap2/voltage.c new file +9 -0
+			return -ETIMEDOUT;
+		}
+		if (loop_cnt > 50) {
+			retries_cnt++;
+			loop_cnt = 0;
+			udelay(10);
+		}
+		vc_bypass_value = voltage_read_reg(vc_bypass_val_reg_offs);
+	}

Where do the loop and retry count numbers come from? This section
could use some comments describing the retry logic.

Quoted 15 lines
arch/arm/mach-omap2/voltage.c new file +15 -0
+	/* 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);
+	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;

arch/arm/mach-omap2/voltage.c line 602

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -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?

Quoted 32 lines
arch/arm/mach-omap2/voltage.c new file +32 -0
+	/* 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;
+	}
+
+	target_vsel = omap_twl_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

arch/arm/mach-omap2/voltage.c line 645

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+	 * 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);
+	}

I'm a little worried about this racing with the PRCM interrupt handler in pm34xx.c. I need to be convinced that this would not interfere with that handler. Even better would be to handle this in an interrupt
handler and get rid of the polling. Is there a reason this is done
with polling instead of handled in interrupt?

Quoted 449 lines
arch/arm/mach-omap2/voltage.c new file +449 -0
+	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);
+
+	timeout = 0;
+	/*
+	 * Wait for TransactionDone. Typical latency is <200us.
+	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
+	 */
+	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);
+
+	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_opp *opp;
+	struct omap_vdd_info *vdd;
+	unsigned long freq;
+
+	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);
+
+	freq = vdd->volt_clk->rate;
+	opp = opp_find_freq_ceil(vdd->opp_dev, &freq);
+	if (IS_ERR(opp)) {
+		pr_warning("%s: Unable to find OPP for vdd_%s freq%ld\n",
+			__func__, voltdm->name, freq);
+		return 0;
+	}
+
+	/*
+	 * Use higher freq voltage even if an exact match is not available
+	 * we are probably masking a clock framework bug, so warn
+	 */
+	if (unlikely(freq != vdd->volt_clk->rate))
+		pr_warning("%s: Available freq %ld != dpll freq %ld.\n",
+			__func__, freq, vdd->volt_clk->rate);
+
+	return opp_get_voltage(opp);
+}
+
+/**
+ * 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);
+	return omap_twl_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);
+
+	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+	/* Enable VP */
+	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_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;
+}
+
+/**
+ * omap_voltage_domain_get	: 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_get(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 < no_scalable_vdd; i++) {
+		if (!(strcmp(name, vdd_info[i].voltdm.name)))
+			return &vdd_info[i].voltdm;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+/**

arch/arm/mach-omap2/voltage.c line 1105

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+ * omap_voltage_init : Volatage init API which does VP and VC init.
+ */
+static int __init omap_voltage_init(void)
+{
+	int i;
+
+	if (!cpu_is_omap34xx()) {
+		pr_warning("%s: voltage driver support not added\n", __func__);
+		return 0;
+	}

This is redundant, and doesn't need a warning.

arch/arm/mach-omap2/voltage.c line 1111

Quoted 5 lines
arch/arm/mach-omap2/voltage.c new file +5 -0
+	if (cpu_is_omap34xx()) {
+		volt_mod = OMAP3430_GR_MOD;
+		vdd_info = omap3_vdd_info;
+		no_scalable_vdd = OMAP3_NO_SCALABLE_VDD;
+	}

rather, just 'else return 0' here, and it makes it cleaner for adding OMAP4 support.

Quoted 102 lines
arch/arm/mach-omap2/voltage.c new file +8 -0
+	init_voltagecontroller();
+	for (i = 0; i < no_scalable_vdd; i++) {
+		vdd_data_configure(&vdd_info[i]);
+		init_voltageprocessor(&vdd_info[i]);
+	}
+	return 0;
+}
+device_initcall(omap_voltage_init);
arch/arm/plat-omap/include/plat/voltage.h new file +88 -0
new file mode 100644
index 0000000..fc9778b
@@ -0,0 +1,132 @@
+/*
+ * OMAP Voltage Management Routines
+ *
+ * Author: Thara Gopinath	<[email protected]>
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * 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*/
+/**
+ * voltagedomain - omap voltage domain global structure
+ * @name       : Name of the voltage domain which can be used as a unique
+ *               identifier.
+ */
+struct voltagedomain {
+       char *name;
+};
+
+/**
+ * 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;
+};
+
+/**
+ * omap_volt_pmic_info - PMIC specific data required by the voltage driver.
+ * @slew_rate	: PMIC slew rate (in uv/us)
+ * @step_size	: PMIC voltage step size (in uv)
+ */
+struct omap_volt_pmic_info {
+      int slew_rate;
+      int step_size;

arch/arm/plat-omap/include/plat/voltage.h line 98

Quoted 10 lines
arch/arm/plat-omap/include/plat/voltage.h new file +10 -0
+};
+
+/* 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 */

indent

arch/arm/plat-omap/include/plat/voltage.h line 104

Quoted 5 lines
arch/arm/plat-omap/include/plat/voltage.h new file +5 -0
+	u16 vdd0_on;
+	u16 vdd0_onlp;
+	u16 vdd0_ret;
+	u16 vdd0_off;
+/* PRM_VC_CMD_VAL_1 specific bits */

indent

Quoted 18 lines
arch/arm/plat-omap/include/plat/voltage.h new file +18 -0
+	u16 vdd1_on;
+	u16 vdd1_onlp;
+	u16 vdd1_ret;
+	u16 vdd1_off;
+};
+
+struct voltagedomain *omap_voltage_domain_get(char *name);
+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);
+void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info);

arch/arm/plat-omap/include/plat/voltage.h line 132

Quoted 10 lines
arch/arm/plat-omap/include/plat/voltage.h new file +10 -0
+unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
+#ifdef CONFIG_PM
+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_init_vc(struct omap_volt_vc_data *setup_vc) {}
+static inline  void omap_change_voltscale_method(int voltscale_method) {}
+#endif
+
+#endif

Kevin

#7 lore raw

RE: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3

Quoted 24 lines
Quoted 24 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Wednesday, August 25, 2010 5:32 AM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3

Quoted 12 lines · 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.

Quoted 8 lines
Quoted 8 lines
Quoted 6 lines

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.

This is looking pretty good. Mostly minor style issues left to correct.

Thanks for the review.

Quoted 184 lines
Quoted 184 lines
Quoted 170 lines
---
 arch/arm/mach-omap2/Makefile              |    3 +-
 arch/arm/mach-omap2/voltage.c             | 1119 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/voltage.h |  132 ++++
 3 files changed, 1253 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/voltage.c
 create mode 100644 arch/arm/plat-omap/include/plat/voltage.h
arch/arm/mach-omap2/Makefile +2 -1
index 63b2d88..1c095cf 100644
@@ -49,7 +49,8 @@ obj-$(CONFIG_ARCH_OMAP2)          += sdrc2xxx.o
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)           += pm24xx.o
 obj-$(CONFIG_ARCH_OMAP2)           += sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3)           += pm34xx.o sleep34xx.o cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP3)           += pm34xx.o sleep34xx.o voltage.o \
+                                      cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)           += pm44xx.o
 obj-$(CONFIG_PM_DEBUG)                     += pm-debug.o
 
arch/arm/mach-omap2/voltage.c new file +141 -0
new file mode 100644
index 0000000..cb0fcac
@@ -0,0 +1,1119 @@
+/*
+ * OMAP3/OMAP4 Voltage Management Routines
+ *
+ * Author: Thara Gopinath  <[email protected]>
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Rajendra Nayak <[email protected]>
+ * Lesly A M <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * 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/pm.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <plat/omap-pm.h>
+#include <plat/omap34xx.h>
+#include <plat/opp.h>
+#include <plat/opp_twl_tps.h>
+#include <plat/clock.h>
+#include <plat/common.h>
+#include <plat/voltage.h>
+
+#include "prm-regbits-34xx.h"
+
+#define VP_IDLE_TIMEOUT            200
+#define VP_TRANXDONE_TIMEOUT       300
+
+/* 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
+ * @volt_clk               : the clock associated with the vdd.
+ * @opp_dev                : the 'struct device' associated with this vdd.
+ * @volt_data_count        : Number of distinct voltages supported by this vdd.
+ * @nominal_volt   : Nominal voltaged 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 clk *volt_clk;
+   struct device *opp_dev;
+   struct voltagedomain voltdm;
+   int volt_data_count;
+   unsigned long nominal_volt;
+   u8 cmdval_reg;
+   u8 vdd_sr_reg;
+};
+static struct omap_vdd_info *vdd_info;
+/*
+ * Number of scalable voltage domains.
+ */
+static int no_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,

arch/arm/mach-omap2/voltage.c line 151

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+                   .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
+                   .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
+           },
+           .voltdm = {
+                   .name = "core",
+           },
+   },
+};
+
+#define OMAP3_NO_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)

Use of 'NO' here has already been commented on in earlier versions. Please use the _NUM or _NR suffix which is common.

Quoted 1 line
Quoted 1 line

Same issue with the name of the variable that this is assigned to.

Yep.. Will fix this one

Quoted 133 lines
Quoted 133 lines
Quoted 133 lines
arch/arm/mach-omap2/voltage.c new file +132 -0
+/* 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;
+   }
+   vsel = omap_twl_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) |
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/voltage.c line 289

Quoted 5 lines
arch/arm/mach-omap2/voltage.c new file +5 -0
+                   (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);

insert blank line when starting a new logical section, especially when its separated by a comment. There a lots of these to fixup.

Ok.. Will implement this

Quoted 222 lines
Quoted 222 lines
Quoted 222 lines
arch/arm/mach-omap2/voltage.c new file +221 -0
+   /* 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)
+{
+   unsigned long curr_volt;
+   struct omap_volt_data *volt_data;
+   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->volt_clk = clk_get(NULL, "dpll1_ck");
+           vdd->opp_dev = omap2_get_mpuss_device();
+           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->volt_clk = clk_get(NULL, "l3_ick");
+           vdd->opp_dev = omap2_get_l3_device();
+           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;
+   }
+
+   if (IS_ERR(vdd->volt_clk)) {
+           pr_warning("%s: unable to get clk for vdd_%s\n",
+                   __func__, vdd->voltdm.name);
+           return;
+   }
+   if (!vdd->opp_dev) {
+           pr_warning("%s: unable to get the opp device for vdd_%s\n",
+                   __func__, vdd->voltdm.name);
+           return;
+   }
+
+   curr_volt = omap_voltage_get_nom_volt(&vdd->voltdm);
+   if (!curr_volt) {
+           pr_warning("%s: unable to find current voltage for vdd_%s\n",
+                   __func__, vdd->voltdm.name);
+           return;
+   }
+
+   volt_data = omap_voltage_get_voltdata(&vdd->voltdm, curr_volt);
+   if (IS_ERR(volt_data)) {
+           pr_warning("%s: Unable to get volt table for vdd_%s at init",
+                   __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 = 1200000;
+
+   /* VPCONFIG bit fields */
+   vdd->vp_reg.vpconfig_erroroffset = (OMAP3_VP_CONFIG_ERROROFFSET <<
+                            OMAP3430_ERROROFFSET_SHIFT);
+   vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
+   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));
+
+   /* Set the init voltage */
+   vp_latch_vsel(vdd);
+
+   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+   /* Force update of voltage */
+   voltage_write_reg(vdd->vp_offs.vpconfig,
+                   (vpconfig | vdd->vp_reg.vpconfig_forceupdate));
+   /* Clear force bit */
+   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
+}
+
+static void __init vdd_data_configure(struct omap_vdd_info *vdd)
+{
+   if (cpu_is_omap34xx())
+           omap3_vdd_data_configure(vdd);
+}
+static void __init init_voltagecontroller(void)
+{
+   if (cpu_is_omap34xx())
+           omap3_init_voltagecontroller();
+}
+
+/*
+ * 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;
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/voltage.c line 516

Quoted 6 lines
arch/arm/mach-omap2/voltage.c new file +6 -0
+           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 ?

else this should return. I will update it

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
arch/arm/mach-omap2/voltage.c new file +40 -0
+   /* 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;
+   }
+
+   target_vsel = omap_twl_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);
+
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/voltage.c line 563

Quoted 6 lines
arch/arm/mach-omap2/voltage.c new file +6 -0
+   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);
+
+   while ((vc_bypass_value & vc_valid) != 0x0) {

the '!= 0x0' is redundant

Ok will take this in

Quoted 7 lines
Quoted 7 lines

arch/arm/mach-omap2/voltage.c line 567

Quoted 5 lines
arch/arm/mach-omap2/voltage.c new file +4 -0
+           loop_cnt++;
+           if (retries_cnt > 10) {
+                   pr_warning("%s: Loop count exceeded in check SR I2C"
+                           "write during voltgae scaling\n", __func__);

string is confusing

Will fix this.

Quoted 11 lines
Quoted 11 lines
Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +9 -0
+                   return -ETIMEDOUT;
+           }
+           if (loop_cnt > 50) {
+                   retries_cnt++;
+                   loop_cnt = 0;
+                   udelay(10);
+           }
+           vc_bypass_value = voltage_read_reg(vc_bypass_val_reg_offs);
+   }
Quoted 2 lines
Quoted 2 lines

Where do the loop and retry count numbers come from? This section
could use some comments describing the retry logic.

Hmmm... I can try putting in some comments. I had actually taken in This piece of code from the older version of smartreflex.c. I haven't changed anything in this function. Hence all the logic and errors in the old code exist. Btw vc_bypass is not the official voltage scaling method supported.

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
arch/arm/mach-omap2/voltage.c new file +19 -0
+   /* 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);
+   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;
+
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/voltage.c line 602

Quoted 6 lines
arch/arm/mach-omap2/voltage.c new file +6 -0
+   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?

else this should return. I will update it

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
arch/arm/mach-omap2/voltage.c new file +40 -0
+   /* 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;
+   }
+
+   target_vsel = omap_twl_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;
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/voltage.c line 641

Quoted 2 lines
arch/arm/mach-omap2/voltage.c new file +2 -0
+           udelay(1);
+   }

I'm a little worried about this racing with the PRCM interrupt handler in pm34xx.c. I need to be convinced that this would not interfere with that handler. Even better would be to handle this in an interrupt
handler and get rid of the polling. Is there a reason this is done
with polling instead of handled in interrupt?

Yes this will not race as the TRANXDONE is not enabled in the PRM_IRQENABLE register. Intention behind keeping this in polling mode is to avoid the delays/complications in getting an interrupt, calling a handler and updating the prcm interrupt handler to call a callback etc. This is rather short and sweet checking of the status.

Quoted 454 lines
Quoted 454 lines
Quoted 454 lines
arch/arm/mach-omap2/voltage.c new file +453 -0
+   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);
+
+   timeout = 0;
+   /*
+    * Wait for TransactionDone. Typical latency is <200us.
+    * Depends on SMPSWAITTIMEMIN/MAX and voltage change
+    */
+   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);
+
+   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_opp *opp;
+   struct omap_vdd_info *vdd;
+   unsigned long freq;
+
+   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);
+
+   freq = vdd->volt_clk->rate;
+   opp = opp_find_freq_ceil(vdd->opp_dev, &freq);
+   if (IS_ERR(opp)) {
+           pr_warning("%s: Unable to find OPP for vdd_%s freq%ld\n",
+                   __func__, voltdm->name, freq);
+           return 0;
+   }
+
+   /*
+    * Use higher freq voltage even if an exact match is not available
+    * we are probably masking a clock framework bug, so warn
+    */
+   if (unlikely(freq != vdd->volt_clk->rate))
+           pr_warning("%s: Available freq %ld != dpll freq %ld.\n",
+                   __func__, freq, vdd->volt_clk->rate);
+
+   return opp_get_voltage(opp);
+}
+
+/**
+ * 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);
+   return omap_twl_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);
+
+   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
+   /* Enable VP */
+   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_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;
+}
+
+/**
+ * omap_voltage_domain_get : 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_get(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 < no_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)
+{
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/voltage.c line 1105

Quoted 6 lines
arch/arm/mach-omap2/voltage.c new file +6 -0
+   int i;
+
+   if (!cpu_is_omap34xx()) {
+           pr_warning("%s: voltage driver support not added\n", __func__);
+           return 0;
+   }

This is redundant, and doesn't need a warning.

Ok

Quoted 9 lines
Quoted 9 lines

arch/arm/mach-omap2/voltage.c line 1111

Quoted 6 lines
arch/arm/mach-omap2/voltage.c new file +5 -0
+   if (cpu_is_omap34xx()) {
+           volt_mod = OMAP3430_GR_MOD;
+           vdd_info = omap3_vdd_info;
+           no_scalable_vdd = OMAP3_NO_SCALABLE_VDD;
+   }

rather, just 'else return 0' here, and it makes it cleaner for adding OMAP4 support.

Ok

Quoted 116 lines
Quoted 116 lines
Quoted 103 lines
arch/arm/mach-omap2/voltage.c new file +8 -0
+   init_voltagecontroller();
+   for (i = 0; i < no_scalable_vdd; i++) {
+           vdd_data_configure(&vdd_info[i]);
+           init_voltageprocessor(&vdd_info[i]);
+   }
+   return 0;
+}
+device_initcall(omap_voltage_init);
arch/arm/plat-omap/include/plat/voltage.h new file +88 -0
new file mode 100644
index 0000000..fc9778b
@@ -0,0 +1,132 @@
+/*
+ * OMAP Voltage Management Routines
+ *
+ * Author: Thara Gopinath  <[email protected]>
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * 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*/
+/**
+ * voltagedomain - omap voltage domain global structure
+ * @name       : Name of the voltage domain which can be used as a unique
+ *               identifier.
+ */
+struct voltagedomain {
+       char *name;
+};
+
+/**
+ * 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;
+};
+
+/**
+ * omap_volt_pmic_info - PMIC specific data required by the voltage driver.
+ * @slew_rate      : PMIC slew rate (in uv/us)
+ * @step_size      : PMIC voltage step size (in uv)
+ */
+struct omap_volt_pmic_info {
+      int slew_rate;
+      int step_size;

arch/arm/plat-omap/include/plat/voltage.h line 98

Quoted 10 lines
arch/arm/plat-omap/include/plat/voltage.h new file +10 -0
+};
+
+/* 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 */

indent

Quoted 7 lines
Quoted 7 lines

arch/arm/plat-omap/include/plat/voltage.h line 104

Quoted 5 lines
arch/arm/plat-omap/include/plat/voltage.h new file +5 -0
+   u16 vdd0_on;
+   u16 vdd0_onlp;
+   u16 vdd0_ret;
+   u16 vdd0_off;
+/* PRM_VC_CMD_VAL_1 specific bits */

indent

Will fix the indent issues

Quoted 31 lines
Quoted 31 lines
Quoted 19 lines
arch/arm/plat-omap/include/plat/voltage.h new file +18 -0
+   u16 vdd1_on;
+   u16 vdd1_onlp;
+   u16 vdd1_ret;
+   u16 vdd1_off;
+};
+
+struct voltagedomain *omap_voltage_domain_get(char *name);
+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);
+void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info);

arch/arm/plat-omap/include/plat/voltage.h line 132

Quoted 10 lines
arch/arm/plat-omap/include/plat/voltage.h new file +10 -0
+unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
+#ifdef CONFIG_PM
+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_init_vc(struct omap_volt_vc_data *setup_vc) {}
+static inline  void omap_change_voltscale_method(int voltscale_method) {}
+#endif
+
+#endif

Kevin

#8 lore raw

Re: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3

In reply to Thara Gopinath
Quoted 18 lines · 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.

[...]

Quoted 21 lines
arch/arm/mach-omap2/voltage.c new file +21 -0
+unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
+{
+	struct omap_opp *opp;
+	struct omap_vdd_info *vdd;
+	unsigned long freq;
+
+	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);
+
+	freq = vdd->volt_clk->rate;
+	opp = opp_find_freq_ceil(vdd->opp_dev, &freq);
+	if (IS_ERR(opp)) {
+		pr_warning("%s: Unable to find OPP for vdd_%s freq%ld\n",
+			__func__, voltdm->name, freq);
+		return 0;
+	}
+

arch/arm/mach-omap2/voltage.c line 760

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+	/*
+	 * Use higher freq voltage even if an exact match is not available
+	 * we are probably masking a clock framework bug, so warn
+	 */
+	if (unlikely(freq != vdd->volt_clk->rate))
+		pr_warning("%s: Available freq %ld != dpll freq %ld.\n",
+			__func__, freq, vdd->volt_clk->rate);
+
+	return opp_get_voltage(opp);
+}

Minor nit...

Rather than having to look this up in the OPP table every time, couldn't this be initialized and stored in struct voltagedomain?

Whenever the voltage is changed, it's updated in struct voltagedomain and doesn't have to be continually looked up in the OPP layer.

Quoted 11 lines
arch/arm/mach-omap2/voltage.c new file +11 -0
+/**
+ * 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;
+

arch/arm/mach-omap2/voltage.c line 782

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+	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);
+	return omap_twl_vsel_to_uv(curr_vsel);
+}

This too. No need to read from the HW, if we just keep track of all the changes in 'struct voltagedomain'.

Kevin

#9 lore raw

Re: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3

In reply to Thara Gopinath
Quoted 15 lines · Thara Gopinath
arch/arm/mach-omap2/voltage.c new file +15 -0
+/*
+ * 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;
+

arch/arm/mach-omap2/voltage.c line 516

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -0
+	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;
+	}

cpu_is_* should not be used every time this path is taken. Rather, all the SoC conditional values should be initialized once at init time.

[...]

Quoted 8 lines
arch/arm/mach-omap2/voltage.c new file +8 -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;

arch/arm/mach-omap2/voltage.c line 602

Quoted 10 lines
arch/arm/mach-omap2/voltage.c new file +10 -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;
+	}

ditto.

Same goes for the OMAP4 patches which add to this.

Kevin

#10 lore raw

PATCH v2 3/8 OMAP3: PM: Adding smartreflex driver support.

In reply to 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 VDD1 and the other associated with VDD2.
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 > /debugfs/pm_debug/smartreflex/sr_<X>/autocomp
To disable smartreflex autocompensation feature
echo 0 > /debugfs/pm_debug/smartreflex/sr_<X>/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.

---
 arch/arm/mach-omap2/Makefile                  |    1 +
 arch/arm/mach-omap2/smartreflex.c             |  973 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   32 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  286 ++++++++
 4 files changed, 1292 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex.c
 create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h
arch/arm/mach-omap2/Makefile +1 -0
index 1c095cf..0754886 100644
@@ -53,6 +53,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
arch/arm/mach-omap2/smartreflex.c new file +973 -0

973 lines not on this page · raw message

arch/arm/plat-omap/Kconfig +32 -0
index e39a417..8056349 100644
@@ -35,6 +35,38 @@ config OMAP_DEBUG_LEDS
 	depends on OMAP_DEBUG_DEVICES
 	default y if LEDS
 
+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 VDD1 and VDD2, user must write 1 to
+	  /debug/pm_debug/Smartreflex/SR<X>/autocomp,
+	  where X is 1 or 2 for OMAP3
+
+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
arch/arm/plat-omap/include/plat/smartreflex.h new file +286 -0

286 lines not on this page · raw message

Signature · 1 line
1.7.1.GIT
#11 lore raw

Re: [PATCHv2 3/8] OMAP3: PM: Adding smartreflex driver support.

Quoted 98 lines · 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 VDD1 and the other associated with VDD2.
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 > /debugfs/pm_debug/smartreflex/sr_<X>/autocomp
To disable smartreflex autocompensation feature
echo 0 > /debugfs/pm_debug/smartreflex/sr_<X>/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.

---
 arch/arm/mach-omap2/Makefile                  |    1 +
 arch/arm/mach-omap2/smartreflex.c             |  973 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   32 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  286 ++++++++
 4 files changed, 1292 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex.c
 create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h
arch/arm/mach-omap2/Makefile +1 -0
index 1c095cf..0754886 100644
@@ -53,6 +53,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
arch/arm/mach-omap2/smartreflex.c new file +37 -0
new file mode 100644
index 0000000..1c871ae
@@ -0,0 +1,973 @@
+/*
+ * OMAP SmartReflex Voltage Control
+ *
+ * Author: Thara Gopinath	<[email protected]>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <[email protected]>
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/kobject.h>
+#include <linux/i2c/twl.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/common.h>
+#include <plat/smartreflex.h>
+

arch/arm/mach-omap2/smartreflex.c line 47

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+#define SMARTREFLEX_NAME_LEN	16
+#define SR_DISABLE_TIMEOUT	200
+
+#ifdef CONFIG_PM_DEBUG
+struct dentry *sr_dbg_dir;
+#endif
+
+struct omap_sr {
+	int			srid;
+	int			is_sr_enable;

sr_enabled would be a better name, and should be a bool

arch/arm/mach-omap2/smartreflex.c line 48

Quoted 1 line
arch/arm/mach-omap2/smartreflex.c new file +1 -0
+	int			is_autocomp_active;

drop the 'is_' prefix, and should be a bool

arch/arm/mach-omap2/smartreflex.c line 49

Quoted 1 line
arch/arm/mach-omap2/smartreflex.c new file +1 -0
+	int			sr_ip_type;

can drop the 'sr_' prefix.

Quoted 23 lines
arch/arm/mach-omap2/smartreflex.c new file +22 -0
+	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_smartreflex_class_data *sr_class;
+static struct omap_smartreflex_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));

arch/arm/mach-omap2/smartreflex.c line 82

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+}
+
+static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
+					u32 value)
+{
+	u32 reg_val;
+	u32 errconfig_offs, errconfig_mask;
+
+	reg_val = __raw_readl(sr->base + offset);
+	reg_val &= ~mask;

insert blank line

Quoted 66 lines
arch/arm/mach-omap2/smartreflex.c new file +66 -0
+	/*
+	 * 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. Now if there is an actual reguest to write to these bits
+	 * they will be set in the nex step.
+	 */
+	if (sr->sr_ip_type == SR_TYPE_V1) {
+		errconfig_offs = ERRCONFIG_V1;
+		errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
+	} else if (sr->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_omap_isr(int irq, void *data)
+{
+	struct omap_sr *sr_info = (struct omap_sr *)data;
+	u32 status = 0;
+
+	if (sr_info->sr_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->sr_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);
+	}
+
+	/* Call the class driver notify function if registered*/
+	if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
+		sr_class->notify(sr_info->voltdm, status);
+

arch/arm/mach-omap2/smartreflex.c line 158

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	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");
+	sys_clk_speed = clk_get_rate(sys_ck);

clock API calls can fail. Please check error codes

Quoted 44 lines
arch/arm/mach-omap2/smartreflex.c new file +44 -0
+	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;
+		}

arch/arm/mach-omap2/smartreflex.c line 212

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	}
+	/* TODO: 3630 and Omap4 specific bit field values */
+}
+
+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__);

This should probably be WARN_ONCE(), otherwise it looks like this warn will keep coming on a board without a class driver registered.

arch/arm/mach-omap2/smartreflex.c line 218

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+		return;
+	}
+
+	sr->is_autocomp_active = 1;
+	if (sr_class->enable(sr->voltdm))
+		sr->is_autocomp_active = 0;

This is a bit confusing on first read. Why not

	if (!sr_class->enable(sr->voltdm))
		sr->is_autocomp_active = 1;
Quoted 22 lines
arch/arm/mach-omap2/smartreflex.c new file +21 -0
+}
+
+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->is_autocomp_active == 1) {
+		sr_class->disable(sr->voltdm, 1);
+		sr->is_autocomp_active = 0;
+	}
 
+}
+
+/*
+ * 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

arch/arm/mach-omap2/smartreflex.c line 249

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+ * 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[SMARTREFLEX_NAME_LEN + 1];

this string is on the stack, but disappears after this function finished...

arch/arm/mach-omap2/smartreflex.c line 259

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
+	int ret = 0;
+
+	if (sr_class->class_type == SR_CLASS2 &&
+		sr_class->notify_flags && sr_info->irq) {
+
+		strcpy(name, "sr_");
+		strcat(name, sr_info->voltdm->name);
+		ret = request_irq(sr_info->irq, sr_omap_isr,
+				IRQF_DISABLED, name, (void *)sr_info);

but here, 'name' is passed to request_irq() which just uses a pointer to it. So after this function terminates, any accesses to that pointer will be undefined.

arch/arm/mach-omap2/smartreflex.c line 272

Quoted 13 lines
arch/arm/mach-omap2/smartreflex.c new file +13 -0
+		if (ret) {
+			struct resource *mem;
+
+			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);
+			kfree(sr_info);
+
+			dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
+				"interrupt handler. Smartreflex will"
+				"not function as desired\n", __func__);

here you use the sr_info pointer after you free it.

Quoted 77 lines
arch/arm/mach-omap2/smartreflex.c new file +77 -0
+			return ret;
+		}
+	}
+
+	if (pdata && pdata->enable_on_init)
+		sr_start_vddautocomp(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__);

arch/arm/mach-omap2/smartreflex.c line 359

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+
+	/* 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

minor: common issue with all the kerneldoc headers here, but the correct format for the first line is:

/**
* foobar() - short function description of foobar

Quoted 189 lines

+ * 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.
+ */

arch/arm/mach-omap2/smartreflex.c new file +179 -0
+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_warn(&sr->pdev->dev, "%s: Missing pdata\n", __func__);
+	}
+
+	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+		SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
+	if (sr->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->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_warn(&sr->pdev->dev, "%s: Missing pdata\n", __func__);
+	}
+
+	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+		SRCONFIG_SENENABLE |
+		(sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
+	if (sr->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->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->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->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;
+	}

arch/arm/mach-omap2/smartreflex.c line 558

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+
+	/* errminlimit is opp dependent and hence linked to voltage */
+	sr->err_minlimit = volt_data->sr_errminlimit;
+
+	/* Enable the clocks */
+	if (!sr->is_sr_enable) {
+		struct omap_sr_data *pdata = sr->pdev->dev.platform_data;
+
+		if (pdata && pdata->device_enable) {
+			ret = pdata->device_enable(sr->pdev);

Please use the runtime PM API, which will invoke the omap_device layer. This should just be a pm_runtime_get_sync()

Quoted 56 lines
arch/arm/mach-omap2/smartreflex.c new file +56 -0
+			if (ret)
+				return ret;
+		} else {
+			dev_warn(&sr->pdev->dev, "%s: Not able to turn on SR"
+				"clocks during enable. So returning\n",
+				__func__);
+			return -EPERM;
+		}
+		sr->is_sr_enable = 1;
+	}
+
+	/* 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);
+	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;
+	}
+
+	/* Check if SR clocks are already disabled. If yes do nothing */
+	if (!sr->is_sr_enable)
+		return;
+
+	/* Check if SR is already disabled. If yes just disable the clocks */
+	if (!(sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE))
+		goto disable_clocks;
+
+	if (sr->sr_ip_type == SR_TYPE_V1)
+		sr_v1_disable(sr);
+	else if (sr->sr_ip_type == SR_TYPE_V2)
+		sr_v2_disable(sr);

arch/arm/mach-omap2/smartreflex.c line 624

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+
+disable_clocks:
+	pdata = sr->pdev->dev.platform_data;
+	if (pdata && pdata->device_idle) {
+		pdata->device_idle(sr->pdev);
+	} else {
+		dev_warn(&sr->pdev->dev, "%s: Unable to turn off clocks"
+			"during SR disable\n", __func__);
+		return;
+	}

and this should be a pm_runtime_put()

Quoted 15 lines
arch/arm/mach-omap2/smartreflex.c new file +15 -0
+	sr->is_sr_enable = 0;
+}
+
+/**
+ * omap_smartreflex_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_smartreflex_enable(struct voltagedomain *voltdm)
+{

arch/arm/mach-omap2/smartreflex.c line 649

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	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->is_autocomp_active)
+		return;

from here

arch/arm/mach-omap2/smartreflex.c line 656

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+	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);

to here, this looks an awful lot like sr_start_autocomp()

Quoted 23 lines
arch/arm/mach-omap2/smartreflex.c new file +23 -0
+}
+
+/**
+ * omap_smartreflex_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_smartreflex_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;
+	}
+

arch/arm/mach-omap2/smartreflex.c line 689

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	if (!sr->is_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);

likewise for sr_stop_autocomp.

Quoted 155 lines
arch/arm/mach-omap2/smartreflex.c new file +155 -0
+}
+/**
+ * omap_smartreflex_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_smartreflex_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->is_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_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 omap_sr_register_class(struct omap_smartreflex_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_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_smartreflex_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;
+}
+
+#ifdef CONFIG_PM_DEBUG
+/* 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->is_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");
+#endif
+
+static int __init omap_smartreflex_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;
+	int ret = 0;
+#ifdef CONFIG_PM_DEBUG
+	char name[SMARTREFLEX_NAME_LEN + 1];
+	struct dentry *dbg_dir;
+#endif
+
+	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__);

arch/arm/mach-omap2/smartreflex.c line 854

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+		ret = -ENODEV;
+		goto err_free_devinfo;
+	}
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+	sr_info->pdev = pdev;
+	sr_info->srid = pdev->id;
+	sr_info->voltdm = pdata->voltdm;
+	sr_info->is_autocomp_active = 0;
+	sr_info->clk_length = 0;

minor: setting to zero isn't needed due to kzalloc above.

Quoted 16 lines
arch/arm/mach-omap2/smartreflex.c new file +16 -0
+	sr_info->sr_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.

arch/arm/mach-omap2/smartreflex.c line 880

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	 */
+	if (sr_class) {
+		ret = sr_late_init(sr_info);
+		if (ret) {
+			pr_warning("%s: Error in SR late init\n", __func__);
+			return ret;
+		}
+	}
+
+#ifdef CONFIG_PM_DEBUG

this depends on debugfs support too. Also, please read the "#ifdefs are ugly" section of Documentation/SubmittingPatches in order to get rid of the #ifdefs in the main code flow.

arch/arm/mach-omap2/smartreflex.c line 884

Quoted 4 lines
arch/arm/mach-omap2/smartreflex.c new file +4 -0
+	/* Create the debug fs enteries */
+	strcpy(name, "sr_");
+	strcat(name, sr_info->voltdm->name);
+	dbg_dir = debugfs_create_dir(name, sr_dbg_dir);

again, 'name' is on the stack and will disappear. You should double check the debugfs layer, but I doubt that it makes a copy of this string.

Quoted 49 lines
arch/arm/mach-omap2/smartreflex.c new file +49 -0
+	(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
+				(void *)sr_info, &pm_sr_fops);
+#endif
+
+	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
+	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_smartreflex_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;
+	}
+
+	/* Disable Autocompensation if enabled before removing the module */
+	if (sr_info->is_autocomp_active == 1)
+		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_smartreflex_remove,
+	.driver		= {
+		.name	= "smartreflex",

arch/arm/mach-omap2/smartreflex.c line 943

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+	},
+};
+
+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

... or?

arch/arm/mach-omap2/smartreflex.c line 952

Quoted 9 lines
arch/arm/mach-omap2/smartreflex.c new file +9 -0
+	 */
+	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__);
+
+#ifdef CONFIG_PM_DEBUG
+	sr_dbg_dir = debugfs_create_dir("smartreflex", pm_dbg_main_dir);
+#endif

Please see "#ifdefs are ugly" section of
Documentation/SubmittingPatches.

Quoted 198 lines
arch/arm/mach-omap2/smartreflex.c new file +21 -0
+	ret = platform_driver_probe(&smartreflex_driver,
+				omap_smartreflex_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");
arch/arm/plat-omap/Kconfig +32 -0
index e39a417..8056349 100644
@@ -35,6 +35,38 @@ config OMAP_DEBUG_LEDS
 	depends on OMAP_DEBUG_DEVICES
 	default y if LEDS
 
+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 VDD1 and VDD2, user must write 1 to
+	  /debug/pm_debug/Smartreflex/SR<X>/autocomp,
+	  where X is 1 or 2 for OMAP3
+
+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
arch/arm/plat-omap/include/plat/smartreflex.h new file +128 -0
new file mode 100644
index 0000000..8954c86
@@ -0,0 +1,286 @@
+/*
+ * OMAP Smartreflex Defines and Routines
+ *
+ * Author: Thara Gopinath	<[email protected]>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <[email protected]>
+ *
+ * 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

arch/arm/plat-omap/include/plat/smartreflex.h line 138

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+#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

minor: use lower-case letters in hex numbers

Quoted 6 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +6 -0
+#define OMAP3430_SR1_SENPAVGWEIGHT	0x03
+#define OMAP3430_SR1_SENNAVGWEIGHT	0x03
+
+#define OMAP3430_SR2_SENPAVGWEIGHT	0x01
+#define OMAP3430_SR2_SENNAVGWEIGHT	0x01
+

arch/arm/plat-omap/include/plat/smartreflex.h line 155

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+#define OMAP3430_SR_ERRWEIGHT		0x04
+#define OMAP3430_SR_ERRMAXLIMIT		0x02
+
+/* TODO:3630/OMAP4 values if it has to come from this file */
+
+#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING
+#define SR_TESTING_NVALUES	1
+#else
+#define SR_TESTING_NVALUES	0
+#endif

This is just a new define with the same values as the original define. Just drop this, and in the code, do:

#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING
static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
struct omap_sr_data *sr_data)

{
        /* function body here */
}
else
static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
				struct omap_sr_data *sr_data) {}

#endif

Quoted 89 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +89 -0
+/**
+ * omap_smartreflex_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;
+};
+
+/**
+ * omap_smartreflex_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_smartreflex_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
+
+/**
+ * omap_smartreflex_class_data : Structure to be populated by
+ * Smartreflex class driver with corresponding class enable disable API's
+ *
+ * @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_smartreflex_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;
+};
+
+/**
+ * omap_smartreflex_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.

arch/arm/plat-omap/include/plat/smartreflex.h line 255

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+ * @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;
+	int (*device_enable)(struct platform_device *pdev);
+	int (*device_shutdown)(struct platform_device *pdev);
+	int (*device_idle)(struct platform_device *pdev);

These function pointers should all be dropped in favor of using the runtime PM API.

Quoted 21 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +21 -0
+};
+
+/*
+ * Smartreflex module enable/disable interface.
+ * NOTE: if smartreflex is not enabled from sysfs, these functions will not
+ * do anything.
+ */
+void omap_smartreflex_enable(struct voltagedomain *voltdm);
+void omap_smartreflex_disable(struct voltagedomain *voltdm);
+void omap_smartreflex_disable_reset_volt(struct voltagedomain *voltdm);
+
+/* 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 omap_sr_register_class(struct omap_smartreflex_class_data *class_data);
+
+/* API to register the pmic specific data with the smartreflex driver. */

arch/arm/plat-omap/include/plat/smartreflex.h line 286

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+void omap_sr_register_pmic(struct omap_smartreflex_pmic_data *pmic_data);
+#else
+static inline void omap_smartreflex_enable(struct voltagedomain *voltdm) {}
+static inline void omap_smartreflex_disable(struct voltagedomain *voltdm) {}
+static inline void omap_smartreflex_disable_reset_volt(
+		struct voltagedomain *voltdm) {}
+static inline void omap_sr_register_pmic(
+		struct omap_smartreflex_pmic_data *pmic_data) {}
+#endif
+#endif

These function names could all be unified a bit better. Some are 'omap_smartreflex_', some are 'sr_' and some are 'omap_sr'.

How about using 'omap_sr' for all the public functions.

Kevin

#12 lore raw

RE: [PATCHv2 3/8] OMAP3: PM: Adding smartreflex driver support.

Quoted 114 lines
Quoted 114 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Thursday, August 26, 2010 3:52 AM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 3/8] OMAP3: PM: Adding smartreflex driver support.

Quoted 102 lines · 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 VDD1 and the other associated with VDD2.
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 > /debugfs/pm_debug/smartreflex/sr_<X>/autocomp
To disable smartreflex autocompensation feature
echo 0 > /debugfs/pm_debug/smartreflex/sr_<X>/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.

---
 arch/arm/mach-omap2/Makefile                  |    1 +
 arch/arm/mach-omap2/smartreflex.c             |  973 +++++++++++++++++++++++++
 arch/arm/plat-omap/Kconfig                    |   32 +
 arch/arm/plat-omap/include/plat/smartreflex.h |  286 ++++++++
 4 files changed, 1292 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex.c
 create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h
arch/arm/mach-omap2/Makefile +1 -0
index 1c095cf..0754886 100644
@@ -53,6 +53,7 @@ obj-$(CONFIG_ARCH_OMAP3)          += pm34xx.o sleep34xx.o voltage.o \
                                       cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)           += pm44xx.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
arch/arm/mach-omap2/smartreflex.c new file +41 -0
new file mode 100644
index 0000000..1c871ae
@@ -0,0 +1,973 @@
+/*
+ * OMAP SmartReflex Voltage Control
+ *
+ * Author: Thara Gopinath  <[email protected]>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <[email protected]>
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/kobject.h>
+#include <linux/i2c/twl.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/common.h>
+#include <plat/smartreflex.h>
+
+#define SMARTREFLEX_NAME_LEN       16
+#define SR_DISABLE_TIMEOUT 200
+
+#ifdef CONFIG_PM_DEBUG
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 47

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+struct dentry *sr_dbg_dir;
+#endif
+
+struct omap_sr {
+   int                     srid;
+   int                     is_sr_enable;

sr_enabled would be a better name, and should be a bool

OK

Quoted 4 lines
Quoted 4 lines

arch/arm/mach-omap2/smartreflex.c line 48

Quoted 2 lines
arch/arm/mach-omap2/smartreflex.c new file +1 -0
+   int                     is_autocomp_active;

drop the 'is_' prefix, and should be a bool

OK

Quoted 4 lines
Quoted 4 lines

arch/arm/mach-omap2/smartreflex.c line 49

Quoted 2 lines
arch/arm/mach-omap2/smartreflex.c new file +1 -0
+   int                     sr_ip_type;

can drop the 'sr_' prefix.

OK

Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
arch/arm/mach-omap2/smartreflex.c new file +19 -0
+   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_smartreflex_class_data *sr_class;
+static struct omap_smartreflex_pmic_data *sr_pmic_data;
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
arch/arm/mach-omap2/smartreflex.c new file +7 -0
+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)
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 82

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+{
+   u32 reg_val;
+   u32 errconfig_offs, errconfig_mask;
+
+   reg_val = __raw_readl(sr->base + offset);
+   reg_val &= ~mask;

insert blank line

Will do

Quoted 129 lines
Quoted 129 lines
Quoted 67 lines
arch/arm/mach-omap2/smartreflex.c new file +66 -0
+   /*
+    * 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. Now if there is an actual reguest to write to these bits
+    * they will be set in the nex step.
+    */
+   if (sr->sr_ip_type == SR_TYPE_V1) {
+           errconfig_offs = ERRCONFIG_V1;
+           errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
+   } else if (sr->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_omap_isr(int irq, void *data)
+{
+   struct omap_sr *sr_info = (struct omap_sr *)data;
+   u32 status = 0;
+
+   if (sr_info->sr_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->sr_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);
+   }
+
+   /* Call the class driver notify function if registered*/
+   if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
+           sr_class->notify(sr_info->voltdm, status);
+

arch/arm/mach-omap2/smartreflex.c line 158

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+   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");
+   sys_clk_speed = clk_get_rate(sys_ck);

clock API calls can fail. Please check error codes

Quoted 49 lines
arch/arm/mach-omap2/smartreflex.c new file +49 -0
+   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;
+           }
+   }
+   /* TODO: 3630 and Omap4 specific bit field values */
+}
+
+static void sr_start_vddautocomp(struct omap_sr *sr)
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 212

Quoted 5 lines
arch/arm/mach-omap2/smartreflex.c new file +5 -0
+{
+   if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) {
+           dev_warn(&sr->pdev->dev,
+                   "%s: smartreflex class driver not registered\n",
+                   __func__);

This should probably be WARN_ONCE(), otherwise it looks like this warn will keep coming on a board without a class driver registered.

I am not sure. This is the hook to enable SR from user space. Once failed with the above why should user be keeping on trying again and again until he fixes the error.

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+           return;
+   }
+
+   sr->is_autocomp_active = 1;
+   if (sr_class->enable(sr->voltdm))
+           sr->is_autocomp_active = 0;
Quoted 4 lines
Quoted 4 lines

This is a bit confusing on first read. Why not

     if (!sr_class->enable(sr->voltdm))
             sr->is_autocomp_active = 1;

Looks ok to me.. Modifying is_autocomp_active has been tricky all way long. Cannot now think of any issues in doing the way you are suggesting. So I will give it a try and see if it works

Quoted 37 lines
Quoted 37 lines
Quoted 23 lines
arch/arm/mach-omap2/smartreflex.c new file +21 -0
+}
+
+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->is_autocomp_active == 1) {
+           sr_class->disable(sr->voltdm, 1);
+           sr->is_autocomp_active = 0;
+   }
 
+}
+
+/*
+ * 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

arch/arm/mach-omap2/smartreflex.c line 249

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+ * 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[SMARTREFLEX_NAME_LEN + 1];

this string is on the stack, but disappears after this function finished...

Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+   struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
+   int ret = 0;
+
+   if (sr_class->class_type == SR_CLASS2 &&
+           sr_class->notify_flags && sr_info->irq) {
+
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 259

Quoted 4 lines
arch/arm/mach-omap2/smartreflex.c new file +4 -0
+           strcpy(name, "sr_");
+           strcat(name, sr_info->voltdm->name);
+           ret = request_irq(sr_info->irq, sr_omap_isr,
+                           IRQF_DISABLED, name, (void *)sr_info);

but here, 'name' is passed to request_irq() which just uses a pointer to it. So after this function terminates, any accesses to that pointer will be undefined.

Yes .. true.. Will fix this..

Quoted 16 lines
Quoted 16 lines
Quoted 4 lines
arch/arm/mach-omap2/smartreflex.c new file +3 -0
+           if (ret) {
+                   struct resource *mem;
+

arch/arm/mach-omap2/smartreflex.c line 272

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+                   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);
+                   kfree(sr_info);
+
+                   dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
+                           "interrupt handler. Smartreflex will"
+                           "not function as desired\n", __func__);

here you use the sr_info pointer after you free it.

Will fix this

Quoted 92 lines
Quoted 92 lines
Quoted 78 lines
arch/arm/mach-omap2/smartreflex.c new file +77 -0
+                   return ret;
+           }
+   }
+
+   if (pdata && pdata->enable_on_init)
+           sr_start_vddautocomp(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__);

arch/arm/mach-omap2/smartreflex.c line 359

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+
+   /* 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

minor: common issue with all the kerneldoc headers here, but the correct format for the first line is:

Quoted 2 lines
Quoted 2 lines

/**
* foobar() - short function description of foobar

Will fix this one..

Quoted 195 lines
Quoted 195 lines
Quoted 195 lines

+ * 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.
+ */

arch/arm/mach-omap2/smartreflex.c new file +184 -0
+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_warn(&sr->pdev->dev, "%s: Missing pdata\n", __func__);
+   }
+
+   sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+           SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
+   if (sr->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->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_warn(&sr->pdev->dev, "%s: Missing pdata\n", __func__);
+   }
+
+   sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+           SRCONFIG_SENENABLE |
+           (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
+   if (sr->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->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->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->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;
+
+   /* Enable the clocks */
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 558

Quoted 5 lines
arch/arm/mach-omap2/smartreflex.c new file +5 -0
+   if (!sr->is_sr_enable) {
+           struct omap_sr_data *pdata = sr->pdev->dev.platform_data;
+
+           if (pdata && pdata->device_enable) {
+                   ret = pdata->device_enable(sr->pdev);

Please use the runtime PM API, which will invoke the omap_device layer. This should just be a pm_runtime_get_sync()

As I mentioned before, IMHO this conversion shld be done only once runtime pm gets upstreamed. Otherwise we will be simply creating one more dependency in upstreaming this code.

Quoted 98 lines
Quoted 98 lines
Quoted 57 lines
arch/arm/mach-omap2/smartreflex.c new file +56 -0
+                   if (ret)
+                           return ret;
+           } else {
+                   dev_warn(&sr->pdev->dev, "%s: Not able to turn on SR"
+                           "clocks during enable. So returning\n",
+                           __func__);
+                   return -EPERM;
+           }
+           sr->is_sr_enable = 1;
+   }
+
+   /* 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);
+   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;
+   }
+
+   /* Check if SR clocks are already disabled. If yes do nothing */
+   if (!sr->is_sr_enable)
+           return;
+
+   /* Check if SR is already disabled. If yes just disable the clocks */
+   if (!(sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE))
+           goto disable_clocks;
+
+   if (sr->sr_ip_type == SR_TYPE_V1)
+           sr_v1_disable(sr);
+   else if (sr->sr_ip_type == SR_TYPE_V2)
+           sr_v2_disable(sr);

arch/arm/mach-omap2/smartreflex.c line 624

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+
+disable_clocks:
+   pdata = sr->pdev->dev.platform_data;
+   if (pdata && pdata->device_idle) {
+           pdata->device_idle(sr->pdev);
+   } else {
+           dev_warn(&sr->pdev->dev, "%s: Unable to turn off clocks"
+                   "during SR disable\n", __func__);
+           return;
+   }

and this should be a pm_runtime_put()

Quoted 15 lines
arch/arm/mach-omap2/smartreflex.c new file +15 -0
+   sr->is_sr_enable = 0;
+}
+
+/**
+ * omap_smartreflex_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_smartreflex_enable(struct voltagedomain *voltdm)
+{

arch/arm/mach-omap2/smartreflex.c line 649

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+   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->is_autocomp_active)
+           return;

from here

Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 656

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+   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);

to here, this looks an awful lot like sr_start_autocomp()

Yes both will enable smartreflex. One is called from user side and other from kernel side. Are you suggesting creating a third API to just keep the above piece of code ??

Quoted 196 lines
Quoted 196 lines
Quoted 24 lines
arch/arm/mach-omap2/smartreflex.c new file +23 -0
+}
+
+/**
+ * omap_smartreflex_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_smartreflex_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;
+   }
+

arch/arm/mach-omap2/smartreflex.c line 689

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+   if (!sr->is_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);

likewise for sr_stop_autocomp.

Quoted 159 lines
arch/arm/mach-omap2/smartreflex.c new file +159 -0
+}
+/**
+ * omap_smartreflex_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_smartreflex_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->is_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_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 omap_sr_register_class(struct omap_smartreflex_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_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_smartreflex_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;
+}
+
+#ifdef CONFIG_PM_DEBUG
+/* 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->is_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");
+#endif
+
+static int __init omap_smartreflex_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;
+   int ret = 0;
+#ifdef CONFIG_PM_DEBUG
+   char name[SMARTREFLEX_NAME_LEN + 1];
+   struct dentry *dbg_dir;
+#endif
+
+   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);
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 854

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+
+   sr_info->pdev = pdev;
+   sr_info->srid = pdev->id;
+   sr_info->voltdm = pdata->voltdm;
+   sr_info->is_autocomp_active = 0;
+   sr_info->clk_length = 0;

minor: setting to zero isn't needed due to kzalloc above.

Will fix this.

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
arch/arm/mach-omap2/smartreflex.c new file +22 -0
+   sr_info->sr_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;
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 777

Quoted 4 lines
arch/arm/mach-omap2/smartreflex.c new file +4 -0
+           }
+   }
+
+#ifdef CONFIG_PM_DEBUG

this depends on debugfs support too. Also, please read the "#ifdefs are ugly" section of Documentation/SubmittingPatches in order to get rid of the #ifdefs in the main code flow.

Again shouldn't CONFIG_PM_DEBUG e dependent on debugfs??
I agree it is ugly. But then this piece of code is indeed dependent on CONFIG_PM_DEBUG. I can put a check on sr_dbg_dir but still creation of sr_dbg_dir will have to be under CONFIG_PM_DEBUG

Quoted 9 lines
Quoted 9 lines

arch/arm/mach-omap2/smartreflex.c line 884

Quoted 5 lines
arch/arm/mach-omap2/smartreflex.c new file +4 -0
+   /* Create the debug fs enteries */
+   strcpy(name, "sr_");
+   strcat(name, sr_info->voltdm->name);
+   dbg_dir = debugfs_create_dir(name, sr_dbg_dir);

again, 'name' is on the stack and will disappear. You should double check the debugfs layer, but I doubt that it makes a copy of this string.

Will fix this one.

Quoted 63 lines
Quoted 63 lines
Quoted 50 lines
arch/arm/mach-omap2/smartreflex.c new file +49 -0
+   (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
+                           (void *)sr_info, &pm_sr_fops);
+#endif
+
+   dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
+   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_smartreflex_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;
+   }
+
+   /* Disable Autocompensation if enabled before removing the module */
+   if (sr_info->is_autocomp_active == 1)
+           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_smartreflex_remove,
+   .driver         = {
+           .name   = "smartreflex",

arch/arm/mach-omap2/smartreflex.c line 943

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+   },
+};
+
+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

... or?

Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
arch/arm/mach-omap2/smartreflex.c new file +4 -0
+    */
+   if (sr_pmic_data && sr_pmic_data->sr_pmic_init)
+           sr_pmic_data->sr_pmic_init();
+   else
Quoted 8 lines

arch/arm/mach-omap2/smartreflex.c line 952

Quoted 5 lines
arch/arm/mach-omap2/smartreflex.c new file +5 -0
+           pr_warning("%s: No PMIC hook to init smartreflex\n", __func__);
+
+#ifdef CONFIG_PM_DEBUG
+   sr_dbg_dir = debugfs_create_dir("smartreflex", pm_dbg_main_dir);
+#endif

Please see "#ifdefs are ugly" section of
Documentation/SubmittingPatches.

But this piece is actually dependent on CONFIG_PM_DEBUG

Quoted 204 lines
Quoted 204 lines

arch/arm/plat-

Quoted 66 lines
arch/arm/mach-omap2/smartreflex.c new file +21 -0
+   ret = platform_driver_probe(&smartreflex_driver,
+                           omap_smartreflex_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");
arch/arm/plat-omap/Kconfig +32 -0
index e39a417..8056349 100644
@@ -35,6 +35,38 @@ config OMAP_DEBUG_LEDS
    depends on OMAP_DEBUG_DEVICES
    default y if LEDS
 
+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 VDD1 and VDD2, user must write 1 to
+     /debug/pm_debug/Smartreflex/SR<X>/autocomp,
+     where X is 1 or 2 for OMAP3
+
+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
arch/arm/plat- renamed from arch/arm/plat-omap/include/plat/smartreflex.h +0 -0

omap/include/plat/smartreflex.h

Quoted 137 lines

new file mode 100644
index 0000000..8954c86

arch/arm/plat-omap/include/plat/smartreflex.h new file +132 -0
@@ -0,0 +1,286 @@
+/*
+ * OMAP Smartreflex Defines and Routines
+ *
+ * Author: Thara Gopinath  <[email protected]>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <[email protected]>
+ *
+ * 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
Quoted 8 lines
Quoted 8 lines

arch/arm/plat-omap/include/plat/smartreflex.h line 138

Quoted 6 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +6 -0
+
+/*
+ * 3430 specific values. Maybe these should be passed from board file or
+ * pmic structures.
+ */
+#define OMAP3430_SR_ACCUMDATA              0x1F4

minor: use lower-case letters in hex numbers

OK

Quoted 21 lines
Quoted 21 lines
Quoted 7 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +6 -0
+#define OMAP3430_SR1_SENPAVGWEIGHT 0x03
+#define OMAP3430_SR1_SENNAVGWEIGHT 0x03
+
+#define OMAP3430_SR2_SENPAVGWEIGHT 0x01
+#define OMAP3430_SR2_SENNAVGWEIGHT 0x01
+

arch/arm/plat-omap/include/plat/smartreflex.h line 155

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+#define OMAP3430_SR_ERRWEIGHT              0x04
+#define OMAP3430_SR_ERRMAXLIMIT            0x02
+
+/* TODO:3630/OMAP4 values if it has to come from this file */
+
+#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING
+#define SR_TESTING_NVALUES 1
+#else
+#define SR_TESTING_NVALUES 0
+#endif

This is just a new define with the same values as the original define. Just drop this, and in the code, do:

Quoted 10 lines
Quoted 10 lines

#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING
static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
struct omap_sr_data *sr_data)

{
       /* function body here */
}
else
static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
                             struct omap_sr_data *sr_data) {}

#endif

OK

Quoted 140 lines
Quoted 140 lines
Quoted 91 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +89 -0
+/**
+ * omap_smartreflex_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;
+};
+
+/**
+ * omap_smartreflex_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_smartreflex_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
+
+/**
+ * omap_smartreflex_class_data : Structure to be populated by
+ * Smartreflex class driver with corresponding class enable disable API's
+ *
+ * @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_smartreflex_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;
+};
+
+/**
+ * omap_smartreflex_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.

arch/arm/plat-omap/include/plat/smartreflex.h line 255

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+ * @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;
+   int (*device_enable)(struct platform_device *pdev);
+   int (*device_shutdown)(struct platform_device *pdev);
+   int (*device_idle)(struct platform_device *pdev);

These function pointers should all be dropped in favor of using the runtime PM API.

Quoted 21 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +21 -0
+};
+
+/*
+ * Smartreflex module enable/disable interface.
+ * NOTE: if smartreflex is not enabled from sysfs, these functions will not
+ * do anything.
+ */
+void omap_smartreflex_enable(struct voltagedomain *voltdm);
+void omap_smartreflex_disable(struct voltagedomain *voltdm);
+void omap_smartreflex_disable_reset_volt(struct voltagedomain *voltdm);
+
+/* 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 omap_sr_register_class(struct omap_smartreflex_class_data *class_data);
+
+/* API to register the pmic specific data with the smartreflex driver. */

arch/arm/plat-omap/include/plat/smartreflex.h line 286

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+void omap_sr_register_pmic(struct omap_smartreflex_pmic_data *pmic_data);
+#else
+static inline void omap_smartreflex_enable(struct voltagedomain *voltdm) {}
+static inline void omap_smartreflex_disable(struct voltagedomain *voltdm) {}
+static inline void omap_smartreflex_disable_reset_volt(
+           struct voltagedomain *voltdm) {}
+static inline void omap_sr_register_pmic(
+           struct omap_smartreflex_pmic_data *pmic_data) {}
+#endif
+#endif

These function names could all be unified a bit better. Some are 'omap_smartreflex_', some are 'sr_' and some are 'omap_sr'.

Quoted 1 line
Quoted 1 line

How about using 'omap_sr' for all the public functions.

Yes sr_ are the APIs that will be called from smartreflex class driver and omap_smartreflex are the ones that will be called from rest of the code. I can change omap_smartreflex_ ones to omap_sr.

Quoted 2 lines
Quoted 2 lines

Kevin

#13 lore raw

Re: [PATCHv2 3/8] OMAP3: PM: Adding smartreflex driver support.

"Gopinath, Thara" <[email protected]> writes:

[...]

Quoted 35 lines
Quoted 35 lines
Quoted 35 lines
Quoted 15 lines
arch/arm/mach-omap2/smartreflex.c new file +15 -0
+   sr->is_sr_enable = 0;
+}
+
+/**
+ * omap_smartreflex_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_smartreflex_enable(struct voltagedomain *voltdm)
+{

arch/arm/mach-omap2/smartreflex.c line 649

Quoted 10 lines
arch/arm/mach-omap2/smartreflex.c new file +10 -0
+   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->is_autocomp_active)
+           return;

from here

Quoted 6 lines
arch/arm/mach-omap2/smartreflex.c new file +6 -0
+   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);
Quoted 5 lines
Quoted 1 line
Quoted 1 line

to here, this looks an awful lot like sr_start_autocomp()

Yes both will enable smartreflex. One is called from user side and other from kernel side. Are you suggesting creating a third API to just keep the above piece of code ??

No, I'm suggesting you just call sr_start_vddautocomp() here.

[...]

Quoted 35 lines
Quoted 35 lines
Quoted 35 lines
Quoted 21 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +21 -0
+};
+
+/*
+ * Smartreflex module enable/disable interface.
+ * NOTE: if smartreflex is not enabled from sysfs, these functions will not
+ * do anything.
+ */
+void omap_smartreflex_enable(struct voltagedomain *voltdm);
+void omap_smartreflex_disable(struct voltagedomain *voltdm);
+void omap_smartreflex_disable_reset_volt(struct voltagedomain *voltdm);
+
+/* 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 omap_sr_register_class(struct omap_smartreflex_class_data *class_data);
+
+/* API to register the pmic specific data with the smartreflex driver. */

arch/arm/plat-omap/include/plat/smartreflex.h line 286

Quoted 10 lines
arch/arm/plat-omap/include/plat/smartreflex.h new file +10 -0
+void omap_sr_register_pmic(struct omap_smartreflex_pmic_data *pmic_data);
+#else
+static inline void omap_smartreflex_enable(struct voltagedomain *voltdm) {}
+static inline void omap_smartreflex_disable(struct voltagedomain *voltdm) {}
+static inline void omap_smartreflex_disable_reset_volt(
+           struct voltagedomain *voltdm) {}
+static inline void omap_sr_register_pmic(
+           struct omap_smartreflex_pmic_data *pmic_data) {}
+#endif
+#endif

These function names could all be unified a bit better. Some are 'omap_smartreflex_', some are 'sr_' and some are 'omap_sr'.

Quoted 5 lines
Quoted 1 line
Quoted 1 line

How about using 'omap_sr' for all the public functions.

Yes sr_ are the APIs that will be called from smartreflex class driver and omap_smartreflex are the ones that will be called from rest of the code. I can change omap_smartreflex_ ones to omap_sr.

OK.

Kevin

#14 lore raw

PATCH v2 4/8 OMAP3: PM: Adding smartreflex device file.

In reply to 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.

---
 arch/arm/mach-omap2/Makefile    |    2 +-
 arch/arm/mach-omap2/sr_device.c |  185 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/sr_device.c
arch/arm/mach-omap2/Makefile +1 -1
index 0754886..f259bb8 100644
@@ -53,7 +53,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
arch/arm/mach-omap2/sr_device.c new file +185 -0

185 lines not on this page · raw message

Signature · 1 line
1.7.1.GIT
#15 lore raw

Re: [PATCHv2 4/8] OMAP3: PM: Adding smartreflex device file.

Quoted 168 lines · 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.

---
 arch/arm/mach-omap2/Makefile    |    2 +-
 arch/arm/mach-omap2/sr_device.c |  185 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/sr_device.c
arch/arm/mach-omap2/Makefile +1 -1
index 0754886..f259bb8 100644
@@ -53,7 +53,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
arch/arm/mach-omap2/sr_device.c new file +133 -0
new file mode 100644
index 0000000..3bd0170
@@ -0,0 +1,185 @@
+/*
+ * OMAP3/OMAP4 smartreflex device file
+ *
+ * Author: Thara Gopinath	<[email protected]>
+ *
+ * Based originally on code from smartreflex.c
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <[email protected]>
+ *
+ * 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/control.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/opp.h>
+#include <plat/smartreflex.h>
+#include <plat/voltage.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
+	},
+};
+
+/* Read EFUSE values from control registers for OMAP3430 */
+static void __init sr_read_efuse(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 {
+		sr_data->senn_mod =
+				((omap_ctrl_readl(dev_data->efuse_sr_control) &
+				(0x3 << dev_data->sennenable_shift)) >>
+				dev_data->sennenable_shift);
+		sr_data->senp_mod =
+				((omap_ctrl_readl(dev_data->efuse_sr_control) &
+				(0x3 << dev_data->senpenable_shift)) >>
+				dev_data->senpenable_shift);
+	}
+
+	for (i = 0; i < dev_data->volts_supported; i++)
+		dev_data->volt_data[i].sr_nvalue = omap_ctrl_readl(
+				dev_data->efuse_nvalues_offs[i]);
+}
+
+/*
+ * Hard coded nvalues for testing purposes for OMAP3430,
+ * may cause device to hang!
+ */
+static void __init sr_set_testing_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];
+}
+
+static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
+				struct omap_sr_data *sr_data)
+{
+	if (SR_TESTING_NVALUES)
+		sr_set_testing_nvalues(dev_data, sr_data);
+	else
+		sr_read_efuse(dev_data, sr_data);
+}
+
+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__);

arch/arm/mach-omap2/sr_device.c line 143

Quoted 10 lines
arch/arm/mach-omap2/sr_device.c new file +10 -0
+		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.
+	 */

here, do:

	sr_data->enable_on_init = false;

arch/arm/mach-omap2/sr_device.c line 146

Quoted 3 lines
arch/arm/mach-omap2/sr_device.c new file +3 -0
+	if (cpu_is_omap343x()) {
+		if (omap_rev() == OMAP3430_REV_ES3_1)
+			sr_data->enable_on_init = true;

and drop the rest of this

arch/arm/mach-omap2/sr_device.c line 151

Quoted 5 lines
arch/arm/mach-omap2/sr_device.c new file +5 -0
+		else
+			sr_data->enable_on_init = false;
+	} else {
+		sr_data->enable_on_init = false;
+	}

until here.

arch/arm/mach-omap2/sr_device.c line 154

Quoted 3 lines
arch/arm/mach-omap2/sr_device.c new file +3 -0
+	sr_data->device_enable = omap_device_enable;
+	sr_data->device_shutdown = omap_device_shutdown;
+	sr_data->device_idle = omap_device_idle;

Please drop these and use runtime PM as suggested in previous patch.

Quoted 13 lines
arch/arm/mach-omap2/sr_device.c new file +13 -0
+	sr_data->voltdm = omap_voltage_domain_get(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;
+	}

arch/arm/mach-omap2/sr_device.c line 177

Quoted 10 lines
arch/arm/mach-omap2/sr_device.c new file +10 -0
+	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);

This looks like it fixes the kmemleak reported by Artem/Nishanth, right?

arch/arm/mach-omap2/sr_device.c line 185

Quoted 8 lines
arch/arm/mach-omap2/sr_device.c new file +8 -0
+	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);

Kevin

#16 lore raw

RE: [PATCHv2 4/8] OMAP3: PM: Adding smartreflex device file.

Quoted 200 lines
Quoted 200 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Thursday, August 26, 2010 3:57 AM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 4/8] OMAP3: PM: Adding smartreflex device file.

Quoted 168 lines · 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.

---
 arch/arm/mach-omap2/Makefile    |    2 +-
 arch/arm/mach-omap2/sr_device.c |  185 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-omap2/sr_device.c
arch/arm/mach-omap2/Makefile +1 -1
index 0754886..f259bb8 100644
@@ -53,7 +53,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 					   cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
arch/arm/mach-omap2/sr_device.c new file +133 -0
new file mode 100644
index 0000000..3bd0170
@@ -0,0 +1,185 @@
+/*
+ * OMAP3/OMAP4 smartreflex device file
+ *
+ * Author: Thara Gopinath	<[email protected]>
+ *
+ * Based originally on code from smartreflex.c
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <[email protected]>
+ *
+ * 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/control.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/opp.h>
+#include <plat/smartreflex.h>
+#include <plat/voltage.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
+	},
+};
+
+/* Read EFUSE values from control registers for OMAP3430 */
+static void __init sr_read_efuse(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 {
+		sr_data->senn_mod =
+				((omap_ctrl_readl(dev_data->efuse_sr_control) &
+				(0x3 << dev_data->sennenable_shift)) >>
+				dev_data->sennenable_shift);
+		sr_data->senp_mod =
+				((omap_ctrl_readl(dev_data->efuse_sr_control) &
+				(0x3 << dev_data->senpenable_shift)) >>
+				dev_data->senpenable_shift);
+	}
+
+	for (i = 0; i < dev_data->volts_supported; i++)
+		dev_data->volt_data[i].sr_nvalue = omap_ctrl_readl(
+				dev_data->efuse_nvalues_offs[i]);
+}
+
+/*
+ * Hard coded nvalues for testing purposes for OMAP3430,
+ * may cause device to hang!
+ */
+static void __init sr_set_testing_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];
+}
+
+static void __init sr_set_nvalues(struct omap_sr_dev_data *dev_data,
+				struct omap_sr_data *sr_data)
+{
+	if (SR_TESTING_NVALUES)
+		sr_set_testing_nvalues(dev_data, sr_data);
+	else
+		sr_read_efuse(dev_data, sr_data);
+}
+
+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__);

arch/arm/mach-omap2/sr_device.c line 143

Quoted 10 lines
arch/arm/mach-omap2/sr_device.c new file +10 -0
+		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.
+	 */

here, do:

	sr_data->enable_on_init = false;

arch/arm/mach-omap2/sr_device.c line 146

Quoted 3 lines
arch/arm/mach-omap2/sr_device.c new file +3 -0
+	if (cpu_is_omap343x()) {
+		if (omap_rev() == OMAP3430_REV_ES3_1)
+			sr_data->enable_on_init = true;

and drop the rest of this

Quoted 7 lines
Quoted 7 lines

arch/arm/mach-omap2/sr_device.c line 151

Quoted 5 lines
arch/arm/mach-omap2/sr_device.c new file +5 -0
+		else
+			sr_data->enable_on_init = false;
+	} else {
+		sr_data->enable_on_init = false;
+	}

until here.

Will fix this one.

Quoted 6 lines
Quoted 6 lines

arch/arm/mach-omap2/sr_device.c line 154

Quoted 4 lines
arch/arm/mach-omap2/sr_device.c new file +3 -0
+	sr_data->device_enable = omap_device_enable;
+	sr_data->device_shutdown = omap_device_shutdown;
+	sr_data->device_idle = omap_device_idle;

Please drop these and use runtime PM as suggested in previous patch.

At this stage I am not sure whether we should make smartreflex patches dependent on runtime pm. I would like to do the conversion once and for all once runtime pm is up streamed.

Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
arch/arm/mach-omap2/sr_device.c new file +17 -0
+	sr_data->voltdm = omap_voltage_domain_get(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);
Quoted 8 lines
Quoted 8 lines

arch/arm/mach-omap2/sr_device.c line 177

Quoted 6 lines
arch/arm/mach-omap2/sr_device.c new file +6 -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);

This looks like it fixes the kmemleak reported by Artem/Nishanth, right?

Yes .. I have replied to the original mail

Regards
Thara

#17 lore raw

Re: [PATCHv2 4/8] OMAP3: PM: Adding smartreflex device file.

"Gopinath, Thara" <[email protected]> writes:

[...]

Quoted 9 lines
Quoted 5 lines
Quoted 5 lines

arch/arm/mach-omap2/sr_device.c line 154

Quoted 3 lines
arch/arm/mach-omap2/sr_device.c new file +3 -0
+	sr_data->device_enable = omap_device_enable;
+	sr_data->device_shutdown = omap_device_shutdown;
+	sr_data->device_idle = omap_device_idle;

Please drop these and use runtime PM as suggested in previous patch.

At this stage I am not sure whether we should make smartreflex patches dependent on runtime pm. I would like to do the conversion once and for all once runtime pm is up streamed.

Using runtime PM instead of the sr_data-> calls will simplify this patch.

Also, runtime PM core for OMAP will be merged this merge window. If you use my 'pm-core' branch for testing, you will have it included in your baseline, along with all the other things that are targeted for merge in 2.6.37.

Kevin

#18 lore raw

RE: [PATCHv2 4/8] OMAP3: PM: Adding smartreflex device file.

Quoted 24 lines
Quoted 24 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Tuesday, September 14, 2010 9:33 PM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 4/8] OMAP3: PM: Adding smartreflex device file.

"Gopinath, Thara" <[email protected]> writes:

[...]

Quoted 9 lines
Quoted 5 lines
Quoted 5 lines

arch/arm/mach-omap2/sr_device.c line 154

Quoted 3 lines
arch/arm/mach-omap2/sr_device.c new file +3 -0
+	sr_data->device_enable = omap_device_enable;
+	sr_data->device_shutdown = omap_device_shutdown;
+	sr_data->device_idle = omap_device_idle;

Please drop these and use runtime PM as suggested in previous patch.

At this stage I am not sure whether we should make smartreflex patches dependent on runtime pm. I would like to do the conversion once and for all once runtime pm is up streamed.

Quoted 7 lines
Quoted 7 lines

Using runtime PM instead of the sr_data-> calls will simplify this patch.

Also, runtime PM core for OMAP will be merged this merge window. If you use my 'pm-core' branch for testing, you will have it included in your baseline, along with all the other things that are targeted for merge in 2.6.37.

Is this branch latest kernel + stuff targeted for 2.6.37 ??

Regards
Thara

#19 lore raw

PATCH v2 5/8 OMAP3: PM: Adding smartreflex hwmod data

In reply to 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.

---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |  249 ++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/control.h  |   27 +++
 2 files changed, 276 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +249 -0
index 5d8eb58..c9f0948 100644
@@ -17,6 +17,8 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/control.h>
+#include <plat/smartreflex.h>
 
 #include "omap_hwmod_common_data.h"
 
@@ -36,6 +38,8 @@ static struct omap_hwmod omap3xxx_iva_hwmod;
 static struct omap_hwmod omap3xxx_l3_main_hwmod;
 static struct omap_hwmod omap3xxx_l4_core_hwmod;
 static struct omap_hwmod omap3xxx_l4_per_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 = {
@@ -90,9 +94,47 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
 	.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 */
@@ -197,6 +239,209 @@ static struct omap_hwmod omap3xxx_iva_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,
@@ -204,6 +449,10 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l4_wkup_hwmod,
 	&omap3xxx_mpu_hwmod,
 	&omap3xxx_iva_hwmod,
+	&omap34xx_sr1_hwmod,
+	&omap34xx_sr2_hwmod,
+	&omap36xx_sr1_hwmod,
+	&omap36xx_sr2_hwmod,
 	NULL,
 };
 
arch/arm/plat-omap/include/plat/control.h +27 -0
index 131bf40..46e166d 100644
@@ -144,6 +144,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 \
@@ -160,6 +169,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)
Signature · 1 line
1.7.1.GIT
#20 lore raw

Re: [PATCHv2 5/8] OMAP3: PM: Adding smartreflex hwmod data

Quoted 7 lines · 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.

FWIW, the SR hwmods are still not enabling by default because the clock fwk fails due to missing clockdomain.

I've been manually working around by adding

	.clkdm_name	= "wkup_clkdm",

to sr*_fck, but I know that's not the correct fix.

Kevin

Quoted 348 lines
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |  249 ++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/control.h  |   27 +++
 2 files changed, 276 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +249 -0
index 5d8eb58..c9f0948 100644
@@ -17,6 +17,8 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/control.h>
+#include <plat/smartreflex.h>
 
 #include "omap_hwmod_common_data.h"
 
@@ -36,6 +38,8 @@ static struct omap_hwmod omap3xxx_iva_hwmod;
 static struct omap_hwmod omap3xxx_l3_main_hwmod;
 static struct omap_hwmod omap3xxx_l4_core_hwmod;
 static struct omap_hwmod omap3xxx_l4_per_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 = {
@@ -90,9 +94,47 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
 	.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 */
@@ -197,6 +239,209 @@ static struct omap_hwmod omap3xxx_iva_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,
@@ -204,6 +449,10 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l4_wkup_hwmod,
 	&omap3xxx_mpu_hwmod,
 	&omap3xxx_iva_hwmod,
+	&omap34xx_sr1_hwmod,
+	&omap34xx_sr2_hwmod,
+	&omap36xx_sr1_hwmod,
+	&omap36xx_sr2_hwmod,
 	NULL,
 };
 
arch/arm/plat-omap/include/plat/control.h +27 -0
index 131bf40..46e166d 100644
@@ -144,6 +144,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 \
@@ -160,6 +169,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)
#21 lore raw

PATCH v2 6/8 OMAP3: PM: Adding smartreflex class3 driver

In reply to 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.

---
 arch/arm/mach-omap2/Makefile             |    1 +
 arch/arm/mach-omap2/board-3430sdp.c      |    2 +
 arch/arm/mach-omap2/board-3630sdp.c      |    2 +
 arch/arm/mach-omap2/board-zoom3.c        |    2 +
 arch/arm/mach-omap2/smartreflex-class3.c |   61 ++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/smartreflex-class3.h |   23 +++++++++++
 arch/arm/plat-omap/Kconfig               |    9 ++++
 7 files changed, 100 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/smartreflex-class3.c
 create mode 100644 arch/arm/mach-omap2/smartreflex-class3.h
arch/arm/mach-omap2/Makefile +1 -0
index f259bb8..8ead729 100644
@@ -54,6 +54,7 @@ obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o voltage.o \
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.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
arch/arm/mach-omap2/board-3430sdp.c +2 -0
index 67b95b5f..9a04a2e 100644
@@ -47,6 +47,7 @@
 #include "sdram-qimonda-hyb18m512160af-6.h"
 #include "hsmmc.h"
 #include "pm.h"
+#include "smartreflex-class3.h"
 
 #define CONFIG_DISABLE_HFCLK 1
 
@@ -813,6 +814,7 @@ static void __init omap_3430sdp_init(void)
 	sdp3430_display_init();
 	enable_board_wakeup_source();
 	usb_ehci_init(&ehci_pdata);
+	sr_class3_init();
 }
 
 MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
arch/arm/mach-omap2/board-3630sdp.c +2 -0
index b359c3f..597b1a3 100644
@@ -25,6 +25,7 @@
 
 #include "mux.h"
 #include "sdram-hynix-h8mbx00u0mer-0em.h"
+#include "smartreflex-class3.h"
 
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
 
@@ -214,6 +215,7 @@ static void __init omap_sdp_init(void)
 	board_flash_init(sdp_flash_partitions, chip_sel_sdp);
 	enable_board_wakeup_source();
 	usb_ehci_init(&ehci_pdata);
+	sr_class3_init();
 }
 
 MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
arch/arm/mach-omap2/board-zoom3.c +2 -0
index 6ca0b83..03411b2 100644
@@ -24,6 +24,7 @@
 
 #include "mux.h"
 #include "sdram-hynix-h8mbx00u0mer-0em.h"
+#include "smartreflex-class3.h"
 
 static struct omap_board_config_kernel zoom_config[] __initdata = {
 };
@@ -120,6 +121,7 @@ static void __init omap_zoom_init(void)
 
 	omap_mux_init_gpio(64, OMAP_PIN_OUTPUT);
 	usb_ehci_init(&ehci_pdata);
+	sr_class3_init();
 }
 
 MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
arch/arm/mach-omap2/smartreflex-class3.c new file +61 -0

61 lines not on this page · raw message

arch/arm/mach-omap2/smartreflex-class3.h new file +23 -0
new file mode 100644
index 0000000..4d86037
@@ -0,0 +1,23 @@
+/*
+ * Smartreflex Class 3 Routines
+ *
+ * Author: Thara Gopinath      <[email protected]>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <[email protected]>
+ *
+ * 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_SMARTREFLEXCLASS3_H
+#define __ARCH_ARM_MACH_OMAP2_SMARTREFLEXCLASS3_H
+
+#ifdef CONFIG_OMAP_SMARTREFLEX_CLASS3
+int sr_class3_init(void);
+#else
+static int sr_class3_init(void) { return 0; }
+#endif
+
+#endif
arch/arm/plat-omap/Kconfig +9 -0
index 8056349..af7acc9 100644
@@ -67,6 +67,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 caliberation.
+
 config OMAP_RESET_CLOCKS
 	bool "Reset unused clocks during boot"
 	depends on ARCH_OMAP
Signature · 1 line
1.7.1.GIT
#22 lore raw

Re: [PATCHv2 6/8] OMAP3: PM: Adding smartreflex class3 driver

Quoted 7 lines · 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.

Quoted 6 lines
---
 arch/arm/mach-omap2/Makefile             |    1 +
 arch/arm/mach-omap2/board-3430sdp.c      |    2 +
 arch/arm/mach-omap2/board-3630sdp.c      |    2 +
 arch/arm/mach-omap2/board-zoom3.c        |    2 +

I think this should be board-zoom-peripherals.c so it is enabled for Zoom2 also.

Quoted 3 lines
 arch/arm/mach-omap2/smartreflex-class3.c |   61 ++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/smartreflex-class3.h |   23 +++++++++++
 arch/arm/plat-omap/Kconfig               |    9 ++++

Please separate this into the 2 patches. One for the class driver, and a second to modify the board files.

Kevin

#23 lore raw

RE: [PATCHv2 6/8] OMAP3: PM: Adding smartreflex class3 driver

Quoted 29 lines
Quoted 29 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Thursday, August 26, 2010 4:01 AM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 6/8] OMAP3: PM: Adding smartreflex class3 driver

Quoted 7 lines · 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.

Quoted 6 lines
---
 arch/arm/mach-omap2/Makefile             |    1 +
 arch/arm/mach-omap2/board-3430sdp.c      |    2 +
 arch/arm/mach-omap2/board-3630sdp.c      |    2 +
 arch/arm/mach-omap2/board-zoom3.c        |    2 +

I think this should be board-zoom-peripherals.c so it is enabled for Zoom2 also.

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
 arch/arm/mach-omap2/smartreflex-class3.c |   61 ++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/smartreflex-class3.h |   23 +++++++++++
 arch/arm/plat-omap/Kconfig               |    9 ++++

Please separate this into the 2 patches. One for the class driver, and a second to modify the board files.

Will do this.
Regards
Thara

Quoted 2 lines
Quoted 2 lines

Kevin

#24 lore raw

PATCH v2 7/8 OMAP3: PM: Adding T2 enabling of smartreflex support

In reply to 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.

---
 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(-)
drivers/mfd/twl-core.c +5 -2
index 720e099..677b903 100644
@@ -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
drivers/mfd/twl4030-power.c +29 -0
index 7efa878..0e4d215 100644
@@ -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_smartreflex_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;
include/linux/i2c/twl.h +1 -0
index 6de90bf..b02011e 100644
@@ -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 {
Signature · 1 line
1.7.1.GIT
#25 lore raw

PATCH v2 8/8 OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers

In reply to 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. By default only a read of these parameters are permitted. If you need to write into them then
echo 1 > /pm_debug/enable_sr_vp_debug

The voltage parameters can be viewed at

	/pm_debug/voltage/vdd_<x>/<parameter>

and the smartreflex parameters can be viewed at
/pm_debug/smartreflex/sr_<x>/<parameter>

where <x> is mpu or core for OMAP3.

---
 arch/arm/mach-omap2/pm-debug.c                |   13 ++
 arch/arm/mach-omap2/smartreflex.c             |   40 ++++++-
 arch/arm/mach-omap2/voltage.c                 |  164 ++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/smartreflex.h |    1 -
 arch/arm/plat-omap/include/plat/voltage.h     |    5 +
 5 files changed, 216 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/pm-debug.c +13 -0
index fed8da1..b748baa 100644
@@ -31,6 +31,7 @@
 #include <plat/board.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
+#include <plat/voltage.h>
 
 #include "prm.h"
 #include "cm.h"
@@ -556,6 +557,16 @@ static int option_set(void *data, u64 val)
 	if (option == &enable_off_mode)
 		omap3_pm_off_mode_enable(val);
 
+	if (option == &enable_sr_vp_debug && val)
+		pr_notice("Beware that enabling this option will allow user "
+			"to override the system defined vp and sr parameters "
+			"All the updated parameters will take effect next "
+			"time smartreflex is enabled. Also this option "
+			"disables the automatic vp errorgain and sr errormin "
+			"limit changes as per the voltage. Users will have "
+			"to explicitly write values into the debug fs "
+			"entries corresponding to these if they want to see "
+			"them changing according to the VDD voltage\n");
 	return 0;
 }
 
@@ -609,6 +620,8 @@ static int __init pm_dbg_init(void)
 				   &sleep_while_idle, &pm_dbg_option_fops);
 	(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
 				   &wakeup_timer_seconds, &pm_dbg_option_fops);
+	(void) debugfs_create_file("enable_sr_vp_debug",  S_IRUGO | S_IWUGO, d,
+				   &enable_sr_vp_debug, &pm_dbg_option_fops);
 	pm_dbg_main_dir = d;
 	pm_dbg_init_done = 1;
 
arch/arm/mach-omap2/smartreflex.c +38 -2
index 1c871ae..bc611d1 100644
@@ -547,8 +547,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 debug option is enabled, the user might have over ridden
+	 * this parameter so do not get it from voltage table
+	 */
+	if (!enable_sr_vp_debug)
+		sr->err_minlimit = volt_data->sr_errminlimit;
 
 	/* Enable the clocks */
 	if (!sr->is_sr_enable) {
@@ -812,8 +817,32 @@ 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)
+{
+	if (enable_sr_vp_debug) {
+		u32 *option = data;
+		*option = val;
+	} else {
+		pr_notice("%s: DEBUG option not enabled!\n	\
+			echo 1 > pm_debug/enable_sr_vp_debug - to enable\n",
+			__func__);
+	}
+	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");
 #endif
 
 static int __init omap_smartreflex_probe(struct platform_device *pdev)
@@ -884,6 +913,13 @@ static int __init omap_smartreflex_probe(struct platform_device *pdev)
 	dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
 	(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);
+
 #endif
 
 	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
arch/arm/mach-omap2/voltage.c +160 -4

214 lines not on this page · raw message

arch/arm/plat-omap/include/plat/smartreflex.h +0 -1
index 8954c86..08f7d07 100644
@@ -24,7 +24,6 @@
 #include <plat/voltage.h>
 
 #ifdef CONFIG_PM_DEBUG
-extern struct dentry *pm_dbg_main_dir;
 extern struct dentry *sr_dbg_dir;
 #endif
 
arch/arm/plat-omap/include/plat/voltage.h +5 -0
index fc9778b..c6fe2d6 100644
@@ -14,6 +14,11 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 #define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 
+extern u32 enable_sr_vp_debug;
+#ifdef CONFIG_PM_DEBUG
+extern struct dentry *pm_dbg_main_dir;
+#endif
+
 #define VOLTSCALE_VPFORCEUPDATE		1
 #define VOLTSCALE_VCBYPASS		2
 
Signature · 1 line
1.7.1.GIT
#26 lore raw

Re: [PATCHv2 8/8] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers

Quoted 230 lines · 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. By default only a read of these parameters are permitted. If you need to write into them then
echo 1 > /pm_debug/enable_sr_vp_debug

The voltage parameters can be viewed at

	/pm_debug/voltage/vdd_<x>/<parameter>

and the smartreflex parameters can be viewed at
/pm_debug/smartreflex/sr_<x>/<parameter>

where <x> is mpu or core for OMAP3.

---
 arch/arm/mach-omap2/pm-debug.c                |   13 ++
 arch/arm/mach-omap2/smartreflex.c             |   40 ++++++-
 arch/arm/mach-omap2/voltage.c                 |  164 ++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/smartreflex.h |    1 -
 arch/arm/plat-omap/include/plat/voltage.h     |    5 +
 5 files changed, 216 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/pm-debug.c +13 -0
index fed8da1..b748baa 100644
@@ -31,6 +31,7 @@
 #include <plat/board.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
+#include <plat/voltage.h>
 
 #include "prm.h"
 #include "cm.h"
@@ -556,6 +557,16 @@ static int option_set(void *data, u64 val)
 	if (option == &enable_off_mode)
 		omap3_pm_off_mode_enable(val);
 
+	if (option == &enable_sr_vp_debug && val)
+		pr_notice("Beware that enabling this option will allow user "
+			"to override the system defined vp and sr parameters "
+			"All the updated parameters will take effect next "
+			"time smartreflex is enabled. Also this option "
+			"disables the automatic vp errorgain and sr errormin "
+			"limit changes as per the voltage. Users will have "
+			"to explicitly write values into the debug fs "
+			"entries corresponding to these if they want to see "
+			"them changing according to the VDD voltage\n");
 	return 0;
 }
 
@@ -609,6 +620,8 @@ static int __init pm_dbg_init(void)
 				   &sleep_while_idle, &pm_dbg_option_fops);
 	(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
 				   &wakeup_timer_seconds, &pm_dbg_option_fops);
+	(void) debugfs_create_file("enable_sr_vp_debug",  S_IRUGO | S_IWUGO, d,
+				   &enable_sr_vp_debug, &pm_dbg_option_fops);
 	pm_dbg_main_dir = d;
 	pm_dbg_init_done = 1;
 
arch/arm/mach-omap2/smartreflex.c +38 -2
index 1c871ae..bc611d1 100644
@@ -547,8 +547,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 debug option is enabled, the user might have over ridden
+	 * this parameter so do not get it from voltage table
+	 */
+	if (!enable_sr_vp_debug)
+		sr->err_minlimit = volt_data->sr_errminlimit;
 
 	/* Enable the clocks */
 	if (!sr->is_sr_enable) {
@@ -812,8 +817,32 @@ 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)
+{
+	if (enable_sr_vp_debug) {
+		u32 *option = data;
+		*option = val;
+	} else {
+		pr_notice("%s: DEBUG option not enabled!\n	\
+			echo 1 > pm_debug/enable_sr_vp_debug - to enable\n",
+			__func__);
+	}
+	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");
 #endif
 
 static int __init omap_smartreflex_probe(struct platform_device *pdev)
@@ -884,6 +913,13 @@ static int __init omap_smartreflex_probe(struct platform_device *pdev)
 	dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
 	(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);
+
 #endif
 
 	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
arch/arm/mach-omap2/voltage.c +75 -0
index cb0fcac..d15c5cb 100644
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/debugfs.h>
 
 #include <plat/omap-pm.h>
 #include <plat/omap34xx.h>
@@ -37,6 +38,13 @@
 #define VP_IDLE_TIMEOUT		200
 #define VP_TRANXDONE_TIMEOUT	300
 
+#ifdef CONFIG_PM_DEBUG
+static struct dentry *voltage_dir;
+#endif
+
+/* VP SR debug support */
+u32 enable_sr_vp_debug;
+
 /* PRM voltage module */
 static u32 volt_mod;
 
@@ -228,6 +236,73 @@ static inline void voltage_write_reg(u8 offset, u32 value)
 	prm_write_mod_reg(value, volt_mod, offset);
 }
 
+/* Voltage debugfs support */
+#ifdef CONFIG_PM_DEBUG
+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)
+{
+	if (enable_sr_vp_debug) {
+		u32 *option = data;
+		if (!option) {
+			pr_warning("Wrong paramater passed\n");
+			return -EINVAL;
+		}
+		*option = val;
+	} else {
+		pr_notice("DEBUG option not enabled!"
+			"echo 1 > pm_debug/enable_sr_vp_debug - to enable\n");
+	}
+	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);
+	*val = omap_twl_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(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");
+#endif
+
 static void vp_latch_vsel(struct omap_vdd_info *vdd)
 {
 	u32 vpconfig;
@@ -480,8 +555,49 @@ static void __init init_voltageprocessor(struct omap_vdd_info *vdd)
 

arch/arm/mach-omap2/voltage.c static void __init init_voltageprocessor(struct omap_vdd_info *vdd) · line 565

Quoted 10 lines
arch/arm/mach-omap2/voltage.c +6 -0
 static void __init vdd_data_configure(struct omap_vdd_info *vdd)
 {
+#ifdef CONFIG_PM_DEBUG
+	struct dentry *vdd_debug;
+	char name[16];
+#endif
 	if (cpu_is_omap34xx())
 		omap3_vdd_data_configure(vdd);
+
+#ifdef CONFIG_PM_DEBUG

I'd rather just drop the #ifdefs here and make this conditional on the existence of 'voltage_dir'. More on this below...

Quoted 105 lines
arch/arm/mach-omap2/voltage.c +76 -4
+	strcpy(name, "vdd_");
+	strcat(name, vdd->voltdm.name);
+	vdd_debug = debugfs_create_dir(name, voltage_dir);
+	(void) debugfs_create_file("vp_errorgain", S_IRUGO | S_IWUGO,
+				vdd_debug,
+				&(vdd->vp_reg.vpconfig_errorgain),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_smpswaittimemin", S_IRUGO | S_IWUGO,
+				vdd_debug,
+				&(vdd->vp_reg.vstepmin_smpswaittimemin),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_stepmin", S_IRUGO | S_IWUGO, vdd_debug,
+				&(vdd->vp_reg.vstepmin_stepmin),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_smpswaittimemax", S_IRUGO | S_IWUGO,
+				vdd_debug,
+				&(vdd->vp_reg.vstepmax_smpswaittimemax),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_stepmax", S_IRUGO | S_IWUGO, vdd_debug,
+				&(vdd->vp_reg.vstepmax_stepmax),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_vddmax", S_IRUGO | S_IWUGO, vdd_debug,
+				&(vdd->vp_reg.vlimitto_vddmax),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_vddmin", S_IRUGO | S_IWUGO, vdd_debug,
+				&(vdd->vp_reg.vlimitto_vddmin),
+				&vp_debug_fops);
+	(void) debugfs_create_file("vp_timeout", S_IRUGO | S_IWUGO, vdd_debug,
+				&(vdd->vp_reg.vlimitto_timeout),
+				&vp_debug_fops);
+	(void) debugfs_create_file("curr_vp_volt", S_IRUGO, vdd_debug,
+				(void *) vdd, &vp_volt_debug_fops);
+	(void) debugfs_create_file("curr_nominal_volt", S_IRUGO, vdd_debug,
+				(void *) vdd, &nom_volt_debug_fops);
+#endif
 }
 static void __init init_voltagecontroller(void)
 {
@@ -541,8 +657,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 the debug option is
+	 * enabled allow the override of errorgain from user side
+	 */
+	if (!enable_sr_vp_debug && 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;
@@ -627,8 +746,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 the debug option is
+	 * enabled allow the override of errorgain from user side.
+	 */
+	if (!enable_sr_vp_debug && volt_data)
 		vdd->vp_reg.vpconfig_errorgain =
 					volt_data->vp_errgain;
 	/*
@@ -811,6 +933,37 @@ void omap_vp_enable(struct voltagedomain *voltdm)
 	if (!voltscale_vpforceupdate)
 		vp_latch_vsel(vdd);
 
+	/*
+	 * If debug is enabled, it is likely that the following parameters
+	 * were set from user space so rewrite them.
+	 */
+	if (enable_sr_vp_debug) {
+		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));
+	}
+
 	vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
 	/* Enable VP */
 	voltage_write_reg(vdd->vp_offs.vpconfig,

arch/arm/mach-omap2/voltage.c static int __init omap_voltage_init(void) · line 1262

Quoted 6 lines
arch/arm/mach-omap2/voltage.c +3 -0
@@ -1104,6 +1257,9 @@ static int __init omap_voltage_init(void)
 		return 0;
 	}
 
+#ifdef CONFIG_PM_DEBUG
+	voltage_dir = debugfs_create_dir("voltage", pm_dbg_main_dir);
+#endif

This also depends on CONFIG_DEBUG_FS.

Quoted 20 lines
arch/arm/mach-omap2/voltage.c +0 -0
 	if (cpu_is_omap34xx()) {
 		volt_mod = OMAP3430_GR_MOD;
 		vdd_info = omap3_vdd_info;
arch/arm/plat-omap/include/plat/smartreflex.h +0 -1
index 8954c86..08f7d07 100644
@@ -24,7 +24,6 @@
 #include <plat/voltage.h>
 
 #ifdef CONFIG_PM_DEBUG
-extern struct dentry *pm_dbg_main_dir;
 extern struct dentry *sr_dbg_dir;
 #endif
 
arch/arm/plat-omap/include/plat/voltage.h +0 -0
index fc9778b..c6fe2d6 100644

arch/arm/plat-omap/include/plat/voltage.h line 20

Quoted 7 lines
arch/arm/plat-omap/include/plat/voltage.h +4 -0
@@ -14,6 +14,11 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 #define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 
+extern u32 enable_sr_vp_debug;
+#ifdef CONFIG_PM_DEBUG
+extern struct dentry *pm_dbg_main_dir;
+#endif

Ah, now I see where this is included from. This should be part of
the patch that makes this global (PATCH 1/8).

arch/arm/plat-omap/include/plat/voltage.h line 23

Quoted 2 lines
arch/arm/plat-omap/include/plat/voltage.h +0 -0
 #define VOLTSCALE_VPFORCEUPDATE		1
 #define VOLTSCALE_VCBYPASS		2

Kevin

#27 lore raw

RE: [PATCHv2 8/8] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers

Quoted 364 lines
Quoted 364 lines

-----Original Message-----
From: Kevin Hilman [mailto:[email protected]]
Sent: Wednesday, August 25, 2010 5:23 AM
To: Gopinath, Thara
Cc: [email protected]; [email protected]; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand; Derrick, David
Subject: Re: [PATCHv2 8/8] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers

Quoted 230 lines · 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. By default only a read of these parameters are permitted. If you need to write into them then
echo 1 > /pm_debug/enable_sr_vp_debug

The voltage parameters can be viewed at

    /pm_debug/voltage/vdd_<x>/<parameter>

and the smartreflex parameters can be viewed at
/pm_debug/smartreflex/sr_<x>/<parameter>

where <x> is mpu or core for OMAP3.

---
 arch/arm/mach-omap2/pm-debug.c                |   13 ++
 arch/arm/mach-omap2/smartreflex.c             |   40 ++++++-
 arch/arm/mach-omap2/voltage.c                 |  164 ++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/smartreflex.h |    1 -
 arch/arm/plat-omap/include/plat/voltage.h     |    5 +
 5 files changed, 216 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/pm-debug.c +13 -0
index fed8da1..b748baa 100644
@@ -31,6 +31,7 @@
 #include <plat/board.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
+#include <plat/voltage.h>
 
 #include "prm.h"
 #include "cm.h"
@@ -556,6 +557,16 @@ static int option_set(void *data, u64 val)
    if (option == &enable_off_mode)
            omap3_pm_off_mode_enable(val);
 
+   if (option == &enable_sr_vp_debug && val)
+           pr_notice("Beware that enabling this option will allow user "
+                   "to override the system defined vp and sr parameters "
+                   "All the updated parameters will take effect next "
+                   "time smartreflex is enabled. Also this option "
+                   "disables the automatic vp errorgain and sr errormin "
+                   "limit changes as per the voltage. Users will have "
+                   "to explicitly write values into the debug fs "
+                   "entries corresponding to these if they want to see "
+                   "them changing according to the VDD voltage\n");
    return 0;
 }
 
@@ -609,6 +620,8 @@ static int __init pm_dbg_init(void)
                               &sleep_while_idle, &pm_dbg_option_fops);
    (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
                               &wakeup_timer_seconds, &pm_dbg_option_fops);
+   (void) debugfs_create_file("enable_sr_vp_debug",  S_IRUGO | S_IWUGO, d,
+                              &enable_sr_vp_debug, &pm_dbg_option_fops);
    pm_dbg_main_dir = d;
    pm_dbg_init_done = 1;
 
arch/arm/mach-omap2/smartreflex.c +38 -2
index 1c871ae..bc611d1 100644
@@ -547,8 +547,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 debug option is enabled, the user might have over ridden
+    * this parameter so do not get it from voltage table
+    */
+   if (!enable_sr_vp_debug)
+           sr->err_minlimit = volt_data->sr_errminlimit;
 
    /* Enable the clocks */
    if (!sr->is_sr_enable) {
@@ -812,8 +817,32 @@ 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)
+{
+   if (enable_sr_vp_debug) {
+           u32 *option = data;
+           *option = val;
+   } else {
+           pr_notice("%s: DEBUG option not enabled!\n      \
+                   echo 1 > pm_debug/enable_sr_vp_debug - to enable\n",
+                   __func__);
+   }
+   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");
 #endif
 
 static int __init omap_smartreflex_probe(struct platform_device *pdev)
@@ -884,6 +913,13 @@ static int __init omap_smartreflex_probe(struct platform_device *pdev)
    dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
    (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);
+
 #endif
 
    dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
arch/arm/mach-omap2/voltage.c +75 -0
index cb0fcac..d15c5cb 100644
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/debugfs.h>
 
 #include <plat/omap-pm.h>
 #include <plat/omap34xx.h>
@@ -37,6 +38,13 @@
 #define VP_IDLE_TIMEOUT            200
 #define VP_TRANXDONE_TIMEOUT       300
 
+#ifdef CONFIG_PM_DEBUG
+static struct dentry *voltage_dir;
+#endif
+
+/* VP SR debug support */
+u32 enable_sr_vp_debug;
+
 /* PRM voltage module */
 static u32 volt_mod;
 
@@ -228,6 +236,73 @@ static inline void voltage_write_reg(u8 offset, u32 value)
    prm_write_mod_reg(value, volt_mod, offset);
 }
 
+/* Voltage debugfs support */
+#ifdef CONFIG_PM_DEBUG
+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)
+{
+   if (enable_sr_vp_debug) {
+           u32 *option = data;
+           if (!option) {
+                   pr_warning("Wrong paramater passed\n");
+                   return -EINVAL;
+           }
+           *option = val;
+   } else {
+           pr_notice("DEBUG option not enabled!"
+                   "echo 1 > pm_debug/enable_sr_vp_debug - to enable\n");
+   }
+   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);
+   *val = omap_twl_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(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");
+#endif
+
 static void vp_latch_vsel(struct omap_vdd_info *vdd)
 {
    u32 vpconfig;
@@ -480,8 +555,49 @@ static void __init init_voltageprocessor(struct omap_vdd_info *vdd)
 

arch/arm/mach-omap2/voltage.c static void __init init_voltageprocessor(struct omap_vdd_info *vdd) · line 565

Quoted 10 lines
arch/arm/mach-omap2/voltage.c +6 -0
 static void __init vdd_data_configure(struct omap_vdd_info *vdd)
 {
+#ifdef CONFIG_PM_DEBUG
+   struct dentry *vdd_debug;
+   char name[16];
+#endif
    if (cpu_is_omap34xx())
            omap3_vdd_data_configure(vdd);
+
+#ifdef CONFIG_PM_DEBUG

I'd rather just drop the #ifdefs here and make this conditional on the existence of 'voltage_dir'. More on this below...

Quoted 108 lines
arch/arm/mach-omap2/voltage.c +76 -4
+   strcpy(name, "vdd_");
+   strcat(name, vdd->voltdm.name);
+   vdd_debug = debugfs_create_dir(name, voltage_dir);
+   (void) debugfs_create_file("vp_errorgain", S_IRUGO | S_IWUGO,
+                           vdd_debug,
+                           &(vdd->vp_reg.vpconfig_errorgain),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_smpswaittimemin", S_IRUGO | S_IWUGO,
+                           vdd_debug,
+                           &(vdd->vp_reg.vstepmin_smpswaittimemin),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_stepmin", S_IRUGO | S_IWUGO, vdd_debug,
+                           &(vdd->vp_reg.vstepmin_stepmin),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_smpswaittimemax", S_IRUGO | S_IWUGO,
+                           vdd_debug,
+                           &(vdd->vp_reg.vstepmax_smpswaittimemax),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_stepmax", S_IRUGO | S_IWUGO, vdd_debug,
+                           &(vdd->vp_reg.vstepmax_stepmax),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_vddmax", S_IRUGO | S_IWUGO, vdd_debug,
+                           &(vdd->vp_reg.vlimitto_vddmax),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_vddmin", S_IRUGO | S_IWUGO, vdd_debug,
+                           &(vdd->vp_reg.vlimitto_vddmin),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("vp_timeout", S_IRUGO | S_IWUGO, vdd_debug,
+                           &(vdd->vp_reg.vlimitto_timeout),
+                           &vp_debug_fops);
+   (void) debugfs_create_file("curr_vp_volt", S_IRUGO, vdd_debug,
+                           (void *) vdd, &vp_volt_debug_fops);
+   (void) debugfs_create_file("curr_nominal_volt", S_IRUGO, vdd_debug,
+                           (void *) vdd, &nom_volt_debug_fops);
+#endif
 }
 static void __init init_voltagecontroller(void)
 {
@@ -541,8 +657,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 the debug option is
+    * enabled allow the override of errorgain from user side
+    */
+   if (!enable_sr_vp_debug && 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;
@@ -627,8 +746,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 the debug option is
+    * enabled allow the override of errorgain from user side.
+    */
+   if (!enable_sr_vp_debug && volt_data)
            vdd->vp_reg.vpconfig_errorgain =
                                    volt_data->vp_errgain;
    /*
@@ -811,6 +933,37 @@ void omap_vp_enable(struct voltagedomain *voltdm)
    if (!voltscale_vpforceupdate)
            vp_latch_vsel(vdd);
 
+   /*
+    * If debug is enabled, it is likely that the following parameters
+    * were set from user space so rewrite them.
+    */
+   if (enable_sr_vp_debug) {
+           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));
+   }
+
    vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
    /* Enable VP */
    voltage_write_reg(vdd->vp_offs.vpconfig,
@@ -1104,6 +1257,9 @@ static int __init omap_voltage_init(void)
            return 0;
    }
 
Quoted 5 lines
Quoted 5 lines

arch/arm/mach-omap2/voltage.c static int __init omap_voltage_init(void) · line 1262

Quoted 3 lines
arch/arm/mach-omap2/voltage.c +3 -0
+#ifdef CONFIG_PM_DEBUG
+   voltage_dir = debugfs_create_dir("voltage", pm_dbg_main_dir);
+#endif

This also depends on CONFIG_DEBUG_FS.

Shouldn't CONFIG_PM_DEBUG depend on CONFIG_DEBUG_FS??

Quoted 25 lines
Quoted 25 lines

arch/arm/plat-

Quoted 5 lines
arch/arm/mach-omap2/voltage.c +0 -0
    if (cpu_is_omap34xx()) {
            volt_mod = OMAP3430_GR_MOD;
            vdd_info = omap3_vdd_info;
arch/arm/plat- renamed from arch/arm/plat-omap/include/plat/smartreflex.h +0 -0

omap/include/plat/smartreflex.h

Quoted 19 lines

index 8954c86..08f7d07 100644

arch/arm/plat-omap/include/plat/smartreflex.h +0 -1
@@ -24,7 +24,6 @@
 #include <plat/voltage.h>
 
 #ifdef CONFIG_PM_DEBUG
-extern struct dentry *pm_dbg_main_dir;
 extern struct dentry *sr_dbg_dir;
 #endif
 
arch/arm/plat-omap/include/plat/voltage.h +0 -0
index fc9778b..c6fe2d6 100644
@@ -14,6 +14,11 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 #define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 
Quoted 7 lines
Quoted 7 lines

arch/arm/plat-omap/include/plat/voltage.h line 20

Quoted 4 lines
arch/arm/plat-omap/include/plat/voltage.h +4 -0
+extern u32 enable_sr_vp_debug;
+#ifdef CONFIG_PM_DEBUG
+extern struct dentry *pm_dbg_main_dir;
+#endif

Ah, now I see where this is included from. This should be part of
the patch that makes this global (PATCH 1/8).

At that point (PATCH1/8), this file doesn't even exist.

Quoted 6 lines
Quoted 6 lines

arch/arm/plat-omap/include/plat/voltage.h line 23

Quoted 4 lines
arch/arm/plat-omap/include/plat/voltage.h +0 -0
 #define VOLTSCALE_VPFORCEUPDATE            1
 #define VOLTSCALE_VCBYPASS         2

Kevin

#28 lore raw

Re: [PATCHv2 8/8] OMAP3: PM: Adding debug support to Voltage and Smartreflex drivers

"Gopinath, Thara" <[email protected]> writes:

[...]

Quoted 8 lines
Quoted 5 lines
Quoted 5 lines

arch/arm/mach-omap2/voltage.c static int __init omap_voltage_init(void) · line 1262

Quoted 3 lines
arch/arm/mach-omap2/voltage.c +3 -0
+#ifdef CONFIG_PM_DEBUG
+   voltage_dir = debugfs_create_dir("voltage", pm_dbg_main_dir);
+#endif

This also depends on CONFIG_DEBUG_FS.

Shouldn't CONFIG_PM_DEBUG depend on CONFIG_DEBUG_FS??

No. There are plenty of PM debug features that don't use debugfs.

Kevin