All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Add a generic cpufreq-cpu0 driver
@ 2012-08-05 15:05 ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: cpufreq-u79uwXL29TY76Z2rM5mHXA, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Kevin Hilman, Nishanth Menon, Russell King - ARM Linux,
	Mike Turquette, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Changes since v1:
* Rebase on v3.6-rc1
* Add a patch introducing regulator_set_voltage_tol()
* Address review comments on v1

Richard Zhao (1):
  ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp

Shawn Guo (3):
  PM / OPP: Initialize OPP table from device tree
  regulator: add a new API regulator_set_voltage_tol()
  cpufreq: Add a generic cpufreq-cpu0 driver

 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |   55 ++++
 Documentation/devicetree/bindings/power/opp.txt    |   25 ++
 arch/arm/kernel/smp.c                              |   54 ++++
 drivers/base/power/opp.c                           |   65 +++++
 drivers/cpufreq/Kconfig                            |   11 +
 drivers/cpufreq/Makefile                           |    2 +
 drivers/cpufreq/cpufreq-cpu0.c                     |  271 ++++++++++++++++++++
 include/linux/opp.h                                |    8 +
 include/linux/regulator/consumer.h                 |    7 +
 9 files changed, 498 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
 create mode 100644 Documentation/devicetree/bindings/power/opp.txt
 create mode 100644 drivers/cpufreq/cpufreq-cpu0.c

-- 
1.7.5.4

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

* [PATCH v2 0/4] Add a generic cpufreq-cpu0 driver
@ 2012-08-05 15:05 ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

Changes since v1:
* Rebase on v3.6-rc1
* Add a patch introducing regulator_set_voltage_tol()
* Address review comments on v1

Richard Zhao (1):
  ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp

Shawn Guo (3):
  PM / OPP: Initialize OPP table from device tree
  regulator: add a new API regulator_set_voltage_tol()
  cpufreq: Add a generic cpufreq-cpu0 driver

 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |   55 ++++
 Documentation/devicetree/bindings/power/opp.txt    |   25 ++
 arch/arm/kernel/smp.c                              |   54 ++++
 drivers/base/power/opp.c                           |   65 +++++
 drivers/cpufreq/Kconfig                            |   11 +
 drivers/cpufreq/Makefile                           |    2 +
 drivers/cpufreq/cpufreq-cpu0.c                     |  271 ++++++++++++++++++++
 include/linux/opp.h                                |    8 +
 include/linux/regulator/consumer.h                 |    7 +
 9 files changed, 498 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
 create mode 100644 Documentation/devicetree/bindings/power/opp.txt
 create mode 100644 drivers/cpufreq/cpufreq-cpu0.c

-- 
1.7.5.4

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

* [PATCH v2 1/4] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp
  2012-08-05 15:05 ` Shawn Guo
@ 2012-08-05 15:05     ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: cpufreq-u79uwXL29TY76Z2rM5mHXA, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Kevin Hilman, Nishanth Menon, Russell King - ARM Linux,
	Mike Turquette, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	Richard Zhao, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

From: Richard Zhao <richard.zhao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different
arch has different per-cpu loops_per_jiffy definition.

Signed-off-by: Richard Zhao <richard.zhao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Acked-by: Russell King <rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
Acked-by: Santosh Shilimkar <santosh.shilimkar-l0cyMroinI0@public.gmane.org>
---
 arch/arm/kernel/smp.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad2..8e03567 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -25,6 +25,7 @@
 #include <linux/percpu.h>
 #include <linux/clockchips.h>
 #include <linux/completion.h>
+#include <linux/cpufreq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -584,3 +585,56 @@ int setup_profiling_timer(unsigned int multiplier)
 {
 	return -EINVAL;
 }
+
+#ifdef CONFIG_CPU_FREQ
+
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
+static unsigned long global_l_p_j_ref;
+static unsigned long global_l_p_j_ref_freq;
+
+static int cpufreq_callback(struct notifier_block *nb,
+					unsigned long val, void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	int cpu = freq->cpu;
+
+	if (freq->flags & CPUFREQ_CONST_LOOPS)
+		return NOTIFY_OK;
+
+	if (!per_cpu(l_p_j_ref, cpu)) {
+		per_cpu(l_p_j_ref, cpu) =
+			per_cpu(cpu_data, cpu).loops_per_jiffy;
+		per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+		if (!global_l_p_j_ref) {
+			global_l_p_j_ref = loops_per_jiffy;
+			global_l_p_j_ref_freq = freq->old;
+		}
+	}
+
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+		loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
+						global_l_p_j_ref_freq,
+						freq->new);
+		per_cpu(cpu_data, cpu).loops_per_jiffy =
+			cpufreq_scale(per_cpu(l_p_j_ref, cpu),
+					per_cpu(l_p_j_ref_freq, cpu),
+					freq->new);
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_notifier = {
+	.notifier_call  = cpufreq_callback,
+};
+
+static int __init register_cpufreq_notifier(void)
+{
+	return cpufreq_register_notifier(&cpufreq_notifier,
+						CPUFREQ_TRANSITION_NOTIFIER);
+}
+core_initcall(register_cpufreq_notifier);
+
+#endif
-- 
1.7.5.4

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

* [PATCH v2 1/4] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp
@ 2012-08-05 15:05     ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Richard Zhao <richard.zhao@linaro.org>

If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different
arch has different per-cpu loops_per_jiffy definition.

Signed-off-by: Richard Zhao <richard.zhao@linaro.org>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/kernel/smp.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad2..8e03567 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -25,6 +25,7 @@
 #include <linux/percpu.h>
 #include <linux/clockchips.h>
 #include <linux/completion.h>
+#include <linux/cpufreq.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -584,3 +585,56 @@ int setup_profiling_timer(unsigned int multiplier)
 {
 	return -EINVAL;
 }
+
+#ifdef CONFIG_CPU_FREQ
+
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
+static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
+static unsigned long global_l_p_j_ref;
+static unsigned long global_l_p_j_ref_freq;
+
+static int cpufreq_callback(struct notifier_block *nb,
+					unsigned long val, void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	int cpu = freq->cpu;
+
+	if (freq->flags & CPUFREQ_CONST_LOOPS)
+		return NOTIFY_OK;
+
+	if (!per_cpu(l_p_j_ref, cpu)) {
+		per_cpu(l_p_j_ref, cpu) =
+			per_cpu(cpu_data, cpu).loops_per_jiffy;
+		per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+		if (!global_l_p_j_ref) {
+			global_l_p_j_ref = loops_per_jiffy;
+			global_l_p_j_ref_freq = freq->old;
+		}
+	}
+
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+		loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
+						global_l_p_j_ref_freq,
+						freq->new);
+		per_cpu(cpu_data, cpu).loops_per_jiffy =
+			cpufreq_scale(per_cpu(l_p_j_ref, cpu),
+					per_cpu(l_p_j_ref_freq, cpu),
+					freq->new);
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_notifier = {
+	.notifier_call  = cpufreq_callback,
+};
+
+static int __init register_cpufreq_notifier(void)
+{
+	return cpufreq_register_notifier(&cpufreq_notifier,
+						CPUFREQ_TRANSITION_NOTIFIER);
+}
+core_initcall(register_cpufreq_notifier);
+
+#endif
-- 
1.7.5.4

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

* [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
  2012-08-05 15:05 ` Shawn Guo
@ 2012-08-05 15:05     ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: cpufreq-u79uwXL29TY76Z2rM5mHXA, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Kevin Hilman, Nishanth Menon, Russell King - ARM Linux,
	Mike Turquette, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

With a lot of devices booting from device tree nowadays, it requires
that OPP table can be initialized from device tree.  The patch adds
a helper function of_init_opp_table together with a binding doc for
that purpose.

Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 Documentation/devicetree/bindings/power/opp.txt |   25 +++++++++
 drivers/base/power/opp.c                        |   65 +++++++++++++++++++++++
 include/linux/opp.h                             |    8 +++
 3 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/opp.txt

diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
new file mode 100644
index 0000000..2238520
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/opp.txt
@@ -0,0 +1,25 @@
+* Generic OPP Interface
+
+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.
+
+Properties:
+- operating-points: An array of 3-tuples items, and each item consists
+  of frequency and voltage like <freq-kHz vol-uV>.
+	freq: clock frequency in kHz
+	vol: voltage in microvolt
+
+Examples:
+
+cpu@0 {
+	compatible = "arm,cortex-a9";
+	reg = <0>;
+	next-level-cache = <&L2>;
+	operating-points = <
+		/* kHz    uV */
+		792000  1100000
+		396000  950000
+		198000  850000
+	>;
+};
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index ac993ea..1bf1be8 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -22,6 +22,7 @@
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
+#include <linux/of.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -674,3 +675,67 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
 
 	return &dev_opp->head;
 }
+
+#ifdef CONFIG_OF
+/**
+ * of_init_opp_table() - Initialize opp table from device tree
+ * @dev:	device pointer used to lookup device OPPs.
+ *
+ * Register the initial OPP table with the OPP library for given device.
+ */
+int of_init_opp_table(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const char *propname = "operating-points";
+	const struct property *pp;
+	u32 *opp;
+	int ret, i, nr;
+
+	pp = of_find_property(np, propname, NULL);
+	if (!pp) {
+		dev_err(dev, "%s: Unable to find property", __func__);
+		return -ENODEV;
+	}
+
+	opp = kzalloc(pp->length, GFP_KERNEL);
+	if (!opp) {
+		dev_err(dev, "%s: Unable to allocate array\n", __func__);
+		return -ENOMEM;
+	}
+
+	nr = pp->length / sizeof(u32);
+	ret = of_property_read_u32_array(np, propname, opp, nr);
+	if (ret) {
+		dev_err(dev, "%s: Unable to read OPPs\n", __func__);
+		goto out;
+	}
+
+	if (nr % 2) {
+		dev_err(dev, "%s: Invalid OPP list\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nr /= 2;
+	for (i = 0; i < nr; i++) {
+		/*
+		 * Each OPP is a set of tuples consisting of frequency and
+		 * voltage like <freq-kHz vol-uV>.
+		 */
+		u32 *val = opp + i * 2;
+
+		val[0] *= 1000;
+		ret = opp_add(dev, val[0], val[1]);
+		if (ret) {
+			dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
+				 __func__, val[0], ret);
+			continue;
+		}
+	}
+
+	ret = 0;
+out:
+	kfree(opp);
+	return ret;
+}
+#endif
diff --git a/include/linux/opp.h b/include/linux/opp.h
index 2a4e5fa..214e0eb 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -48,6 +48,14 @@ int opp_disable(struct device *dev, unsigned long freq);
 
 struct srcu_notifier_head *opp_get_notifier(struct device *dev);
 
+#ifdef CONFIG_OF
+int of_init_opp_table(struct device *dev);
+#else
+static inline int of_init_opp_table(struct device *dev)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_OF */
 #else
 static inline unsigned long opp_get_voltage(struct opp *opp)
 {
-- 
1.7.5.4

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

* [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
@ 2012-08-05 15:05     ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

With a lot of devices booting from device tree nowadays, it requires
that OPP table can be initialized from device tree.  The patch adds
a helper function of_init_opp_table together with a binding doc for
that purpose.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 Documentation/devicetree/bindings/power/opp.txt |   25 +++++++++
 drivers/base/power/opp.c                        |   65 +++++++++++++++++++++++
 include/linux/opp.h                             |    8 +++
 3 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/opp.txt

diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
new file mode 100644
index 0000000..2238520
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/opp.txt
@@ -0,0 +1,25 @@
+* Generic OPP Interface
+
+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.
+
+Properties:
+- operating-points: An array of 3-tuples items, and each item consists
+  of frequency and voltage like <freq-kHz vol-uV>.
+	freq: clock frequency in kHz
+	vol: voltage in microvolt
+
+Examples:
+
+cpu at 0 {
+	compatible = "arm,cortex-a9";
+	reg = <0>;
+	next-level-cache = <&L2>;
+	operating-points = <
+		/* kHz    uV */
+		792000  1100000
+		396000  950000
+		198000  850000
+	>;
+};
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index ac993ea..1bf1be8 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -22,6 +22,7 @@
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
+#include <linux/of.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -674,3 +675,67 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
 
 	return &dev_opp->head;
 }
+
+#ifdef CONFIG_OF
+/**
+ * of_init_opp_table() - Initialize opp table from device tree
+ * @dev:	device pointer used to lookup device OPPs.
+ *
+ * Register the initial OPP table with the OPP library for given device.
+ */
+int of_init_opp_table(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const char *propname = "operating-points";
+	const struct property *pp;
+	u32 *opp;
+	int ret, i, nr;
+
+	pp = of_find_property(np, propname, NULL);
+	if (!pp) {
+		dev_err(dev, "%s: Unable to find property", __func__);
+		return -ENODEV;
+	}
+
+	opp = kzalloc(pp->length, GFP_KERNEL);
+	if (!opp) {
+		dev_err(dev, "%s: Unable to allocate array\n", __func__);
+		return -ENOMEM;
+	}
+
+	nr = pp->length / sizeof(u32);
+	ret = of_property_read_u32_array(np, propname, opp, nr);
+	if (ret) {
+		dev_err(dev, "%s: Unable to read OPPs\n", __func__);
+		goto out;
+	}
+
+	if (nr % 2) {
+		dev_err(dev, "%s: Invalid OPP list\n", __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	nr /= 2;
+	for (i = 0; i < nr; i++) {
+		/*
+		 * Each OPP is a set of tuples consisting of frequency and
+		 * voltage like <freq-kHz vol-uV>.
+		 */
+		u32 *val = opp + i * 2;
+
+		val[0] *= 1000;
+		ret = opp_add(dev, val[0], val[1]);
+		if (ret) {
+			dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
+				 __func__, val[0], ret);
+			continue;
+		}
+	}
+
+	ret = 0;
+out:
+	kfree(opp);
+	return ret;
+}
+#endif
diff --git a/include/linux/opp.h b/include/linux/opp.h
index 2a4e5fa..214e0eb 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -48,6 +48,14 @@ int opp_disable(struct device *dev, unsigned long freq);
 
 struct srcu_notifier_head *opp_get_notifier(struct device *dev);
 
+#ifdef CONFIG_OF
+int of_init_opp_table(struct device *dev);
+#else
+static inline int of_init_opp_table(struct device *dev)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_OF */
 #else
 static inline unsigned long opp_get_voltage(struct opp *opp)
 {
-- 
1.7.5.4

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

* [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
  2012-08-05 15:05 ` Shawn Guo
@ 2012-08-05 15:05     ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: cpufreq-u79uwXL29TY76Z2rM5mHXA, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Kevin Hilman, Nishanth Menon, Russell King - ARM Linux,
	Mike Turquette, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

There are some use cases where a voltage range could be reasonably
specified by a target voltage and tolerance.  Add a new API
regulator_set_voltage_tol() wrapping regulator_set_voltage() call
to ease the users.

Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 include/linux/regulator/consumer.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index da339fd..2160352 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -352,4 +352,11 @@ static inline void regulator_set_drvdata(struct regulator *regulator,
 
 #endif
 
+static inline int regulator_set_voltage_tol(struct regulator *regulator,
+					    int new_uV, int tol_uV)
+{
+	return regulator_set_voltage(regulator,
+				     new_uV - tol_uV, new_uV + tol_uV);
+}
+
 #endif
-- 
1.7.5.4

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

* [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
@ 2012-08-05 15:05     ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

There are some use cases where a voltage range could be reasonably
specified by a target voltage and tolerance.  Add a new API
regulator_set_voltage_tol() wrapping regulator_set_voltage() call
to ease the users.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 include/linux/regulator/consumer.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index da339fd..2160352 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -352,4 +352,11 @@ static inline void regulator_set_drvdata(struct regulator *regulator,
 
 #endif
 
+static inline int regulator_set_voltage_tol(struct regulator *regulator,
+					    int new_uV, int tol_uV)
+{
+	return regulator_set_voltage(regulator,
+				     new_uV - tol_uV, new_uV + tol_uV);
+}
+
 #endif
-- 
1.7.5.4

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

* [PATCH v2 4/4] cpufreq: Add a generic cpufreq-cpu0 driver
  2012-08-05 15:05 ` Shawn Guo
@ 2012-08-05 15:05     ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: cpufreq-u79uwXL29TY76Z2rM5mHXA, linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Kevin Hilman, Nishanth Menon, Russell King - ARM Linux,
	Mike Turquette, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

It adds a generic cpufreq driver for CPU0 frequency management based on
clk, regulator, OPP and device tree support.  It can support both
uniprocessor (UP) and those symmetric multiprocessor (SMP) systems which
share clock and voltage across all CPUs.

Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |   55 ++++
 drivers/cpufreq/Kconfig                            |   11 +
 drivers/cpufreq/Makefile                           |    2 +
 drivers/cpufreq/cpufreq-cpu0.c                     |  271 ++++++++++++++++++++
 4 files changed, 339 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
 create mode 100644 drivers/cpufreq/cpufreq-cpu0.c

diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
new file mode 100644
index 0000000..4416ccc
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -0,0 +1,55 @@
+Generic CPU0 cpufreq driver
+
+It is a generic cpufreq driver for CPU0 frequency management.  It
+supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
+systems which share clock and voltage across all CPUs.
+
+Both required and optional properties listed below must be defined
+under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+
+Optional properties:
+- clock-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+- voltage-tolerance: Specify the CPU voltage tolerance in percentage.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz    uV */
+			792000  1100000
+			396000  950000
+			198000  850000
+		>;
+		transition-latency = <61036>; /* two CLK32 periods */
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index e24a2a1..ea512f4 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -179,6 +179,17 @@ config CPU_FREQ_GOV_CONSERVATIVE
 
 	  If in doubt, say N.
 
+config GENERIC_CPUFREQ_CPU0
+	bool "Generic CPU0 cpufreq driver"
+	depends on HAVE_CLK && REGULATOR && PM_OPP && OF
+	select CPU_FREQ_TABLE
+	help
+	  This adds a generic cpufreq driver for CPU0 frequency management.
+	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
+	  systems which share clock and voltage across all CPUs.
+
+	  If in doubt, say N.
+
 menu "x86 CPU frequency scaling drivers"
 depends on X86
 source "drivers/cpufreq/Kconfig.x86"
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 9531fc2..a378ed2 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
 # CPUfreq cross-arch helpers
 obj-$(CONFIG_CPU_FREQ_TABLE)		+= freq_table.o
 
+obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)	+= cpufreq-cpu0.o
+
 ##################################################################################
 # x86 drivers.
 # Link order matters. K8 is preferred to ACPI because of firmware bugs in early
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
new file mode 100644
index 0000000..fd3bac6
--- /dev/null
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * Reuse some codes from drivers/cpufreq/omap-cpufreq.c
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+static unsigned int transition_latency;
+static unsigned int voltage_tolerance; /* in percentage */
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct regulator *cpu_reg;
+static struct cpufreq_frequency_table *freq_table;
+
+static int cpu0_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int cpu0_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int cpu0_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	struct opp *opp;
+	unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	if (cpu_reg) {
+		opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
+		if (IS_ERR(opp)) {
+			pr_err("failed to find OPP for %ld\n", freq_Hz);
+			return PTR_ERR(opp);
+		}
+		volt = opp_get_voltage(opp);
+		tol = volt * voltage_tolerance / 100;
+		volt_old = regulator_get_voltage(cpu_reg);
+	}
+
+	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
+		 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+		 freqs.new / 1000, volt ? volt / 1000 : -1);
+
+	/* scaling up?  scale voltage before frequency */
+	if (cpu_reg && freqs.new > freqs.old) {
+		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
+		if (ret) {
+			pr_err("failed to scale voltage up: %d\n", ret);
+			freqs.new = freqs.old;
+			return ret;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		if (cpu_reg)
+			regulator_set_voltage_tol(cpu_reg, volt_old, tol);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (cpu_reg && freqs.new < freqs.old) {
+		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
+		if (ret) {
+			pr_err("failed to scale voltage down: %d\n", ret);
+			clk_set_rate(cpu_clk, freqs.old * 1000);
+			freqs.new = freqs.old;
+			return ret;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	/*
+	 * The driver only supports the SMP configuartion where all processors
+	 * share the clock and voltage and clock.  Use cpufreq affected_cpus
+	 * interface to have all CPUs scaled together.
+	 */
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int cpu0_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *cpu0_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver cpu0_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = cpu0_verify_speed,
+	.target = cpu0_set_target,
+	.get = cpu0_get_speed,
+	.init = cpu0_cpufreq_init,
+	.exit = cpu0_cpufreq_exit,
+	.name = "generic_cpu0",
+	.attr = cpu0_cpufreq_attr,
+};
+
+static int __devinit cpu0_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find cpu0 node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get cpu0 device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	cpu_reg = regulator_get(cpu_dev, "cpu0");
+	if (IS_ERR(cpu_reg)) {
+		pr_warn("failed to get cpu0 regulator\n");
+		cpu_reg = NULL;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
+
+	if (of_property_read_u32(np, "clock-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	if (cpu_reg) {
+		struct opp *opp;
+		unsigned long min_uV, max_uV;
+		int i;
+
+		/*
+		 * OPP is maintained in order of increasing frequency, and
+		 * freq_table initialised from OPP is therefore sorted in the
+		 * same order.
+		 */
+		for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+			;
+		opp = opp_find_freq_exact(cpu_dev,
+				freq_table[0].frequency * 1000, true);
+		min_uV = opp_get_voltage(opp);
+		opp = opp_find_freq_exact(cpu_dev,
+				freq_table[i-1].frequency * 1000, true);
+		max_uV = opp_get_voltage(opp);
+		ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
+		if (ret > 0)
+			transition_latency += ret * 1000;
+	}
+
+	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(cpu0_cpufreq_driver_init);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>");
+MODULE_DESCRIPTION("Generic CPU0 cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.5.4

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

* [PATCH v2 4/4] cpufreq: Add a generic cpufreq-cpu0 driver
@ 2012-08-05 15:05     ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-05 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

It adds a generic cpufreq driver for CPU0 frequency management based on
clk, regulator, OPP and device tree support.  It can support both
uniprocessor (UP) and those symmetric multiprocessor (SMP) systems which
share clock and voltage across all CPUs.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |   55 ++++
 drivers/cpufreq/Kconfig                            |   11 +
 drivers/cpufreq/Makefile                           |    2 +
 drivers/cpufreq/cpufreq-cpu0.c                     |  271 ++++++++++++++++++++
 4 files changed, 339 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
 create mode 100644 drivers/cpufreq/cpufreq-cpu0.c

diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
new file mode 100644
index 0000000..4416ccc
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -0,0 +1,55 @@
+Generic CPU0 cpufreq driver
+
+It is a generic cpufreq driver for CPU0 frequency management.  It
+supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
+systems which share clock and voltage across all CPUs.
+
+Both required and optional properties listed below must be defined
+under node /cpus/cpu at 0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+
+Optional properties:
+- clock-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+- voltage-tolerance: Specify the CPU voltage tolerance in percentage.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu at 0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz    uV */
+			792000  1100000
+			396000  950000
+			198000  850000
+		>;
+		transition-latency = <61036>; /* two CLK32 periods */
+	};
+
+	cpu at 1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu at 2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu at 3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index e24a2a1..ea512f4 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -179,6 +179,17 @@ config CPU_FREQ_GOV_CONSERVATIVE
 
 	  If in doubt, say N.
 
+config GENERIC_CPUFREQ_CPU0
+	bool "Generic CPU0 cpufreq driver"
+	depends on HAVE_CLK && REGULATOR && PM_OPP && OF
+	select CPU_FREQ_TABLE
+	help
+	  This adds a generic cpufreq driver for CPU0 frequency management.
+	  It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
+	  systems which share clock and voltage across all CPUs.
+
+	  If in doubt, say N.
+
 menu "x86 CPU frequency scaling drivers"
 depends on X86
 source "drivers/cpufreq/Kconfig.x86"
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 9531fc2..a378ed2 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
 # CPUfreq cross-arch helpers
 obj-$(CONFIG_CPU_FREQ_TABLE)		+= freq_table.o
 
+obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)	+= cpufreq-cpu0.o
+
 ##################################################################################
 # x86 drivers.
 # Link order matters. K8 is preferred to ACPI because of firmware bugs in early
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
new file mode 100644
index 0000000..fd3bac6
--- /dev/null
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * Reuse some codes from drivers/cpufreq/omap-cpufreq.c
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+static unsigned int transition_latency;
+static unsigned int voltage_tolerance; /* in percentage */
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct regulator *cpu_reg;
+static struct cpufreq_frequency_table *freq_table;
+
+static int cpu0_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int cpu0_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int cpu0_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	struct opp *opp;
+	unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	if (cpu_reg) {
+		opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
+		if (IS_ERR(opp)) {
+			pr_err("failed to find OPP for %ld\n", freq_Hz);
+			return PTR_ERR(opp);
+		}
+		volt = opp_get_voltage(opp);
+		tol = volt * voltage_tolerance / 100;
+		volt_old = regulator_get_voltage(cpu_reg);
+	}
+
+	pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
+		 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+		 freqs.new / 1000, volt ? volt / 1000 : -1);
+
+	/* scaling up?  scale voltage before frequency */
+	if (cpu_reg && freqs.new > freqs.old) {
+		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
+		if (ret) {
+			pr_err("failed to scale voltage up: %d\n", ret);
+			freqs.new = freqs.old;
+			return ret;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		if (cpu_reg)
+			regulator_set_voltage_tol(cpu_reg, volt_old, tol);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (cpu_reg && freqs.new < freqs.old) {
+		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
+		if (ret) {
+			pr_err("failed to scale voltage down: %d\n", ret);
+			clk_set_rate(cpu_clk, freqs.old * 1000);
+			freqs.new = freqs.old;
+			return ret;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	/*
+	 * The driver only supports the SMP configuartion where all processors
+	 * share the clock and voltage and clock.  Use cpufreq affected_cpus
+	 * interface to have all CPUs scaled together.
+	 */
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int cpu0_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *cpu0_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver cpu0_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = cpu0_verify_speed,
+	.target = cpu0_set_target,
+	.get = cpu0_get_speed,
+	.init = cpu0_cpufreq_init,
+	.exit = cpu0_cpufreq_exit,
+	.name = "generic_cpu0",
+	.attr = cpu0_cpufreq_attr,
+};
+
+static int __devinit cpu0_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu at 0");
+	if (!np) {
+		pr_err("failed to find cpu0 node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get cpu0 device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	cpu_reg = regulator_get(cpu_dev, "cpu0");
+	if (IS_ERR(cpu_reg)) {
+		pr_warn("failed to get cpu0 regulator\n");
+		cpu_reg = NULL;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
+
+	if (of_property_read_u32(np, "clock-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	if (cpu_reg) {
+		struct opp *opp;
+		unsigned long min_uV, max_uV;
+		int i;
+
+		/*
+		 * OPP is maintained in order of increasing frequency, and
+		 * freq_table initialised from OPP is therefore sorted in the
+		 * same order.
+		 */
+		for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+			;
+		opp = opp_find_freq_exact(cpu_dev,
+				freq_table[0].frequency * 1000, true);
+		min_uV = opp_get_voltage(opp);
+		opp = opp_find_freq_exact(cpu_dev,
+				freq_table[i-1].frequency * 1000, true);
+		max_uV = opp_get_voltage(opp);
+		ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
+		if (ret > 0)
+			transition_latency += ret * 1000;
+	}
+
+	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(cpu0_cpufreq_driver_init);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Generic CPU0 cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.5.4

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

* Re: [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
  2012-08-05 15:05     ` Shawn Guo
@ 2012-08-06  2:50         ` Rob Herring
  -1 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2012-08-06  2:50 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Kevin Hilman, Nishanth Menon, Mike Turquette, Richard Zhao,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Mark Brown,
	cpufreq-u79uwXL29TY76Z2rM5mHXA, Rafael J. Wysocki,
	Shilimkar Santosh, Russell King - ARM Linux,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 08/05/2012 10:05 AM, Shawn Guo wrote:
> With a lot of devices booting from device tree nowadays, it requires
> that OPP table can be initialized from device tree.  The patch adds
> a helper function of_init_opp_table together with a binding doc for
> that purpose.
> 
> Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/power/opp.txt |   25 +++++++++
>  drivers/base/power/opp.c                        |   65 +++++++++++++++++++++++
>  include/linux/opp.h                             |    8 +++
>  3 files changed, 98 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/opp.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
> new file mode 100644
> index 0000000..2238520
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/opp.txt
> @@ -0,0 +1,25 @@
> +* Generic OPP Interface
> +
> +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.
> +
> +Properties:
> +- operating-points: An array of 3-tuples items, and each item consists

3 tuples?

> +  of frequency and voltage like <freq-kHz vol-uV>.
> +	freq: clock frequency in kHz
> +	vol: voltage in microvolt

Although maybe 3 fields would be good for a flags field? I'm concerned
it's a pretty generic name and not very future proof. What about
transition times? Not sure how you would represent that as it probably
depends on which points you are changing between rather than a property
of the opp.

I'm not saying we have to address that now, but just have some path in
the future.

> +
> +Examples:
> +
> +cpu@0 {
> +	compatible = "arm,cortex-a9";
> +	reg = <0>;
> +	next-level-cache = <&L2>;
> +	operating-points = <
> +		/* kHz    uV */
> +		792000  1100000
> +		396000  950000
> +		198000  850000
> +	>;
> +};
> diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> index ac993ea..1bf1be8 100644
> --- a/drivers/base/power/opp.c
> +++ b/drivers/base/power/opp.c
> @@ -22,6 +22,7 @@
>  #include <linux/rculist.h>
>  #include <linux/rcupdate.h>
>  #include <linux/opp.h>
> +#include <linux/of.h>
>  
>  /*
>   * Internal data structure organization with the OPP layer library is as
> @@ -674,3 +675,67 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
>  
>  	return &dev_opp->head;
>  }
> +
> +#ifdef CONFIG_OF
> +/**
> + * of_init_opp_table() - Initialize opp table from device tree
> + * @dev:	device pointer used to lookup device OPPs.
> + *
> + * Register the initial OPP table with the OPP library for given device.
> + */
> +int of_init_opp_table(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	const char *propname = "operating-points";
> +	const struct property *pp;
> +	u32 *opp;
> +	int ret, i, nr;
> +
> +	pp = of_find_property(np, propname, NULL);
> +	if (!pp) {
> +		dev_err(dev, "%s: Unable to find property", __func__);
> +		return -ENODEV;
> +	}
> +
> +	opp = kzalloc(pp->length, GFP_KERNEL);
> +	if (!opp) {
> +		dev_err(dev, "%s: Unable to allocate array\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	nr = pp->length / sizeof(u32);
> +	ret = of_property_read_u32_array(np, propname, opp, nr);
> +	if (ret) {
> +		dev_err(dev, "%s: Unable to read OPPs\n", __func__);
> +		goto out;
> +	}
> +
> +	if (nr % 2) {
> +		dev_err(dev, "%s: Invalid OPP list\n", __func__);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	nr /= 2;
> +	for (i = 0; i < nr; i++) {
> +		/*
> +		 * Each OPP is a set of tuples consisting of frequency and
> +		 * voltage like <freq-kHz vol-uV>.
> +		 */
> +		u32 *val = opp + i * 2;
> +
> +		val[0] *= 1000;
> +		ret = opp_add(dev, val[0], val[1]);
> +		if (ret) {
> +			dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
> +				 __func__, val[0], ret);
> +			continue;
> +		}
> +	}

I think this whole function can be written more concisely. Just iterate
over the property and avoid the intermediate array allocation.

Rob

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

* [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
@ 2012-08-06  2:50         ` Rob Herring
  0 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2012-08-06  2:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/05/2012 10:05 AM, Shawn Guo wrote:
> With a lot of devices booting from device tree nowadays, it requires
> that OPP table can be initialized from device tree.  The patch adds
> a helper function of_init_opp_table together with a binding doc for
> that purpose.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  Documentation/devicetree/bindings/power/opp.txt |   25 +++++++++
>  drivers/base/power/opp.c                        |   65 +++++++++++++++++++++++
>  include/linux/opp.h                             |    8 +++
>  3 files changed, 98 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/opp.txt
> 
> diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
> new file mode 100644
> index 0000000..2238520
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/opp.txt
> @@ -0,0 +1,25 @@
> +* Generic OPP Interface
> +
> +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.
> +
> +Properties:
> +- operating-points: An array of 3-tuples items, and each item consists

3 tuples?

> +  of frequency and voltage like <freq-kHz vol-uV>.
> +	freq: clock frequency in kHz
> +	vol: voltage in microvolt

Although maybe 3 fields would be good for a flags field? I'm concerned
it's a pretty generic name and not very future proof. What about
transition times? Not sure how you would represent that as it probably
depends on which points you are changing between rather than a property
of the opp.

I'm not saying we have to address that now, but just have some path in
the future.

> +
> +Examples:
> +
> +cpu at 0 {
> +	compatible = "arm,cortex-a9";
> +	reg = <0>;
> +	next-level-cache = <&L2>;
> +	operating-points = <
> +		/* kHz    uV */
> +		792000  1100000
> +		396000  950000
> +		198000  850000
> +	>;
> +};
> diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> index ac993ea..1bf1be8 100644
> --- a/drivers/base/power/opp.c
> +++ b/drivers/base/power/opp.c
> @@ -22,6 +22,7 @@
>  #include <linux/rculist.h>
>  #include <linux/rcupdate.h>
>  #include <linux/opp.h>
> +#include <linux/of.h>
>  
>  /*
>   * Internal data structure organization with the OPP layer library is as
> @@ -674,3 +675,67 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
>  
>  	return &dev_opp->head;
>  }
> +
> +#ifdef CONFIG_OF
> +/**
> + * of_init_opp_table() - Initialize opp table from device tree
> + * @dev:	device pointer used to lookup device OPPs.
> + *
> + * Register the initial OPP table with the OPP library for given device.
> + */
> +int of_init_opp_table(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	const char *propname = "operating-points";
> +	const struct property *pp;
> +	u32 *opp;
> +	int ret, i, nr;
> +
> +	pp = of_find_property(np, propname, NULL);
> +	if (!pp) {
> +		dev_err(dev, "%s: Unable to find property", __func__);
> +		return -ENODEV;
> +	}
> +
> +	opp = kzalloc(pp->length, GFP_KERNEL);
> +	if (!opp) {
> +		dev_err(dev, "%s: Unable to allocate array\n", __func__);
> +		return -ENOMEM;
> +	}
> +
> +	nr = pp->length / sizeof(u32);
> +	ret = of_property_read_u32_array(np, propname, opp, nr);
> +	if (ret) {
> +		dev_err(dev, "%s: Unable to read OPPs\n", __func__);
> +		goto out;
> +	}
> +
> +	if (nr % 2) {
> +		dev_err(dev, "%s: Invalid OPP list\n", __func__);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	nr /= 2;
> +	for (i = 0; i < nr; i++) {
> +		/*
> +		 * Each OPP is a set of tuples consisting of frequency and
> +		 * voltage like <freq-kHz vol-uV>.
> +		 */
> +		u32 *val = opp + i * 2;
> +
> +		val[0] *= 1000;
> +		ret = opp_add(dev, val[0], val[1]);
> +		if (ret) {
> +			dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
> +				 __func__, val[0], ret);
> +			continue;
> +		}
> +	}

I think this whole function can be written more concisely. Just iterate
over the property and avoid the intermediate array allocation.

Rob

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

* Re: [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
  2012-08-06  2:50         ` Rob Herring
@ 2012-08-06  3:19           ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-06  3:19 UTC (permalink / raw)
  To: Rob Herring
  Cc: cpufreq, linux-pm, Kevin Hilman, Nishanth Menon,
	Russell King - ARM Linux, Mike Turquette, devicetree-discuss,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel

On Sun, Aug 05, 2012 at 09:50:32PM -0500, Rob Herring wrote:
> > +Properties:
> > +- operating-points: An array of 3-tuples items, and each item consists
> 
> 3 tuples?
> 
It's the case of v1, and I forgot updating it.  Thanks for spotting it.

> > +  of frequency and voltage like <freq-kHz vol-uV>.
> > +	freq: clock frequency in kHz
> > +	vol: voltage in microvolt
> 
> Although maybe 3 fields would be good for a flags field? I'm concerned
> it's a pretty generic name and not very future proof. What about
> transition times? Not sure how you would represent that as it probably
> depends on which points you are changing between rather than a property
> of the opp.
> 
This is a binding for OPP, which does not define transition times.

As for cpufreq, we only need to represent a possible maximum transition
latency.  The driver will ask regulator subsystem for voltage latency,
while the clock latency is defined in DT. 

> I think this whole function can be written more concisely. Just iterate
> over the property and avoid the intermediate array allocation.
> 
I'm not sure about that, since directly iterating over the property
means we have to take care of all these sanity checks done in API
of_property_read_u32_array().

-- 
Regards,
Shawn


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

* [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
@ 2012-08-06  3:19           ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-06  3:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Aug 05, 2012 at 09:50:32PM -0500, Rob Herring wrote:
> > +Properties:
> > +- operating-points: An array of 3-tuples items, and each item consists
> 
> 3 tuples?
> 
It's the case of v1, and I forgot updating it.  Thanks for spotting it.

> > +  of frequency and voltage like <freq-kHz vol-uV>.
> > +	freq: clock frequency in kHz
> > +	vol: voltage in microvolt
> 
> Although maybe 3 fields would be good for a flags field? I'm concerned
> it's a pretty generic name and not very future proof. What about
> transition times? Not sure how you would represent that as it probably
> depends on which points you are changing between rather than a property
> of the opp.
> 
This is a binding for OPP, which does not define transition times.

As for cpufreq, we only need to represent a possible maximum transition
latency.  The driver will ask regulator subsystem for voltage latency,
while the clock latency is defined in DT. 

> I think this whole function can be written more concisely. Just iterate
> over the property and avoid the intermediate array allocation.
> 
I'm not sure about that, since directly iterating over the property
means we have to take care of all these sanity checks done in API
of_property_read_u32_array().

-- 
Regards,
Shawn

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

* Re: [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
  2012-08-06  3:19           ` Shawn Guo
@ 2012-08-06  4:43             ` Rob Herring
  -1 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2012-08-06  4:43 UTC (permalink / raw)
  To: Shawn Guo
  Cc: cpufreq, linux-pm, Kevin Hilman, Nishanth Menon,
	Russell King - ARM Linux, Mike Turquette, devicetree-discuss,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel

On 08/05/2012 10:19 PM, Shawn Guo wrote:
> On Sun, Aug 05, 2012 at 09:50:32PM -0500, Rob Herring wrote:
>>> +Properties:
>>> +- operating-points: An array of 3-tuples items, and each item consists
>>
>> 3 tuples?
>>
> It's the case of v1, and I forgot updating it.  Thanks for spotting it.
> 
>>> +  of frequency and voltage like <freq-kHz vol-uV>.
>>> +	freq: clock frequency in kHz
>>> +	vol: voltage in microvolt
>>
>> Although maybe 3 fields would be good for a flags field? I'm concerned
>> it's a pretty generic name and not very future proof. What about
>> transition times? Not sure how you would represent that as it probably
>> depends on which points you are changing between rather than a property
>> of the opp.
>>
> This is a binding for OPP, which does not define transition times.
> 
> As for cpufreq, we only need to represent a possible maximum transition
> latency.  The driver will ask regulator subsystem for voltage latency,
> while the clock latency is defined in DT. 
> 
>> I think this whole function can be written more concisely. Just iterate
>> over the property and avoid the intermediate array allocation.
>>
> I'm not sure about that, since directly iterating over the property
> means we have to take care of all these sanity checks done in API
> of_property_read_u32_array().
> 

This won't work?:

of_property_for_each_u32(...) {
	if (i & 0x1) {
		volt = val;
		ret = opp_add(dev, freq, volt);
		if (ret)
			...
	} else
		freq = val * 1000;

	i++;
}

Rob

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

* [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
@ 2012-08-06  4:43             ` Rob Herring
  0 siblings, 0 replies; 24+ messages in thread
From: Rob Herring @ 2012-08-06  4:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/05/2012 10:19 PM, Shawn Guo wrote:
> On Sun, Aug 05, 2012 at 09:50:32PM -0500, Rob Herring wrote:
>>> +Properties:
>>> +- operating-points: An array of 3-tuples items, and each item consists
>>
>> 3 tuples?
>>
> It's the case of v1, and I forgot updating it.  Thanks for spotting it.
> 
>>> +  of frequency and voltage like <freq-kHz vol-uV>.
>>> +	freq: clock frequency in kHz
>>> +	vol: voltage in microvolt
>>
>> Although maybe 3 fields would be good for a flags field? I'm concerned
>> it's a pretty generic name and not very future proof. What about
>> transition times? Not sure how you would represent that as it probably
>> depends on which points you are changing between rather than a property
>> of the opp.
>>
> This is a binding for OPP, which does not define transition times.
> 
> As for cpufreq, we only need to represent a possible maximum transition
> latency.  The driver will ask regulator subsystem for voltage latency,
> while the clock latency is defined in DT. 
> 
>> I think this whole function can be written more concisely. Just iterate
>> over the property and avoid the intermediate array allocation.
>>
> I'm not sure about that, since directly iterating over the property
> means we have to take care of all these sanity checks done in API
> of_property_read_u32_array().
> 

This won't work?:

of_property_for_each_u32(...) {
	if (i & 0x1) {
		volt = val;
		ret = opp_add(dev, freq, volt);
		if (ret)
			...
	} else
		freq = val * 1000;

	i++;
}

Rob

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

* Re: [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
  2012-08-06  4:43             ` Rob Herring
@ 2012-08-06  5:23               ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-06  5:23 UTC (permalink / raw)
  To: Rob Herring
  Cc: cpufreq, linux-pm, Kevin Hilman, Nishanth Menon,
	Russell King - ARM Linux, Mike Turquette, devicetree-discuss,
	Mark Brown, Rafael J. Wysocki, Shilimkar Santosh, Richard Zhao,
	linux-arm-kernel

On Sun, Aug 05, 2012 at 11:43:04PM -0500, Rob Herring wrote:
> On 08/05/2012 10:19 PM, Shawn Guo wrote:
> > On Sun, Aug 05, 2012 at 09:50:32PM -0500, Rob Herring wrote:
> >> I think this whole function can be written more concisely. Just iterate
> >> over the property and avoid the intermediate array allocation.
> >>
> > I'm not sure about that, since directly iterating over the property
> > means we have to take care of all these sanity checks done in API
> > of_property_read_u32_array().
> > 
> 
> This won't work?:
> 
It should work.  But I rewrote the function like below after I find
the sanity check is simple enough to take care of it on our own.

The code does look more concise and still easy to read.

Regards,
Shawn

int of_init_opp_table(struct device *dev)
{
        const struct property *prop;
        const __be32 *val;
        int nr;

        prop = of_find_property(dev->of_node, "operating-points", NULL);
        if (!prop)
                return -ENODEV;
        if (!prop->value)
                return -ENODATA;

        /*
         * Each OPP is a set of tuples consisting of frequency and
         * voltage like <freq-kHz vol-uV>.
         */
        nr = prop->length / sizeof(u32);
        if (nr % 2) {
                dev_err(dev, "%s: Invalid OPP list\n", __func__);
                return -EINVAL;
        }

        val = prop->value;
        while (nr) {
                unsigned long freq = be32_to_cpup(val++) * 1000;
                unsigned long volt = be32_to_cpup(val++);

                if (opp_add(dev, freq, volt)) {
                        dev_warn(dev, "%s: Failed to add OPP %ld\n",
                                 __func__, freq);
                        continue;
                }
                nr -= 2;
        }

        return 0;
}


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

* [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree
@ 2012-08-06  5:23               ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-06  5:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Aug 05, 2012 at 11:43:04PM -0500, Rob Herring wrote:
> On 08/05/2012 10:19 PM, Shawn Guo wrote:
> > On Sun, Aug 05, 2012 at 09:50:32PM -0500, Rob Herring wrote:
> >> I think this whole function can be written more concisely. Just iterate
> >> over the property and avoid the intermediate array allocation.
> >>
> > I'm not sure about that, since directly iterating over the property
> > means we have to take care of all these sanity checks done in API
> > of_property_read_u32_array().
> > 
> 
> This won't work?:
> 
It should work.  But I rewrote the function like below after I find
the sanity check is simple enough to take care of it on our own.

The code does look more concise and still easy to read.

Regards,
Shawn

int of_init_opp_table(struct device *dev)
{
        const struct property *prop;
        const __be32 *val;
        int nr;

        prop = of_find_property(dev->of_node, "operating-points", NULL);
        if (!prop)
                return -ENODEV;
        if (!prop->value)
                return -ENODATA;

        /*
         * Each OPP is a set of tuples consisting of frequency and
         * voltage like <freq-kHz vol-uV>.
         */
        nr = prop->length / sizeof(u32);
        if (nr % 2) {
                dev_err(dev, "%s: Invalid OPP list\n", __func__);
                return -EINVAL;
        }

        val = prop->value;
        while (nr) {
                unsigned long freq = be32_to_cpup(val++) * 1000;
                unsigned long volt = be32_to_cpup(val++);

                if (opp_add(dev, freq, volt)) {
                        dev_warn(dev, "%s: Failed to add OPP %ld\n",
                                 __func__, freq);
                        continue;
                }
                nr -= 2;
        }

        return 0;
}

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

* Re: [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
  2012-08-05 15:05     ` Shawn Guo
@ 2012-08-08 13:35       ` Mark Brown
  -1 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2012-08-08 13:35 UTC (permalink / raw)
  To: Shawn Guo
  Cc: cpufreq, linux-pm, Rafael J. Wysocki, Kevin Hilman,
	Nishanth Menon, Shilimkar Santosh, Richard Zhao,
	Russell King - ARM Linux, Mike Turquette, devicetree-discuss,
	linux-arm-kernel

On Sun, Aug 05, 2012 at 11:05:20PM +0800, Shawn Guo wrote:
> There are some use cases where a voltage range could be reasonably
> specified by a target voltage and tolerance.  Add a new API
> regulator_set_voltage_tol() wrapping regulator_set_voltage() call
> to ease the users.

Applied, thanks!  It's on a separate branch so can easily be either
applied somewhere else or merged into another tree if required for
dependencies, just let me know.

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

* [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
@ 2012-08-08 13:35       ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2012-08-08 13:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Aug 05, 2012 at 11:05:20PM +0800, Shawn Guo wrote:
> There are some use cases where a voltage range could be reasonably
> specified by a target voltage and tolerance.  Add a new API
> regulator_set_voltage_tol() wrapping regulator_set_voltage() call
> to ease the users.

Applied, thanks!  It's on a separate branch so can easily be either
applied somewhere else or merged into another tree if required for
dependencies, just let me know.

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

* Re: [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
  2012-08-08 13:35       ` Mark Brown
@ 2012-08-08 14:30         ` Shawn Guo
  -1 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-08 14:30 UTC (permalink / raw)
  To: Mark Brown
  Cc: cpufreq, linux-pm, Rafael J. Wysocki, Kevin Hilman,
	Nishanth Menon, Shilimkar Santosh, Richard Zhao,
	Russell King - ARM Linux, Mike Turquette, devicetree-discuss,
	linux-arm-kernel

On Wed, Aug 08, 2012 at 02:35:40PM +0100, Mark Brown wrote:
> Applied, thanks!  It's on a separate branch so can easily be either
> applied somewhere else or merged into another tree if required for
> dependencies, just let me know.

I intended to have the whole series go via cpufreq tree with your ack
on this patch.  But I could also ask Rafael to merge your branch to
resolve the dependency.

-- 
Regards,
Shawn


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

* [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
@ 2012-08-08 14:30         ` Shawn Guo
  0 siblings, 0 replies; 24+ messages in thread
From: Shawn Guo @ 2012-08-08 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 08, 2012 at 02:35:40PM +0100, Mark Brown wrote:
> Applied, thanks!  It's on a separate branch so can easily be either
> applied somewhere else or merged into another tree if required for
> dependencies, just let me know.

I intended to have the whole series go via cpufreq tree with your ack
on this patch.  But I could also ask Rafael to merge your branch to
resolve the dependency.

-- 
Regards,
Shawn

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

* Re: [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
  2012-08-08 14:30         ` Shawn Guo
@ 2012-08-09 10:53           ` Mark Brown
  -1 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2012-08-09 10:53 UTC (permalink / raw)
  To: Shawn Guo
  Cc: cpufreq, linux-pm, Rafael J. Wysocki, Kevin Hilman,
	Nishanth Menon, Shilimkar Santosh, Richard Zhao,
	Russell King - ARM Linux, Mike Turquette, devicetree-discuss,
	linux-arm-kernel

On Wed, Aug 08, 2012 at 10:30:07PM +0800, Shawn Guo wrote:
> On Wed, Aug 08, 2012 at 02:35:40PM +0100, Mark Brown wrote:

> > Applied, thanks!  It's on a separate branch so can easily be either
> > applied somewhere else or merged into another tree if required for
> > dependencies, just let me know.

> I intended to have the whole series go via cpufreq tree with your ack
> on this patch.  But I could also ask Rafael to merge your branch to
> resolve the dependency.

I anticipate wanting the new API in other trees too (I have one likely
use in mind) so having it only in the cpufreq tree would be inconvenient.
The whole reason to have this in the regulator API is that it's
something that's useful outside your cpufreq code!

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

* [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol()
@ 2012-08-09 10:53           ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2012-08-09 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 08, 2012 at 10:30:07PM +0800, Shawn Guo wrote:
> On Wed, Aug 08, 2012 at 02:35:40PM +0100, Mark Brown wrote:

> > Applied, thanks!  It's on a separate branch so can easily be either
> > applied somewhere else or merged into another tree if required for
> > dependencies, just let me know.

> I intended to have the whole series go via cpufreq tree with your ack
> on this patch.  But I could also ask Rafael to merge your branch to
> resolve the dependency.

I anticipate wanting the new API in other trees too (I have one likely
use in mind) so having it only in the cpufreq tree would be inconvenient.
The whole reason to have this in the regulator API is that it's
something that's useful outside your cpufreq code!

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

end of thread, other threads:[~2012-08-09 10:53 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-05 15:05 [PATCH v2 0/4] Add a generic cpufreq-cpu0 driver Shawn Guo
2012-08-05 15:05 ` Shawn Guo
     [not found] ` <1344179121-17738-1-git-send-email-shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2012-08-05 15:05   ` [PATCH v2 1/4] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp Shawn Guo
2012-08-05 15:05     ` Shawn Guo
2012-08-05 15:05   ` [PATCH v2 2/4] PM / OPP: Initialize OPP table from device tree Shawn Guo
2012-08-05 15:05     ` Shawn Guo
     [not found]     ` <1344179121-17738-3-git-send-email-shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2012-08-06  2:50       ` Rob Herring
2012-08-06  2:50         ` Rob Herring
2012-08-06  3:19         ` Shawn Guo
2012-08-06  3:19           ` Shawn Guo
2012-08-06  4:43           ` Rob Herring
2012-08-06  4:43             ` Rob Herring
2012-08-06  5:23             ` Shawn Guo
2012-08-06  5:23               ` Shawn Guo
2012-08-05 15:05   ` [PATCH v2 3/4] regulator: add a new API regulator_set_voltage_tol() Shawn Guo
2012-08-05 15:05     ` Shawn Guo
2012-08-08 13:35     ` Mark Brown
2012-08-08 13:35       ` Mark Brown
2012-08-08 14:30       ` Shawn Guo
2012-08-08 14:30         ` Shawn Guo
2012-08-09 10:53         ` Mark Brown
2012-08-09 10:53           ` Mark Brown
2012-08-05 15:05   ` [PATCH v2 4/4] cpufreq: Add a generic cpufreq-cpu0 driver Shawn Guo
2012-08-05 15:05     ` Shawn Guo

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.