All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] OMAP OPP layer for 2.6.37
@ 2010-09-15 21:56 ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-omap; +Cc: linux-arm-kernel

This series introduces a layer to manage Operating Performance Points (OPPs)
for OMAP SoCs.

Special thanks to Nishanth for doing the bulk of the work on this
series and to Thara for doing significant review, testing and updates.

Kevin Hilman (1):
  OMAP3: remove OPP interfaces from OMAP PM layer

Nishanth Menon (2):
  OMAP: introduce OPP layer for device-specific OPPs
  OMAP3: OPP: add OPP table data and initialization

Paul Walmsley (1):
  OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code

 Documentation/arm/OMAP/omap_pm                |   83 +++++
 arch/arm/mach-omap2/Makefile                  |    2 +
 arch/arm/mach-omap2/io.c                      |    3 +-
 arch/arm/mach-omap2/opp3xxx_data.c            |  126 +++++++
 arch/arm/mach-omap2/pm.c                      |    6 +
 arch/arm/mach-omap2/pm.h                      |    1 +
 arch/arm/plat-omap/Makefile                   |    6 +
 arch/arm/plat-omap/include/plat/omap-pm.h     |   31 +--
 arch/arm/plat-omap/include/plat/opp.h         |  145 ++++++++
 arch/arm/plat-omap/include/plat/opp_twl_tps.h |   21 ++
 arch/arm/plat-omap/omap-pm-noop.c             |   11 +-
 arch/arm/plat-omap/opp.c                      |  461 +++++++++++++++++++++++++
 arch/arm/plat-omap/opp_twl_tps.c              |   41 +++
 13 files changed, 904 insertions(+), 33 deletions(-)
 create mode 100644 arch/arm/mach-omap2/opp3xxx_data.c
 create mode 100644 arch/arm/plat-omap/include/plat/opp.h
 create mode 100644 arch/arm/plat-omap/include/plat/opp_twl_tps.h
 create mode 100644 arch/arm/plat-omap/opp.c
 create mode 100644 arch/arm/plat-omap/opp_twl_tps.c

-- 
1.7.2.1


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

* [PATCH 0/4] OMAP OPP layer for 2.6.37
@ 2010-09-15 21:56 ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

This series introduces a layer to manage Operating Performance Points (OPPs)
for OMAP SoCs.

Special thanks to Nishanth for doing the bulk of the work on this
series and to Thara for doing significant review, testing and updates.

Kevin Hilman (1):
  OMAP3: remove OPP interfaces from OMAP PM layer

Nishanth Menon (2):
  OMAP: introduce OPP layer for device-specific OPPs
  OMAP3: OPP: add OPP table data and initialization

Paul Walmsley (1):
  OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code

 Documentation/arm/OMAP/omap_pm                |   83 +++++
 arch/arm/mach-omap2/Makefile                  |    2 +
 arch/arm/mach-omap2/io.c                      |    3 +-
 arch/arm/mach-omap2/opp3xxx_data.c            |  126 +++++++
 arch/arm/mach-omap2/pm.c                      |    6 +
 arch/arm/mach-omap2/pm.h                      |    1 +
 arch/arm/plat-omap/Makefile                   |    6 +
 arch/arm/plat-omap/include/plat/omap-pm.h     |   31 +--
 arch/arm/plat-omap/include/plat/opp.h         |  145 ++++++++
 arch/arm/plat-omap/include/plat/opp_twl_tps.h |   21 ++
 arch/arm/plat-omap/omap-pm-noop.c             |   11 +-
 arch/arm/plat-omap/opp.c                      |  461 +++++++++++++++++++++++++
 arch/arm/plat-omap/opp_twl_tps.c              |   41 +++
 13 files changed, 904 insertions(+), 33 deletions(-)
 create mode 100644 arch/arm/mach-omap2/opp3xxx_data.c
 create mode 100644 arch/arm/plat-omap/include/plat/opp.h
 create mode 100644 arch/arm/plat-omap/include/plat/opp_twl_tps.h
 create mode 100644 arch/arm/plat-omap/opp.c
 create mode 100644 arch/arm/plat-omap/opp_twl_tps.c

-- 
1.7.2.1

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-15 21:56 ` Kevin Hilman
@ 2010-09-15 21:56   ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-omap; +Cc: linux-arm-kernel

From: Nishanth Menon <nm@ti.com>

OMAP SOCs have a standard set of tuples consisting of frequency and
voltage pairs that the device will support per voltage domain.  These
are called Operating Performance Points or OPPs. The actual
definitions of OMAP Operating Points varies over silicon within the
same family of devices. For a specific domain, you can have a set of
{frequency, voltage} pairs. As the kernel boots and more information
is available, a set of these are activated based on the precise nature
of device the kernel boots up on. It is interesting to remember that
each IP which belongs to a voltage domain may define their own set of
OPPs on top of this.

This introduces a common handling OPP mechanism accross all OMAPs.
As a start this is used for OMAP3.

Note: OPP is a concept that can be used in all OMAPs, it is hence
introduced under plat-omap

Contributions include:
Sanjeev Premi for the initial concept:
	http://patchwork.kernel.org/patch/50998/
Kevin Hilman for converting original design to device-based
Kevin Hilman and Paul Walmsey for cleaning up many of the function
abstractions, improvements and data structure handling
Romit Dasgupta for using enums instead of opp pointers
Thara Gopinath, Eduardo Valentin and Vishwanath BS for fixes and
cleanups.

Discussions and comments from:
http://marc.info/?l=linux-omap&m=126033945313269&w=2
http://marc.info/?l=linux-omap&m=125482970102327&w=2
http://marc.info/?t=125809247500002&r=1&w=2
http://marc.info/?l=linux-omap&m=126025973426007&w=2
incorporated.

Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
Cc: Roberto Granados Dorado <x0095451@ti.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com>
Cc: Tero Kristo <Tero.Kristo@nokia.com>
Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Romit Dasgupta <romit@ti.com>
Cc: Sanjeev Premi <premi@ti.com>
Cc: Thara Gopinath <thara@ti.com>
Cc: Vishwanath BS <vishwanath.bs@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 Documentation/arm/OMAP/omap_pm        |   83 ++++++
 arch/arm/plat-omap/Makefile           |    5 +
 arch/arm/plat-omap/include/plat/opp.h |  145 +++++++++++
 arch/arm/plat-omap/opp.c              |  461 +++++++++++++++++++++++++++++++++
 4 files changed, 694 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/opp.h
 create mode 100644 arch/arm/plat-omap/opp.c

diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
index 5389440..6527cdf 100644
--- a/Documentation/arm/OMAP/omap_pm
+++ b/Documentation/arm/OMAP/omap_pm
@@ -127,3 +127,86 @@ implementation needs:
 10. (*pdata->cpu_set_freq)(unsigned long f)
 
 11. (*pdata->cpu_get_freq)(void)
+
+OMAP OPP Layer
+==============
+OMAP SOCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. This
+is called Operating Performance Point or OPP. The actual definitions
+of OMAP OPP varies over silicon within the same family of devices.
+For a specific domain, you can have a set of {frequency, voltage}
+pairs. As the kernel boots and more information is available, a set
+of these are activated based on the precise nature of device the kernel
+boots up on. It is interesting to remember that each IP which belongs
+to a voltage domain may define their own set of OPPs on top of this.
+
+OPP layer of its own depends on silicon specific implementation and
+board specific data to finalize on the final set of OPPs available
+in a system
+
+Initial list initialization:
+---------------------------
+The normal initialization sequence is for boardxyz_init_irq to call
+omap2_init_common_hw (for omap2+) and which in turn does the default
+setup required.
+
+Silicon specific initialization: First the OPP layer needs to be told
+to initialize the tables for OMAP3, there are two options here:
+a) If the desire is to use the default tables defined for that silicon,
+the board file does not need to call any initialization function, the
+defaults are setup as part of initialization flow when
+omap2_init_common_hw is called.
+
+b) board files would like to customize the default definition. In this
+case, board file needs to call explicitly prior to table operations.
+the sequence is:
+boardxyz_init_irq()
+{
+	... do things ..
+	omap3_pm_init_opp_table()
+	.. customizations and other things ..
+	omap2_init_common_hw()
+}
+1. omap3_pm_init_opp_table - this in turn calls opp_init_list for all
+OPP types. This is the generic silicon operating points, however, the
+system may have additional features or customizations required. This
+flexibility is provided by the following apis:
+
+Query functions:
+----------------
+Search for OPPs for various cases:
+2. opp_find_freq_exact - exact search function
+3. opp_find_freq_floor - round_up search function
+4. opp_find_freq_ceil - round_down search function
+
+OPP modifier functions:
+----------------------
+This allows opp layer users to add customized OPPs or change the table
+for any need they may have
+5. opp_add - add a new OPP - NOTE: use struct omap_opp_def and define
+the custom OPP with OMAP_OPP_DEF for usage.
+6. opp_enable - enable a disabled OPP
+7. opp_disable - disable an enabled OPP
+
+OPP Data retrieval functions:
+----------------------------
+The following sets of functions are useful for drivers to retrieve
+data stored in opp layer for various functions.
+8. opp_get_voltage - retrieve voltage for an opp
+9. opp_get_freq - get the frequency for an opp
+10. opp_get_opp_count - get number of opps enabled for a domain
+
+Cpufreq table generation:
+------------------------
+11. opp_init_cpufreq_table - this translates the OPP layer's internal
+OPP arrangement into a table understood and operated upon by the
+cpufreq layer.
+
+Data Structures:
+---------------
+struct omap_opp * is a handle structure whose internals are known only
+to the OPP layer and is meant to hide the complexity away from users of
+opp layer.
+
+struct omap_opp_def * is the definitions that users can interface with
+opp layer and is meant to define one OPP.
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9405831..c718a0a 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -12,6 +12,11 @@ obj-  :=
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+# OPP support in (OMAP3+ only at the moment)
+ifdef CONFIG_PM
+obj-$(CONFIG_ARCH_OMAP3) += opp.o
+endif
+
 # omap_device support (OMAP2+ only at the moment)
 obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
new file mode 100644
index 0000000..997b56e
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/opp.h
@@ -0,0 +1,145 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ * Copyright (C) 2009 Deep Root Systems, LLC.
+ *	Kevin Hilman
+ *
+ * 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_OPP_H
+#define __ASM_ARM_OMAP_OPP_H
+
+#include <linux/err.h>
+#include <linux/cpufreq.h>
+
+#include <plat/common.h>
+
+/**
+ * struct omap_opp_def - OMAP OPP Definition
+ * @hwmod_name:	Name of the hwmod for this domain
+ * @freq:	Frequency in hertz corresponding to this OPP
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @enabled:	True/false - is this OPP enabled/disabled by default
+ *
+ * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
+ * pairs that the device will support per voltage domain. This is called
+ * Operating Points or OPP. The actual definitions of OMAP Operating Points
+ * varies over silicon within the same family of devices. For a specific
+ * domain, you can have a set of {frequency, voltage} pairs and this is denoted
+ * by an array of omap_opp_def. As the kernel boots and more information is
+ * available, a set of these are activated based on the precise nature of
+ * device the kernel boots up on. It is interesting to remember that each IP
+ * which belongs to a voltage domain may define their own set of OPPs on top
+ * of this - but this is handled by the appropriate driver.
+ */
+struct omap_opp_def {
+	char *hwmod_name;
+
+	unsigned long freq;
+	unsigned long u_volt;
+
+	bool enabled;
+};
+
+/*
+ * Initialization wrapper used to define an OPP.
+ * To point at the end of a terminator of a list of OPPs,
+ * use OMAP_OPP_DEF(NULL, 0, 0, 0)
+ */
+#define OMAP_OPP_DEF(_hwmod_name, _enabled, _freq, _uv)	\
+{						\
+	.hwmod_name	= _hwmod_name,		\
+	.enabled	= _enabled,		\
+	.freq		= _freq,		\
+	.u_volt		= _uv,			\
+}
+
+struct omap_opp;
+
+#ifdef CONFIG_PM
+
+unsigned long opp_get_voltage(const struct omap_opp *opp);
+
+unsigned long opp_get_freq(const struct omap_opp *opp);
+
+int opp_get_opp_count(struct device *dev);
+
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled);
+
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
+
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
+
+int opp_add(const struct omap_opp_def *opp_def);
+
+int opp_enable(struct omap_opp *opp);
+
+int opp_disable(struct omap_opp *opp);
+
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table);
+#else
+static inline unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_get_opp_count(struct omap_opp *oppl)
+{
+	return 0;
+}
+
+static inline struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
+						   unsigned long freq,
+						   bool enabled)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
+						   unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl,
+						  unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_add(struct omap_opp *oppl,
+				       const struct omap_opp_def *opp_def)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int opp_enable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_disable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline
+void opp_init_cpufreq_table(struct omap_opp *opps,
+			    struct cpufreq_frequency_table **table)
+{
+}
+
+#endif		/* CONFIG_PM */
+#endif		/* __ASM_ARM_OMAP_OPP_H */
diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
new file mode 100644
index 0000000..17f93b2
--- /dev/null
+++ b/arch/arm/plat-omap/opp.c
@@ -0,0 +1,461 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <plat/opp.h>
+#include <plat/omap_device.h>
+
+/**
+ * struct omap_opp - OMAP OPP description structure
+ * @enabled:	true/false - marking this OPP as enabled/disabled
+ * @rate:	Frequency in hertz
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @dev_opp:	contains the device_opp struct
+ *
+ * This structure stores the OPP information for a given domain.
+ */
+struct omap_opp {
+	struct list_head node;
+
+	bool enabled;
+	unsigned long rate;
+	unsigned long u_volt;
+
+	struct device_opp *dev_opp;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:	list node
+ * @oh:		hwmod handle
+ * @dev:	device handle
+ * @opp_list:	list of opps
+ * @opp_count:	num opps
+ * @enabled_opp_count:	how many opps are actually enabled
+ *
+ * This is an internal datastructure maintaining the link to
+ * omap_opps attached to a domain device. This structure is not
+ * meant to be shared with users as it private to opp layer.
+ */
+struct device_opp {
+	struct list_head node;
+
+	struct omap_hwmod *oh;
+	struct device *dev;
+
+	struct list_head opp_list;
+	u32 opp_count;
+	u32 enabled_opp_count;
+};
+
+static LIST_HEAD(dev_opp_list);
+
+/**
+ * find_device_opp() - find device_opp struct using device pointer
+ * @dev:	device pointer used to lookup device OPPs
+ *
+ * Search list of device OPPs for one containing matching device.
+ *
+ * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * -EINVAL based on type of error.
+ */
+static struct device_opp *find_device_opp(struct device *dev)
+{
+	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
+
+	if (unlikely(!dev || IS_ERR(dev))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (tmp_dev_opp->dev == dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	return dev_opp;
+}
+
+/**
+ * opp_get_voltage() - Gets the voltage corresponding to an opp
+ * @opp:	opp for which voltage has to be returned for
+ *
+ * Return voltage in micro volt corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->u_volt;
+}
+
+/**
+ * opp_get_freq() - Gets the frequency corresponding to an opp
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Return frequency in hertz corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->rate;
+}
+
+/**
+ * opp_get_opp_count() - Get number of opps enabled in the opp list
+ * @opp_type:	OPP type we want to count
+ *
+ * This functions returns the number of opps if there are any OPPs enabled,
+ * else returns corresponding error value.
+ */
+int opp_get_opp_count(struct device *dev)
+{
+	struct device_opp *dev_opp;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return -ENODEV;
+
+	return dev_opp->enabled_opp_count;
+}
+
+/**
+ * opp_find_freq_exact() - search for an exact frequency
+ * @opp_type:	OPP type we want to search in.
+ * @freq:	frequency to search for
+ * @enabled:	enabled/disabled OPP to search for
+ *
+ * Searches for exact match in the opp list and returns handle to the matching
+ * opp if found, else returns ERR_PTR in case of error and should be handled
+ * using IS_ERR.
+ *
+ * Note enabled is a modifier for the search. if enabled=true, then the match is
+ * for exact matching frequency and is enabled. if false, the match is for exact
+ * frequency which is disabled.
+ */
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate == freq) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_ceil() - Search for an rounded ceil freq
+ * @opp_type:	OPP type where we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching ceil *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next highest available frequency *
+ *	freq = 350000;
+ *	opp = opp_find_freq_ceil(OPP_MPU, &freq))
+ *	if (IS_ERR(opp))
+ *		pr_err("unable to find a higher frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in ascending order *
+ *	freq = 0; * Search for the lowest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_ceil(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq++; * for next higher match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate >= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_floor() - Search for an rounded floor freq
+ * @opp_type:	OPP type we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching floor *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the next match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next lowest available frequency
+ *	freq = 350000;
+ *	opp = opp_find_freq_floor(OPP_MPU, &freq)))
+ *	if (IS_ERR(opp))
+ *		pr_err ("unable to find a lower frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in descending order *
+ *	freq = ULONG_MAX; * search highest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_floor(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq--; * for next lower match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry_reverse(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate <= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/* wrapper to reuse converting opp_def to opp struct */
+static void omap_opp_populate(struct omap_opp *opp,
+			      const struct omap_opp_def *opp_def)
+{
+	opp->rate = opp_def->freq;
+	opp->enabled = opp_def->enabled;
+	opp->u_volt = opp_def->u_volt;
+}
+
+/**
+ * opp_add()  - Add an OPP table from a table definitions
+ * @opp_def:	omap_opp_def to describe the OPP which we want to add.
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ */
+int opp_add(const struct omap_opp_def *opp_def)
+{
+	struct omap_hwmod *oh;
+	struct device *dev = NULL;
+	struct device_opp *tmp_dev_opp, *dev_opp = NULL;
+	struct omap_opp *opp, *new_opp;
+	struct platform_device *pdev;
+	struct list_head *head;
+
+	/* find the correct hwmod, and device */
+	if (!opp_def->hwmod_name) {
+		pr_err("%s: missing name of omap_hwmod, ignoring.\n", __func__);
+		return -EINVAL;
+	}
+	oh = omap_hwmod_lookup(opp_def->hwmod_name);
+	if (!oh || !oh->od) {
+		pr_warn("%s: no hwmod or odev for %s, cannot add OPPs.\n",
+			__func__, opp_def->hwmod_name);
+		return -EINVAL;
+	}
+	pdev = &oh->od->pdev;
+	dev = &oh->od->pdev.dev;
+
+	/* Check for existing list for 'dev' */
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (dev == tmp_dev_opp->dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	if (!dev_opp) {
+		/* Allocate a new device OPP table */
+		dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL);
+		if (!dev_opp) {
+			pr_warning("%s: unable to allocate device struct\n",
+				__func__);
+			return -ENOMEM;
+		}
+
+		dev_opp->oh = oh;
+		dev_opp->dev = &oh->od->pdev.dev;
+		INIT_LIST_HEAD(&dev_opp->opp_list);
+
+		list_add(&dev_opp->node, &dev_opp_list);
+	}
+
+	/* allocate new OPP node */
+	new_opp = kzalloc(sizeof(struct omap_opp), GFP_KERNEL);
+	if (!new_opp) {
+		if (list_empty(&dev_opp->opp_list)) {
+			list_del(&dev_opp->node);
+			kfree(dev_opp);
+		}
+		pr_warning("%s: unable to allocate new opp node\n",
+			__func__);
+		return -ENOMEM;
+	}
+	omap_opp_populate(new_opp, opp_def);
+
+	/* Insert new OPP in order of increasing frequency */
+	head = &dev_opp->opp_list;
+	list_for_each_entry_reverse(opp, &dev_opp->opp_list, node) {
+		if (new_opp->rate >= opp->rate) {
+			head = &opp->node;
+			break;
+		}
+	}
+	list_add(&new_opp->node, head);
+	dev_opp->opp_count++;
+	if (new_opp->enabled)
+		dev_opp->enabled_opp_count++;
+
+	return 0;
+}
+
+/**
+ * opp_enable() - Enable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Enables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_enable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count++;
+
+	opp->enabled = true;
+
+	return 0;
+}
+
+/**
+ * opp_disable() - Disable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Disables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_disable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count--;
+
+	opp->enabled = false;
+
+	return 0;
+}
+
+/**
+ * opp_init_cpufreq_table() - create a cpufreq table for a domain
+ * @opp_type:	OPP type to initialize this list for
+ * @table:	Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided domain - this assumes that the
+ * opp list is already initialized and ready for usage
+ */
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *opp;
+	struct cpufreq_frequency_table *freq_table;
+	int i = 0;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		pr_warning("%s: unable to find device\n", __func__);
+		return;
+	}
+
+	freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
+			     (dev_opp->enabled_opp_count + 1), GFP_ATOMIC);
+	if (!freq_table) {
+		pr_warning("%s: failed to allocate frequency table\n",
+			   __func__);
+		return;
+	}
+
+	list_for_each_entry(opp, &dev_opp->opp_list, node) {
+		if (opp->enabled) {
+			freq_table[i].index = i;
+			freq_table[i].frequency = opp->rate / 1000;
+			i++;
+		}
+	}
+
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	*table = &freq_table[0];
+}
-- 
1.7.2.1


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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-15 21:56   ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Nishanth Menon <nm@ti.com>

OMAP SOCs have a standard set of tuples consisting of frequency and
voltage pairs that the device will support per voltage domain.  These
are called Operating Performance Points or OPPs. The actual
definitions of OMAP Operating Points varies over silicon within the
same family of devices. For a specific domain, you can have a set of
{frequency, voltage} pairs. As the kernel boots and more information
is available, a set of these are activated based on the precise nature
of device the kernel boots up on. It is interesting to remember that
each IP which belongs to a voltage domain may define their own set of
OPPs on top of this.

This introduces a common handling OPP mechanism accross all OMAPs.
As a start this is used for OMAP3.

Note: OPP is a concept that can be used in all OMAPs, it is hence
introduced under plat-omap

Contributions include:
Sanjeev Premi for the initial concept:
	http://patchwork.kernel.org/patch/50998/
Kevin Hilman for converting original design to device-based
Kevin Hilman and Paul Walmsey for cleaning up many of the function
abstractions, improvements and data structure handling
Romit Dasgupta for using enums instead of opp pointers
Thara Gopinath, Eduardo Valentin and Vishwanath BS for fixes and
cleanups.

Discussions and comments from:
http://marc.info/?l=linux-omap&m=126033945313269&w=2
http://marc.info/?l=linux-omap&m=125482970102327&w=2
http://marc.info/?t=125809247500002&r=1&w=2
http://marc.info/?l=linux-omap&m=126025973426007&w=2
incorporated.

Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
Cc: Roberto Granados Dorado <x0095451@ti.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com>
Cc: Tero Kristo <Tero.Kristo@nokia.com>
Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Romit Dasgupta <romit@ti.com>
Cc: Sanjeev Premi <premi@ti.com>
Cc: Thara Gopinath <thara@ti.com>
Cc: Vishwanath BS <vishwanath.bs@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 Documentation/arm/OMAP/omap_pm        |   83 ++++++
 arch/arm/plat-omap/Makefile           |    5 +
 arch/arm/plat-omap/include/plat/opp.h |  145 +++++++++++
 arch/arm/plat-omap/opp.c              |  461 +++++++++++++++++++++++++++++++++
 4 files changed, 694 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/opp.h
 create mode 100644 arch/arm/plat-omap/opp.c

diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
index 5389440..6527cdf 100644
--- a/Documentation/arm/OMAP/omap_pm
+++ b/Documentation/arm/OMAP/omap_pm
@@ -127,3 +127,86 @@ implementation needs:
 10. (*pdata->cpu_set_freq)(unsigned long f)
 
 11. (*pdata->cpu_get_freq)(void)
+
+OMAP OPP Layer
+==============
+OMAP SOCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. This
+is called Operating Performance Point or OPP. The actual definitions
+of OMAP OPP varies over silicon within the same family of devices.
+For a specific domain, you can have a set of {frequency, voltage}
+pairs. As the kernel boots and more information is available, a set
+of these are activated based on the precise nature of device the kernel
+boots up on. It is interesting to remember that each IP which belongs
+to a voltage domain may define their own set of OPPs on top of this.
+
+OPP layer of its own depends on silicon specific implementation and
+board specific data to finalize on the final set of OPPs available
+in a system
+
+Initial list initialization:
+---------------------------
+The normal initialization sequence is for boardxyz_init_irq to call
+omap2_init_common_hw (for omap2+) and which in turn does the default
+setup required.
+
+Silicon specific initialization: First the OPP layer needs to be told
+to initialize the tables for OMAP3, there are two options here:
+a) If the desire is to use the default tables defined for that silicon,
+the board file does not need to call any initialization function, the
+defaults are setup as part of initialization flow when
+omap2_init_common_hw is called.
+
+b) board files would like to customize the default definition. In this
+case, board file needs to call explicitly prior to table operations.
+the sequence is:
+boardxyz_init_irq()
+{
+	... do things ..
+	omap3_pm_init_opp_table()
+	.. customizations and other things ..
+	omap2_init_common_hw()
+}
+1. omap3_pm_init_opp_table - this in turn calls opp_init_list for all
+OPP types. This is the generic silicon operating points, however, the
+system may have additional features or customizations required. This
+flexibility is provided by the following apis:
+
+Query functions:
+----------------
+Search for OPPs for various cases:
+2. opp_find_freq_exact - exact search function
+3. opp_find_freq_floor - round_up search function
+4. opp_find_freq_ceil - round_down search function
+
+OPP modifier functions:
+----------------------
+This allows opp layer users to add customized OPPs or change the table
+for any need they may have
+5. opp_add - add a new OPP - NOTE: use struct omap_opp_def and define
+the custom OPP with OMAP_OPP_DEF for usage.
+6. opp_enable - enable a disabled OPP
+7. opp_disable - disable an enabled OPP
+
+OPP Data retrieval functions:
+----------------------------
+The following sets of functions are useful for drivers to retrieve
+data stored in opp layer for various functions.
+8. opp_get_voltage - retrieve voltage for an opp
+9. opp_get_freq - get the frequency for an opp
+10. opp_get_opp_count - get number of opps enabled for a domain
+
+Cpufreq table generation:
+------------------------
+11. opp_init_cpufreq_table - this translates the OPP layer's internal
+OPP arrangement into a table understood and operated upon by the
+cpufreq layer.
+
+Data Structures:
+---------------
+struct omap_opp * is a handle structure whose internals are known only
+to the OPP layer and is meant to hide the complexity away from users of
+opp layer.
+
+struct omap_opp_def * is the definitions that users can interface with
+opp layer and is meant to define one OPP.
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9405831..c718a0a 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -12,6 +12,11 @@ obj-  :=
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+# OPP support in (OMAP3+ only at the moment)
+ifdef CONFIG_PM
+obj-$(CONFIG_ARCH_OMAP3) += opp.o
+endif
+
 # omap_device support (OMAP2+ only at the moment)
 obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
new file mode 100644
index 0000000..997b56e
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/opp.h
@@ -0,0 +1,145 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ * Copyright (C) 2009 Deep Root Systems, LLC.
+ *	Kevin Hilman
+ *
+ * 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_OPP_H
+#define __ASM_ARM_OMAP_OPP_H
+
+#include <linux/err.h>
+#include <linux/cpufreq.h>
+
+#include <plat/common.h>
+
+/**
+ * struct omap_opp_def - OMAP OPP Definition
+ * @hwmod_name:	Name of the hwmod for this domain
+ * @freq:	Frequency in hertz corresponding to this OPP
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @enabled:	True/false - is this OPP enabled/disabled by default
+ *
+ * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
+ * pairs that the device will support per voltage domain. This is called
+ * Operating Points or OPP. The actual definitions of OMAP Operating Points
+ * varies over silicon within the same family of devices. For a specific
+ * domain, you can have a set of {frequency, voltage} pairs and this is denoted
+ * by an array of omap_opp_def. As the kernel boots and more information is
+ * available, a set of these are activated based on the precise nature of
+ * device the kernel boots up on. It is interesting to remember that each IP
+ * which belongs to a voltage domain may define their own set of OPPs on top
+ * of this - but this is handled by the appropriate driver.
+ */
+struct omap_opp_def {
+	char *hwmod_name;
+
+	unsigned long freq;
+	unsigned long u_volt;
+
+	bool enabled;
+};
+
+/*
+ * Initialization wrapper used to define an OPP.
+ * To point at the end of a terminator of a list of OPPs,
+ * use OMAP_OPP_DEF(NULL, 0, 0, 0)
+ */
+#define OMAP_OPP_DEF(_hwmod_name, _enabled, _freq, _uv)	\
+{						\
+	.hwmod_name	= _hwmod_name,		\
+	.enabled	= _enabled,		\
+	.freq		= _freq,		\
+	.u_volt		= _uv,			\
+}
+
+struct omap_opp;
+
+#ifdef CONFIG_PM
+
+unsigned long opp_get_voltage(const struct omap_opp *opp);
+
+unsigned long opp_get_freq(const struct omap_opp *opp);
+
+int opp_get_opp_count(struct device *dev);
+
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled);
+
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
+
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
+
+int opp_add(const struct omap_opp_def *opp_def);
+
+int opp_enable(struct omap_opp *opp);
+
+int opp_disable(struct omap_opp *opp);
+
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table);
+#else
+static inline unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_get_opp_count(struct omap_opp *oppl)
+{
+	return 0;
+}
+
+static inline struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
+						   unsigned long freq,
+						   bool enabled)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
+						   unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl,
+						  unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_add(struct omap_opp *oppl,
+				       const struct omap_opp_def *opp_def)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int opp_enable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_disable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline
+void opp_init_cpufreq_table(struct omap_opp *opps,
+			    struct cpufreq_frequency_table **table)
+{
+}
+
+#endif		/* CONFIG_PM */
+#endif		/* __ASM_ARM_OMAP_OPP_H */
diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
new file mode 100644
index 0000000..17f93b2
--- /dev/null
+++ b/arch/arm/plat-omap/opp.c
@@ -0,0 +1,461 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <plat/opp.h>
+#include <plat/omap_device.h>
+
+/**
+ * struct omap_opp - OMAP OPP description structure
+ * @enabled:	true/false - marking this OPP as enabled/disabled
+ * @rate:	Frequency in hertz
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @dev_opp:	contains the device_opp struct
+ *
+ * This structure stores the OPP information for a given domain.
+ */
+struct omap_opp {
+	struct list_head node;
+
+	bool enabled;
+	unsigned long rate;
+	unsigned long u_volt;
+
+	struct device_opp *dev_opp;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:	list node
+ * @oh:		hwmod handle
+ * @dev:	device handle
+ * @opp_list:	list of opps
+ * @opp_count:	num opps
+ * @enabled_opp_count:	how many opps are actually enabled
+ *
+ * This is an internal datastructure maintaining the link to
+ * omap_opps attached to a domain device. This structure is not
+ * meant to be shared with users as it private to opp layer.
+ */
+struct device_opp {
+	struct list_head node;
+
+	struct omap_hwmod *oh;
+	struct device *dev;
+
+	struct list_head opp_list;
+	u32 opp_count;
+	u32 enabled_opp_count;
+};
+
+static LIST_HEAD(dev_opp_list);
+
+/**
+ * find_device_opp() - find device_opp struct using device pointer
+ * @dev:	device pointer used to lookup device OPPs
+ *
+ * Search list of device OPPs for one containing matching device.
+ *
+ * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * -EINVAL based on type of error.
+ */
+static struct device_opp *find_device_opp(struct device *dev)
+{
+	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
+
+	if (unlikely(!dev || IS_ERR(dev))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (tmp_dev_opp->dev == dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	return dev_opp;
+}
+
+/**
+ * opp_get_voltage() - Gets the voltage corresponding to an opp
+ * @opp:	opp for which voltage has to be returned for
+ *
+ * Return voltage in micro volt corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->u_volt;
+}
+
+/**
+ * opp_get_freq() - Gets the frequency corresponding to an opp
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Return frequency in hertz corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->rate;
+}
+
+/**
+ * opp_get_opp_count() - Get number of opps enabled in the opp list
+ * @opp_type:	OPP type we want to count
+ *
+ * This functions returns the number of opps if there are any OPPs enabled,
+ * else returns corresponding error value.
+ */
+int opp_get_opp_count(struct device *dev)
+{
+	struct device_opp *dev_opp;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return -ENODEV;
+
+	return dev_opp->enabled_opp_count;
+}
+
+/**
+ * opp_find_freq_exact() - search for an exact frequency
+ * @opp_type:	OPP type we want to search in.
+ * @freq:	frequency to search for
+ * @enabled:	enabled/disabled OPP to search for
+ *
+ * Searches for exact match in the opp list and returns handle to the matching
+ * opp if found, else returns ERR_PTR in case of error and should be handled
+ * using IS_ERR.
+ *
+ * Note enabled is a modifier for the search. if enabled=true, then the match is
+ * for exact matching frequency and is enabled. if false, the match is for exact
+ * frequency which is disabled.
+ */
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate == freq) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_ceil() - Search for an rounded ceil freq
+ * @opp_type:	OPP type where we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching ceil *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next highest available frequency *
+ *	freq = 350000;
+ *	opp = opp_find_freq_ceil(OPP_MPU, &freq))
+ *	if (IS_ERR(opp))
+ *		pr_err("unable to find a higher frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in ascending order *
+ *	freq = 0; * Search for the lowest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_ceil(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq++; * for next higher match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate >= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_floor() - Search for an rounded floor freq
+ * @opp_type:	OPP type we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching floor *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the next match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next lowest available frequency
+ *	freq = 350000;
+ *	opp = opp_find_freq_floor(OPP_MPU, &freq)))
+ *	if (IS_ERR(opp))
+ *		pr_err ("unable to find a lower frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in descending order *
+ *	freq = ULONG_MAX; * search highest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_floor(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq--; * for next lower match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry_reverse(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate <= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/* wrapper to reuse converting opp_def to opp struct */
+static void omap_opp_populate(struct omap_opp *opp,
+			      const struct omap_opp_def *opp_def)
+{
+	opp->rate = opp_def->freq;
+	opp->enabled = opp_def->enabled;
+	opp->u_volt = opp_def->u_volt;
+}
+
+/**
+ * opp_add()  - Add an OPP table from a table definitions
+ * @opp_def:	omap_opp_def to describe the OPP which we want to add.
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ */
+int opp_add(const struct omap_opp_def *opp_def)
+{
+	struct omap_hwmod *oh;
+	struct device *dev = NULL;
+	struct device_opp *tmp_dev_opp, *dev_opp = NULL;
+	struct omap_opp *opp, *new_opp;
+	struct platform_device *pdev;
+	struct list_head *head;
+
+	/* find the correct hwmod, and device */
+	if (!opp_def->hwmod_name) {
+		pr_err("%s: missing name of omap_hwmod, ignoring.\n", __func__);
+		return -EINVAL;
+	}
+	oh = omap_hwmod_lookup(opp_def->hwmod_name);
+	if (!oh || !oh->od) {
+		pr_warn("%s: no hwmod or odev for %s, cannot add OPPs.\n",
+			__func__, opp_def->hwmod_name);
+		return -EINVAL;
+	}
+	pdev = &oh->od->pdev;
+	dev = &oh->od->pdev.dev;
+
+	/* Check for existing list for 'dev' */
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (dev == tmp_dev_opp->dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	if (!dev_opp) {
+		/* Allocate a new device OPP table */
+		dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL);
+		if (!dev_opp) {
+			pr_warning("%s: unable to allocate device struct\n",
+				__func__);
+			return -ENOMEM;
+		}
+
+		dev_opp->oh = oh;
+		dev_opp->dev = &oh->od->pdev.dev;
+		INIT_LIST_HEAD(&dev_opp->opp_list);
+
+		list_add(&dev_opp->node, &dev_opp_list);
+	}
+
+	/* allocate new OPP node */
+	new_opp = kzalloc(sizeof(struct omap_opp), GFP_KERNEL);
+	if (!new_opp) {
+		if (list_empty(&dev_opp->opp_list)) {
+			list_del(&dev_opp->node);
+			kfree(dev_opp);
+		}
+		pr_warning("%s: unable to allocate new opp node\n",
+			__func__);
+		return -ENOMEM;
+	}
+	omap_opp_populate(new_opp, opp_def);
+
+	/* Insert new OPP in order of increasing frequency */
+	head = &dev_opp->opp_list;
+	list_for_each_entry_reverse(opp, &dev_opp->opp_list, node) {
+		if (new_opp->rate >= opp->rate) {
+			head = &opp->node;
+			break;
+		}
+	}
+	list_add(&new_opp->node, head);
+	dev_opp->opp_count++;
+	if (new_opp->enabled)
+		dev_opp->enabled_opp_count++;
+
+	return 0;
+}
+
+/**
+ * opp_enable() - Enable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Enables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_enable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count++;
+
+	opp->enabled = true;
+
+	return 0;
+}
+
+/**
+ * opp_disable() - Disable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Disables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_disable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count--;
+
+	opp->enabled = false;
+
+	return 0;
+}
+
+/**
+ * opp_init_cpufreq_table() - create a cpufreq table for a domain
+ * @opp_type:	OPP type to initialize this list for
+ * @table:	Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided domain - this assumes that the
+ * opp list is already initialized and ready for usage
+ */
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *opp;
+	struct cpufreq_frequency_table *freq_table;
+	int i = 0;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		pr_warning("%s: unable to find device\n", __func__);
+		return;
+	}
+
+	freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
+			     (dev_opp->enabled_opp_count + 1), GFP_ATOMIC);
+	if (!freq_table) {
+		pr_warning("%s: failed to allocate frequency table\n",
+			   __func__);
+		return;
+	}
+
+	list_for_each_entry(opp, &dev_opp->opp_list, node) {
+		if (opp->enabled) {
+			freq_table[i].index = i;
+			freq_table[i].frequency = opp->rate / 1000;
+			i++;
+		}
+	}
+
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	*table = &freq_table[0];
+}
-- 
1.7.2.1

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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-15 21:56 ` Kevin Hilman
@ 2010-09-15 21:56   ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-omap; +Cc: linux-arm-kernel

From: Paul Walmsley <paul@pwsan.com>

The OPP layer code should be independent of the PMIC,
introduce the TWL/TPS-specific code out to its own file.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Romit Dasgupta <romit@ti.com>
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/plat-omap/Makefile                   |    1 +
 arch/arm/plat-omap/include/plat/opp_twl_tps.h |   21 +++++++++++++
 arch/arm/plat-omap/opp_twl_tps.c              |   41 +++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/opp_twl_tps.h
 create mode 100644 arch/arm/plat-omap/opp_twl_tps.c

diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index c718a0a..a88879c 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 # OPP support in (OMAP3+ only at the moment)
 ifdef CONFIG_PM
 obj-$(CONFIG_ARCH_OMAP3) += opp.o
+obj-$(CONFIG_TWL4030_CORE) += opp_twl_tps.o
 endif
 
 # omap_device support (OMAP2+ only at the moment)
diff --git a/arch/arm/plat-omap/include/plat/opp_twl_tps.h b/arch/arm/plat-omap/include/plat/opp_twl_tps.h
new file mode 100644
index 0000000..8784e5f
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/opp_twl_tps.h
@@ -0,0 +1,21 @@
+/*
+ * opp_twl_tps.h - TWL/TPS-specific headers for the OPP code
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *
+ * 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.
+ *
+ * XXX This code belongs as part of some other TWL/TPS code.
+ */
+#ifndef _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
+#define _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
+
+#include <linux/kernel.h>
+
+unsigned long omap_twl_vsel_to_uv(const u8 vsel);
+u8 omap_twl_uv_to_vsel(unsigned long uV);
+
+#endif
diff --git a/arch/arm/plat-omap/opp_twl_tps.c b/arch/arm/plat-omap/opp_twl_tps.c
new file mode 100644
index 0000000..112f106
--- /dev/null
+++ b/arch/arm/plat-omap/opp_twl_tps.c
@@ -0,0 +1,41 @@
+/*
+ * opp_twl_tps.c - TWL/TPS-specific functions for the OPP code
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated.
+ * Nishanth Menon
+ * Copyright (C) 2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * XXX This code should be part of some other TWL/TPS code.
+ */
+
+#include <plat/opp_twl_tps.h>
+
+/**
+ * omap_twl_vsel_to_vdc - convert TWL/TPS VSEL value to microvolts DC
+ * @vsel: TWL/TPS VSEL value to convert
+ *
+ * Returns the microvolts DC that the TWL/TPS family of PMICs should
+ * generate when programmed with @vsel.
+ */
+unsigned long omap_twl_vsel_to_uv(const u8 vsel)
+{
+	return (((vsel * 125) + 6000)) * 100;
+}
+
+/**
+ * omap_twl_uv_to_vsel - convert microvolts DC to TWL/TPS VSEL value
+ * @uv: microvolts DC to convert
+ *
+ * Returns the VSEL value necessary for the TWL/TPS family of PMICs to
+ * generate an output voltage equal to or greater than @uv microvolts DC.
+ */
+u8 omap_twl_uv_to_vsel(unsigned long uv)
+{
+	/* Round up to higher voltage */
+	return DIV_ROUND_UP(uv - 600000, 12500);
+}
-- 
1.7.2.1


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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-15 21:56   ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Paul Walmsley <paul@pwsan.com>

The OPP layer code should be independent of the PMIC,
introduce the TWL/TPS-specific code out to its own file.

Signed-off-by: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Romit Dasgupta <romit@ti.com>
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/plat-omap/Makefile                   |    1 +
 arch/arm/plat-omap/include/plat/opp_twl_tps.h |   21 +++++++++++++
 arch/arm/plat-omap/opp_twl_tps.c              |   41 +++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/opp_twl_tps.h
 create mode 100644 arch/arm/plat-omap/opp_twl_tps.c

diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index c718a0a..a88879c 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 # OPP support in (OMAP3+ only at the moment)
 ifdef CONFIG_PM
 obj-$(CONFIG_ARCH_OMAP3) += opp.o
+obj-$(CONFIG_TWL4030_CORE) += opp_twl_tps.o
 endif
 
 # omap_device support (OMAP2+ only at the moment)
diff --git a/arch/arm/plat-omap/include/plat/opp_twl_tps.h b/arch/arm/plat-omap/include/plat/opp_twl_tps.h
new file mode 100644
index 0000000..8784e5f
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/opp_twl_tps.h
@@ -0,0 +1,21 @@
+/*
+ * opp_twl_tps.h - TWL/TPS-specific headers for the OPP code
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *
+ * 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.
+ *
+ * XXX This code belongs as part of some other TWL/TPS code.
+ */
+#ifndef _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
+#define _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
+
+#include <linux/kernel.h>
+
+unsigned long omap_twl_vsel_to_uv(const u8 vsel);
+u8 omap_twl_uv_to_vsel(unsigned long uV);
+
+#endif
diff --git a/arch/arm/plat-omap/opp_twl_tps.c b/arch/arm/plat-omap/opp_twl_tps.c
new file mode 100644
index 0000000..112f106
--- /dev/null
+++ b/arch/arm/plat-omap/opp_twl_tps.c
@@ -0,0 +1,41 @@
+/*
+ * opp_twl_tps.c - TWL/TPS-specific functions for the OPP code
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated.
+ * Nishanth Menon
+ * Copyright (C) 2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * XXX This code should be part of some other TWL/TPS code.
+ */
+
+#include <plat/opp_twl_tps.h>
+
+/**
+ * omap_twl_vsel_to_vdc - convert TWL/TPS VSEL value to microvolts DC
+ * @vsel: TWL/TPS VSEL value to convert
+ *
+ * Returns the microvolts DC that the TWL/TPS family of PMICs should
+ * generate when programmed with @vsel.
+ */
+unsigned long omap_twl_vsel_to_uv(const u8 vsel)
+{
+	return (((vsel * 125) + 6000)) * 100;
+}
+
+/**
+ * omap_twl_uv_to_vsel - convert microvolts DC to TWL/TPS VSEL value
+ * @uv: microvolts DC to convert
+ *
+ * Returns the VSEL value necessary for the TWL/TPS family of PMICs to
+ * generate an output voltage equal to or greater than @uv microvolts DC.
+ */
+u8 omap_twl_uv_to_vsel(unsigned long uv)
+{
+	/* Round up to higher voltage */
+	return DIV_ROUND_UP(uv - 600000, 12500);
+}
-- 
1.7.2.1

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

* [PATCH 3/4] OMAP3: remove OPP interfaces from OMAP PM layer
  2010-09-15 21:56 ` Kevin Hilman
@ 2010-09-15 21:56   ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-omap; +Cc: linux-arm-kernel

With new OPP layer, OPP users will access OPP API directly instead of
using OMAP PM layer, so remove all notions of OPPs from the OMAP PM
layer.

Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/io.c                  |    3 +-
 arch/arm/plat-omap/include/plat/omap-pm.h |   31 +++++++++-------------------
 arch/arm/plat-omap/omap-pm-noop.c         |   11 +---------
 3 files changed, 12 insertions(+), 33 deletions(-)

diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index b9ea70b..c09bf10 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -323,8 +323,7 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
 		omap2430_hwmod_init();
 	else if (cpu_is_omap34xx())
 		omap3xxx_hwmod_init();
-	/* The OPP tables have to be registered before a clk init */
-	omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps);
+	omap_pm_if_early_init();
 
 	if (cpu_is_omap2420())
 		omap2420_clk_init();
diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 728fbb9..c5b533d 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -19,24 +19,7 @@
 #include <linux/clk.h>
 
 #include "powerdomain.h"
-
-/**
- * struct omap_opp - clock frequency-to-OPP ID table for DSP, MPU
- * @rate: target clock rate
- * @opp_id: OPP ID
- * @min_vdd: minimum VDD1 voltage (in millivolts) for this OPP
- *
- * Operating performance point data.  Can vary by OMAP chip and board.
- */
-struct omap_opp {
-	unsigned long rate;
-	u8 opp_id;
-	u16 min_vdd;
-};
-
-extern struct omap_opp *mpu_opps;
-extern struct omap_opp *dsp_opps;
-extern struct omap_opp *l3_opps;
+#include <plat/opp.h>
 
 /*
  * agent_id values for use with omap_pm_set_min_bus_tput():
@@ -59,9 +42,11 @@ extern struct omap_opp *l3_opps;
  * framework starts.  The "_if_" is to avoid name collisions with the
  * PM idle-loop code.
  */
-int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table,
-				 struct omap_opp *dsp_opp_table,
-				 struct omap_opp *l3_opp_table);
+#ifdef CONFIG_OMAP_PM_NONE
+#define omap_pm_if_early_init() 0
+#else
+int __init omap_pm_if_early_init(void);
+#endif
 
 /**
  * omap_pm_if_init - OMAP PM init code called after clock fw init
@@ -69,7 +54,11 @@ int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table,
  * The main initialization code.  OPP tables are passed in here.  The
  * "_if_" is to avoid name collisions with the PM idle-loop code.
  */
+#ifdef CONFIG_OMAP_PM_NONE
+#define omap_pm_if_init() 0
+#else
 int __init omap_pm_if_init(void);
+#endif
 
 /**
  * omap_pm_if_exit - OMAP PM exit code
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index e129ce8..ca75abb 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -26,10 +26,6 @@
 
 #include <plat/powerdomain.h>
 
-struct omap_opp *dsp_opps;
-struct omap_opp *mpu_opps;
-struct omap_opp *l3_opps;
-
 /*
  * Device-driver-originated constraints (via board-*.c files)
  */
@@ -308,13 +304,8 @@ int omap_pm_get_dev_context_loss_count(struct device *dev)
 
 
 /* Should be called before clk framework init */
-int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table,
-				 struct omap_opp *dsp_opp_table,
-				 struct omap_opp *l3_opp_table)
+int __init omap_pm_if_early_init(void)
 {
-	mpu_opps = mpu_opp_table;
-	dsp_opps = dsp_opp_table;
-	l3_opps = l3_opp_table;
 	return 0;
 }
 
-- 
1.7.2.1


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

* [PATCH 3/4] OMAP3: remove OPP interfaces from OMAP PM layer
@ 2010-09-15 21:56   ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

With new OPP layer, OPP users will access OPP API directly instead of
using OMAP PM layer, so remove all notions of OPPs from the OMAP PM
layer.

Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/io.c                  |    3 +-
 arch/arm/plat-omap/include/plat/omap-pm.h |   31 +++++++++-------------------
 arch/arm/plat-omap/omap-pm-noop.c         |   11 +---------
 3 files changed, 12 insertions(+), 33 deletions(-)

diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index b9ea70b..c09bf10 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -323,8 +323,7 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
 		omap2430_hwmod_init();
 	else if (cpu_is_omap34xx())
 		omap3xxx_hwmod_init();
-	/* The OPP tables have to be registered before a clk init */
-	omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps);
+	omap_pm_if_early_init();
 
 	if (cpu_is_omap2420())
 		omap2420_clk_init();
diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 728fbb9..c5b533d 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -19,24 +19,7 @@
 #include <linux/clk.h>
 
 #include "powerdomain.h"
-
-/**
- * struct omap_opp - clock frequency-to-OPP ID table for DSP, MPU
- * @rate: target clock rate
- * @opp_id: OPP ID
- * @min_vdd: minimum VDD1 voltage (in millivolts) for this OPP
- *
- * Operating performance point data.  Can vary by OMAP chip and board.
- */
-struct omap_opp {
-	unsigned long rate;
-	u8 opp_id;
-	u16 min_vdd;
-};
-
-extern struct omap_opp *mpu_opps;
-extern struct omap_opp *dsp_opps;
-extern struct omap_opp *l3_opps;
+#include <plat/opp.h>
 
 /*
  * agent_id values for use with omap_pm_set_min_bus_tput():
@@ -59,9 +42,11 @@ extern struct omap_opp *l3_opps;
  * framework starts.  The "_if_" is to avoid name collisions with the
  * PM idle-loop code.
  */
-int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table,
-				 struct omap_opp *dsp_opp_table,
-				 struct omap_opp *l3_opp_table);
+#ifdef CONFIG_OMAP_PM_NONE
+#define omap_pm_if_early_init() 0
+#else
+int __init omap_pm_if_early_init(void);
+#endif
 
 /**
  * omap_pm_if_init - OMAP PM init code called after clock fw init
@@ -69,7 +54,11 @@ int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table,
  * The main initialization code.  OPP tables are passed in here.  The
  * "_if_" is to avoid name collisions with the PM idle-loop code.
  */
+#ifdef CONFIG_OMAP_PM_NONE
+#define omap_pm_if_init() 0
+#else
 int __init omap_pm_if_init(void);
+#endif
 
 /**
  * omap_pm_if_exit - OMAP PM exit code
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index e129ce8..ca75abb 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -26,10 +26,6 @@
 
 #include <plat/powerdomain.h>
 
-struct omap_opp *dsp_opps;
-struct omap_opp *mpu_opps;
-struct omap_opp *l3_opps;
-
 /*
  * Device-driver-originated constraints (via board-*.c files)
  */
@@ -308,13 +304,8 @@ int omap_pm_get_dev_context_loss_count(struct device *dev)
 
 
 /* Should be called before clk framework init */
-int __init omap_pm_if_early_init(struct omap_opp *mpu_opp_table,
-				 struct omap_opp *dsp_opp_table,
-				 struct omap_opp *l3_opp_table)
+int __init omap_pm_if_early_init(void)
 {
-	mpu_opps = mpu_opp_table;
-	dsp_opps = dsp_opp_table;
-	l3_opps = l3_opp_table;
 	return 0;
 }
 
-- 
1.7.2.1

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

* [PATCH 4/4] OMAP3: OPP: add OPP table data and initialization
  2010-09-15 21:56 ` Kevin Hilman
@ 2010-09-15 21:56   ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-omap; +Cc: linux-arm-kernel

From: Nishanth Menon <nm@ti.com>

Add OPP data for OMAP34xx and OMAP36xx and initialization functions
to populate OPP tables based on current SoC.

Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/Makefile       |    2 +
 arch/arm/mach-omap2/opp3xxx_data.c |  126 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.c           |    6 ++
 arch/arm/mach-omap2/pm.h           |    1 +
 4 files changed, 135 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/opp3xxx_data.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 88d3a1e..33acca9 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -57,6 +57,8 @@ obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
 
+obj-$(CONFIG_ARCH_OMAP3)		+= opp3xxx_data.o
+
 endif
 
 # PRCM
diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
new file mode 100644
index 0000000..df0bfa0
--- /dev/null
+++ b/arch/arm/mach-omap2/opp3xxx_data.c
@@ -0,0 +1,126 @@
+/*
+ * OMAP3 resource init/change_level/validate_level functions
+ *
+ * Copyright (C) 2009 - 2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ * Copyright (C) 2009 - 2010 Deep Root Systems, LLC.
+ *	Kevin Hilman
+ * Copyright (C) 2010 Nokia Corporation.
+ *      Eduardo Valentin
+ *
+ * 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * History:
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <plat/opp.h>
+#include <plat/cpu.h>
+
+static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
+	/* MPU OPP1 */
+	OMAP_OPP_DEF("mpu", true, 125000000, 975000),
+	/* MPU OPP2 */
+	OMAP_OPP_DEF("mpu", true, 250000000, 1075000),
+	/* MPU OPP3 */
+	OMAP_OPP_DEF("mpu", true, 500000000, 1200000),
+	/* MPU OPP4 */
+	OMAP_OPP_DEF("mpu", true, 550000000, 1270000),
+	/* MPU OPP5 */
+	OMAP_OPP_DEF("mpu", true, 600000000, 1350000),
+
+	/*
+	 * L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is
+	 * almost the same than the one at 83MHz thus providing very little
+	 * gain for the power point of view. In term of energy it will even
+	 * increase the consumption due to the very negative performance
+	 * impact that frequency will do to the MPU and the whole system in
+	 * general.
+	 */
+	OMAP_OPP_DEF("l3_main", false, 41500000, 975000),
+	/* L3 OPP2 */
+	OMAP_OPP_DEF("l3_main", true, 83000000, 1050000),
+	/* L3 OPP3 */
+	OMAP_OPP_DEF("l3_main", true, 166000000, 1150000),
+
+
+	/* DSP OPP1 */
+	OMAP_OPP_DEF("iva", true, 90000000, 975000),
+	/* DSP OPP2 */
+	OMAP_OPP_DEF("iva", true, 180000000, 1075000),
+	/* DSP OPP3 */
+	OMAP_OPP_DEF("iva", true, 360000000, 1200000),
+	/* DSP OPP4 */
+	OMAP_OPP_DEF("iva", true, 400000000, 1270000),
+	/* DSP OPP5 */
+	OMAP_OPP_DEF("iva", true, 430000000, 1350000),
+};
+static u32 omap34xx_opp_def_size = ARRAY_SIZE(omap34xx_opp_def_list);
+
+static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
+	/* MPU OPP1 - OPP50 */
+	OMAP_OPP_DEF("mpu", true,  300000000, 930000),
+	/* MPU OPP2 - OPP100 */
+	OMAP_OPP_DEF("mpu", true,  600000000, 1100000),
+	/* MPU OPP3 - OPP-Turbo */
+	OMAP_OPP_DEF("mpu", false, 800000000, 1260000),
+	/* MPU OPP4 - OPP-SB */
+	OMAP_OPP_DEF("mpu", false, 1000000000, 1350000),
+
+	/* L3 OPP1 - OPP50 */
+	OMAP_OPP_DEF("l3_main", true, 100000000, 930000),
+	/* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */
+	OMAP_OPP_DEF("l3_main", true, 200000000, 1137500),
+
+	/* DSP OPP1 - OPP50 */
+	OMAP_OPP_DEF("iva", true,  260000000, 930000),
+	/* DSP OPP2 - OPP100 */
+	OMAP_OPP_DEF("iva", true,  520000000, 1100000),
+	/* DSP OPP3 - OPP-Turbo */
+	OMAP_OPP_DEF("iva", false, 660000000, 1260000),
+	/* DSP OPP4 - OPP-SB */
+	OMAP_OPP_DEF("iva", false, 800000000, 1350000),
+};
+static u32 omap36xx_opp_def_size = ARRAY_SIZE(omap36xx_opp_def_list);
+
+/* Temp variable to allow multiple calls */
+static u8 __initdata omap3_table_init;
+
+int __init omap3_pm_init_opp_table(void)
+{
+	struct omap_opp_def *opp_def, *omap3_opp_def_list;
+	u32 omap3_opp_def_size;
+	int i, r;
+
+	/*
+	 * Allow multiple calls, but initialize only if not already initalized
+	 * even if the previous call failed, coz, no reason we'd succeed again
+	 */
+	if (omap3_table_init)
+		return 0;
+	omap3_table_init = 1;
+
+	omap3_opp_def_list = cpu_is_omap3630() ? omap36xx_opp_def_list :
+		omap34xx_opp_def_list;
+	omap3_opp_def_size = cpu_is_omap3630() ? omap36xx_opp_def_size :
+		omap34xx_opp_def_size;
+
+	opp_def = omap3_opp_def_list;
+	for (i = 0; i < omap3_opp_def_size; i++) {
+		r = opp_add(opp_def++);
+		if (r)
+			pr_err("unable to add OPP %ld Hz for %s\n",
+			       opp_def->freq, opp_def->hwmod_name);
+	}
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 68f9f2e..4ea59df 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -18,6 +18,8 @@
 #include <plat/omap_device.h>
 #include <plat/common.h>
 
+#include "pm.h"
+
 static struct omap_device_pm_latency *pm_lats;
 
 static struct device *mpu_dev;
@@ -76,6 +78,10 @@ static void omap2_init_processor_devices(void)
 static int __init omap2_common_pm_init(void)
 {
 	omap2_init_processor_devices();
+
+	if (cpu_is_omap34xx())
+		omap3_pm_init_opp_table();
+
 	omap_pm_if_init();
 
 	return 0;
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 3de6ece..9c9f943 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -22,6 +22,7 @@ extern void omap_sram_idle(void);
 extern int omap3_can_sleep(void);
 extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
+extern int omap3_pm_init_opp_table(void);
 
 struct cpuidle_params {
 	u8  valid;
-- 
1.7.2.1


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

* [PATCH 4/4] OMAP3: OPP: add OPP table data and initialization
@ 2010-09-15 21:56   ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-15 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Nishanth Menon <nm@ti.com>

Add OPP data for OMAP34xx and OMAP36xx and initialization functions
to populate OPP tables based on current SoC.

Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
 arch/arm/mach-omap2/Makefile       |    2 +
 arch/arm/mach-omap2/opp3xxx_data.c |  126 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.c           |    6 ++
 arch/arm/mach-omap2/pm.h           |    1 +
 4 files changed, 135 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-omap2/opp3xxx_data.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 88d3a1e..33acca9 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -57,6 +57,8 @@ obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
 
+obj-$(CONFIG_ARCH_OMAP3)		+= opp3xxx_data.o
+
 endif
 
 # PRCM
diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
new file mode 100644
index 0000000..df0bfa0
--- /dev/null
+++ b/arch/arm/mach-omap2/opp3xxx_data.c
@@ -0,0 +1,126 @@
+/*
+ * OMAP3 resource init/change_level/validate_level functions
+ *
+ * Copyright (C) 2009 - 2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ * Copyright (C) 2009 - 2010 Deep Root Systems, LLC.
+ *	Kevin Hilman
+ * Copyright (C) 2010 Nokia Corporation.
+ *      Eduardo Valentin
+ *
+ * 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.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * History:
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <plat/opp.h>
+#include <plat/cpu.h>
+
+static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
+	/* MPU OPP1 */
+	OMAP_OPP_DEF("mpu", true, 125000000, 975000),
+	/* MPU OPP2 */
+	OMAP_OPP_DEF("mpu", true, 250000000, 1075000),
+	/* MPU OPP3 */
+	OMAP_OPP_DEF("mpu", true, 500000000, 1200000),
+	/* MPU OPP4 */
+	OMAP_OPP_DEF("mpu", true, 550000000, 1270000),
+	/* MPU OPP5 */
+	OMAP_OPP_DEF("mpu", true, 600000000, 1350000),
+
+	/*
+	 * L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is
+	 * almost the same than the one at 83MHz thus providing very little
+	 * gain for the power point of view. In term of energy it will even
+	 * increase the consumption due to the very negative performance
+	 * impact that frequency will do to the MPU and the whole system in
+	 * general.
+	 */
+	OMAP_OPP_DEF("l3_main", false, 41500000, 975000),
+	/* L3 OPP2 */
+	OMAP_OPP_DEF("l3_main", true, 83000000, 1050000),
+	/* L3 OPP3 */
+	OMAP_OPP_DEF("l3_main", true, 166000000, 1150000),
+
+
+	/* DSP OPP1 */
+	OMAP_OPP_DEF("iva", true, 90000000, 975000),
+	/* DSP OPP2 */
+	OMAP_OPP_DEF("iva", true, 180000000, 1075000),
+	/* DSP OPP3 */
+	OMAP_OPP_DEF("iva", true, 360000000, 1200000),
+	/* DSP OPP4 */
+	OMAP_OPP_DEF("iva", true, 400000000, 1270000),
+	/* DSP OPP5 */
+	OMAP_OPP_DEF("iva", true, 430000000, 1350000),
+};
+static u32 omap34xx_opp_def_size = ARRAY_SIZE(omap34xx_opp_def_list);
+
+static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
+	/* MPU OPP1 - OPP50 */
+	OMAP_OPP_DEF("mpu", true,  300000000, 930000),
+	/* MPU OPP2 - OPP100 */
+	OMAP_OPP_DEF("mpu", true,  600000000, 1100000),
+	/* MPU OPP3 - OPP-Turbo */
+	OMAP_OPP_DEF("mpu", false, 800000000, 1260000),
+	/* MPU OPP4 - OPP-SB */
+	OMAP_OPP_DEF("mpu", false, 1000000000, 1350000),
+
+	/* L3 OPP1 - OPP50 */
+	OMAP_OPP_DEF("l3_main", true, 100000000, 930000),
+	/* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */
+	OMAP_OPP_DEF("l3_main", true, 200000000, 1137500),
+
+	/* DSP OPP1 - OPP50 */
+	OMAP_OPP_DEF("iva", true,  260000000, 930000),
+	/* DSP OPP2 - OPP100 */
+	OMAP_OPP_DEF("iva", true,  520000000, 1100000),
+	/* DSP OPP3 - OPP-Turbo */
+	OMAP_OPP_DEF("iva", false, 660000000, 1260000),
+	/* DSP OPP4 - OPP-SB */
+	OMAP_OPP_DEF("iva", false, 800000000, 1350000),
+};
+static u32 omap36xx_opp_def_size = ARRAY_SIZE(omap36xx_opp_def_list);
+
+/* Temp variable to allow multiple calls */
+static u8 __initdata omap3_table_init;
+
+int __init omap3_pm_init_opp_table(void)
+{
+	struct omap_opp_def *opp_def, *omap3_opp_def_list;
+	u32 omap3_opp_def_size;
+	int i, r;
+
+	/*
+	 * Allow multiple calls, but initialize only if not already initalized
+	 * even if the previous call failed, coz, no reason we'd succeed again
+	 */
+	if (omap3_table_init)
+		return 0;
+	omap3_table_init = 1;
+
+	omap3_opp_def_list = cpu_is_omap3630() ? omap36xx_opp_def_list :
+		omap34xx_opp_def_list;
+	omap3_opp_def_size = cpu_is_omap3630() ? omap36xx_opp_def_size :
+		omap34xx_opp_def_size;
+
+	opp_def = omap3_opp_def_list;
+	for (i = 0; i < omap3_opp_def_size; i++) {
+		r = opp_add(opp_def++);
+		if (r)
+			pr_err("unable to add OPP %ld Hz for %s\n",
+			       opp_def->freq, opp_def->hwmod_name);
+	}
+
+	return 0;
+}
+
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 68f9f2e..4ea59df 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -18,6 +18,8 @@
 #include <plat/omap_device.h>
 #include <plat/common.h>
 
+#include "pm.h"
+
 static struct omap_device_pm_latency *pm_lats;
 
 static struct device *mpu_dev;
@@ -76,6 +78,10 @@ static void omap2_init_processor_devices(void)
 static int __init omap2_common_pm_init(void)
 {
 	omap2_init_processor_devices();
+
+	if (cpu_is_omap34xx())
+		omap3_pm_init_opp_table();
+
 	omap_pm_if_init();
 
 	return 0;
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 3de6ece..9c9f943 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -22,6 +22,7 @@ extern void omap_sram_idle(void);
 extern int omap3_can_sleep(void);
 extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
+extern int omap3_pm_init_opp_table(void);
 
 struct cpuidle_params {
 	u8  valid;
-- 
1.7.2.1

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

* RE: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-15 21:56   ` Kevin Hilman
@ 2010-09-16 10:25     ` Gopinath, Thara
  -1 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 10:25 UTC (permalink / raw)
  To: Kevin Hilman, linux-omap; +Cc: linux-arm-kernel



>>-----Original Message-----
>>From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Kevin
>>Hilman
>>Sent: Thursday, September 16, 2010 3:27 AM
>>To: linux-omap@vger.kernel.org
>>Cc: linux-arm-kernel@lists.infradead.org
>>Subject: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
>>
>>From: Nishanth Menon <nm@ti.com>
>>
>>OMAP SOCs have a standard set of tuples consisting of frequency and
>>voltage pairs that the device will support per voltage domain.  These
>>are called Operating Performance Points or OPPs. The actual
>>definitions of OMAP Operating Points varies over silicon within the
>>same family of devices. For a specific domain, you can have a set of
>>{frequency, voltage} pairs. As the kernel boots and more information
>>is available, a set of these are activated based on the precise nature
>>of device the kernel boots up on. It is interesting to remember that
>>each IP which belongs to a voltage domain may define their own set of
>>OPPs on top of this.
>>
>>This introduces a common handling OPP mechanism accross all OMAPs.
>>As a start this is used for OMAP3.
>>
>>Note: OPP is a concept that can be used in all OMAPs, it is hence
>>introduced under plat-omap
>>
>>Contributions include:
>>Sanjeev Premi for the initial concept:
>>	http://patchwork.kernel.org/patch/50998/
>>Kevin Hilman for converting original design to device-based
>>Kevin Hilman and Paul Walmsey for cleaning up many of the function
>>abstractions, improvements and data structure handling
>>Romit Dasgupta for using enums instead of opp pointers
>>Thara Gopinath, Eduardo Valentin and Vishwanath BS for fixes and
>>cleanups.
>>
>>Discussions and comments from:
>>http://marc.info/?l=linux-omap&m=126033945313269&w=2
>>http://marc.info/?l=linux-omap&m=125482970102327&w=2
>>http://marc.info/?t=125809247500002&r=1&w=2
>>http://marc.info/?l=linux-omap&m=126025973426007&w=2
>>incorporated.
>>
>>Cc: Benoit Cousson <b-cousson@ti.com>
>>Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
>>Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
>>Cc: Roberto Granados Dorado <x0095451@ti.com>
>>Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com>
>>Cc: Tero Kristo <Tero.Kristo@nokia.com>
>>Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
>>Cc: Paul Walmsley <paul@pwsan.com>
>>Cc: Romit Dasgupta <romit@ti.com>
>>Cc: Sanjeev Premi <premi@ti.com>
>>Cc: Thara Gopinath <thara@ti.com>
>>Cc: Vishwanath BS <vishwanath.bs@ti.com>
>>Signed-off-by: Nishanth Menon <nm@ti.com>
>>Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
>>---
>> Documentation/arm/OMAP/omap_pm        |   83 ++++++
>> arch/arm/plat-omap/Makefile           |    5 +
>> arch/arm/plat-omap/include/plat/opp.h |  145 +++++++++++
>> arch/arm/plat-omap/opp.c              |  461 +++++++++++++++++++++++++++++++++
>> 4 files changed, 694 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/plat-omap/include/plat/opp.h
>> create mode 100644 arch/arm/plat-omap/opp.c
>>
>>diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
>>index 5389440..6527cdf 100644
>>--- a/Documentation/arm/OMAP/omap_pm
>>+++ b/Documentation/arm/OMAP/omap_pm
>>@@ -127,3 +127,86 @@ implementation needs:
>> 10. (*pdata->cpu_set_freq)(unsigned long f)
>>
>> 11. (*pdata->cpu_get_freq)(void)
>>+
>>+OMAP OPP Layer
>>+==============
>>+OMAP SOCs have a standard set of tuples consisting of frequency and
>>+voltage pairs that the device will support per voltage domain. This
>>+is called Operating Performance Point or OPP. The actual definitions
>>+of OMAP OPP varies over silicon within the same family of devices.
>>+For a specific domain, you can have a set of {frequency, voltage}
>>+pairs. As the kernel boots and more information is available, a set
>>+of these are activated based on the precise nature of device the kernel
>>+boots up on. It is interesting to remember that each IP which belongs
>>+to a voltage domain may define their own set of OPPs on top of this.
>>+
>>+OPP layer of its own depends on silicon specific implementation and
>>+board specific data to finalize on the final set of OPPs available
>>+in a system
>>+
>>+Initial list initialization:
>>+---------------------------
>>+The normal initialization sequence is for boardxyz_init_irq to call
>>+omap2_init_common_hw (for omap2+) and which in turn does the default
>>+setup required.
>>+
>>+Silicon specific initialization: First the OPP layer needs to be told
>>+to initialize the tables for OMAP3, there are two options here:
>>+a) If the desire is to use the default tables defined for that silicon,
>>+the board file does not need to call any initialization function, the
>>+defaults are setup as part of initialization flow when
>>+omap2_init_common_hw is called.
>>+
>>+b) board files would like to customize the default definition. In this
>>+case, board file needs to call explicitly prior to table operations.
>>+the sequence is:
>>+boardxyz_init_irq()
>>+{
>>+	... do things ..
>>+	omap3_pm_init_opp_table()
>>+	.. customizations and other things ..
>>+	omap2_init_common_hw()
>>+}
>>+1. omap3_pm_init_opp_table - this in turn calls opp_init_list for all
>>+OPP types. This is the generic silicon operating points, however, the
>>+system may have additional features or customizations required. This
>>+flexibility is provided by the following apis:
>>+
>>+Query functions:
>>+----------------
>>+Search for OPPs for various cases:
>>+2. opp_find_freq_exact - exact search function
>>+3. opp_find_freq_floor - round_up search function
>>+4. opp_find_freq_ceil - round_down search function
>>+
>>+OPP modifier functions:
>>+----------------------
>>+This allows opp layer users to add customized OPPs or change the table
>>+for any need they may have
>>+5. opp_add - add a new OPP - NOTE: use struct omap_opp_def and define
>>+the custom OPP with OMAP_OPP_DEF for usage.
>>+6. opp_enable - enable a disabled OPP
>>+7. opp_disable - disable an enabled OPP
>>+
>>+OPP Data retrieval functions:
>>+----------------------------
>>+The following sets of functions are useful for drivers to retrieve
>>+data stored in opp layer for various functions.
>>+8. opp_get_voltage - retrieve voltage for an opp
>>+9. opp_get_freq - get the frequency for an opp
>>+10. opp_get_opp_count - get number of opps enabled for a domain
>>+
>>+Cpufreq table generation:
>>+------------------------
>>+11. opp_init_cpufreq_table - this translates the OPP layer's internal
>>+OPP arrangement into a table understood and operated upon by the
>>+cpufreq layer.
>>+
>>+Data Structures:
>>+---------------
>>+struct omap_opp * is a handle structure whose internals are known only
>>+to the OPP layer and is meant to hide the complexity away from users of
>>+opp layer.
>>+
>>+struct omap_opp_def * is the definitions that users can interface with
>>+opp layer and is meant to define one OPP.
>>diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
>>index 9405831..c718a0a 100644
>>--- a/arch/arm/plat-omap/Makefile
>>+++ b/arch/arm/plat-omap/Makefile
>>@@ -12,6 +12,11 @@ obj-  :=
>> # OCPI interconnect support for 1710, 1610 and 5912
>> obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
>>
>>+# OPP support in (OMAP3+ only at the moment)
>>+ifdef CONFIG_PM
>>+obj-$(CONFIG_ARCH_OMAP3) += opp.o
>>+endif
>>+
>> # omap_device support (OMAP2+ only at the moment)
>> obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
>> obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
>>diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
>>new file mode 100644
>>index 0000000..997b56e
>>--- /dev/null
>>+++ b/arch/arm/plat-omap/include/plat/opp.h
>>@@ -0,0 +1,145 @@
>>+/*
>>+ * OMAP OPP Interface
>>+ *
>>+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
>>+ *	Nishanth Menon
>>+ *	Romit Dasgupta <romit@ti.com>
>>+ * Copyright (C) 2009 Deep Root Systems, LLC.
>>+ *	Kevin Hilman
>>+ *
>>+ * 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_OPP_H
>>+#define __ASM_ARM_OMAP_OPP_H
>>+
>>+#include <linux/err.h>
>>+#include <linux/cpufreq.h>
>>+
>>+#include <plat/common.h>
>>+
>>+/**
>>+ * struct omap_opp_def - OMAP OPP Definition
>>+ * @hwmod_name:	Name of the hwmod for this domain
>>+ * @freq:	Frequency in hertz corresponding to this OPP
>>+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
>>+ * @enabled:	True/false - is this OPP enabled/disabled by default
>>+ *
>>+ * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
>>+ * pairs that the device will support per voltage domain. This is called
>>+ * Operating Points or OPP. The actual definitions of OMAP Operating Points
>>+ * varies over silicon within the same family of devices. For a specific
>>+ * domain, you can have a set of {frequency, voltage} pairs and this is denoted
>>+ * by an array of omap_opp_def. As the kernel boots and more information is
>>+ * available, a set of these are activated based on the precise nature of
>>+ * device the kernel boots up on. It is interesting to remember that each IP
>>+ * which belongs to a voltage domain may define their own set of OPPs on top
>>+ * of this - but this is handled by the appropriate driver.
>>+ */
>>+struct omap_opp_def {
>>+	char *hwmod_name;
>>+
>>+	unsigned long freq;
>>+	unsigned long u_volt;
>>+
>>+	bool enabled;
>>+};
>>+
>>+/*
>>+ * Initialization wrapper used to define an OPP.
>>+ * To point at the end of a terminator of a list of OPPs,
>>+ * use OMAP_OPP_DEF(NULL, 0, 0, 0)
>>+ */
>>+#define OMAP_OPP_DEF(_hwmod_name, _enabled, _freq, _uv)	\
>>+{						\
>>+	.hwmod_name	= _hwmod_name,		\
>>+	.enabled	= _enabled,		\
>>+	.freq		= _freq,		\
>>+	.u_volt		= _uv,			\
>>+}
>>+
>>+struct omap_opp;
>>+
>>+#ifdef CONFIG_PM
>>+
>>+unsigned long opp_get_voltage(const struct omap_opp *opp);
>>+
>>+unsigned long opp_get_freq(const struct omap_opp *opp);
>>+
>>+int opp_get_opp_count(struct device *dev);
>>+
>>+struct omap_opp *opp_find_freq_exact(struct device *dev,
>>+				     unsigned long freq, bool enabled);
>>+
>>+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
>>+
>>+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
>>+
>>+int opp_add(const struct omap_opp_def *opp_def);
>>+
>>+int opp_enable(struct omap_opp *opp);
>>+
>>+int opp_disable(struct omap_opp *opp);
>>+
>>+void opp_init_cpufreq_table(struct device *dev,
>>+			    struct cpufreq_frequency_table **table);
>>+#else

Hello Kevin,

IN case of CONFIG_PM not being defined the else part will cause a compilation break as
the signature of these APIs defined in the else part do not match with the signature in
the if part.

>>+static inline unsigned long opp_get_voltage(const struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline unsigned long opp_get_freq(const struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline int opp_get_opp_count(struct omap_opp *oppl)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
>>+						   unsigned long freq,
>>+						   bool enabled)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
>>+						   unsigned long *freq)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl,
>>+						  unsigned long *freq)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline struct omap_opp *opp_add(struct omap_opp *oppl,
>>+				       const struct omap_opp_def *opp_def)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline int opp_enable(struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline int opp_disable(struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline
>>+void opp_init_cpufreq_table(struct omap_opp *opps,
>>+			    struct cpufreq_frequency_table **table)
>>+{
>>+}
>>+
>>+#endif		/* CONFIG_PM */
>>+#endif		/* __ASM_ARM_OMAP_OPP_H */

<snip>

Regards
Thara

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 10:25     ` Gopinath, Thara
  0 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 10:25 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-owner at vger.kernel.org] On Behalf Of Kevin
>>Hilman
>>Sent: Thursday, September 16, 2010 3:27 AM
>>To: linux-omap at vger.kernel.org
>>Cc: linux-arm-kernel at lists.infradead.org
>>Subject: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
>>
>>From: Nishanth Menon <nm@ti.com>
>>
>>OMAP SOCs have a standard set of tuples consisting of frequency and
>>voltage pairs that the device will support per voltage domain.  These
>>are called Operating Performance Points or OPPs. The actual
>>definitions of OMAP Operating Points varies over silicon within the
>>same family of devices. For a specific domain, you can have a set of
>>{frequency, voltage} pairs. As the kernel boots and more information
>>is available, a set of these are activated based on the precise nature
>>of device the kernel boots up on. It is interesting to remember that
>>each IP which belongs to a voltage domain may define their own set of
>>OPPs on top of this.
>>
>>This introduces a common handling OPP mechanism accross all OMAPs.
>>As a start this is used for OMAP3.
>>
>>Note: OPP is a concept that can be used in all OMAPs, it is hence
>>introduced under plat-omap
>>
>>Contributions include:
>>Sanjeev Premi for the initial concept:
>>	http://patchwork.kernel.org/patch/50998/
>>Kevin Hilman for converting original design to device-based
>>Kevin Hilman and Paul Walmsey for cleaning up many of the function
>>abstractions, improvements and data structure handling
>>Romit Dasgupta for using enums instead of opp pointers
>>Thara Gopinath, Eduardo Valentin and Vishwanath BS for fixes and
>>cleanups.
>>
>>Discussions and comments from:
>>http://marc.info/?l=linux-omap&m=126033945313269&w=2
>>http://marc.info/?l=linux-omap&m=125482970102327&w=2
>>http://marc.info/?t=125809247500002&r=1&w=2
>>http://marc.info/?l=linux-omap&m=126025973426007&w=2
>>incorporated.
>>
>>Cc: Benoit Cousson <b-cousson@ti.com>
>>Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
>>Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
>>Cc: Roberto Granados Dorado <x0095451@ti.com>
>>Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com>
>>Cc: Tero Kristo <Tero.Kristo@nokia.com>
>>Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
>>Cc: Paul Walmsley <paul@pwsan.com>
>>Cc: Romit Dasgupta <romit@ti.com>
>>Cc: Sanjeev Premi <premi@ti.com>
>>Cc: Thara Gopinath <thara@ti.com>
>>Cc: Vishwanath BS <vishwanath.bs@ti.com>
>>Signed-off-by: Nishanth Menon <nm@ti.com>
>>Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
>>---
>> Documentation/arm/OMAP/omap_pm        |   83 ++++++
>> arch/arm/plat-omap/Makefile           |    5 +
>> arch/arm/plat-omap/include/plat/opp.h |  145 +++++++++++
>> arch/arm/plat-omap/opp.c              |  461 +++++++++++++++++++++++++++++++++
>> 4 files changed, 694 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/plat-omap/include/plat/opp.h
>> create mode 100644 arch/arm/plat-omap/opp.c
>>
>>diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
>>index 5389440..6527cdf 100644
>>--- a/Documentation/arm/OMAP/omap_pm
>>+++ b/Documentation/arm/OMAP/omap_pm
>>@@ -127,3 +127,86 @@ implementation needs:
>> 10. (*pdata->cpu_set_freq)(unsigned long f)
>>
>> 11. (*pdata->cpu_get_freq)(void)
>>+
>>+OMAP OPP Layer
>>+==============
>>+OMAP SOCs have a standard set of tuples consisting of frequency and
>>+voltage pairs that the device will support per voltage domain. This
>>+is called Operating Performance Point or OPP. The actual definitions
>>+of OMAP OPP varies over silicon within the same family of devices.
>>+For a specific domain, you can have a set of {frequency, voltage}
>>+pairs. As the kernel boots and more information is available, a set
>>+of these are activated based on the precise nature of device the kernel
>>+boots up on. It is interesting to remember that each IP which belongs
>>+to a voltage domain may define their own set of OPPs on top of this.
>>+
>>+OPP layer of its own depends on silicon specific implementation and
>>+board specific data to finalize on the final set of OPPs available
>>+in a system
>>+
>>+Initial list initialization:
>>+---------------------------
>>+The normal initialization sequence is for boardxyz_init_irq to call
>>+omap2_init_common_hw (for omap2+) and which in turn does the default
>>+setup required.
>>+
>>+Silicon specific initialization: First the OPP layer needs to be told
>>+to initialize the tables for OMAP3, there are two options here:
>>+a) If the desire is to use the default tables defined for that silicon,
>>+the board file does not need to call any initialization function, the
>>+defaults are setup as part of initialization flow when
>>+omap2_init_common_hw is called.
>>+
>>+b) board files would like to customize the default definition. In this
>>+case, board file needs to call explicitly prior to table operations.
>>+the sequence is:
>>+boardxyz_init_irq()
>>+{
>>+	... do things ..
>>+	omap3_pm_init_opp_table()
>>+	.. customizations and other things ..
>>+	omap2_init_common_hw()
>>+}
>>+1. omap3_pm_init_opp_table - this in turn calls opp_init_list for all
>>+OPP types. This is the generic silicon operating points, however, the
>>+system may have additional features or customizations required. This
>>+flexibility is provided by the following apis:
>>+
>>+Query functions:
>>+----------------
>>+Search for OPPs for various cases:
>>+2. opp_find_freq_exact - exact search function
>>+3. opp_find_freq_floor - round_up search function
>>+4. opp_find_freq_ceil - round_down search function
>>+
>>+OPP modifier functions:
>>+----------------------
>>+This allows opp layer users to add customized OPPs or change the table
>>+for any need they may have
>>+5. opp_add - add a new OPP - NOTE: use struct omap_opp_def and define
>>+the custom OPP with OMAP_OPP_DEF for usage.
>>+6. opp_enable - enable a disabled OPP
>>+7. opp_disable - disable an enabled OPP
>>+
>>+OPP Data retrieval functions:
>>+----------------------------
>>+The following sets of functions are useful for drivers to retrieve
>>+data stored in opp layer for various functions.
>>+8. opp_get_voltage - retrieve voltage for an opp
>>+9. opp_get_freq - get the frequency for an opp
>>+10. opp_get_opp_count - get number of opps enabled for a domain
>>+
>>+Cpufreq table generation:
>>+------------------------
>>+11. opp_init_cpufreq_table - this translates the OPP layer's internal
>>+OPP arrangement into a table understood and operated upon by the
>>+cpufreq layer.
>>+
>>+Data Structures:
>>+---------------
>>+struct omap_opp * is a handle structure whose internals are known only
>>+to the OPP layer and is meant to hide the complexity away from users of
>>+opp layer.
>>+
>>+struct omap_opp_def * is the definitions that users can interface with
>>+opp layer and is meant to define one OPP.
>>diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
>>index 9405831..c718a0a 100644
>>--- a/arch/arm/plat-omap/Makefile
>>+++ b/arch/arm/plat-omap/Makefile
>>@@ -12,6 +12,11 @@ obj-  :=
>> # OCPI interconnect support for 1710, 1610 and 5912
>> obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
>>
>>+# OPP support in (OMAP3+ only at the moment)
>>+ifdef CONFIG_PM
>>+obj-$(CONFIG_ARCH_OMAP3) += opp.o
>>+endif
>>+
>> # omap_device support (OMAP2+ only at the moment)
>> obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
>> obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
>>diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
>>new file mode 100644
>>index 0000000..997b56e
>>--- /dev/null
>>+++ b/arch/arm/plat-omap/include/plat/opp.h
>>@@ -0,0 +1,145 @@
>>+/*
>>+ * OMAP OPP Interface
>>+ *
>>+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
>>+ *	Nishanth Menon
>>+ *	Romit Dasgupta <romit@ti.com>
>>+ * Copyright (C) 2009 Deep Root Systems, LLC.
>>+ *	Kevin Hilman
>>+ *
>>+ * 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_OPP_H
>>+#define __ASM_ARM_OMAP_OPP_H
>>+
>>+#include <linux/err.h>
>>+#include <linux/cpufreq.h>
>>+
>>+#include <plat/common.h>
>>+
>>+/**
>>+ * struct omap_opp_def - OMAP OPP Definition
>>+ * @hwmod_name:	Name of the hwmod for this domain
>>+ * @freq:	Frequency in hertz corresponding to this OPP
>>+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
>>+ * @enabled:	True/false - is this OPP enabled/disabled by default
>>+ *
>>+ * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
>>+ * pairs that the device will support per voltage domain. This is called
>>+ * Operating Points or OPP. The actual definitions of OMAP Operating Points
>>+ * varies over silicon within the same family of devices. For a specific
>>+ * domain, you can have a set of {frequency, voltage} pairs and this is denoted
>>+ * by an array of omap_opp_def. As the kernel boots and more information is
>>+ * available, a set of these are activated based on the precise nature of
>>+ * device the kernel boots up on. It is interesting to remember that each IP
>>+ * which belongs to a voltage domain may define their own set of OPPs on top
>>+ * of this - but this is handled by the appropriate driver.
>>+ */
>>+struct omap_opp_def {
>>+	char *hwmod_name;
>>+
>>+	unsigned long freq;
>>+	unsigned long u_volt;
>>+
>>+	bool enabled;
>>+};
>>+
>>+/*
>>+ * Initialization wrapper used to define an OPP.
>>+ * To point at the end of a terminator of a list of OPPs,
>>+ * use OMAP_OPP_DEF(NULL, 0, 0, 0)
>>+ */
>>+#define OMAP_OPP_DEF(_hwmod_name, _enabled, _freq, _uv)	\
>>+{						\
>>+	.hwmod_name	= _hwmod_name,		\
>>+	.enabled	= _enabled,		\
>>+	.freq		= _freq,		\
>>+	.u_volt		= _uv,			\
>>+}
>>+
>>+struct omap_opp;
>>+
>>+#ifdef CONFIG_PM
>>+
>>+unsigned long opp_get_voltage(const struct omap_opp *opp);
>>+
>>+unsigned long opp_get_freq(const struct omap_opp *opp);
>>+
>>+int opp_get_opp_count(struct device *dev);
>>+
>>+struct omap_opp *opp_find_freq_exact(struct device *dev,
>>+				     unsigned long freq, bool enabled);
>>+
>>+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
>>+
>>+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
>>+
>>+int opp_add(const struct omap_opp_def *opp_def);
>>+
>>+int opp_enable(struct omap_opp *opp);
>>+
>>+int opp_disable(struct omap_opp *opp);
>>+
>>+void opp_init_cpufreq_table(struct device *dev,
>>+			    struct cpufreq_frequency_table **table);
>>+#else

Hello Kevin,

IN case of CONFIG_PM not being defined the else part will cause a compilation break as
the signature of these APIs defined in the else part do not match with the signature in
the if part.

>>+static inline unsigned long opp_get_voltage(const struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline unsigned long opp_get_freq(const struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline int opp_get_opp_count(struct omap_opp *oppl)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
>>+						   unsigned long freq,
>>+						   bool enabled)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
>>+						   unsigned long *freq)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl,
>>+						  unsigned long *freq)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline struct omap_opp *opp_add(struct omap_opp *oppl,
>>+				       const struct omap_opp_def *opp_def)
>>+{
>>+	return ERR_PTR(-EINVAL);
>>+}
>>+
>>+static inline int opp_enable(struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline int opp_disable(struct omap_opp *opp)
>>+{
>>+	return 0;
>>+}
>>+
>>+static inline
>>+void opp_init_cpufreq_table(struct omap_opp *opps,
>>+			    struct cpufreq_frequency_table **table)
>>+{
>>+}
>>+
>>+#endif		/* CONFIG_PM */
>>+#endif		/* __ASM_ARM_OMAP_OPP_H */

<snip>

Regards
Thara

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

* RE: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 10:25     ` Gopinath, Thara
@ 2010-09-16 10:32       ` Menon, Nishanth
  -1 siblings, 0 replies; 62+ messages in thread
From: Menon, Nishanth @ 2010-09-16 10:32 UTC (permalink / raw)
  To: Gopinath, Thara, Kevin Hilman, linux-omap; +Cc: linux-arm-kernel

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Gopinath, Thara

[...]
> >>diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-
> omap/include/plat/opp.h
> >>new file mode 100644
> >>index 0000000..997b56e
> >>--- /dev/null
> >>+++ b/arch/arm/plat-omap/include/plat/opp.h
[..]
> >>+
> >>+#ifdef CONFIG_PM
> >>+
[..]
> >>+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long
> *freq);
> >>+
> >>+int opp_add(const struct omap_opp_def *opp_def);
> >>+
> >>+int opp_enable(struct omap_opp *opp);
> >>+
> >>+int opp_disable(struct omap_opp *opp);
> >>+
> >>+void opp_init_cpufreq_table(struct device *dev,
> >>+			    struct cpufreq_frequency_table **table);
> >>+#else
> 
> Hello Kevin,
> 
> IN case of CONFIG_PM not being defined the else part will cause a
> compilation break as
> the signature of these APIs defined in the else part do not match with the
> signature in
> the if part.
> 
Thanks for the catch. Will send a patch for this.
Regards,
Nishanth Menon

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 10:32       ` Menon, Nishanth
  0 siblings, 0 replies; 62+ messages in thread
From: Menon, Nishanth @ 2010-09-16 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
> owner at vger.kernel.org] On Behalf Of Gopinath, Thara

[...]
> >>diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-
> omap/include/plat/opp.h
> >>new file mode 100644
> >>index 0000000..997b56e
> >>--- /dev/null
> >>+++ b/arch/arm/plat-omap/include/plat/opp.h
[..]
> >>+
> >>+#ifdef CONFIG_PM
> >>+
[..]
> >>+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long
> *freq);
> >>+
> >>+int opp_add(const struct omap_opp_def *opp_def);
> >>+
> >>+int opp_enable(struct omap_opp *opp);
> >>+
> >>+int opp_disable(struct omap_opp *opp);
> >>+
> >>+void opp_init_cpufreq_table(struct device *dev,
> >>+			    struct cpufreq_frequency_table **table);
> >>+#else
> 
> Hello Kevin,
> 
> IN case of CONFIG_PM not being defined the else part will cause a
> compilation break as
> the signature of these APIs defined in the else part do not match with the
> signature in
> the if part.
> 
Thanks for the catch. Will send a patch for this.
Regards,
Nishanth Menon

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

* RE: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 10:32       ` Menon, Nishanth
@ 2010-09-16 10:33         ` Gopinath, Thara
  -1 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 10:33 UTC (permalink / raw)
  To: Menon, Nishanth, Kevin Hilman, linux-omap; +Cc: linux-arm-kernel



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, September 16, 2010 4:02 PM
>>To: Gopinath, Thara; Kevin Hilman; linux-omap@vger.kernel.org
>>Cc: linux-arm-kernel@lists.infradead.org
>>Subject: RE: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
>>
>>> -----Original Message-----
>>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>>> owner@vger.kernel.org] On Behalf Of Gopinath, Thara
>>
>>[...]
>>> >>diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-
>>> omap/include/plat/opp.h
>>> >>new file mode 100644
>>> >>index 0000000..997b56e
>>> >>--- /dev/null
>>> >>+++ b/arch/arm/plat-omap/include/plat/opp.h
>>[..]
>>> >>+
>>> >>+#ifdef CONFIG_PM
>>> >>+
>>[..]
>>> >>+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long
>>> *freq);
>>> >>+
>>> >>+int opp_add(const struct omap_opp_def *opp_def);
>>> >>+
>>> >>+int opp_enable(struct omap_opp *opp);
>>> >>+
>>> >>+int opp_disable(struct omap_opp *opp);
>>> >>+
>>> >>+void opp_init_cpufreq_table(struct device *dev,
>>> >>+			    struct cpufreq_frequency_table **table);
>>> >>+#else
>>>
>>> Hello Kevin,
>>>
>>> IN case of CONFIG_PM not being defined the else part will cause a
>>> compilation break as
>>> the signature of these APIs defined in the else part do not match with the
>>> signature in
>>> the if part.
>>>
>>Thanks for the catch. Will send a patch for this.

I learnt this the hard way by actually hitting the issue :-)!!

Regards
Thara

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 10:33         ` Gopinath, Thara
  0 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 10:33 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, September 16, 2010 4:02 PM
>>To: Gopinath, Thara; Kevin Hilman; linux-omap at vger.kernel.org
>>Cc: linux-arm-kernel at lists.infradead.org
>>Subject: RE: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
>>
>>> -----Original Message-----
>>> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
>>> owner at vger.kernel.org] On Behalf Of Gopinath, Thara
>>
>>[...]
>>> >>diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-
>>> omap/include/plat/opp.h
>>> >>new file mode 100644
>>> >>index 0000000..997b56e
>>> >>--- /dev/null
>>> >>+++ b/arch/arm/plat-omap/include/plat/opp.h
>>[..]
>>> >>+
>>> >>+#ifdef CONFIG_PM
>>> >>+
>>[..]
>>> >>+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long
>>> *freq);
>>> >>+
>>> >>+int opp_add(const struct omap_opp_def *opp_def);
>>> >>+
>>> >>+int opp_enable(struct omap_opp *opp);
>>> >>+
>>> >>+int opp_disable(struct omap_opp *opp);
>>> >>+
>>> >>+void opp_init_cpufreq_table(struct device *dev,
>>> >>+			    struct cpufreq_frequency_table **table);
>>> >>+#else
>>>
>>> Hello Kevin,
>>>
>>> IN case of CONFIG_PM not being defined the else part will cause a
>>> compilation break as
>>> the signature of these APIs defined in the else part do not match with the
>>> signature in
>>> the if part.
>>>
>>Thanks for the catch. Will send a patch for this.

I learnt this the hard way by actually hitting the issue :-)!!

Regards
Thara

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

* RE: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-15 21:56   ` Kevin Hilman
@ 2010-09-16 10:40     ` Gopinath, Thara
  -1 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 10:40 UTC (permalink / raw)
  To: Kevin Hilman, linux-omap; +Cc: linux-arm-kernel



>>-----Original Message-----
>>From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Kevin
>>Hilman
>>Sent: Thursday, September 16, 2010 3:27 AM
>>To: linux-omap@vger.kernel.org
>>Cc: linux-arm-kernel@lists.infradead.org
>>Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>From: Paul Walmsley <paul@pwsan.com>
>>
>>The OPP layer code should be independent of the PMIC,
>>introduce the TWL/TPS-specific code out to its own file.

Hello Kevin,

I have been using this code for a while now. I really do not think wee need a separate
file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
layer is interested in these conversions. Voltage layer has a structure that can be populated with
the information required from the PMIC. We only need to add two more function pointers to this structure. This info can then be passed from the actual PMIC driver file. This will make it much
more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel. So please consider dropping this patch from this series.

Regards
Thara

>>
>>Signed-off-by: Paul Walmsley <paul@pwsan.com>
>>Signed-off-by: Romit Dasgupta <romit@ti.com>
>>Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
>>Signed-off-by: Nishanth Menon <nm@ti.com>
>>Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
>>---
>> arch/arm/plat-omap/Makefile                   |    1 +
>> arch/arm/plat-omap/include/plat/opp_twl_tps.h |   21 +++++++++++++
>> arch/arm/plat-omap/opp_twl_tps.c              |   41 +++++++++++++++++++++++++
>> 3 files changed, 63 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/plat-omap/include/plat/opp_twl_tps.h
>> create mode 100644 arch/arm/plat-omap/opp_twl_tps.c
>>
>>diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
>>index c718a0a..a88879c 100644
>>--- a/arch/arm/plat-omap/Makefile
>>+++ b/arch/arm/plat-omap/Makefile
>>@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
>> # OPP support in (OMAP3+ only at the moment)
>> ifdef CONFIG_PM
>> obj-$(CONFIG_ARCH_OMAP3) += opp.o
>>+obj-$(CONFIG_TWL4030_CORE) += opp_twl_tps.o
>> endif
>>
>> # omap_device support (OMAP2+ only at the moment)
>>diff --git a/arch/arm/plat-omap/include/plat/opp_twl_tps.h b/arch/arm/plat-
>>omap/include/plat/opp_twl_tps.h
>>new file mode 100644
>>index 0000000..8784e5f
>>--- /dev/null
>>+++ b/arch/arm/plat-omap/include/plat/opp_twl_tps.h
>>@@ -0,0 +1,21 @@
>>+/*
>>+ * opp_twl_tps.h - TWL/TPS-specific headers for the OPP code
>>+ *
>>+ * Copyright (C) 2009 Texas Instruments Incorporated.
>>+ *	Nishanth Menon
>>+ *
>>+ * 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.
>>+ *
>>+ * XXX This code belongs as part of some other TWL/TPS code.
>>+ */
>>+#ifndef _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
>>+#define _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
>>+
>>+#include <linux/kernel.h>
>>+
>>+unsigned long omap_twl_vsel_to_uv(const u8 vsel);
>>+u8 omap_twl_uv_to_vsel(unsigned long uV);
>>+
>>+#endif
>>diff --git a/arch/arm/plat-omap/opp_twl_tps.c b/arch/arm/plat-omap/opp_twl_tps.c
>>new file mode 100644
>>index 0000000..112f106
>>--- /dev/null
>>+++ b/arch/arm/plat-omap/opp_twl_tps.c
>>@@ -0,0 +1,41 @@
>>+/*
>>+ * opp_twl_tps.c - TWL/TPS-specific functions for the OPP code
>>+ *
>>+ * Copyright (C) 2009 Texas Instruments Incorporated.
>>+ * Nishanth Menon
>>+ * Copyright (C) 2009 Nokia Corporation
>>+ * Paul Walmsley
>>+ *
>>+ * This program is free software; you can redistribute it and/or modify
>>+ * it under the terms of the GNU General Public License version 2 as
>>+ * published by the Free Software Foundation.
>>+ *
>>+ * XXX This code should be part of some other TWL/TPS code.
>>+ */
>>+
>>+#include <plat/opp_twl_tps.h>
>>+
>>+/**
>>+ * omap_twl_vsel_to_vdc - convert TWL/TPS VSEL value to microvolts DC
>>+ * @vsel: TWL/TPS VSEL value to convert
>>+ *
>>+ * Returns the microvolts DC that the TWL/TPS family of PMICs should
>>+ * generate when programmed with @vsel.
>>+ */
>>+unsigned long omap_twl_vsel_to_uv(const u8 vsel)
>>+{
>>+	return (((vsel * 125) + 6000)) * 100;
>>+}
>>+
>>+/**
>>+ * omap_twl_uv_to_vsel - convert microvolts DC to TWL/TPS VSEL value
>>+ * @uv: microvolts DC to convert
>>+ *
>>+ * Returns the VSEL value necessary for the TWL/TPS family of PMICs to
>>+ * generate an output voltage equal to or greater than @uv microvolts DC.
>>+ */
>>+u8 omap_twl_uv_to_vsel(unsigned long uv)
>>+{
>>+	/* Round up to higher voltage */
>>+	return DIV_ROUND_UP(uv - 600000, 12500);
>>+}
>>--
>>1.7.2.1
>>
>>--
>>To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>>the body of a message to majordomo@vger.kernel.org
>>More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-16 10:40     ` Gopinath, Thara
  0 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 10:40 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-owner at vger.kernel.org] On Behalf Of Kevin
>>Hilman
>>Sent: Thursday, September 16, 2010 3:27 AM
>>To: linux-omap at vger.kernel.org
>>Cc: linux-arm-kernel at lists.infradead.org
>>Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>From: Paul Walmsley <paul@pwsan.com>
>>
>>The OPP layer code should be independent of the PMIC,
>>introduce the TWL/TPS-specific code out to its own file.

Hello Kevin,

I have been using this code for a while now. I really do not think wee need a separate
file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
layer is interested in these conversions. Voltage layer has a structure that can be populated with
the information required from the PMIC. We only need to add two more function pointers to this structure. This info can then be passed from the actual PMIC driver file. This will make it much
more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel. So please consider dropping this patch from this series.

Regards
Thara

>>
>>Signed-off-by: Paul Walmsley <paul@pwsan.com>
>>Signed-off-by: Romit Dasgupta <romit@ti.com>
>>Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
>>Signed-off-by: Nishanth Menon <nm@ti.com>
>>Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
>>---
>> arch/arm/plat-omap/Makefile                   |    1 +
>> arch/arm/plat-omap/include/plat/opp_twl_tps.h |   21 +++++++++++++
>> arch/arm/plat-omap/opp_twl_tps.c              |   41 +++++++++++++++++++++++++
>> 3 files changed, 63 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/plat-omap/include/plat/opp_twl_tps.h
>> create mode 100644 arch/arm/plat-omap/opp_twl_tps.c
>>
>>diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
>>index c718a0a..a88879c 100644
>>--- a/arch/arm/plat-omap/Makefile
>>+++ b/arch/arm/plat-omap/Makefile
>>@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
>> # OPP support in (OMAP3+ only at the moment)
>> ifdef CONFIG_PM
>> obj-$(CONFIG_ARCH_OMAP3) += opp.o
>>+obj-$(CONFIG_TWL4030_CORE) += opp_twl_tps.o
>> endif
>>
>> # omap_device support (OMAP2+ only at the moment)
>>diff --git a/arch/arm/plat-omap/include/plat/opp_twl_tps.h b/arch/arm/plat-
>>omap/include/plat/opp_twl_tps.h
>>new file mode 100644
>>index 0000000..8784e5f
>>--- /dev/null
>>+++ b/arch/arm/plat-omap/include/plat/opp_twl_tps.h
>>@@ -0,0 +1,21 @@
>>+/*
>>+ * opp_twl_tps.h - TWL/TPS-specific headers for the OPP code
>>+ *
>>+ * Copyright (C) 2009 Texas Instruments Incorporated.
>>+ *	Nishanth Menon
>>+ *
>>+ * 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.
>>+ *
>>+ * XXX This code belongs as part of some other TWL/TPS code.
>>+ */
>>+#ifndef _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
>>+#define _ARCH_ARM_PLAT_OMAP_OPP_TWL_TPS_H
>>+
>>+#include <linux/kernel.h>
>>+
>>+unsigned long omap_twl_vsel_to_uv(const u8 vsel);
>>+u8 omap_twl_uv_to_vsel(unsigned long uV);
>>+
>>+#endif
>>diff --git a/arch/arm/plat-omap/opp_twl_tps.c b/arch/arm/plat-omap/opp_twl_tps.c
>>new file mode 100644
>>index 0000000..112f106
>>--- /dev/null
>>+++ b/arch/arm/plat-omap/opp_twl_tps.c
>>@@ -0,0 +1,41 @@
>>+/*
>>+ * opp_twl_tps.c - TWL/TPS-specific functions for the OPP code
>>+ *
>>+ * Copyright (C) 2009 Texas Instruments Incorporated.
>>+ * Nishanth Menon
>>+ * Copyright (C) 2009 Nokia Corporation
>>+ * Paul Walmsley
>>+ *
>>+ * This program is free software; you can redistribute it and/or modify
>>+ * it under the terms of the GNU General Public License version 2 as
>>+ * published by the Free Software Foundation.
>>+ *
>>+ * XXX This code should be part of some other TWL/TPS code.
>>+ */
>>+
>>+#include <plat/opp_twl_tps.h>
>>+
>>+/**
>>+ * omap_twl_vsel_to_vdc - convert TWL/TPS VSEL value to microvolts DC
>>+ * @vsel: TWL/TPS VSEL value to convert
>>+ *
>>+ * Returns the microvolts DC that the TWL/TPS family of PMICs should
>>+ * generate when programmed with @vsel.
>>+ */
>>+unsigned long omap_twl_vsel_to_uv(const u8 vsel)
>>+{
>>+	return (((vsel * 125) + 6000)) * 100;
>>+}
>>+
>>+/**
>>+ * omap_twl_uv_to_vsel - convert microvolts DC to TWL/TPS VSEL value
>>+ * @uv: microvolts DC to convert
>>+ *
>>+ * Returns the VSEL value necessary for the TWL/TPS family of PMICs to
>>+ * generate an output voltage equal to or greater than @uv microvolts DC.
>>+ */
>>+u8 omap_twl_uv_to_vsel(unsigned long uv)
>>+{
>>+	/* Round up to higher voltage */
>>+	return DIV_ROUND_UP(uv - 600000, 12500);
>>+}
>>--
>>1.7.2.1
>>
>>--
>>To unsubscribe from this list: send the line "unsubscribe linux-omap" in
>>the body of a message to majordomo at vger.kernel.org
>>More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-16 10:40     ` Gopinath, Thara
@ 2010-09-16 12:15       ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 12:15 UTC (permalink / raw)
  To: Gopinath, Thara; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
> 
>>> -----Original Message-----
>>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of Kevin
>>> Hilman
>>> Sent: Thursday, September 16, 2010 3:27 AM
>>> To: linux-omap@vger.kernel.org
>>> Cc: linux-arm-kernel@lists.infradead.org
>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>
>>> From: Paul Walmsley <paul@pwsan.com>
>>>
>>> The OPP layer code should be independent of the PMIC,
>>> introduce the TWL/TPS-specific code out to its own file.
> 
> Hello Kevin,
> 
> I have been using this code for a while now. I really do not think wee need a separate
> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
This split introduces a PMIC level abstraction already. Do you have a 
suggestion which file it should go to? It is definitely not part of 
opp.c, not part of other existing twl files as well. the job of this 
file was to introduce conversion routines which can be used by any layer 
(voltage layer if need be - it used to be srf and smartreflex before)..
in fact one of your voltage layer patches introduces capability for 6030 
as well
http://marc.info/?l=linux-omap&m=128213020927919&w=2

> layer is interested in these conversions. Voltage layer has a structure that can be populated with
> the information required from the PMIC. We only need to add two more function pointers to this structure.
 > This info can then be passed from the actual PMIC driver file. This 
will make it much
> more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
> in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel.
I think the problem is with the voltage layer (which has not been posted 
upstream) which is using hard coded function pointer. What the patchset 
should have done is to introduce function pointers registration from 
twl_tps.c to voltage layer and voltage layer should ideally been using 
function pointers by itself.

 > So please consider dropping this patch from this series.
I think I disagree - rationale for having this separated as a pmic 
specific file is still sound, only the implementation of the future 
framework should have changed (it should be using function pointers 
instead of hardcoded function names). in fact I can add additional 
suggestion for the voltage layer: the pmic selection should be done from 
a board file - This will allow voltage layer to handle numerous PMICs 
and combination of PMICs controlling various domains as well.. the only 
neat way to handle it is ofcourse using function pointers.


PS: Suggestion
- please fix your mailer to round off for 70/80 chars..
- might be good to point folks to rfc patchset for voltage layer to give 
context.

-- 
Regards,
Nishanth Menon

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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-16 12:15       ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 12:15 UTC (permalink / raw)
  To: linux-arm-kernel

Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
> 
>>> -----Original Message-----
>>> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-owner at vger.kernel.org] On Behalf Of Kevin
>>> Hilman
>>> Sent: Thursday, September 16, 2010 3:27 AM
>>> To: linux-omap at vger.kernel.org
>>> Cc: linux-arm-kernel at lists.infradead.org
>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>
>>> From: Paul Walmsley <paul@pwsan.com>
>>>
>>> The OPP layer code should be independent of the PMIC,
>>> introduce the TWL/TPS-specific code out to its own file.
> 
> Hello Kevin,
> 
> I have been using this code for a while now. I really do not think wee need a separate
> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
This split introduces a PMIC level abstraction already. Do you have a 
suggestion which file it should go to? It is definitely not part of 
opp.c, not part of other existing twl files as well. the job of this 
file was to introduce conversion routines which can be used by any layer 
(voltage layer if need be - it used to be srf and smartreflex before)..
in fact one of your voltage layer patches introduces capability for 6030 
as well
http://marc.info/?l=linux-omap&m=128213020927919&w=2

> layer is interested in these conversions. Voltage layer has a structure that can be populated with
> the information required from the PMIC. We only need to add two more function pointers to this structure.
 > This info can then be passed from the actual PMIC driver file. This 
will make it much
> more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
> in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel.
I think the problem is with the voltage layer (which has not been posted 
upstream) which is using hard coded function pointer. What the patchset 
should have done is to introduce function pointers registration from 
twl_tps.c to voltage layer and voltage layer should ideally been using 
function pointers by itself.

 > So please consider dropping this patch from this series.
I think I disagree - rationale for having this separated as a pmic 
specific file is still sound, only the implementation of the future 
framework should have changed (it should be using function pointers 
instead of hardcoded function names). in fact I can add additional 
suggestion for the voltage layer: the pmic selection should be done from 
a board file - This will allow voltage layer to handle numerous PMICs 
and combination of PMICs controlling various domains as well.. the only 
neat way to handle it is ofcourse using function pointers.


PS: Suggestion
- please fix your mailer to round off for 70/80 chars..
- might be good to point folks to rfc patchset for voltage layer to give 
context.

-- 
Regards,
Nishanth Menon

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-15 21:56   ` Kevin Hilman
@ 2010-09-16 12:19     ` Linus Walleij
  -1 siblings, 0 replies; 62+ messages in thread
From: Linus Walleij @ 2010-09-16 12:19 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, linux-arm-kernel

2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:

> OMAP SOCs have a standard set of tuples consisting of frequency and
> voltage pairs that the device will support per voltage domain.  These
> are called Operating Performance Points or OPPs.
> (...)
> This introduces a common handling OPP mechanism accross all OMAPs.
> As a start this is used for OMAP3.

OPPs are a generic concept, it's in silicon construction textbooks and all.
Should this code not be made generic instead? You wouldn't make
regulators or even DMA platform-specific these days, so why should
OPPs be?

What in this code is actually OMAP-specific, more than that you name
some functions omap_*, and how hard would it be to put it under
arch/arm/common/*.c
arch/arm/include/asm/*.h

Possible even higher up in the directory hiearchy in include/linux/opp.h
for the header and drivers/opp/*.c, because I think SuperH and power
are not that different in this respect.

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

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 12:19     ` Linus Walleij
  0 siblings, 0 replies; 62+ messages in thread
From: Linus Walleij @ 2010-09-16 12:19 UTC (permalink / raw)
  To: linux-arm-kernel

2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:

> OMAP SOCs have a standard set of tuples consisting of frequency and
> voltage pairs that the device will support per voltage domain. ?These
> are called Operating Performance Points or OPPs.
> (...)
> This introduces a common handling OPP mechanism accross all OMAPs.
> As a start this is used for OMAP3.

OPPs are a generic concept, it's in silicon construction textbooks and all.
Should this code not be made generic instead? You wouldn't make
regulators or even DMA platform-specific these days, so why should
OPPs be?

What in this code is actually OMAP-specific, more than that you name
some functions omap_*, and how hard would it be to put it under
arch/arm/common/*.c
arch/arm/include/asm/*.h

Possible even higher up in the directory hiearchy in include/linux/opp.h
for the header and drivers/opp/*.c, because I think SuperH and power
are not that different in this respect.

Yours,
Linus Walleij

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 12:19     ` Linus Walleij
@ 2010-09-16 12:40       ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 12:40 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

Linus Walleij had written, on 09/16/2010 07:19 AM, the following:
> 2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:
> 
>> OMAP SOCs have a standard set of tuples consisting of frequency and
>> voltage pairs that the device will support per voltage domain.  These
>> are called Operating Performance Points or OPPs.
>> (...)
>> This introduces a common handling OPP mechanism accross all OMAPs.
>> As a start this is used for OMAP3.
> 
> OPPs are a generic concept, it's in silicon construction textbooks and all.
> Should this code not be made generic instead? You wouldn't make
> regulators or even DMA platform-specific these days, so why should
> OPPs be?
As far as I see this patch :
hwmod[1] which is omap specific which inturn depends on omap_device. - 
this impacts opp_add function in the opp layer.

[1] http://marc.info/?l=linux-omap&m=128226580816341&w=2
-- 
Regards,
Nishanth Menon

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 12:40       ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

Linus Walleij had written, on 09/16/2010 07:19 AM, the following:
> 2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:
> 
>> OMAP SOCs have a standard set of tuples consisting of frequency and
>> voltage pairs that the device will support per voltage domain.  These
>> are called Operating Performance Points or OPPs.
>> (...)
>> This introduces a common handling OPP mechanism accross all OMAPs.
>> As a start this is used for OMAP3.
> 
> OPPs are a generic concept, it's in silicon construction textbooks and all.
> Should this code not be made generic instead? You wouldn't make
> regulators or even DMA platform-specific these days, so why should
> OPPs be?
As far as I see this patch :
hwmod[1] which is omap specific which inturn depends on omap_device. - 
this impacts opp_add function in the opp layer.

[1] http://marc.info/?l=linux-omap&m=128226580816341&w=2
-- 
Regards,
Nishanth Menon

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 12:40       ` Nishanth Menon
@ 2010-09-16 13:24         ` Linus Walleij
  -1 siblings, 0 replies; 62+ messages in thread
From: Linus Walleij @ 2010-09-16 13:24 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

Nishanth Menon wrote:
> Linus Walleij had written, on 09/16/2010 07:19 AM, the following:
>> 2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:
>>
>>> OMAP SOCs have a standard set of tuples consisting of frequency and
>>> voltage pairs that the device will support per voltage domain.  These
>>> are called Operating Performance Points or OPPs.
>>> (...)
>>> This introduces a common handling OPP mechanism accross all OMAPs.
>>> As a start this is used for OMAP3.
>> OPPs are a generic concept, it's in silicon construction textbooks and all.
>> Should this code not be made generic instead? You wouldn't make
>> regulators or even DMA platform-specific these days, so why should
>> OPPs be?
> As far as I see this patch :
> hwmod[1] which is omap specific which inturn depends on omap_device. - 
> this impacts opp_add function in the opp layer.

Then wrap your local OPP in some clever way:

struct omap_opp {
    struct hwmod foo;
    struct opp opp;
};

container_of() is your friend.

Alternatively and not as elegant is to provide an
void *private_data; in the generic opp struct.

And similar design patterns for code and other
platform-specific hooks. Overridable struct opp_ops
for example, the same way we just abstracted the
l2x0 operations for example.

It's not like there are no precedents in the linux kernel
on how to handle a superclass of some struct, so 
how hard can it be?

The fact that a single struct member is OMAP-specific doesn't
nix the fact that the major part of this OPP framework
is generic code.

Yours,
Linus Walleij

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 13:24         ` Linus Walleij
  0 siblings, 0 replies; 62+ messages in thread
From: Linus Walleij @ 2010-09-16 13:24 UTC (permalink / raw)
  To: linux-arm-kernel

Nishanth Menon wrote:
> Linus Walleij had written, on 09/16/2010 07:19 AM, the following:
>> 2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:
>>
>>> OMAP SOCs have a standard set of tuples consisting of frequency and
>>> voltage pairs that the device will support per voltage domain.  These
>>> are called Operating Performance Points or OPPs.
>>> (...)
>>> This introduces a common handling OPP mechanism accross all OMAPs.
>>> As a start this is used for OMAP3.
>> OPPs are a generic concept, it's in silicon construction textbooks and all.
>> Should this code not be made generic instead? You wouldn't make
>> regulators or even DMA platform-specific these days, so why should
>> OPPs be?
> As far as I see this patch :
> hwmod[1] which is omap specific which inturn depends on omap_device. - 
> this impacts opp_add function in the opp layer.

Then wrap your local OPP in some clever way:

struct omap_opp {
    struct hwmod foo;
    struct opp opp;
};

container_of() is your friend.

Alternatively and not as elegant is to provide an
void *private_data; in the generic opp struct.

And similar design patterns for code and other
platform-specific hooks. Overridable struct opp_ops
for example, the same way we just abstracted the
l2x0 operations for example.

It's not like there are no precedents in the linux kernel
on how to handle a superclass of some struct, so 
how hard can it be?

The fact that a single struct member is OMAP-specific doesn't
nix the fact that the major part of this OPP framework
is generic code.

Yours,
Linus Walleij

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

* RE: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-16 12:15       ` Nishanth Menon
@ 2010-09-16 13:51         ` Gopinath, Thara
  -1 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 13:51 UTC (permalink / raw)
  To: Menon, Nishanth; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, September 16, 2010 5:45 PM
>>To: Gopinath, Thara
>>Cc: Kevin Hilman; linux-omap@vger.kernel.org; linux-arm-kernel@lists.infradead.org
>>Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
>>>
>>>>> -----Original Message-----
>>>>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of
>>Kevin
>>>>> Hilman
>>>>> Sent: Thursday, September 16, 2010 3:27 AM
>>>>> To: linux-omap@vger.kernel.org
>>>>> Cc: linux-arm-kernel@lists.infradead.org
>>>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>
>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>
>>>>> The OPP layer code should be independent of the PMIC,
>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>
>>> Hello Kevin,
>>>
>>> I have been using this code for a while now. I really do not think wee need a separate
>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>This split introduces a PMIC level abstraction already. Do you have a
>>suggestion which file it should go to? It is definitely not part of
>>opp.c, not part of other existing twl files as well. the job of this
>>file was to introduce conversion routines which can be used by any layer
>>(voltage layer if need be - it used to be srf and smartreflex before)..
>>in fact one of your voltage layer patches introduces capability for 6030
>>as well
>>http://marc.info/?l=linux-omap&m=128213020927919&w=2

Yes one of my patches has introduces this coz I had no other way
to add OMAP4 support. But I still do not understand why cant these
APIs be implemented in twl-core.c or twl4030-power.c? 

>>
>>> layer is interested in these conversions. Voltage layer has a structure that can be populated with
>>> the information required from the PMIC. We only need to add two more function pointers to this
>>structure.
>> > This info can then be passed from the actual PMIC driver file. This
>>will make it much
>>> more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
>>> in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and
>>omap_twl_uv_to_vsel.
>>I think the problem is with the voltage layer (which has not been posted
>>upstream) which is using hard coded function pointer. What the patchset
>>should have done is to introduce function pointers registration from
>>twl_tps.c to voltage layer and voltage layer should ideally been using
>>function pointers by itself.
>>
>> > So please consider dropping this patch from this series.
>>I think I disagree - rationale for having this separated as a pmic
>>specific file is still sound, only the implementation of the future
>>framework should have changed (it should be using function pointers
>>instead of hardcoded function names). in fact I can add additional
>>suggestion for the voltage layer: the pmic selection should be done from
>>a board file - This will allow voltage layer to handle numerous PMICs
>>and combination of PMICs controlling various domains as well.. the only
>>neat way to handle it is ofcourse using function pointers.

Exactly if voltage layer has to use a func ptr, why not let them be populated
by the PMIC driver files directly?

>>
>>
>>PS: Suggestion
>>- please fix your mailer to round off for 70/80 char.

Will try.

>>- might be good to point folks to rfc patchset for voltage layer to give
>>context.

https://patchwork.kernel.org/patch/119429/

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

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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-16 13:51         ` Gopinath, Thara
  0 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-16 13:51 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, September 16, 2010 5:45 PM
>>To: Gopinath, Thara
>>Cc: Kevin Hilman; linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org
>>Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
>>>
>>>>> -----Original Message-----
>>>>> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-owner at vger.kernel.org] On Behalf Of
>>Kevin
>>>>> Hilman
>>>>> Sent: Thursday, September 16, 2010 3:27 AM
>>>>> To: linux-omap at vger.kernel.org
>>>>> Cc: linux-arm-kernel at lists.infradead.org
>>>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>
>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>
>>>>> The OPP layer code should be independent of the PMIC,
>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>
>>> Hello Kevin,
>>>
>>> I have been using this code for a while now. I really do not think wee need a separate
>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>This split introduces a PMIC level abstraction already. Do you have a
>>suggestion which file it should go to? It is definitely not part of
>>opp.c, not part of other existing twl files as well. the job of this
>>file was to introduce conversion routines which can be used by any layer
>>(voltage layer if need be - it used to be srf and smartreflex before)..
>>in fact one of your voltage layer patches introduces capability for 6030
>>as well
>>http://marc.info/?l=linux-omap&m=128213020927919&w=2

Yes one of my patches has introduces this coz I had no other way
to add OMAP4 support. But I still do not understand why cant these
APIs be implemented in twl-core.c or twl4030-power.c? 

>>
>>> layer is interested in these conversions. Voltage layer has a structure that can be populated with
>>> the information required from the PMIC. We only need to add two more function pointers to this
>>structure.
>> > This info can then be passed from the actual PMIC driver file. This
>>will make it much
>>> more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
>>> in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and
>>omap_twl_uv_to_vsel.
>>I think the problem is with the voltage layer (which has not been posted
>>upstream) which is using hard coded function pointer. What the patchset
>>should have done is to introduce function pointers registration from
>>twl_tps.c to voltage layer and voltage layer should ideally been using
>>function pointers by itself.
>>
>> > So please consider dropping this patch from this series.
>>I think I disagree - rationale for having this separated as a pmic
>>specific file is still sound, only the implementation of the future
>>framework should have changed (it should be using function pointers
>>instead of hardcoded function names). in fact I can add additional
>>suggestion for the voltage layer: the pmic selection should be done from
>>a board file - This will allow voltage layer to handle numerous PMICs
>>and combination of PMICs controlling various domains as well.. the only
>>neat way to handle it is ofcourse using function pointers.

Exactly if voltage layer has to use a func ptr, why not let them be populated
by the PMIC driver files directly?

>>
>>
>>PS: Suggestion
>>- please fix your mailer to round off for 70/80 char.

Will try.

>>- might be good to point folks to rfc patchset for voltage layer to give
>>context.

https://patchwork.kernel.org/patch/119429/

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

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-15 21:56   ` Kevin Hilman
@ 2010-09-16 13:54     ` Roger Quadros
  -1 siblings, 0 replies; 62+ messages in thread
From: Roger Quadros @ 2010-09-16 13:54 UTC (permalink / raw)
  To: nm; +Cc: ext Kevin Hilman, linux-omap, linux-arm-kernel

Nishant,

Since you are anyways re-sending this you might as well fix these nits.

On 09/16/2010 12:56 AM, ext Kevin Hilman wrote:
> From: Nishanth Menon<nm@ti.com>
>

> diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
> new file mode 100644
> index 0000000..17f93b2
> --- /dev/null
> +++ b/arch/arm/plat-omap/opp.c
> @@ -0,0 +1,461 @@
> +/*
> + * OMAP OPP Interface
> + *
> + * Copyright (C) 2009-2010 Texas Instruments Incorporated.
> + *     Nishanth Menon
> + *     Romit Dasgupta<romit@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +

> +/**
> + * opp_get_voltage() - Gets the voltage corresponding to an opp
> + * @opp:       opp for which voltage has to be returned for
> + *
> + * Return voltage in micro volt corresponding to the opp, else
> + * return 0
> + */
> +unsigned long opp_get_voltage(const struct omap_opp *opp)
> +{
> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {

If !opp->enabled, then is it really an invalid parameter being passed?

I'm not user if people need to know the voltage of a disabled OPP, but 
do we need to limit it?

> +               pr_err("%s: Invalid parameters being passed\n", __func__);
> +               return 0;
> +       }
> +
> +       return opp->u_volt;
> +}
> +
> +/**
> + * opp_get_freq() - Gets the frequency corresponding to an opp
> + * @opp:       opp for which frequency has to be returned for
> + *
> + * Return frequency in hertz corresponding to the opp, else
> + * return 0
> + */
> +unsigned long opp_get_freq(const struct omap_opp *opp)
> +{
> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {

ditto.

> +               pr_err("%s: Invalid parameters being passed\n", __func__);
> +               return 0;
> +       }
> +
> +       return opp->rate;
> +}
> +
> +/**
> + * opp_get_opp_count() - Get number of opps enabled in the opp list
> + * @opp_type:  OPP type we want to count
> + *
> + * This functions returns the number of opps if there are any OPPs enabled,
> + * else returns corresponding error value.
> + */
> +int opp_get_opp_count(struct device *dev)
> +{
> +       struct device_opp *dev_opp;
> +
> +       dev_opp = find_device_opp(dev);
> +       if (IS_ERR(dev_opp))
> +               return -ENODEV;
> +
> +       return dev_opp->enabled_opp_count;
> +}
> +
> +/**
> + * opp_find_freq_exact() - search for an exact frequency
> + * @opp_type:  OPP type we want to search in.
> + * @freq:      frequency to search for
> + * @enabled:   enabled/disabled OPP to search for
> + *
> + * Searches for exact match in the opp list and returns handle to the matching
> + * opp if found, else returns ERR_PTR in case of error and should be handled
> + * using IS_ERR.
> + *
> + * Note enabled is a modifier for the search. if enabled=true, then the match is

Good to add some punctuation after 'Note'.

> + * for exact matching frequency and is enabled. if false, the match is for exact
> + * frequency which is disabled.
> + */

cheers,
-roger

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 13:54     ` Roger Quadros
  0 siblings, 0 replies; 62+ messages in thread
From: Roger Quadros @ 2010-09-16 13:54 UTC (permalink / raw)
  To: linux-arm-kernel

Nishant,

Since you are anyways re-sending this you might as well fix these nits.

On 09/16/2010 12:56 AM, ext Kevin Hilman wrote:
> From: Nishanth Menon<nm@ti.com>
>

> diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
> new file mode 100644
> index 0000000..17f93b2
> --- /dev/null
> +++ b/arch/arm/plat-omap/opp.c
> @@ -0,0 +1,461 @@
> +/*
> + * OMAP OPP Interface
> + *
> + * Copyright (C) 2009-2010 Texas Instruments Incorporated.
> + *     Nishanth Menon
> + *     Romit Dasgupta<romit@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +

> +/**
> + * opp_get_voltage() - Gets the voltage corresponding to an opp
> + * @opp:       opp for which voltage has to be returned for
> + *
> + * Return voltage in micro volt corresponding to the opp, else
> + * return 0
> + */
> +unsigned long opp_get_voltage(const struct omap_opp *opp)
> +{
> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {

If !opp->enabled, then is it really an invalid parameter being passed?

I'm not user if people need to know the voltage of a disabled OPP, but 
do we need to limit it?

> +               pr_err("%s: Invalid parameters being passed\n", __func__);
> +               return 0;
> +       }
> +
> +       return opp->u_volt;
> +}
> +
> +/**
> + * opp_get_freq() - Gets the frequency corresponding to an opp
> + * @opp:       opp for which frequency has to be returned for
> + *
> + * Return frequency in hertz corresponding to the opp, else
> + * return 0
> + */
> +unsigned long opp_get_freq(const struct omap_opp *opp)
> +{
> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {

ditto.

> +               pr_err("%s: Invalid parameters being passed\n", __func__);
> +               return 0;
> +       }
> +
> +       return opp->rate;
> +}
> +
> +/**
> + * opp_get_opp_count() - Get number of opps enabled in the opp list
> + * @opp_type:  OPP type we want to count
> + *
> + * This functions returns the number of opps if there are any OPPs enabled,
> + * else returns corresponding error value.
> + */
> +int opp_get_opp_count(struct device *dev)
> +{
> +       struct device_opp *dev_opp;
> +
> +       dev_opp = find_device_opp(dev);
> +       if (IS_ERR(dev_opp))
> +               return -ENODEV;
> +
> +       return dev_opp->enabled_opp_count;
> +}
> +
> +/**
> + * opp_find_freq_exact() - search for an exact frequency
> + * @opp_type:  OPP type we want to search in.
> + * @freq:      frequency to search for
> + * @enabled:   enabled/disabled OPP to search for
> + *
> + * Searches for exact match in the opp list and returns handle to the matching
> + * opp if found, else returns ERR_PTR in case of error and should be handled
> + * using IS_ERR.
> + *
> + * Note enabled is a modifier for the search. if enabled=true, then the match is

Good to add some punctuation after 'Note'.

> + * for exact matching frequency and is enabled. if false, the match is for exact
> + * frequency which is disabled.
> + */

cheers,
-roger

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 13:54     ` Roger Quadros
@ 2010-09-16 14:01       ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 14:01 UTC (permalink / raw)
  To: Roger Quadros; +Cc: ext Kevin Hilman, linux-omap, linux-arm-kernel

Roger Quadros had written, on 09/16/2010 08:54 AM, the following:
> Since you are anyways re-sending this you might as well fix these nits.
thanks for reviewing..

> 
[..]

>> diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
>> new file mode 100644
>> index 0000000..17f93b2
>> --- /dev/null
>> +++ b/arch/arm/plat-omap/opp.c
>> @@ -0,0 +1,461 @@
>> +/*
>> + * OMAP OPP Interface
>> + *
>> + * Copyright (C) 2009-2010 Texas Instruments Incorporated.
>> + *     Nishanth Menon
>> + *     Romit Dasgupta<romit@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
> 
>> +/**
>> + * opp_get_voltage() - Gets the voltage corresponding to an opp
>> + * @opp:       opp for which voltage has to be returned for
>> + *
>> + * Return voltage in micro volt corresponding to the opp, else
>> + * return 0
>> + */
>> +unsigned long opp_get_voltage(const struct omap_opp *opp)
>> +{
>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
> 
> If !opp->enabled, then is it really an invalid parameter being passed?
> 
> I'm not user if people need to know the voltage of a disabled OPP, but 
> do we need to limit it?
> 
>> +               pr_err("%s: Invalid parameters being passed\n", __func__);
>> +               return 0;
>> +       }
>> +
>> +       return opp->u_volt;
>> +}
>> +
>> +/**
>> + * opp_get_freq() - Gets the frequency corresponding to an opp
>> + * @opp:       opp for which frequency has to be returned for
>> + *
>> + * Return frequency in hertz corresponding to the opp, else
>> + * return 0
>> + */
>> +unsigned long opp_get_freq(const struct omap_opp *opp)
>> +{
>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
> 
> ditto.

Yes, the intent here was for opp operational apis to function ONLY on 
the enabled opps - this helps to pull out any bugs in the users
who might be unintentionally using bad params.

do you have any usecase you can think of where we might want to use 
these on a disabled opp?

> 
>> +               pr_err("%s: Invalid parameters being passed\n", __func__);
>> +               return 0;
>> +       }
>> +
>> +       return opp->rate;
>> +}
>> +
>> +/**
>> + * opp_get_opp_count() - Get number of opps enabled in the opp list
>> + * @opp_type:  OPP type we want to count
>> + *
>> + * This functions returns the number of opps if there are any OPPs enabled,
>> + * else returns corresponding error value.
>> + */
>> +int opp_get_opp_count(struct device *dev)
>> +{
>> +       struct device_opp *dev_opp;
>> +
>> +       dev_opp = find_device_opp(dev);
>> +       if (IS_ERR(dev_opp))
>> +               return -ENODEV;
>> +
>> +       return dev_opp->enabled_opp_count;
>> +}
>> +
>> +/**
>> + * opp_find_freq_exact() - search for an exact frequency
>> + * @opp_type:  OPP type we want to search in.
>> + * @freq:      frequency to search for
>> + * @enabled:   enabled/disabled OPP to search for
>> + *
>> + * Searches for exact match in the opp list and returns handle to the matching
>> + * opp if found, else returns ERR_PTR in case of error and should be handled
>> + * using IS_ERR.
>> + *
>> + * Note enabled is a modifier for the search. if enabled=true, then the match is
> 
> Good to add some punctuation after 'Note'.

Thanks will do

> 
>> + * for exact matching frequency and is enabled. if false, the match is for exact
>> + * frequency which is disabled.
>> + */
> 
> cheers,
> -roger


-- 
Regards,
Nishanth Menon

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 14:01       ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 14:01 UTC (permalink / raw)
  To: linux-arm-kernel

Roger Quadros had written, on 09/16/2010 08:54 AM, the following:
> Since you are anyways re-sending this you might as well fix these nits.
thanks for reviewing..

> 
[..]

>> diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
>> new file mode 100644
>> index 0000000..17f93b2
>> --- /dev/null
>> +++ b/arch/arm/plat-omap/opp.c
>> @@ -0,0 +1,461 @@
>> +/*
>> + * OMAP OPP Interface
>> + *
>> + * Copyright (C) 2009-2010 Texas Instruments Incorporated.
>> + *     Nishanth Menon
>> + *     Romit Dasgupta<romit@ti.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
> 
>> +/**
>> + * opp_get_voltage() - Gets the voltage corresponding to an opp
>> + * @opp:       opp for which voltage has to be returned for
>> + *
>> + * Return voltage in micro volt corresponding to the opp, else
>> + * return 0
>> + */
>> +unsigned long opp_get_voltage(const struct omap_opp *opp)
>> +{
>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
> 
> If !opp->enabled, then is it really an invalid parameter being passed?
> 
> I'm not user if people need to know the voltage of a disabled OPP, but 
> do we need to limit it?
> 
>> +               pr_err("%s: Invalid parameters being passed\n", __func__);
>> +               return 0;
>> +       }
>> +
>> +       return opp->u_volt;
>> +}
>> +
>> +/**
>> + * opp_get_freq() - Gets the frequency corresponding to an opp
>> + * @opp:       opp for which frequency has to be returned for
>> + *
>> + * Return frequency in hertz corresponding to the opp, else
>> + * return 0
>> + */
>> +unsigned long opp_get_freq(const struct omap_opp *opp)
>> +{
>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
> 
> ditto.

Yes, the intent here was for opp operational apis to function ONLY on 
the enabled opps - this helps to pull out any bugs in the users
who might be unintentionally using bad params.

do you have any usecase you can think of where we might want to use 
these on a disabled opp?

> 
>> +               pr_err("%s: Invalid parameters being passed\n", __func__);
>> +               return 0;
>> +       }
>> +
>> +       return opp->rate;
>> +}
>> +
>> +/**
>> + * opp_get_opp_count() - Get number of opps enabled in the opp list
>> + * @opp_type:  OPP type we want to count
>> + *
>> + * This functions returns the number of opps if there are any OPPs enabled,
>> + * else returns corresponding error value.
>> + */
>> +int opp_get_opp_count(struct device *dev)
>> +{
>> +       struct device_opp *dev_opp;
>> +
>> +       dev_opp = find_device_opp(dev);
>> +       if (IS_ERR(dev_opp))
>> +               return -ENODEV;
>> +
>> +       return dev_opp->enabled_opp_count;
>> +}
>> +
>> +/**
>> + * opp_find_freq_exact() - search for an exact frequency
>> + * @opp_type:  OPP type we want to search in.
>> + * @freq:      frequency to search for
>> + * @enabled:   enabled/disabled OPP to search for
>> + *
>> + * Searches for exact match in the opp list and returns handle to the matching
>> + * opp if found, else returns ERR_PTR in case of error and should be handled
>> + * using IS_ERR.
>> + *
>> + * Note enabled is a modifier for the search. if enabled=true, then the match is
> 
> Good to add some punctuation after 'Note'.

Thanks will do

> 
>> + * for exact matching frequency and is enabled. if false, the match is for exact
>> + * frequency which is disabled.
>> + */
> 
> cheers,
> -roger


-- 
Regards,
Nishanth Menon

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

* Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-16 13:51         ` Gopinath, Thara
@ 2010-09-16 14:06           ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 14:06 UTC (permalink / raw)
  To: Gopinath, Thara; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

Gopinath, Thara had written, on 09/16/2010 08:51 AM, the following:
> 
>>> -----Original Message-----
>>> From: Menon, Nishanth
>>> Sent: Thursday, September 16, 2010 5:45 PM
>>> To: Gopinath, Thara
>>> Cc: Kevin Hilman; linux-omap@vger.kernel.org; linux-arm-kernel@lists.infradead.org
>>> Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>
>>> Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
>>>>>> -----Original Message-----
>>>>>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of
>>> Kevin
>>>>>> Hilman
>>>>>> Sent: Thursday, September 16, 2010 3:27 AM
>>>>>> To: linux-omap@vger.kernel.org
>>>>>> Cc: linux-arm-kernel@lists.infradead.org
>>>>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>>
>>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>>
>>>>>> The OPP layer code should be independent of the PMIC,
>>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>> Hello Kevin,
>>>>
>>>> I have been using this code for a while now. I really do not think wee need a separate
>>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>> This split introduces a PMIC level abstraction already. Do you have a
>>> suggestion which file it should go to? It is definitely not part of
>>> opp.c, not part of other existing twl files as well. the job of this
>>> file was to introduce conversion routines which can be used by any layer
>>> (voltage layer if need be - it used to be srf and smartreflex before)..
>>> in fact one of your voltage layer patches introduces capability for 6030
>>> as well
>>> http://marc.info/?l=linux-omap&m=128213020927919&w=2
> 
> Yes one of my patches has introduces this coz I had no other way
> to add OMAP4 support. But I still do not understand why cant these
> APIs be implemented in twl-core.c or twl4030-power.c? 
Why there? Twl power does regulator operations not conversion 
operations. core is not the place either as it is function independent.

> 
>>>> layer is interested in these conversions. Voltage layer has a structure that can be populated with
>>>> the information required from the PMIC. We only need to add two more function pointers to this
>>> structure.
>>>> This info can then be passed from the actual PMIC driver file. This
>>> will make it much
>>>> more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
>>>> in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and
>>> omap_twl_uv_to_vsel.
>>> I think the problem is with the voltage layer (which has not been posted
>>> upstream) which is using hard coded function pointer. What the patchset
>>> should have done is to introduce function pointers registration from
>>> twl_tps.c to voltage layer and voltage layer should ideally been using
>>> function pointers by itself.
>>>
>>>> So please consider dropping this patch from this series.
>>> I think I disagree - rationale for having this separated as a pmic
>>> specific file is still sound, only the implementation of the future
>>> framework should have changed (it should be using function pointers
>>> instead of hardcoded function names). in fact I can add additional
>>> suggestion for the voltage layer: the pmic selection should be done from
>>> a board file - This will allow voltage layer to handle numerous PMICs
>>> and combination of PMICs controlling various domains as well.. the only
>>> neat way to handle it is ofcourse using function pointers.
> 
> Exactly if voltage layer has to use a func ptr, why not let them be populated
> by the PMIC driver files directly?
Again, we are going into the details of how voltage layer will be 
implemented.. What suggestion do you do when on board x vdd1 is driven 
by PMIC1, vdd2 by PMIC2? it will have to be somesort of different 
registration mechanism. but nothing prevents the framework from 
registering the pointers defined in twl_tps.c



> 
>>>
>>> PS: Suggestion
>>> - please fix your mailer to round off for 70/80 char.
> 
> Will try.
> 
>>> - might be good to point folks to rfc patchset for voltage layer to give
>>> context.
> 
> https://patchwork.kernel.org/patch/119429/

thanks..

-- 
Regards,
Nishanth Menon

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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-16 14:06           ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 14:06 UTC (permalink / raw)
  To: linux-arm-kernel

Gopinath, Thara had written, on 09/16/2010 08:51 AM, the following:
> 
>>> -----Original Message-----
>>> From: Menon, Nishanth
>>> Sent: Thursday, September 16, 2010 5:45 PM
>>> To: Gopinath, Thara
>>> Cc: Kevin Hilman; linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org
>>> Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>
>>> Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
>>>>>> -----Original Message-----
>>>>>> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-owner at vger.kernel.org] On Behalf Of
>>> Kevin
>>>>>> Hilman
>>>>>> Sent: Thursday, September 16, 2010 3:27 AM
>>>>>> To: linux-omap at vger.kernel.org
>>>>>> Cc: linux-arm-kernel at lists.infradead.org
>>>>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>>
>>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>>
>>>>>> The OPP layer code should be independent of the PMIC,
>>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>> Hello Kevin,
>>>>
>>>> I have been using this code for a while now. I really do not think wee need a separate
>>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>> This split introduces a PMIC level abstraction already. Do you have a
>>> suggestion which file it should go to? It is definitely not part of
>>> opp.c, not part of other existing twl files as well. the job of this
>>> file was to introduce conversion routines which can be used by any layer
>>> (voltage layer if need be - it used to be srf and smartreflex before)..
>>> in fact one of your voltage layer patches introduces capability for 6030
>>> as well
>>> http://marc.info/?l=linux-omap&m=128213020927919&w=2
> 
> Yes one of my patches has introduces this coz I had no other way
> to add OMAP4 support. But I still do not understand why cant these
> APIs be implemented in twl-core.c or twl4030-power.c? 
Why there? Twl power does regulator operations not conversion 
operations. core is not the place either as it is function independent.

> 
>>>> layer is interested in these conversions. Voltage layer has a structure that can be populated with
>>>> the information required from the PMIC. We only need to add two more function pointers to this
>>> structure.
>>>> This info can then be passed from the actual PMIC driver file. This
>>> will make it much
>>>> more simpler for OMAP4 where we have different formulas between different revisions of PMIC. Also
>>>> in the omap voltage code we will no longer have to hard code omap_twl_vsel_to_uv and
>>> omap_twl_uv_to_vsel.
>>> I think the problem is with the voltage layer (which has not been posted
>>> upstream) which is using hard coded function pointer. What the patchset
>>> should have done is to introduce function pointers registration from
>>> twl_tps.c to voltage layer and voltage layer should ideally been using
>>> function pointers by itself.
>>>
>>>> So please consider dropping this patch from this series.
>>> I think I disagree - rationale for having this separated as a pmic
>>> specific file is still sound, only the implementation of the future
>>> framework should have changed (it should be using function pointers
>>> instead of hardcoded function names). in fact I can add additional
>>> suggestion for the voltage layer: the pmic selection should be done from
>>> a board file - This will allow voltage layer to handle numerous PMICs
>>> and combination of PMICs controlling various domains as well.. the only
>>> neat way to handle it is ofcourse using function pointers.
> 
> Exactly if voltage layer has to use a func ptr, why not let them be populated
> by the PMIC driver files directly?
Again, we are going into the details of how voltage layer will be 
implemented.. What suggestion do you do when on board x vdd1 is driven 
by PMIC1, vdd2 by PMIC2? it will have to be somesort of different 
registration mechanism. but nothing prevents the framework from 
registering the pointers defined in twl_tps.c



> 
>>>
>>> PS: Suggestion
>>> - please fix your mailer to round off for 70/80 char.
> 
> Will try.
> 
>>> - might be good to point folks to rfc patchset for voltage layer to give
>>> context.
> 
> https://patchwork.kernel.org/patch/119429/

thanks..

-- 
Regards,
Nishanth Menon

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 14:01       ` Nishanth Menon
@ 2010-09-16 14:20         ` Roger Quadros
  -1 siblings, 0 replies; 62+ messages in thread
From: Roger Quadros @ 2010-09-16 14:20 UTC (permalink / raw)
  To: ext Nishanth Menon; +Cc: ext Kevin Hilman, linux-omap, linux-arm-kernel

On 09/16/2010 05:01 PM, ext Nishanth Menon wrote:
> Roger Quadros had written, on 09/16/2010 08:54 AM, the following:
>> Since you are anyways re-sending this you might as well fix these nits.
> thanks for reviewing..
>
>>
> [..]
>
>>> diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
>>> new file mode 100644
>>> index 0000000..17f93b2
>>> --- /dev/null
>>> +++ b/arch/arm/plat-omap/opp.c
>>> @@ -0,0 +1,461 @@
>>> +/*
>>> + * OMAP OPP Interface
>>> + *
>>> + * Copyright (C) 2009-2010 Texas Instruments Incorporated.
>>> + *     Nishanth Menon
>>> + *     Romit Dasgupta<romit@ti.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>
>>> +/**
>>> + * opp_get_voltage() - Gets the voltage corresponding to an opp
>>> + * @opp:       opp for which voltage has to be returned for
>>> + *
>>> + * Return voltage in micro volt corresponding to the opp, else
>>> + * return 0
>>> + */
>>> +unsigned long opp_get_voltage(const struct omap_opp *opp)
>>> +{
>>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
>>
>> If !opp->enabled, then is it really an invalid parameter being passed?
>>
>> I'm not user if people need to know the voltage of a disabled OPP, but
>> do we need to limit it?
>>
>>> +               pr_err("%s: Invalid parameters being passed\n", __func__);
>>> +               return 0;
>>> +       }
>>> +
>>> +       return opp->u_volt;
>>> +}
>>> +
>>> +/**
>>> + * opp_get_freq() - Gets the frequency corresponding to an opp
>>> + * @opp:       opp for which frequency has to be returned for
>>> + *
>>> + * Return frequency in hertz corresponding to the opp, else
>>> + * return 0
>>> + */
>>> +unsigned long opp_get_freq(const struct omap_opp *opp)
>>> +{
>>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
>>
>> ditto.
>
> Yes, the intent here was for opp operational apis to function ONLY on
> the enabled opps - this helps to pull out any bugs in the users
> who might be unintentionally using bad params.
>
OK.

> do you have any usecase you can think of where we might want to use
> these on a disabled opp?

Not really. Based on what is an OPP enabled/disabled? Is it possible for 
an initially enabled OPP to be disabled at some point in time? What 
triggers this disable?
OR  does an OPP enabled at boot time remain enabled throughout the power 
session?

regards,
-roger

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 14:20         ` Roger Quadros
  0 siblings, 0 replies; 62+ messages in thread
From: Roger Quadros @ 2010-09-16 14:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/16/2010 05:01 PM, ext Nishanth Menon wrote:
> Roger Quadros had written, on 09/16/2010 08:54 AM, the following:
>> Since you are anyways re-sending this you might as well fix these nits.
> thanks for reviewing..
>
>>
> [..]
>
>>> diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
>>> new file mode 100644
>>> index 0000000..17f93b2
>>> --- /dev/null
>>> +++ b/arch/arm/plat-omap/opp.c
>>> @@ -0,0 +1,461 @@
>>> +/*
>>> + * OMAP OPP Interface
>>> + *
>>> + * Copyright (C) 2009-2010 Texas Instruments Incorporated.
>>> + *     Nishanth Menon
>>> + *     Romit Dasgupta<romit@ti.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>
>>> +/**
>>> + * opp_get_voltage() - Gets the voltage corresponding to an opp
>>> + * @opp:       opp for which voltage has to be returned for
>>> + *
>>> + * Return voltage in micro volt corresponding to the opp, else
>>> + * return 0
>>> + */
>>> +unsigned long opp_get_voltage(const struct omap_opp *opp)
>>> +{
>>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
>>
>> If !opp->enabled, then is it really an invalid parameter being passed?
>>
>> I'm not user if people need to know the voltage of a disabled OPP, but
>> do we need to limit it?
>>
>>> +               pr_err("%s: Invalid parameters being passed\n", __func__);
>>> +               return 0;
>>> +       }
>>> +
>>> +       return opp->u_volt;
>>> +}
>>> +
>>> +/**
>>> + * opp_get_freq() - Gets the frequency corresponding to an opp
>>> + * @opp:       opp for which frequency has to be returned for
>>> + *
>>> + * Return frequency in hertz corresponding to the opp, else
>>> + * return 0
>>> + */
>>> +unsigned long opp_get_freq(const struct omap_opp *opp)
>>> +{
>>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
>>
>> ditto.
>
> Yes, the intent here was for opp operational apis to function ONLY on
> the enabled opps - this helps to pull out any bugs in the users
> who might be unintentionally using bad params.
>
OK.

> do you have any usecase you can think of where we might want to use
> these on a disabled opp?

Not really. Based on what is an OPP enabled/disabled? Is it possible for 
an initially enabled OPP to be disabled at some point in time? What 
triggers this disable?
OR  does an OPP enabled at boot time remain enabled throughout the power 
session?

regards,
-roger

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 14:20         ` Roger Quadros
@ 2010-09-16 14:43           ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 14:43 UTC (permalink / raw)
  To: Roger Quadros; +Cc: ext Kevin Hilman, linux-omap, linux-arm-kernel

Roger Quadros had written, on 09/16/2010 09:20 AM, the following:
[...]
>>>> +/**
>>>> + * opp_get_freq() - Gets the frequency corresponding to an opp
>>>> + * @opp:       opp for which frequency has to be returned for
>>>> + *
>>>> + * Return frequency in hertz corresponding to the opp, else
>>>> + * return 0
>>>> + */
>>>> +unsigned long opp_get_freq(const struct omap_opp *opp)
>>>> +{
>>>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
>>> ditto.
>> Yes, the intent here was for opp operational apis to function ONLY on
>> the enabled opps - this helps to pull out any bugs in the users
>> who might be unintentionally using bad params.
>>
> OK.
> 
>> do you have any usecase you can think of where we might want to use
>> these on a disabled opp?
> 
> Not really. Based on what is an OPP enabled/disabled? Is it possible for 
> an initially enabled OPP to be disabled at some point in time? What 
> triggers this disable?
> OR  does an OPP enabled at boot time remain enabled throughout the power 
> session?
At this point - enable/disable is done at init time - there is 
flexibility for board files to define their own custom OPPs (as some 
custom boards need to). they dont change once this initial definition is 
done. there are plans to do dynamic enable disable based on previous 
discussion in l-o - the framework to use opp layer in that manner is yet 
to go up yet.

-- 
Regards,
Nishanth Menon

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 14:43           ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 14:43 UTC (permalink / raw)
  To: linux-arm-kernel

Roger Quadros had written, on 09/16/2010 09:20 AM, the following:
[...]
>>>> +/**
>>>> + * opp_get_freq() - Gets the frequency corresponding to an opp
>>>> + * @opp:       opp for which frequency has to be returned for
>>>> + *
>>>> + * Return frequency in hertz corresponding to the opp, else
>>>> + * return 0
>>>> + */
>>>> +unsigned long opp_get_freq(const struct omap_opp *opp)
>>>> +{
>>>> +       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
>>> ditto.
>> Yes, the intent here was for opp operational apis to function ONLY on
>> the enabled opps - this helps to pull out any bugs in the users
>> who might be unintentionally using bad params.
>>
> OK.
> 
>> do you have any usecase you can think of where we might want to use
>> these on a disabled opp?
> 
> Not really. Based on what is an OPP enabled/disabled? Is it possible for 
> an initially enabled OPP to be disabled at some point in time? What 
> triggers this disable?
> OR  does an OPP enabled at boot time remain enabled throughout the power 
> session?
At this point - enable/disable is done at init time - there is 
flexibility for board files to define their own custom OPPs (as some 
custom boards need to). they dont change once this initial definition is 
done. there are plans to do dynamic enable disable based on previous 
discussion in l-o - the framework to use opp layer in that manner is yet 
to go up yet.

-- 
Regards,
Nishanth Menon

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 12:19     ` Linus Walleij
@ 2010-09-16 15:08       ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 15:08 UTC (permalink / raw)
  To: Linus Walleij, Nishanth Menon; +Cc: linux-omap, linux-arm-kernel

Hi Linus,

Linus Walleij <linus.walleij@stericsson.com> writes:

> 2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:
>
>> OMAP SOCs have a standard set of tuples consisting of frequency and
>> voltage pairs that the device will support per voltage domain.  These
>> are called Operating Performance Points or OPPs.
>> (...)
>> This introduces a common handling OPP mechanism accross all OMAPs.
>> As a start this is used for OMAP3.
>
> OPPs are a generic concept, it's in silicon construction textbooks and all.
> Should this code not be made generic instead? You wouldn't make
> regulators or even DMA platform-specific these days, so why should
> OPPs be?

You're right.

> What in this code is actually OMAP-specific

Only the users.  ;)

We currently register OPPs using an OMAP hwmod name, but we could easily
change that to use a struct device instead which would make this
much more generic (note we manage OPPs per-device, not just for the CPU)

The patch below[1] demonstrates quickly how easily we could remove all OMAP
specific stuff from opp.[ch], and move it to the OMAP-specific code that
does the opp_add()

> more than that you name
> some functions omap_*, and how hard would it be to put it under
> arch/arm/common/*.c
> arch/arm/include/asm/*.h
>
> Possible even higher up in the directory hiearchy in include/linux/opp.h
> for the header and drivers/opp/*.c, because I think SuperH and power
> are not that different in this respect.

Yeah, I guess this isn't ARM specific either, so should be at a higher
level. 

Nishanth, can take my hack below and continue this evolution?  As I
demonstrate with this hack, this won't really change anything for us.

Kevin

From 96c4e27ba0cb3d9a056693340c6221bc093bce2c Mon Sep 17 00:00:00 2001
From: Kevin Hilman <khilman@deeprootsystems.com>
Date: Thu, 16 Sep 2010 07:58:16 -0700
Subject: [PATCH] OPP: remove OMAP specifics to make more generic

Internal OPP management is based on 'struct device *', so
we don't need to have omap_hwmod specific knowledge in this layer.

Change opp_add() to take a 'struct device *' instead of using
the OMAP hwmod in the opp_def to lookup the struct device.

Move OMAP-specific hwmod lookups into the OMAP specific layer
which adds OPPs to the database.

Quickly tested on OMAP3 to see that all OPPs are still registered
correctly with CPUfreq

---
 arch/arm/mach-omap2/opp3xxx_data.c    |   18 +++++++++++++++++-
 arch/arm/plat-omap/include/plat/opp.h |    2 +-
 arch/arm/plat-omap/opp.c              |   24 ++----------------------
 3 files changed, 20 insertions(+), 24 deletions(-)

diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
index e337aeb..f3f9ae4 100644
--- a/arch/arm/mach-omap2/opp3xxx_data.c
+++ b/arch/arm/mach-omap2/opp3xxx_data.c
@@ -23,6 +23,7 @@
 
 #include <plat/opp.h>
 #include <plat/cpu.h>
+#include <plat/omap_device.h>
 
 static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
 	/* MPU OPP1 */
@@ -114,7 +115,22 @@ int __init omap3_pm_init_opp_table(void)
 
 	opp_def = omap3_opp_def_list;
 	for (i = 0; i < omap3_opp_def_size; i++) {
-		r = opp_add(opp_def++);
+		struct omap_hwmod *oh;
+		struct device *dev;
+
+		if (!opp_def->hwmod_name) {
+			pr_err("%s: missing name of omap_hwmod, ignoring.\n", __func__);
+			return -EINVAL;
+		}
+		oh = omap_hwmod_lookup(opp_def->hwmod_name);
+		if (!oh || !oh->od) {
+			pr_warn("%s: no hwmod or odev for %s, cannot add OPPs.\n",
+				__func__, opp_def->hwmod_name);
+			return -EINVAL;
+		}
+		dev = &oh->od->pdev.dev;
+
+		r = opp_add(dev, opp_def++);
 		if (r)
 			pr_err("unable to add OPP %ld Hz for %s\n",
 			       opp_def->freq, opp_def->hwmod_name);
diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
index 9af8c83..82cfdd6 100644
--- a/arch/arm/plat-omap/include/plat/opp.h
+++ b/arch/arm/plat-omap/include/plat/opp.h
@@ -75,7 +75,7 @@ struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
 
 struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
 
-int opp_add(const struct omap_opp_def *opp_def);
+int opp_add(struct device *dev, const struct omap_opp_def *opp_def);
 
 int opp_enable(struct omap_opp *opp);
 
diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
index b26326b..f5295ca 100644
--- a/arch/arm/plat-omap/opp.c
+++ b/arch/arm/plat-omap/opp.c
@@ -21,7 +21,6 @@
 #include <linux/list.h>
 
 #include <plat/opp.h>
-#include <plat/omap_device.h>
 
 /**
  * struct omap_opp - OMAP OPP description structure
@@ -58,7 +57,6 @@ struct omap_opp {
 struct device_opp {
 	struct list_head node;
 
-	struct omap_hwmod *oh;
 	struct device *dev;
 
 	struct list_head opp_list;
@@ -291,29 +289,12 @@ static void omap_opp_populate(struct omap_opp *opp,
  *
  * This function adds an opp definition to the opp list and returns status.
  */
-int opp_add(const struct omap_opp_def *opp_def)
+int opp_add(struct device *dev, const struct omap_opp_def *opp_def)
 {
-	struct omap_hwmod *oh;
-	struct device *dev = NULL;
 	struct device_opp *tmp_dev_opp, *dev_opp = NULL;
 	struct omap_opp *opp, *new_opp;
-	struct platform_device *pdev;
 	struct list_head *head;
 
-	/* find the correct hwmod, and device */
-	if (!opp_def->hwmod_name) {
-		pr_err("%s: missing name of omap_hwmod, ignoring.\n", __func__);
-		return -EINVAL;
-	}
-	oh = omap_hwmod_lookup(opp_def->hwmod_name);
-	if (!oh || !oh->od) {
-		pr_warn("%s: no hwmod or odev for %s, cannot add OPPs.\n",
-			__func__, opp_def->hwmod_name);
-		return -EINVAL;
-	}
-	pdev = &oh->od->pdev;
-	dev = &oh->od->pdev.dev;
-
 	/* Check for existing list for 'dev' */
 	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
 		if (dev == tmp_dev_opp->dev) {
@@ -331,8 +312,7 @@ int opp_add(const struct omap_opp_def *opp_def)
 			return -ENOMEM;
 		}
 
-		dev_opp->oh = oh;
-		dev_opp->dev = &oh->od->pdev.dev;
+		dev_opp->dev = dev;
 		INIT_LIST_HEAD(&dev_opp->opp_list);
 
 		list_add(&dev_opp->node, &dev_opp_list);
-- 
1.7.2.1

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

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 15:08       ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 15:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Linus,

Linus Walleij <linus.walleij@stericsson.com> writes:

> 2010/9/15 Kevin Hilman <khilman@deeprootsystems.com>:
>
>> OMAP SOCs have a standard set of tuples consisting of frequency and
>> voltage pairs that the device will support per voltage domain. ?These
>> are called Operating Performance Points or OPPs.
>> (...)
>> This introduces a common handling OPP mechanism accross all OMAPs.
>> As a start this is used for OMAP3.
>
> OPPs are a generic concept, it's in silicon construction textbooks and all.
> Should this code not be made generic instead? You wouldn't make
> regulators or even DMA platform-specific these days, so why should
> OPPs be?

You're right.

> What in this code is actually OMAP-specific

Only the users.  ;)

We currently register OPPs using an OMAP hwmod name, but we could easily
change that to use a struct device instead which would make this
much more generic (note we manage OPPs per-device, not just for the CPU)

The patch below[1] demonstrates quickly how easily we could remove all OMAP
specific stuff from opp.[ch], and move it to the OMAP-specific code that
does the opp_add()

> more than that you name
> some functions omap_*, and how hard would it be to put it under
> arch/arm/common/*.c
> arch/arm/include/asm/*.h
>
> Possible even higher up in the directory hiearchy in include/linux/opp.h
> for the header and drivers/opp/*.c, because I think SuperH and power
> are not that different in this respect.

Yeah, I guess this isn't ARM specific either, so should be at a higher
level. 

Nishanth, can take my hack below and continue this evolution?  As I
demonstrate with this hack, this won't really change anything for us.

Kevin

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 15:08       ` Kevin Hilman
@ 2010-09-16 15:31         ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 15:31 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: Linus Walleij, linux-omap, linux-arm-kernel

Kevin Hilman had written, on 09/16/2010 10:08 AM, the following:
[..]
>> more than that you name
>> some functions omap_*, and how hard would it be to put it under
>> arch/arm/common/*.c
>> arch/arm/include/asm/*.h
>>
>> Possible even higher up in the directory hiearchy in include/linux/opp.h
>> for the header and drivers/opp/*.c, because I think SuperH and power
>> are not that different in this respect.
> 
> Yeah, I guess this isn't ARM specific either, so should be at a higher
> level. 
> 
> Nishanth, can take my hack below and continue this evolution?  As I
> demonstrate with this hack, this won't really change anything for us.

thanks..  The only contention ahead is: where do we want this?
Is drivers/opp/opp_core.c the right place? Given that this is just a 
support library and not really a driver? for some reason lib/opp.c 
does'nt sound just right either :(

[..]

-- 
Regards,
Nishanth Menon

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 15:31         ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

Kevin Hilman had written, on 09/16/2010 10:08 AM, the following:
[..]
>> more than that you name
>> some functions omap_*, and how hard would it be to put it under
>> arch/arm/common/*.c
>> arch/arm/include/asm/*.h
>>
>> Possible even higher up in the directory hiearchy in include/linux/opp.h
>> for the header and drivers/opp/*.c, because I think SuperH and power
>> are not that different in this respect.
> 
> Yeah, I guess this isn't ARM specific either, so should be at a higher
> level. 
> 
> Nishanth, can take my hack below and continue this evolution?  As I
> demonstrate with this hack, this won't really change anything for us.

thanks..  The only contention ahead is: where do we want this?
Is drivers/opp/opp_core.c the right place? Given that this is just a 
support library and not really a driver? for some reason lib/opp.c 
does'nt sound just right either :(

[..]

-- 
Regards,
Nishanth Menon

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 15:31         ` Nishanth Menon
@ 2010-09-16 15:48           ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 15:48 UTC (permalink / raw)
  To: Nishanth Menon; +Cc: Linus Walleij, linux-omap, linux-arm-kernel

Nishanth Menon <nm@ti.com> writes:

> Kevin Hilman had written, on 09/16/2010 10:08 AM, the following:
> [..]
>>> more than that you name
>>> some functions omap_*, and how hard would it be to put it under
>>> arch/arm/common/*.c
>>> arch/arm/include/asm/*.h
>>>
>>> Possible even higher up in the directory hiearchy in include/linux/opp.h
>>> for the header and drivers/opp/*.c, because I think SuperH and power
>>> are not that different in this respect.
>>
>> Yeah, I guess this isn't ARM specific either, so should be at a higher
>> level. 
>>
>> Nishanth, can take my hack below and continue this evolution?  As I
>> demonstrate with this hack, this won't really change anything for us.
>
> thanks..  The only contention ahead is: where do we want this?
> Is drivers/opp/opp_core.c the right place? Given that this is just a
> support library and not really a driver? for some reason lib/opp.c
> does'nt sound just right either :(

Well, since it's not really a driver, I don't think drivers/* is
appropriate.

lib/opp/* seems more appropriate to me with the header at
include/linux/opp.h as Linus suggested.

Kevin


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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 15:48           ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 15:48 UTC (permalink / raw)
  To: linux-arm-kernel

Nishanth Menon <nm@ti.com> writes:

> Kevin Hilman had written, on 09/16/2010 10:08 AM, the following:
> [..]
>>> more than that you name
>>> some functions omap_*, and how hard would it be to put it under
>>> arch/arm/common/*.c
>>> arch/arm/include/asm/*.h
>>>
>>> Possible even higher up in the directory hiearchy in include/linux/opp.h
>>> for the header and drivers/opp/*.c, because I think SuperH and power
>>> are not that different in this respect.
>>
>> Yeah, I guess this isn't ARM specific either, so should be at a higher
>> level. 
>>
>> Nishanth, can take my hack below and continue this evolution?  As I
>> demonstrate with this hack, this won't really change anything for us.
>
> thanks..  The only contention ahead is: where do we want this?
> Is drivers/opp/opp_core.c the right place? Given that this is just a
> support library and not really a driver? for some reason lib/opp.c
> does'nt sound just right either :(

Well, since it's not really a driver, I don't think drivers/* is
appropriate.

lib/opp/* seems more appropriate to me with the header at
include/linux/opp.h as Linus suggested.

Kevin

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 15:48           ` Kevin Hilman
@ 2010-09-16 17:07             ` Linus Walleij
  -1 siblings, 0 replies; 62+ messages in thread
From: Linus Walleij @ 2010-09-16 17:07 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: Nishanth Menon, linux-omap, linux-arm-kernel

2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:

> lib/opp/* seems more appropriate to me with the header at
> include/linux/opp.h as Linus suggested.

I second this. I would love to see the generic OPP stuff in
lib/opp/* so we put it in the right place from the beginning and
don't have to painfully refactor everything later (clk.h
especially comes to mind.)

Yours,
Linus Walleij

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 17:07             ` Linus Walleij
  0 siblings, 0 replies; 62+ messages in thread
From: Linus Walleij @ 2010-09-16 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:

> lib/opp/* seems more appropriate to me with the header at
> include/linux/opp.h as Linus suggested.

I second this. I would love to see the generic OPP stuff in
lib/opp/* so we put it in the right place from the beginning and
don't have to painfully refactor everything later (clk.h
especially comes to mind.)

Yours,
Linus Walleij

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 17:07             ` Linus Walleij
@ 2010-09-16 17:10               ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 17:10 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

Linus Walleij had written, on 09/16/2010 12:07 PM, the following:
> 2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:
> 
>> lib/opp/* seems more appropriate to me with the header at
>> include/linux/opp.h as Linus suggested.
> 
> I second this. I would love to see the generic OPP stuff in
> lib/opp/* so we put it in the right place from the beginning and
> don't have to painfully refactor everything later (clk.h
> especially comes to mind.)
cool.. digging a bit deeper into lib directory, I propose the following:
lib/opp.c
include/linux/opp.h

any soc specific data (for registration etc) -> goes to 
arch/<arch>/mach-<soc>/oppdata_xyz.c or what ever they choose

the intent being lib/ is no place to put mach or arch specific data 
definitions.. it is just noise..

if folks are ok with this, will post a new rev soonish..

-- 
Regards,
Nishanth Menon

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 17:10               ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-16 17:10 UTC (permalink / raw)
  To: linux-arm-kernel

Linus Walleij had written, on 09/16/2010 12:07 PM, the following:
> 2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:
> 
>> lib/opp/* seems more appropriate to me with the header at
>> include/linux/opp.h as Linus suggested.
> 
> I second this. I would love to see the generic OPP stuff in
> lib/opp/* so we put it in the right place from the beginning and
> don't have to painfully refactor everything later (clk.h
> especially comes to mind.)
cool.. digging a bit deeper into lib directory, I propose the following:
lib/opp.c
include/linux/opp.h

any soc specific data (for registration etc) -> goes to 
arch/<arch>/mach-<soc>/oppdata_xyz.c or what ever they choose

the intent being lib/ is no place to put mach or arch specific data 
definitions.. it is just noise..

if folks are ok with this, will post a new rev soonish..

-- 
Regards,
Nishanth Menon

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

* RE: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 17:10               ` Nishanth Menon
@ 2010-09-16 17:13                 ` Shilimkar, Santosh
  -1 siblings, 0 replies; 62+ messages in thread
From: Shilimkar, Santosh @ 2010-09-16 17:13 UTC (permalink / raw)
  To: Menon, Nishanth, Linus Walleij; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of Menon, Nishanth
> Sent: Thursday, September 16, 2010 10:40 PM
> To: Linus Walleij
> Cc: Kevin Hilman; linux-omap@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific
> OPPs
> 
> Linus Walleij had written, on 09/16/2010 12:07 PM, the following:
> > 2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:
> >
> >> lib/opp/* seems more appropriate to me with the header at
> >> include/linux/opp.h as Linus suggested.
> >
> > I second this. I would love to see the generic OPP stuff in
> > lib/opp/* so we put it in the right place from the beginning and
> > don't have to painfully refactor everything later (clk.h
> > especially comes to mind.)
> cool.. digging a bit deeper into lib directory, I propose the following:
> lib/opp.c
> include/linux/opp.h
> 
> any soc specific data (for registration etc) -> goes to
> arch/<arch>/mach-<soc>/oppdata_xyz.c or what ever they choose
> 
> the intent being lib/ is no place to put mach or arch specific data
> definitions.. it is just noise..
> 
> if folks are ok with this, will post a new rev soonish..
> 
If you like may be you can take this thread over lkml just to get more
wider perspective

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 17:13                 ` Shilimkar, Santosh
  0 siblings, 0 replies; 62+ messages in thread
From: Shilimkar, Santosh @ 2010-09-16 17:13 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
> owner at vger.kernel.org] On Behalf Of Menon, Nishanth
> Sent: Thursday, September 16, 2010 10:40 PM
> To: Linus Walleij
> Cc: Kevin Hilman; linux-omap at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org
> Subject: Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific
> OPPs
> 
> Linus Walleij had written, on 09/16/2010 12:07 PM, the following:
> > 2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:
> >
> >> lib/opp/* seems more appropriate to me with the header at
> >> include/linux/opp.h as Linus suggested.
> >
> > I second this. I would love to see the generic OPP stuff in
> > lib/opp/* so we put it in the right place from the beginning and
> > don't have to painfully refactor everything later (clk.h
> > especially comes to mind.)
> cool.. digging a bit deeper into lib directory, I propose the following:
> lib/opp.c
> include/linux/opp.h
> 
> any soc specific data (for registration etc) -> goes to
> arch/<arch>/mach-<soc>/oppdata_xyz.c or what ever they choose
> 
> the intent being lib/ is no place to put mach or arch specific data
> definitions.. it is just noise..
> 
> if folks are ok with this, will post a new rev soonish..
> 
If you like may be you can take this thread over lkml just to get more
wider perspective

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

* Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-16 10:40     ` Gopinath, Thara
@ 2010-09-16 17:16       ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 17:16 UTC (permalink / raw)
  To: Gopinath, Thara; +Cc: linux-omap, linux-arm-kernel

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

[...]

>>>From: Paul Walmsley <paul@pwsan.com>
>>>
>>>The OPP layer code should be independent of the PMIC,
>>>introduce the TWL/TPS-specific code out to its own file.
>
> Hello Kevin,
>
> I have been using this code for a while now. I really do not think wee
> need a separate file for implementing the vsel to voltage in (uV) and
> vice versa formulas. Today only voltage layer is interested in these
> conversions. Voltage layer has a structure that can be populated with
> the information required from the PMIC. We only need to add two more
> function pointers to this structure. This info can then be passed from
> the actual PMIC driver file. This will make it much more simpler for
> OMAP4 where we have different formulas between different revisions of
> PMIC. Also in the omap voltage code we will no longer have to hard
> code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel. 

Feel free to post an RFC series for what you're proposing.  

IMHO, even the voltage layer should not care about these conversions.
The voltage layer should care about voltages, and the PMIC layer should
handle these conversions.  IOW, this stuff is best abstracted in the
PMIC code, or board- or SoC-specific hooks that can be registered with
the PMIC.

> So please consider dropping this patch from this series.

If you pick this up as part of your voltage series (or more likely as a
pre-requisite of your voltage series) we can surely drop it from this
series, at it doesn't really belong with the OPP series.

There are no upstream users of this yet, so dropping it is easy. :)

Kevin


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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-16 17:16       ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 17:16 UTC (permalink / raw)
  To: linux-arm-kernel

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

[...]

>>>From: Paul Walmsley <paul@pwsan.com>
>>>
>>>The OPP layer code should be independent of the PMIC,
>>>introduce the TWL/TPS-specific code out to its own file.
>
> Hello Kevin,
>
> I have been using this code for a while now. I really do not think wee
> need a separate file for implementing the vsel to voltage in (uV) and
> vice versa formulas. Today only voltage layer is interested in these
> conversions. Voltage layer has a structure that can be populated with
> the information required from the PMIC. We only need to add two more
> function pointers to this structure. This info can then be passed from
> the actual PMIC driver file. This will make it much more simpler for
> OMAP4 where we have different formulas between different revisions of
> PMIC. Also in the omap voltage code we will no longer have to hard
> code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel. 

Feel free to post an RFC series for what you're proposing.  

IMHO, even the voltage layer should not care about these conversions.
The voltage layer should care about voltages, and the PMIC layer should
handle these conversions.  IOW, this stuff is best abstracted in the
PMIC code, or board- or SoC-specific hooks that can be registered with
the PMIC.

> So please consider dropping this patch from this series.

If you pick this up as part of your voltage series (or more likely as a
pre-requisite of your voltage series) we can surely drop it from this
series, at it doesn't really belong with the OPP series.

There are no upstream users of this yet, so dropping it is easy. :)

Kevin

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

* Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-09-16 17:13                 ` Shilimkar, Santosh
@ 2010-09-16 18:01                   ` Kevin Hilman
  -1 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 18:01 UTC (permalink / raw)
  To: Shilimkar, Santosh
  Cc: Menon, Nishanth, Linus Walleij, linux-omap, linux-arm-kernel

"Shilimkar, Santosh" <santosh.shilimkar@ti.com> writes:

>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of Menon, Nishanth
>> Sent: Thursday, September 16, 2010 10:40 PM
>> To: Linus Walleij
>> Cc: Kevin Hilman; linux-omap@vger.kernel.org; linux-arm-
>> kernel@lists.infradead.org
>> Subject: Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific
>> OPPs
>> 
>> Linus Walleij had written, on 09/16/2010 12:07 PM, the following:
>> > 2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:
>> >
>> >> lib/opp/* seems more appropriate to me with the header at
>> >> include/linux/opp.h as Linus suggested.
>> >
>> > I second this. I would love to see the generic OPP stuff in
>> > lib/opp/* so we put it in the right place from the beginning and
>> > don't have to painfully refactor everything later (clk.h
>> > especially comes to mind.)
>> cool.. digging a bit deeper into lib directory, I propose the following:
>> lib/opp.c
>> include/linux/opp.h
>> 
>> any soc specific data (for registration etc) -> goes to
>> arch/<arch>/mach-<soc>/oppdata_xyz.c or what ever they choose
>> 
>> the intent being lib/ is no place to put mach or arch specific data
>> definitions.. it is just noise..
>> 
>> if folks are ok with this, will post a new rev soonish..
>> 
> If you like may be you can take this thread over lkml just to get more
> wider perspective

I propose Nishanth does the slight rework to move this to lib/ and then
post to l-o, l-a-k and lkml for RFC.  Note that only the generic parts
should be posted first, the OMAP specific usage of this can be fixed
after the generic parts are accepted.

Kevin

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
@ 2010-09-16 18:01                   ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-09-16 18:01 UTC (permalink / raw)
  To: linux-arm-kernel

"Shilimkar, Santosh" <santosh.shilimkar@ti.com> writes:

>> -----Original Message-----
>> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
>> owner at vger.kernel.org] On Behalf Of Menon, Nishanth
>> Sent: Thursday, September 16, 2010 10:40 PM
>> To: Linus Walleij
>> Cc: Kevin Hilman; linux-omap at vger.kernel.org; linux-arm-
>> kernel at lists.infradead.org
>> Subject: Re: [PATCH 1/4] OMAP: introduce OPP layer for device-specific
>> OPPs
>> 
>> Linus Walleij had written, on 09/16/2010 12:07 PM, the following:
>> > 2010/9/16 Kevin Hilman <khilman@deeprootsystems.com>:
>> >
>> >> lib/opp/* seems more appropriate to me with the header at
>> >> include/linux/opp.h as Linus suggested.
>> >
>> > I second this. I would love to see the generic OPP stuff in
>> > lib/opp/* so we put it in the right place from the beginning and
>> > don't have to painfully refactor everything later (clk.h
>> > especially comes to mind.)
>> cool.. digging a bit deeper into lib directory, I propose the following:
>> lib/opp.c
>> include/linux/opp.h
>> 
>> any soc specific data (for registration etc) -> goes to
>> arch/<arch>/mach-<soc>/oppdata_xyz.c or what ever they choose
>> 
>> the intent being lib/ is no place to put mach or arch specific data
>> definitions.. it is just noise..
>> 
>> if folks are ok with this, will post a new rev soonish..
>> 
> If you like may be you can take this thread over lkml just to get more
> wider perspective

I propose Nishanth does the slight rework to move this to lib/ and then
post to l-o, l-a-k and lkml for RFC.  Note that only the generic parts
should be posted first, the OMAP specific usage of this can be fixed
after the generic parts are accepted.

Kevin

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

* RE: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-16 14:06           ` Nishanth Menon
@ 2010-09-17 14:57             ` Gopinath, Thara
  -1 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-17 14:57 UTC (permalink / raw)
  To: Menon, Nishanth; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, September 16, 2010 7:37 PM
>>To: Gopinath, Thara
>>Cc: Kevin Hilman; linux-omap@vger.kernel.org; linux-arm-kernel@lists.infradead.org
>>Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>Gopinath, Thara had written, on 09/16/2010 08:51 AM, the following:
>>>
>>>>> -----Original Message-----
>>>>> From: Menon, Nishanth
>>>>> Sent: Thursday, September 16, 2010 5:45 PM
>>>>> To: Gopinath, Thara
>>>>> Cc: Kevin Hilman; linux-omap@vger.kernel.org; linux-arm-kernel@lists.infradead.org
>>>>> Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>
>>>>> Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
>>>>>>>> -----Original Message-----
>>>>>>>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-owner@vger.kernel.org] On Behalf Of
>>>>> Kevin
>>>>>>>> Hilman
>>>>>>>> Sent: Thursday, September 16, 2010 3:27 AM
>>>>>>>> To: linux-omap@vger.kernel.org
>>>>>>>> Cc: linux-arm-kernel@lists.infradead.org
>>>>>>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>>>>
>>>>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>>>>
>>>>>>>> The OPP layer code should be independent of the PMIC,
>>>>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>>>> Hello Kevin,
>>>>>>
>>>>>> I have been using this code for a while now. I really do not think wee need a separate
>>>>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>>>> This split introduces a PMIC level abstraction already. Do you have a
>>>>> suggestion which file it should go to? It is definitely not part of
>>>>> opp.c, not part of other existing twl files as well. the job of this
>>>>> file was to introduce conversion routines which can be used by any layer
>>>>> (voltage layer if need be - it used to be srf and smartreflex before)..
>>>>> in fact one of your voltage layer patches introduces capability for 6030
>>>>> as well
>>>>> http://marc.info/?l=linux-omap&m=128213020927919&w=2
>>>
>>> Yes one of my patches has introduces this coz I had no other way
>>> to add OMAP4 support. But I still do not understand why cant these
>>> APIs be implemented in twl-core.c or twl4030-power.c?
>>Why there? Twl power does regulator operations not conversion
>>operations. core is not the place either as it is function independent.

Hello Nishant,

Why  do you say core is not the place. For me core is exactly
the place. It is the PMIC driver file.

Regards
Thara


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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-17 14:57             ` Gopinath, Thara
  0 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-17 14:57 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: Menon, Nishanth
>>Sent: Thursday, September 16, 2010 7:37 PM
>>To: Gopinath, Thara
>>Cc: Kevin Hilman; linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org
>>Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>Gopinath, Thara had written, on 09/16/2010 08:51 AM, the following:
>>>
>>>>> -----Original Message-----
>>>>> From: Menon, Nishanth
>>>>> Sent: Thursday, September 16, 2010 5:45 PM
>>>>> To: Gopinath, Thara
>>>>> Cc: Kevin Hilman; linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org
>>>>> Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>
>>>>> Gopinath, Thara had written, on 09/16/2010 05:40 AM, the following:
>>>>>>>> -----Original Message-----
>>>>>>>> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-owner at vger.kernel.org] On Behalf Of
>>>>> Kevin
>>>>>>>> Hilman
>>>>>>>> Sent: Thursday, September 16, 2010 3:27 AM
>>>>>>>> To: linux-omap at vger.kernel.org
>>>>>>>> Cc: linux-arm-kernel at lists.infradead.org
>>>>>>>> Subject: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>>>>>>>
>>>>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>>>>
>>>>>>>> The OPP layer code should be independent of the PMIC,
>>>>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>>>> Hello Kevin,
>>>>>>
>>>>>> I have been using this code for a while now. I really do not think wee need a separate
>>>>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>>>> This split introduces a PMIC level abstraction already. Do you have a
>>>>> suggestion which file it should go to? It is definitely not part of
>>>>> opp.c, not part of other existing twl files as well. the job of this
>>>>> file was to introduce conversion routines which can be used by any layer
>>>>> (voltage layer if need be - it used to be srf and smartreflex before)..
>>>>> in fact one of your voltage layer patches introduces capability for 6030
>>>>> as well
>>>>> http://marc.info/?l=linux-omap&m=128213020927919&w=2
>>>
>>> Yes one of my patches has introduces this coz I had no other way
>>> to add OMAP4 support. But I still do not understand why cant these
>>> APIs be implemented in twl-core.c or twl4030-power.c?
>>Why there? Twl power does regulator operations not conversion
>>operations. core is not the place either as it is function independent.

Hello Nishant,

Why  do you say core is not the place. For me core is exactly
the place. It is the PMIC driver file.

Regards
Thara

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

* Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-17 14:57             ` Gopinath, Thara
@ 2010-09-17 15:03               ` Nishanth Menon
  -1 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-17 15:03 UTC (permalink / raw)
  To: Gopinath, Thara; +Cc: Kevin Hilman, linux-omap, linux-arm-kernel

Gopinath, Thara had written, on 09/17/2010 09:57 AM, the following:
[..]
>>>>>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>>>>>
>>>>>>>>> The OPP layer code should be independent of the PMIC,
>>>>>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>>>>>
>>>>>>> I have been using this code for a while now. I really do not think wee need a separate
>>>>>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>>>>> This split introduces a PMIC level abstraction already. Do you have a
>>>>>> suggestion which file it should go to? It is definitely not part of
>>>>>> opp.c, not part of other existing twl files as well. the job of this
>>>>>> file was to introduce conversion routines which can be used by any layer
>>>>>> (voltage layer if need be - it used to be srf and smartreflex before)..
>>>>>> in fact one of your voltage layer patches introduces capability for 6030
>>>>>> as well
>>>>>> http://marc.info/?l=linux-omap&m=128213020927919&w=2
>>>> Yes one of my patches has introduces this coz I had no other way
>>>> to add OMAP4 support. But I still do not understand why cant these
>>>> APIs be implemented in twl-core.c or twl4030-power.c?
>>> Why there? Twl power does regulator operations not conversion
>>> operations. core is not the place either as it is function independent.
> 
> Why  do you say core is not the place. For me core is exactly
> the place. It is the PMIC driver file.
See [1] - they are all generic without a specific domain implementation. 
if we are so touchy about the location we want these api implementation, 
I guess core might be a compromise enough.. personally even though I 
believe core should remain specific functionality independent, I dont 
think I have very strong opinions about adding helpers there.. i 
would'nt put registration there though.. That should be in board files..

[1] 
http://git.kernel.org/?p=linux/kernel/git/khilman/linux-omap-pm.git;a=blob;f=drivers/mfd/twl4030-core.c;h=769b34bd48e445880ac0920423d9b73eabaf4cb7;hb=HEAD

-- 
Regards,
Nishanth Menon

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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-17 15:03               ` Nishanth Menon
  0 siblings, 0 replies; 62+ messages in thread
From: Nishanth Menon @ 2010-09-17 15:03 UTC (permalink / raw)
  To: linux-arm-kernel

Gopinath, Thara had written, on 09/17/2010 09:57 AM, the following:
[..]
>>>>>>>>> From: Paul Walmsley <paul@pwsan.com>
>>>>>>>>>
>>>>>>>>> The OPP layer code should be independent of the PMIC,
>>>>>>>>> introduce the TWL/TPS-specific code out to its own file.
>>>>>>>
>>>>>>> I have been using this code for a while now. I really do not think wee need a separate
>>>>>>> file for implementing the vsel to voltage in (uV) and vice versa formulas. Today only voltage
>>>>>> This split introduces a PMIC level abstraction already. Do you have a
>>>>>> suggestion which file it should go to? It is definitely not part of
>>>>>> opp.c, not part of other existing twl files as well. the job of this
>>>>>> file was to introduce conversion routines which can be used by any layer
>>>>>> (voltage layer if need be - it used to be srf and smartreflex before)..
>>>>>> in fact one of your voltage layer patches introduces capability for 6030
>>>>>> as well
>>>>>> http://marc.info/?l=linux-omap&m=128213020927919&w=2
>>>> Yes one of my patches has introduces this coz I had no other way
>>>> to add OMAP4 support. But I still do not understand why cant these
>>>> APIs be implemented in twl-core.c or twl4030-power.c?
>>> Why there? Twl power does regulator operations not conversion
>>> operations. core is not the place either as it is function independent.
> 
> Why  do you say core is not the place. For me core is exactly
> the place. It is the PMIC driver file.
See [1] - they are all generic without a specific domain implementation. 
if we are so touchy about the location we want these api implementation, 
I guess core might be a compromise enough.. personally even though I 
believe core should remain specific functionality independent, I dont 
think I have very strong opinions about adding helpers there.. i 
would'nt put registration there though.. That should be in board files..

[1] 
http://git.kernel.org/?p=linux/kernel/git/khilman/linux-omap-pm.git;a=blob;f=drivers/mfd/twl4030-core.c;h=769b34bd48e445880ac0920423d9b73eabaf4cb7;hb=HEAD

-- 
Regards,
Nishanth Menon

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

* RE: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
  2010-09-16 17:16       ` Kevin Hilman
@ 2010-09-17 15:11         ` Gopinath, Thara
  -1 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-17 15:11 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: linux-omap, linux-arm-kernel



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman@deeprootsystems.com]
>>Sent: Thursday, September 16, 2010 10:46 PM
>>To: Gopinath, Thara
>>Cc: linux-omap@vger.kernel.org; linux-arm-kernel@lists.infradead.org
>>Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>"Gopinath, Thara" <thara@ti.com> writes:
>>
>>[...]
>>
>>>>>From: Paul Walmsley <paul@pwsan.com>
>>>>>
>>>>>The OPP layer code should be independent of the PMIC,
>>>>>introduce the TWL/TPS-specific code out to its own file.
>>>
>>> Hello Kevin,
>>>
>>> I have been using this code for a while now. I really do not think wee
>>> need a separate file for implementing the vsel to voltage in (uV) and
>>> vice versa formulas. Today only voltage layer is interested in these
>>> conversions. Voltage layer has a structure that can be populated with
>>> the information required from the PMIC. We only need to add two more
>>> function pointers to this structure. This info can then be passed from
>>> the actual PMIC driver file. This will make it much more simpler for
>>> OMAP4 where we have different formulas between different revisions of
>>> PMIC. Also in the omap voltage code we will no longer have to hard
>>> code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel.
>>
>>Feel free to post an RFC series for what you're proposing.
>>
>>IMHO, even the voltage layer should not care about these conversions.
>>The voltage layer should care about voltages, and the PMIC layer should
>>handle these conversions.  IOW, this stuff is best abstracted in the
>>PMIC code, or board- or SoC-specific hooks that can be registered with
>>the PMIC.
>>
>>> So please consider dropping this patch from this series.
>>
>>If you pick this up as part of your voltage series (or more likely as a
>>pre-requisite of your voltage series) we can surely drop it from this
>>series, at it doesn't really belong with the OPP series.

Hello Kevin/Nishant

My suggestion is introduce two new APIs in drivers/twl-core.c. Then once voltage
layer support is added call into an API provided by voltage layer to register two APIs.
If both Nishant and you are ok with this I will post this change as par of my voltage
and smartreflex series.

Regards
Thara


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

* [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
@ 2010-09-17 15:11         ` Gopinath, Thara
  0 siblings, 0 replies; 62+ messages in thread
From: Gopinath, Thara @ 2010-09-17 15:11 UTC (permalink / raw)
  To: linux-arm-kernel



>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman at deeprootsystems.com]
>>Sent: Thursday, September 16, 2010 10:46 PM
>>To: Gopinath, Thara
>>Cc: linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org
>>Subject: Re: [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code
>>
>>"Gopinath, Thara" <thara@ti.com> writes:
>>
>>[...]
>>
>>>>>From: Paul Walmsley <paul@pwsan.com>
>>>>>
>>>>>The OPP layer code should be independent of the PMIC,
>>>>>introduce the TWL/TPS-specific code out to its own file.
>>>
>>> Hello Kevin,
>>>
>>> I have been using this code for a while now. I really do not think wee
>>> need a separate file for implementing the vsel to voltage in (uV) and
>>> vice versa formulas. Today only voltage layer is interested in these
>>> conversions. Voltage layer has a structure that can be populated with
>>> the information required from the PMIC. We only need to add two more
>>> function pointers to this structure. This info can then be passed from
>>> the actual PMIC driver file. This will make it much more simpler for
>>> OMAP4 where we have different formulas between different revisions of
>>> PMIC. Also in the omap voltage code we will no longer have to hard
>>> code omap_twl_vsel_to_uv and omap_twl_uv_to_vsel.
>>
>>Feel free to post an RFC series for what you're proposing.
>>
>>IMHO, even the voltage layer should not care about these conversions.
>>The voltage layer should care about voltages, and the PMIC layer should
>>handle these conversions.  IOW, this stuff is best abstracted in the
>>PMIC code, or board- or SoC-specific hooks that can be registered with
>>the PMIC.
>>
>>> So please consider dropping this patch from this series.
>>
>>If you pick this up as part of your voltage series (or more likely as a
>>pre-requisite of your voltage series) we can surely drop it from this
>>series, at it doesn't really belong with the OPP series.

Hello Kevin/Nishant

My suggestion is introduce two new APIs in drivers/twl-core.c. Then once voltage
layer support is added call into an API provided by voltage layer to register two APIs.
If both Nishant and you are ok with this I will post this change as par of my voltage
and smartreflex series.

Regards
Thara

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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-08-11  0:09 [PATCH 0/4] OMAP OPP layer Kevin Hilman
@ 2010-08-11  0:09 ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-08-11  0:09 UTC (permalink / raw)
  To: linux-omap
  Cc: Nishanth Menon, Benoit Cousson,
	Madhusudhan Chikkature Rajashekar, Phil Carmody,
	Roberto Granados Dorado, Santosh Shilimkar,
	Sergio Alberto Aguirre Rodriguez, Tero Kristo, Eduardo Valentin,
	Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Thara Gopinath,
	Vishwanath BS

From: Nishanth Menon <nm@ti.com>

OMAP SOCs have a standard set of tuples consisting of frequency and
voltage pairs that the device will support per voltage domain.  These
are called Operating Performance Points or OPPs. The actual
definitions of OMAP Operating Points varies over silicon within the
same family of devices. For a specific domain, you can have a set of
{frequency, voltage} pairs. As the kernel boots and more information
is available, a set of these are activated based on the precise nature
of device the kernel boots up on. It is interesting to remember that
each IP which belongs to a voltage domain may define their own set of
OPPs on top of this.

This introduces a common handling OPP mechanism accross all OMAPs.
As a start this is used for OMAP3.

Note: OPP is a concept that can be used in all OMAPs, it is hence
introduced under plat-omap

Contributions include:
Sanjeev Premi for the initial concept:
	http://patchwork.kernel.org/patch/50998/
Kevin Hilman for converting original design to device-based
Kevin Hilman and Paul Walmsey for cleaning up many of the function
abstractions, improvements and data structure handling
Romit Dasgupta for using enums instead of opp pointers
Thara Gopinath, Eduardo Valentin and Vishwanath BS for fixes and
cleanups.

Discussions and comments from:
http://marc.info/?l=linux-omap&m=126033945313269&w=2
http://marc.info/?l=linux-omap&m=125482970102327&w=2
http://marc.info/?t=125809247500002&r=1&w=2
http://marc.info/?l=linux-omap&m=126025973426007&w=2
incorporated.

Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
Cc: Roberto Granados Dorado <x0095451@ti.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com>
Cc: Tero Kristo <Tero.Kristo@nokia.com>

Signed-off-by: Eduardo Valentin <eduardo.valentin@nokia.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Romit Dasgupta <romit@ti.com>
Signed-off-by: Sanjeev Premi <premi@ti.com>
Signed-off-by: Thara Gopinath <thara@ti.com>
Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>
---
 Documentation/arm/OMAP/omap_pm        |   93 ++++++
 arch/arm/plat-omap/Makefile           |    5 +
 arch/arm/plat-omap/include/plat/opp.h |  160 ++++++++++
 arch/arm/plat-omap/opp.c              |  513 +++++++++++++++++++++++++++++++++
 4 files changed, 771 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/opp.h
 create mode 100644 arch/arm/plat-omap/opp.c

diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
index 5389440..b046ebc 100644
--- a/Documentation/arm/OMAP/omap_pm
+++ b/Documentation/arm/OMAP/omap_pm
@@ -127,3 +127,96 @@ implementation needs:
 10. (*pdata->cpu_set_freq)(unsigned long f)
 
 11. (*pdata->cpu_get_freq)(void)
+
+OMAP OPP Layer
+==============
+OMAP SOCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. This
+is called Operating Performance Point or OPP. The actual definitions
+of OMAP OPP varies over silicon within the same family of devices.
+For a specific domain, you can have a set of {frequency, voltage}
+pairs. As the kernel boots and more information is available, a set
+of these are activated based on the precise nature of device the kernel
+boots up on. It is interesting to remember that each IP which belongs
+to a voltage domain may define their own set of OPPs on top of this.
+
+OPP layer of its own depends on silicon specific implementation and
+board specific data to finalize on the final set of OPPs available
+in a system
+
+Initial list initialization:
+---------------------------
+The normal initialization sequence is for boardxyz_init_irq to call
+omap2_init_common_hw (for omap2+) and which in turn does the default
+setup required.
+
+Silicon specific initialization: First the OPP layer needs to be told
+to initialize the tables for OMAP3, there are two options here:
+a) If the desire is to use the default tables defined for that silicon,
+the board file does not need to call any initialization function, the
+defaults are setup as part of initialization flow when
+omap2_init_common_hw is called.
+
+b) board files would like to customize the default definition. In this
+case, board file needs to call explicitly prior to table operations.
+the sequence is:
+boardxyz_init_irq()
+{
+	... do things ..
+	omap3_pm_init_opp_table()
+	.. customizations and other things ..
+	omap2_init_common_hw()
+}
+1. omap3_pm_init_opp_table - this in turn calls opp_init_list for all
+OPP types. This is the generic silicon operating points, however, the
+system may have additional features or customizations required. This
+flexibility is provided by the following apis:
+
+Query functions:
+----------------
+Search for OPPs for various cases:
+2. opp_find_freq_exact - exact search function
+3. opp_find_freq_floor - round_up search function
+4. opp_find_freq_ceil - round_down search function
+
+OPP modifier functions:
+----------------------
+This allows opp layer users to add customized OPPs or change the table
+for any need they may have
+5. opp_add - add a new OPP - NOTE: use struct omap_opp_def and define
+the custom OPP with OMAP_OPP_DEF for usage.
+6. opp_enable - enable a disabled OPP
+7. opp_disable - disable an enabled OPP
+
+OPP Data retrieval functions:
+----------------------------
+The following sets of functions are useful for drivers to retrieve
+data stored in opp layer for various functions.
+8. opp_get_voltage - retrieve voltage for an opp
+9. opp_get_freq - get the frequency for an opp
+10. opp_get_opp_count - get number of opps enabled for a domain
+
+Cpufreq table generation:
+------------------------
+11. opp_init_cpufreq_table - this translates the OPP layer's internal
+OPP arrangement into a table understood and operated upon by the
+cpufreq layer.
+
+Deprecated functions:
+--------------------
+To maintain compatibility with out of tree drivers, opp_id is needed.
+OPP IDs are not constant across silicon families, nor are they constant
+within a given silicon family. The rest of the layers should stop using
+these functions at the earliest. For the out of tree drivers currently,
+This is exposed by the following deprecated functions:
+12. opp_find_by_opp_id - get an OPP for an OPP ID
+13. opp_get_opp_id - get the OPP ID for an OPP
+
+Data Structures:
+---------------
+struct omap_opp * is a handle structure whose internals are known only
+to the OPP layer and is meant to hide the complexity away from users of
+opp layer.
+
+struct omap_opp_def * is the definitions that users can interface with
+opp layer and is meant to define one OPP.
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9405831..70b012d 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -12,6 +12,11 @@ obj-  :=
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+# OPP support in (OMAP3+ only at the moment)
+ifdef CONFIG_CPU_FREQ
+obj-$(CONFIG_ARCH_OMAP3) += opp.o
+endif
+
 # omap_device support (OMAP2+ only at the moment)
 obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
new file mode 100644
index 0000000..403b69b
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/opp.h
@@ -0,0 +1,160 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ * Copyright (C) 2009 Deep Root Systems, LLC.
+ *	Kevin Hilman
+ *
+ * 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_OPP_H
+#define __ASM_ARM_OMAP_OPP_H
+
+#include <linux/err.h>
+#include <linux/cpufreq.h>
+
+#include <plat/common.h>
+
+/**
+ * struct omap_opp_def - OMAP OPP Definition
+ * @hwmod_name:	Name of the hwmod for this domain
+ * @freq:	Frequency in hertz corresponding to this OPP
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @enabled:	True/false - is this OPP enabled/disabled by default
+ *
+ * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
+ * pairs that the device will support per voltage domain. This is called
+ * Operating Points or OPP. The actual definitions of OMAP Operating Points
+ * varies over silicon within the same family of devices. For a specific
+ * domain, you can have a set of {frequency, voltage} pairs and this is denoted
+ * by an array of omap_opp_def. As the kernel boots and more information is
+ * available, a set of these are activated based on the precise nature of
+ * device the kernel boots up on. It is interesting to remember that each IP
+ * which belongs to a voltage domain may define their own set of OPPs on top
+ * of this - but this is handled by the appropriate driver.
+ */
+struct omap_opp_def {
+	char *hwmod_name;
+
+	unsigned long freq;
+	unsigned long u_volt;
+
+	bool enabled;
+};
+
+/*
+ * Initialization wrapper used to define an OPP.
+ * To point at the end of a terminator of a list of OPPs,
+ * use OMAP_OPP_DEF(NULL, 0, 0, 0)
+ */
+#define OMAP_OPP_DEF(_hwmod_name, _enabled, _freq, _uv)	\
+{						\
+	.hwmod_name	= _hwmod_name,		\
+	.enabled	= _enabled,		\
+	.freq		= _freq,		\
+	.u_volt		= _uv,			\
+}
+
+struct omap_opp;
+
+#ifdef CONFIG_CPU_FREQ
+
+unsigned long opp_get_voltage(const struct omap_opp *opp);
+
+unsigned long opp_get_freq(const struct omap_opp *opp);
+
+int opp_get_opp_count(struct device *dev);
+
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled);
+
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
+
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
+
+int opp_add(const struct omap_opp_def *opp_def);
+
+int opp_enable(struct omap_opp *opp);
+
+int opp_disable(struct omap_opp *opp);
+
+struct omap_opp *__deprecated opp_find_by_opp_id(struct device *dev,
+						  u8 opp_id);
+u8 __deprecated opp_get_opp_id(struct omap_opp *opp);
+
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table);
+#else
+static inline unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_get_opp_count(struct omap_opp *oppl)
+{
+	return 0;
+}
+
+static inline struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
+						   unsigned long freq,
+						   bool enabled)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
+						   unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl,
+						  unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_add(struct omap_opp *oppl,
+				       const struct omap_opp_def *opp_def)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int opp_enable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_disable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline struct omap_opp *__deprecated
+opp_find_by_opp_id(struct omap_opp *opps, u8 opp_id)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline u8 __deprecated opp_get_opp_id(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline
+void opp_init_cpufreq_table(struct omap_opp *opps,
+			    struct cpufreq_frequency_table **table)
+{
+}
+
+#endif		/* CONFIG_CPU_FREQ */
+#endif		/* __ASM_ARM_OMAP_OPP_H */
diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
new file mode 100644
index 0000000..b9b7bda
--- /dev/null
+++ b/arch/arm/plat-omap/opp.c
@@ -0,0 +1,513 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <plat/opp.h>
+#include <plat/omap_device.h>
+
+/**
+ * struct omap_opp - OMAP OPP description structure
+ * @enabled:	true/false - marking this OPP as enabled/disabled
+ * @rate:	Frequency in hertz
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @opp_id:	opp identifier (deprecated)
+ * @dev_opp:	contains the device_opp struct
+ *
+ * This structure stores the OPP information for a given domain.
+ */
+struct omap_opp {
+	struct list_head node;
+
+	bool enabled;
+	unsigned long rate;
+	unsigned long u_volt;
+	u8 opp_id;
+
+	struct device_opp *dev_opp;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:	list node
+ * @oh:		hwmod handle
+ * @dev:	device handle
+ * @opp_list:	list of opps
+ * @opp_count:	num opps
+ * @enabled_opp_count:	how many opps are actually enabled
+ *
+ * This is an internal datastructure maintaining the link to
+ * omap_opps attached to a domain device. This structure is not
+ * meant to be shared with users as it private to opp layer.
+ */
+struct device_opp {
+	struct list_head node;
+
+	struct omap_hwmod *oh;
+	struct device *dev;
+
+	struct list_head opp_list;
+	u32 opp_count;
+	u32 enabled_opp_count;
+};
+
+static LIST_HEAD(dev_opp_list);
+
+/**
+ * find_device_opp() - find device_opp struct using device pointer
+ * @dev:	device pointer used to lookup device OPPs
+ *
+ * Search list of device OPPs for one containing matching device.
+ *
+ * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * -EINVAL based on type of error.
+ */
+static struct device_opp *find_device_opp(struct device *dev)
+{
+	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
+
+	if (unlikely(!dev || IS_ERR(dev))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (tmp_dev_opp->dev == dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	return dev_opp;
+}
+
+/**
+ * opp_get_voltage() - Gets the voltage corresponding to an opp
+ * @opp:	opp for which voltage has to be returned for
+ *
+ * Return voltage in micro volt corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->u_volt;
+}
+
+/**
+ * opp_get_freq() - Gets the frequency corresponding to an opp
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Return frequency in hertz corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->rate;
+}
+
+/**
+ * opp_find_by_opp_id - look up OPP by OPP ID (deprecated)
+ * @opp_type:	OPP type where we want the look up to happen.
+ * @opp_id:	OPP ID to search for
+ *
+ * Returns the struct omap_opp pointer corresponding to the given OPP
+ * ID @opp_id, or returns NULL on error.
+ */
+struct omap_opp * __deprecated opp_find_by_opp_id(struct device *dev,
+						  u8 opp_id)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->opp_id == opp_id) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_get_opp_id() - Provide OPP ID corresponding to an OPP (deprecated)
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Returns an OPP ID for the OPP required, if error, returns 0
+ */
+u8 __deprecated opp_get_opp_id(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameter being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->opp_id;
+}
+
+/**
+ * opp_get_opp_count() - Get number of opps enabled in the opp list
+ * @opp_type:	OPP type we want to count
+ *
+ * This functions returns the number of opps if there are any OPPs enabled,
+ * else returns corresponding error value.
+ */
+int opp_get_opp_count(struct device *dev)
+{
+	struct device_opp *dev_opp;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return -ENODEV;
+
+	return dev_opp->enabled_opp_count;
+}
+
+/**
+ * opp_find_freq_exact() - search for an exact frequency
+ * @opp_type:	OPP type we want to search in.
+ * @freq:	frequency to search for
+ * @enabled:	enabled/disabled OPP to search for
+ *
+ * Searches for exact match in the opp list and returns handle to the matching
+ * opp if found, else returns ERR_PTR in case of error and should be handled
+ * using IS_ERR.
+ *
+ * Note enabled is a modifier for the search. if enabled=true, then the match is
+ * for exact matching frequency and is enabled. if false, the match is for exact
+ * frequency which is disabled.
+ */
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate == freq) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_ceil() - Search for an rounded ceil freq
+ * @opp_type:	OPP type where we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching ceil *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next highest available frequency *
+ *	freq = 350000;
+ *	opp = opp_find_freq_ceil(OPP_MPU, &freq))
+ *	if (IS_ERR(opp))
+ *		pr_err("unable to find a higher frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in ascending order *
+ *	freq = 0; * Search for the lowest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_ceil(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq++; * for next higher match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate >= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_floor() - Search for an rounded floor freq
+ * @opp_type:	OPP type we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching floor *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the next match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next lowest available frequency
+ *	freq = 350000;
+ *	opp = opp_find_freq_floor(OPP_MPU, &freq)))
+ *	if (IS_ERR(opp))
+ *		pr_err ("unable to find a lower frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in descending order *
+ *	freq = ULONG_MAX; * search highest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_floor(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq--; * for next lower match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry_reverse(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate <= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/* wrapper to reuse converting opp_def to opp struct */
+static void omap_opp_populate(struct omap_opp *opp,
+			      const struct omap_opp_def *opp_def)
+{
+	opp->rate = opp_def->freq;
+	opp->enabled = opp_def->enabled;
+	opp->u_volt = opp_def->u_volt;
+}
+
+/**
+ * opp_add()  - Add an OPP table from a table definitions
+ * @opp_def:	omap_opp_def to describe the OPP which we want to add.
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ */
+int opp_add(const struct omap_opp_def *opp_def)
+{
+	struct omap_hwmod *oh;
+	struct device *dev = NULL;
+	struct device_opp *tmp_dev_opp, *dev_opp = NULL;
+	struct omap_opp *opp, *new_opp;
+	struct platform_device *pdev;
+	struct list_head *head;
+	int i;
+
+	/* find the correct hwmod, and device */
+	if (!opp_def->hwmod_name) {
+		pr_err("%s: missing name of omap_hwmod, ignoring.\n", __func__);
+		return -EINVAL;
+	}
+	oh = omap_hwmod_lookup(opp_def->hwmod_name);
+	if (!oh || !oh->od) {
+		pr_warn("%s: no hwmod or odev for %s, cannot add OPPs.\n",
+			__func__, opp_def->hwmod_name);
+		return -EINVAL;
+	}
+	pdev = &oh->od->pdev;
+	dev = &oh->od->pdev.dev;
+
+	/* Check for existing list for 'dev' */
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (dev == tmp_dev_opp->dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	if (!dev_opp) {
+		/* Allocate a new device OPP table */
+		dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL);
+		if (!dev_opp) {
+			pr_warning("%s: unable to allocate device struct\n",
+				__func__);
+			return -ENOMEM;
+		}
+
+		dev_opp->oh = oh;
+		dev_opp->dev = &oh->od->pdev.dev;
+		INIT_LIST_HEAD(&dev_opp->opp_list);
+
+		list_add(&dev_opp->node, &dev_opp_list);
+	}
+
+	/* allocate new OPP node */
+	new_opp = kzalloc(sizeof(struct omap_opp), GFP_KERNEL);
+	if (!new_opp) {
+		if (list_empty(&dev_opp->opp_list)) {
+			list_del(&dev_opp->node);
+			kfree(dev_opp);
+		}
+		pr_warning("%s: unable to allocate new opp node\n",
+			__func__);
+		return -ENOMEM;
+	}
+	omap_opp_populate(new_opp, opp_def);
+
+	/* Insert new OPP in order of increasing frequency */
+	head = &dev_opp->opp_list;
+	list_for_each_entry_reverse(opp, &dev_opp->opp_list, node) {
+		if (new_opp->rate >= opp->rate) {
+			head = &opp->node;
+			break;
+		}
+	}
+	list_add(&new_opp->node, head);
+	dev_opp->opp_count++;
+	if (new_opp->enabled)
+		dev_opp->enabled_opp_count++;
+
+	/* renumber (deprecated) OPP IDs based on new order */
+	i = 0;
+	list_for_each_entry(opp, &dev_opp->opp_list, node)
+		opp->opp_id = i++;
+
+	return 0;
+}
+
+/**
+ * opp_enable() - Enable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Enables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_enable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count++;
+
+	opp->enabled = true;
+
+	return 0;
+}
+
+/**
+ * opp_disable() - Disable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Disables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_disable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count--;
+
+	opp->enabled = false;
+
+	return 0;
+}
+
+/**
+ * opp_init_cpufreq_table() - create a cpufreq table for a domain
+ * @opp_type:	OPP type to initialize this list for
+ * @table:	Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided domain - this assumes that the
+ * opp list is already initialized and ready for usage
+ */
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *opp;
+	struct cpufreq_frequency_table *freq_table;
+	int i = 0;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		pr_warning("%s: unable to find device\n", __func__);
+		return;
+	}
+
+	freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
+			     (dev_opp->enabled_opp_count + 1), GFP_ATOMIC);
+	if (!freq_table) {
+		pr_warning("%s: failed to allocate frequency table\n",
+			   __func__);
+		return;
+	}
+
+	list_for_each_entry(opp, &dev_opp->opp_list, node) {
+		if (opp->enabled) {
+			freq_table[i].index = i;
+			freq_table[i].frequency = opp->rate / 1000;
+			i++;
+		}
+	}
+
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	*table = &freq_table[0];
+}
-- 
1.7.2.1


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

* [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs
  2010-08-11  0:07 [PATCH 0/4] OMAP OPP layer Kevin Hilman
@ 2010-08-11  0:07 ` Kevin Hilman
  0 siblings, 0 replies; 62+ messages in thread
From: Kevin Hilman @ 2010-08-11  0:07 UTC (permalink / raw)
  To: linux-omap
  Cc: Nishanth Menon, Benoit Cousson,
	Madhusudhan Chikkature Rajashekar, Phil Carmody,
	Roberto Granados Dorado, Santosh Shilimkar,
	Sergio Alberto Aguirre Rodriguez, Tero Kristo, Eduardo Valentin,
	Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Thara Gopinath,
	Vishwanath BS

From: Nishanth Menon <nm@ti.com>

OMAP SOCs have a standard set of tuples consisting of frequency and
voltage pairs that the device will support per voltage domain.  These
are called Operating Performance Points or OPPs. The actual
definitions of OMAP Operating Points varies over silicon within the
same family of devices. For a specific domain, you can have a set of
{frequency, voltage} pairs. As the kernel boots and more information
is available, a set of these are activated based on the precise nature
of device the kernel boots up on. It is interesting to remember that
each IP which belongs to a voltage domain may define their own set of
OPPs on top of this.

This introduces a common handling OPP mechanism accross all OMAPs.
As a start this is used for OMAP3.

Note: OPP is a concept that can be used in all OMAPs, it is hence
introduced under plat-omap

Contributions include:
Sanjeev Premi for the initial concept:
	http://patchwork.kernel.org/patch/50998/
Kevin Hilman for converting original design to device-based
Kevin Hilman and Paul Walmsey for cleaning up many of the function
abstractions, improvements and data structure handling
Romit Dasgupta for using enums instead of opp pointers
Thara Gopinath, Eduardo Valentin and Vishwanath BS for fixes and
cleanups.

Discussions and comments from:
http://marc.info/?l=linux-omap&m=126033945313269&w=2
http://marc.info/?l=linux-omap&m=125482970102327&w=2
http://marc.info/?t=125809247500002&r=1&w=2
http://marc.info/?l=linux-omap&m=126025973426007&w=2
incorporated.

Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com>
Cc: Phil Carmody <ext-phil.2.carmody@nokia.com>
Cc: Roberto Granados Dorado <x0095451@ti.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com>
Cc: Tero Kristo <Tero.Kristo@nokia.com>

Signed-off-by: Eduardo Valentin <eduardo.valentin@nokia.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Romit Dasgupta <romit@ti.com>
Signed-off-by: Sanjeev Premi <premi@ti.com>
Signed-off-by: Thara Gopinath <thara@ti.com>
Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>
---
 Documentation/arm/OMAP/omap_pm        |   93 ++++++
 arch/arm/plat-omap/Makefile           |    5 +
 arch/arm/plat-omap/include/plat/opp.h |  160 ++++++++++
 arch/arm/plat-omap/opp.c              |  513 +++++++++++++++++++++++++++++++++
 4 files changed, 771 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/opp.h
 create mode 100644 arch/arm/plat-omap/opp.c

diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm
index 5389440..b046ebc 100644
--- a/Documentation/arm/OMAP/omap_pm
+++ b/Documentation/arm/OMAP/omap_pm
@@ -127,3 +127,96 @@ implementation needs:
 10. (*pdata->cpu_set_freq)(unsigned long f)
 
 11. (*pdata->cpu_get_freq)(void)
+
+OMAP OPP Layer
+==============
+OMAP SOCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. This
+is called Operating Performance Point or OPP. The actual definitions
+of OMAP OPP varies over silicon within the same family of devices.
+For a specific domain, you can have a set of {frequency, voltage}
+pairs. As the kernel boots and more information is available, a set
+of these are activated based on the precise nature of device the kernel
+boots up on. It is interesting to remember that each IP which belongs
+to a voltage domain may define their own set of OPPs on top of this.
+
+OPP layer of its own depends on silicon specific implementation and
+board specific data to finalize on the final set of OPPs available
+in a system
+
+Initial list initialization:
+---------------------------
+The normal initialization sequence is for boardxyz_init_irq to call
+omap2_init_common_hw (for omap2+) and which in turn does the default
+setup required.
+
+Silicon specific initialization: First the OPP layer needs to be told
+to initialize the tables for OMAP3, there are two options here:
+a) If the desire is to use the default tables defined for that silicon,
+the board file does not need to call any initialization function, the
+defaults are setup as part of initialization flow when
+omap2_init_common_hw is called.
+
+b) board files would like to customize the default definition. In this
+case, board file needs to call explicitly prior to table operations.
+the sequence is:
+boardxyz_init_irq()
+{
+	... do things ..
+	omap3_pm_init_opp_table()
+	.. customizations and other things ..
+	omap2_init_common_hw()
+}
+1. omap3_pm_init_opp_table - this in turn calls opp_init_list for all
+OPP types. This is the generic silicon operating points, however, the
+system may have additional features or customizations required. This
+flexibility is provided by the following apis:
+
+Query functions:
+----------------
+Search for OPPs for various cases:
+2. opp_find_freq_exact - exact search function
+3. opp_find_freq_floor - round_up search function
+4. opp_find_freq_ceil - round_down search function
+
+OPP modifier functions:
+----------------------
+This allows opp layer users to add customized OPPs or change the table
+for any need they may have
+5. opp_add - add a new OPP - NOTE: use struct omap_opp_def and define
+the custom OPP with OMAP_OPP_DEF for usage.
+6. opp_enable - enable a disabled OPP
+7. opp_disable - disable an enabled OPP
+
+OPP Data retrieval functions:
+----------------------------
+The following sets of functions are useful for drivers to retrieve
+data stored in opp layer for various functions.
+8. opp_get_voltage - retrieve voltage for an opp
+9. opp_get_freq - get the frequency for an opp
+10. opp_get_opp_count - get number of opps enabled for a domain
+
+Cpufreq table generation:
+------------------------
+11. opp_init_cpufreq_table - this translates the OPP layer's internal
+OPP arrangement into a table understood and operated upon by the
+cpufreq layer.
+
+Deprecated functions:
+--------------------
+To maintain compatibility with out of tree drivers, opp_id is needed.
+OPP IDs are not constant across silicon families, nor are they constant
+within a given silicon family. The rest of the layers should stop using
+these functions at the earliest. For the out of tree drivers currently,
+This is exposed by the following deprecated functions:
+12. opp_find_by_opp_id - get an OPP for an OPP ID
+13. opp_get_opp_id - get the OPP ID for an OPP
+
+Data Structures:
+---------------
+struct omap_opp * is a handle structure whose internals are known only
+to the OPP layer and is meant to hide the complexity away from users of
+opp layer.
+
+struct omap_opp_def * is the definitions that users can interface with
+opp layer and is meant to define one OPP.
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 9405831..70b012d 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -12,6 +12,11 @@ obj-  :=
 # OCPI interconnect support for 1710, 1610 and 5912
 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
+# OPP support in (OMAP3+ only at the moment)
+ifdef CONFIG_CPU_FREQ
+obj-$(CONFIG_ARCH_OMAP3) += opp.o
+endif
+
 # omap_device support (OMAP2+ only at the moment)
 obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
 obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
diff --git a/arch/arm/plat-omap/include/plat/opp.h b/arch/arm/plat-omap/include/plat/opp.h
new file mode 100644
index 0000000..403b69b
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/opp.h
@@ -0,0 +1,160 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ * Copyright (C) 2009 Deep Root Systems, LLC.
+ *	Kevin Hilman
+ *
+ * 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_OPP_H
+#define __ASM_ARM_OMAP_OPP_H
+
+#include <linux/err.h>
+#include <linux/cpufreq.h>
+
+#include <plat/common.h>
+
+/**
+ * struct omap_opp_def - OMAP OPP Definition
+ * @hwmod_name:	Name of the hwmod for this domain
+ * @freq:	Frequency in hertz corresponding to this OPP
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @enabled:	True/false - is this OPP enabled/disabled by default
+ *
+ * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
+ * pairs that the device will support per voltage domain. This is called
+ * Operating Points or OPP. The actual definitions of OMAP Operating Points
+ * varies over silicon within the same family of devices. For a specific
+ * domain, you can have a set of {frequency, voltage} pairs and this is denoted
+ * by an array of omap_opp_def. As the kernel boots and more information is
+ * available, a set of these are activated based on the precise nature of
+ * device the kernel boots up on. It is interesting to remember that each IP
+ * which belongs to a voltage domain may define their own set of OPPs on top
+ * of this - but this is handled by the appropriate driver.
+ */
+struct omap_opp_def {
+	char *hwmod_name;
+
+	unsigned long freq;
+	unsigned long u_volt;
+
+	bool enabled;
+};
+
+/*
+ * Initialization wrapper used to define an OPP.
+ * To point at the end of a terminator of a list of OPPs,
+ * use OMAP_OPP_DEF(NULL, 0, 0, 0)
+ */
+#define OMAP_OPP_DEF(_hwmod_name, _enabled, _freq, _uv)	\
+{						\
+	.hwmod_name	= _hwmod_name,		\
+	.enabled	= _enabled,		\
+	.freq		= _freq,		\
+	.u_volt		= _uv,			\
+}
+
+struct omap_opp;
+
+#ifdef CONFIG_CPU_FREQ
+
+unsigned long opp_get_voltage(const struct omap_opp *opp);
+
+unsigned long opp_get_freq(const struct omap_opp *opp);
+
+int opp_get_opp_count(struct device *dev);
+
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled);
+
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
+
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
+
+int opp_add(const struct omap_opp_def *opp_def);
+
+int opp_enable(struct omap_opp *opp);
+
+int opp_disable(struct omap_opp *opp);
+
+struct omap_opp *__deprecated opp_find_by_opp_id(struct device *dev,
+						  u8 opp_id);
+u8 __deprecated opp_get_opp_id(struct omap_opp *opp);
+
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table);
+#else
+static inline unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_get_opp_count(struct omap_opp *oppl)
+{
+	return 0;
+}
+
+static inline struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
+						   unsigned long freq,
+						   bool enabled)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
+						   unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl,
+						  unsigned long *freq)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct omap_opp *opp_add(struct omap_opp *oppl,
+				       const struct omap_opp_def *opp_def)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int opp_enable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline int opp_disable(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline struct omap_opp *__deprecated
+opp_find_by_opp_id(struct omap_opp *opps, u8 opp_id)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline u8 __deprecated opp_get_opp_id(struct omap_opp *opp)
+{
+	return 0;
+}
+
+static inline
+void opp_init_cpufreq_table(struct omap_opp *opps,
+			    struct cpufreq_frequency_table **table)
+{
+}
+
+#endif		/* CONFIG_CPU_FREQ */
+#endif		/* __ASM_ARM_OMAP_OPP_H */
diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
new file mode 100644
index 0000000..b9b7bda
--- /dev/null
+++ b/arch/arm/plat-omap/opp.c
@@ -0,0 +1,513 @@
+/*
+ * OMAP OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta <romit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <plat/opp.h>
+#include <plat/omap_device.h>
+
+/**
+ * struct omap_opp - OMAP OPP description structure
+ * @enabled:	true/false - marking this OPP as enabled/disabled
+ * @rate:	Frequency in hertz
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @opp_id:	opp identifier (deprecated)
+ * @dev_opp:	contains the device_opp struct
+ *
+ * This structure stores the OPP information for a given domain.
+ */
+struct omap_opp {
+	struct list_head node;
+
+	bool enabled;
+	unsigned long rate;
+	unsigned long u_volt;
+	u8 opp_id;
+
+	struct device_opp *dev_opp;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:	list node
+ * @oh:		hwmod handle
+ * @dev:	device handle
+ * @opp_list:	list of opps
+ * @opp_count:	num opps
+ * @enabled_opp_count:	how many opps are actually enabled
+ *
+ * This is an internal datastructure maintaining the link to
+ * omap_opps attached to a domain device. This structure is not
+ * meant to be shared with users as it private to opp layer.
+ */
+struct device_opp {
+	struct list_head node;
+
+	struct omap_hwmod *oh;
+	struct device *dev;
+
+	struct list_head opp_list;
+	u32 opp_count;
+	u32 enabled_opp_count;
+};
+
+static LIST_HEAD(dev_opp_list);
+
+/**
+ * find_device_opp() - find device_opp struct using device pointer
+ * @dev:	device pointer used to lookup device OPPs
+ *
+ * Search list of device OPPs for one containing matching device.
+ *
+ * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * -EINVAL based on type of error.
+ */
+static struct device_opp *find_device_opp(struct device *dev)
+{
+	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
+
+	if (unlikely(!dev || IS_ERR(dev))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (tmp_dev_opp->dev == dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	return dev_opp;
+}
+
+/**
+ * opp_get_voltage() - Gets the voltage corresponding to an opp
+ * @opp:	opp for which voltage has to be returned for
+ *
+ * Return voltage in micro volt corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_voltage(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->u_volt;
+}
+
+/**
+ * opp_get_freq() - Gets the frequency corresponding to an opp
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Return frequency in hertz corresponding to the opp, else
+ * return 0
+ */
+unsigned long opp_get_freq(const struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->rate;
+}
+
+/**
+ * opp_find_by_opp_id - look up OPP by OPP ID (deprecated)
+ * @opp_type:	OPP type where we want the look up to happen.
+ * @opp_id:	OPP ID to search for
+ *
+ * Returns the struct omap_opp pointer corresponding to the given OPP
+ * ID @opp_id, or returns NULL on error.
+ */
+struct omap_opp * __deprecated opp_find_by_opp_id(struct device *dev,
+						  u8 opp_id)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->opp_id == opp_id) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_get_opp_id() - Provide OPP ID corresponding to an OPP (deprecated)
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Returns an OPP ID for the OPP required, if error, returns 0
+ */
+u8 __deprecated opp_get_opp_id(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
+		pr_err("%s: Invalid parameter being passed\n", __func__);
+		return 0;
+	}
+
+	return opp->opp_id;
+}
+
+/**
+ * opp_get_opp_count() - Get number of opps enabled in the opp list
+ * @opp_type:	OPP type we want to count
+ *
+ * This functions returns the number of opps if there are any OPPs enabled,
+ * else returns corresponding error value.
+ */
+int opp_get_opp_count(struct device *dev)
+{
+	struct device_opp *dev_opp;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return -ENODEV;
+
+	return dev_opp->enabled_opp_count;
+}
+
+/**
+ * opp_find_freq_exact() - search for an exact frequency
+ * @opp_type:	OPP type we want to search in.
+ * @freq:	frequency to search for
+ * @enabled:	enabled/disabled OPP to search for
+ *
+ * Searches for exact match in the opp list and returns handle to the matching
+ * opp if found, else returns ERR_PTR in case of error and should be handled
+ * using IS_ERR.
+ *
+ * Note enabled is a modifier for the search. if enabled=true, then the match is
+ * for exact matching frequency and is enabled. if false, the match is for exact
+ * frequency which is disabled.
+ */
+struct omap_opp *opp_find_freq_exact(struct device *dev,
+				     unsigned long freq, bool enabled)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate == freq) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_ceil() - Search for an rounded ceil freq
+ * @opp_type:	OPP type where we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching ceil *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next highest available frequency *
+ *	freq = 350000;
+ *	opp = opp_find_freq_ceil(OPP_MPU, &freq))
+ *	if (IS_ERR(opp))
+ *		pr_err("unable to find a higher frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in ascending order *
+ *	freq = 0; * Search for the lowest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_ceil(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq++; * for next higher match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate >= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_floor() - Search for an rounded floor freq
+ * @opp_type:	OPP type we want to search in
+ * @freq:	Start frequency
+ *
+ * Search for the matching floor *enabled* OPP from a starting freq
+ * for a domain.
+ *
+ * Returns *opp and *freq is populated with the next match, else
+ * returns NULL opp if no match, else returns ERR_PTR in case of error.
+ *
+ * Example usages:
+ *	* find match/next lowest available frequency
+ *	freq = 350000;
+ *	opp = opp_find_freq_floor(OPP_MPU, &freq)))
+ *	if (IS_ERR(opp))
+ *		pr_err ("unable to find a lower frequency\n");
+ *	else
+ *		pr_info("match freq = %ld\n", freq);
+ *
+ *	* print all supported frequencies in descending order *
+ *	freq = ULONG_MAX; * search highest enabled frequency *
+ *	while (!IS_ERR(opp = opp_find_freq_floor(OPP_MPU, &freq)) {
+ *		pr_info("freq = %ld\n", freq);
+ *		freq--; * for next lower match *
+ *	}
+ */
+struct omap_opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry_reverse(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->enabled && temp_opp->rate <= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/* wrapper to reuse converting opp_def to opp struct */
+static void omap_opp_populate(struct omap_opp *opp,
+			      const struct omap_opp_def *opp_def)
+{
+	opp->rate = opp_def->freq;
+	opp->enabled = opp_def->enabled;
+	opp->u_volt = opp_def->u_volt;
+}
+
+/**
+ * opp_add()  - Add an OPP table from a table definitions
+ * @opp_def:	omap_opp_def to describe the OPP which we want to add.
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ */
+int opp_add(const struct omap_opp_def *opp_def)
+{
+	struct omap_hwmod *oh;
+	struct device *dev = NULL;
+	struct device_opp *tmp_dev_opp, *dev_opp = NULL;
+	struct omap_opp *opp, *new_opp;
+	struct platform_device *pdev;
+	struct list_head *head;
+	int i;
+
+	/* find the correct hwmod, and device */
+	if (!opp_def->hwmod_name) {
+		pr_err("%s: missing name of omap_hwmod, ignoring.\n", __func__);
+		return -EINVAL;
+	}
+	oh = omap_hwmod_lookup(opp_def->hwmod_name);
+	if (!oh || !oh->od) {
+		pr_warn("%s: no hwmod or odev for %s, cannot add OPPs.\n",
+			__func__, opp_def->hwmod_name);
+		return -EINVAL;
+	}
+	pdev = &oh->od->pdev;
+	dev = &oh->od->pdev.dev;
+
+	/* Check for existing list for 'dev' */
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (dev == tmp_dev_opp->dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	if (!dev_opp) {
+		/* Allocate a new device OPP table */
+		dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL);
+		if (!dev_opp) {
+			pr_warning("%s: unable to allocate device struct\n",
+				__func__);
+			return -ENOMEM;
+		}
+
+		dev_opp->oh = oh;
+		dev_opp->dev = &oh->od->pdev.dev;
+		INIT_LIST_HEAD(&dev_opp->opp_list);
+
+		list_add(&dev_opp->node, &dev_opp_list);
+	}
+
+	/* allocate new OPP node */
+	new_opp = kzalloc(sizeof(struct omap_opp), GFP_KERNEL);
+	if (!new_opp) {
+		if (list_empty(&dev_opp->opp_list)) {
+			list_del(&dev_opp->node);
+			kfree(dev_opp);
+		}
+		pr_warning("%s: unable to allocate new opp node\n",
+			__func__);
+		return -ENOMEM;
+	}
+	omap_opp_populate(new_opp, opp_def);
+
+	/* Insert new OPP in order of increasing frequency */
+	head = &dev_opp->opp_list;
+	list_for_each_entry_reverse(opp, &dev_opp->opp_list, node) {
+		if (new_opp->rate >= opp->rate) {
+			head = &opp->node;
+			break;
+		}
+	}
+	list_add(&new_opp->node, head);
+	dev_opp->opp_count++;
+	if (new_opp->enabled)
+		dev_opp->enabled_opp_count++;
+
+	/* renumber (deprecated) OPP IDs based on new order */
+	i = 0;
+	list_for_each_entry(opp, &dev_opp->opp_list, node)
+		opp->opp_id = i++;
+
+	return 0;
+}
+
+/**
+ * opp_enable() - Enable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Enables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_enable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count++;
+
+	opp->enabled = true;
+
+	return 0;
+}
+
+/**
+ * opp_disable() - Disable a specific OPP
+ * @opp:	Pointer to opp
+ *
+ * Disables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value.
+ *
+ * OPP used here is from the the opp_is_valid/opp_has_freq or other search
+ * functions
+ */
+int opp_disable(struct omap_opp *opp)
+{
+	if (unlikely(!opp || IS_ERR(opp))) {
+		pr_err("%s: Invalid parameters being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	if (opp->enabled && opp->dev_opp)
+		opp->dev_opp->enabled_opp_count--;
+
+	opp->enabled = false;
+
+	return 0;
+}
+
+/**
+ * opp_init_cpufreq_table() - create a cpufreq table for a domain
+ * @opp_type:	OPP type to initialize this list for
+ * @table:	Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided domain - this assumes that the
+ * opp list is already initialized and ready for usage
+ */
+void opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table)
+{
+	struct device_opp *dev_opp;
+	struct omap_opp *opp;
+	struct cpufreq_frequency_table *freq_table;
+	int i = 0;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		pr_warning("%s: unable to find device\n", __func__);
+		return;
+	}
+
+	freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
+			     (dev_opp->enabled_opp_count + 1), GFP_ATOMIC);
+	if (!freq_table) {
+		pr_warning("%s: failed to allocate frequency table\n",
+			   __func__);
+		return;
+	}
+
+	list_for_each_entry(opp, &dev_opp->opp_list, node) {
+		if (opp->enabled) {
+			freq_table[i].index = i;
+			freq_table[i].frequency = opp->rate / 1000;
+			i++;
+		}
+	}
+
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	*table = &freq_table[0];
+}
-- 
1.7.2.1


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

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

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-15 21:56 [PATCH 0/4] OMAP OPP layer for 2.6.37 Kevin Hilman
2010-09-15 21:56 ` Kevin Hilman
2010-09-15 21:56 ` [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs Kevin Hilman
2010-09-15 21:56   ` Kevin Hilman
2010-09-16 10:25   ` Gopinath, Thara
2010-09-16 10:25     ` Gopinath, Thara
2010-09-16 10:32     ` Menon, Nishanth
2010-09-16 10:32       ` Menon, Nishanth
2010-09-16 10:33       ` Gopinath, Thara
2010-09-16 10:33         ` Gopinath, Thara
2010-09-16 12:19   ` Linus Walleij
2010-09-16 12:19     ` Linus Walleij
2010-09-16 12:40     ` Nishanth Menon
2010-09-16 12:40       ` Nishanth Menon
2010-09-16 13:24       ` Linus Walleij
2010-09-16 13:24         ` Linus Walleij
2010-09-16 15:08     ` Kevin Hilman
2010-09-16 15:08       ` Kevin Hilman
2010-09-16 15:31       ` Nishanth Menon
2010-09-16 15:31         ` Nishanth Menon
2010-09-16 15:48         ` Kevin Hilman
2010-09-16 15:48           ` Kevin Hilman
2010-09-16 17:07           ` Linus Walleij
2010-09-16 17:07             ` Linus Walleij
2010-09-16 17:10             ` Nishanth Menon
2010-09-16 17:10               ` Nishanth Menon
2010-09-16 17:13               ` Shilimkar, Santosh
2010-09-16 17:13                 ` Shilimkar, Santosh
2010-09-16 18:01                 ` Kevin Hilman
2010-09-16 18:01                   ` Kevin Hilman
2010-09-16 13:54   ` Roger Quadros
2010-09-16 13:54     ` Roger Quadros
2010-09-16 14:01     ` Nishanth Menon
2010-09-16 14:01       ` Nishanth Menon
2010-09-16 14:20       ` Roger Quadros
2010-09-16 14:20         ` Roger Quadros
2010-09-16 14:43         ` Nishanth Menon
2010-09-16 14:43           ` Nishanth Menon
2010-09-15 21:56 ` [PATCH 2/4] OMAP: OPP: twl/tps: Introduce TWL/TPS-specific code Kevin Hilman
2010-09-15 21:56   ` Kevin Hilman
2010-09-16 10:40   ` Gopinath, Thara
2010-09-16 10:40     ` Gopinath, Thara
2010-09-16 12:15     ` Nishanth Menon
2010-09-16 12:15       ` Nishanth Menon
2010-09-16 13:51       ` Gopinath, Thara
2010-09-16 13:51         ` Gopinath, Thara
2010-09-16 14:06         ` Nishanth Menon
2010-09-16 14:06           ` Nishanth Menon
2010-09-17 14:57           ` Gopinath, Thara
2010-09-17 14:57             ` Gopinath, Thara
2010-09-17 15:03             ` Nishanth Menon
2010-09-17 15:03               ` Nishanth Menon
2010-09-16 17:16     ` Kevin Hilman
2010-09-16 17:16       ` Kevin Hilman
2010-09-17 15:11       ` Gopinath, Thara
2010-09-17 15:11         ` Gopinath, Thara
2010-09-15 21:56 ` [PATCH 3/4] OMAP3: remove OPP interfaces from OMAP PM layer Kevin Hilman
2010-09-15 21:56   ` Kevin Hilman
2010-09-15 21:56 ` [PATCH 4/4] OMAP3: OPP: add OPP table data and initialization Kevin Hilman
2010-09-15 21:56   ` Kevin Hilman
  -- strict thread matches above, loose matches on Subject: below --
2010-08-11  0:09 [PATCH 0/4] OMAP OPP layer Kevin Hilman
2010-08-11  0:09 ` [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs Kevin Hilman
2010-08-11  0:07 [PATCH 0/4] OMAP OPP layer Kevin Hilman
2010-08-11  0:07 ` [PATCH 1/4] OMAP: introduce OPP layer for device-specific OPPs Kevin Hilman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.