All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/3] devfreq: exynos: Add driver for Exynos3250
@ 2014-12-05 16:46 ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi
  Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Tomasz Figa,
	Krzysztof Kozlowski

Hi,

The aim of patchset is to gather feedback about adding new devfreq driver for
Exynos 3250, along with the bindings.

Chanwoo,
You were the author of our initial exynos3_bus.c driver so do you
want me to add your Signed-off-by?

Best regards,
Krzysztof


Krzysztof Kozlowski (3):
  devfreq: dt-bindings: Document Exynos3250 devfreq driver
  devfreq: exynos: Add driver for Exynos3250
  ARM: dts: Add devfreq to Exynos3250 and Rinato board

 .../bindings/arm/samsung/exynos3250-devfreq.txt    |  66 ++
 arch/arm/boot/dts/exynos3250-rinato.dts            |  10 +
 arch/arm/boot/dts/exynos3250.dtsi                  |  32 +
 drivers/devfreq/Kconfig                            |  12 +
 drivers/devfreq/Makefile                           |   1 +
 drivers/devfreq/exynos/Makefile                    |   1 +
 drivers/devfreq/exynos/exynos3_bus.c               | 842 +++++++++++++++++++++
 7 files changed, 964 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
 create mode 100644 drivers/devfreq/exynos/exynos3_bus.c

-- 
1.9.1


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

* [RFC 0/3] devfreq: exynos: Add driver for Exynos3250
@ 2014-12-05 16:46 ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

The aim of patchset is to gather feedback about adding new devfreq driver for
Exynos 3250, along with the bindings.

Chanwoo,
You were the author of our initial exynos3_bus.c driver so do you
want me to add your Signed-off-by?

Best regards,
Krzysztof


Krzysztof Kozlowski (3):
  devfreq: dt-bindings: Document Exynos3250 devfreq driver
  devfreq: exynos: Add driver for Exynos3250
  ARM: dts: Add devfreq to Exynos3250 and Rinato board

 .../bindings/arm/samsung/exynos3250-devfreq.txt    |  66 ++
 arch/arm/boot/dts/exynos3250-rinato.dts            |  10 +
 arch/arm/boot/dts/exynos3250.dtsi                  |  32 +
 drivers/devfreq/Kconfig                            |  12 +
 drivers/devfreq/Makefile                           |   1 +
 drivers/devfreq/exynos/Makefile                    |   1 +
 drivers/devfreq/exynos/exynos3_bus.c               | 842 +++++++++++++++++++++
 7 files changed, 964 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
 create mode 100644 drivers/devfreq/exynos/exynos3_bus.c

-- 
1.9.1

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

* [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
  2014-12-05 16:46 ` Krzysztof Kozlowski
@ 2014-12-05 16:46   ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi
  Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Tomasz Figa,
	Krzysztof Kozlowski

Add documentation for bindings used by Exynos3250 devfreq driver.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt

diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
new file mode 100644
index 000000000000..047955e9e371
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
@@ -0,0 +1,66 @@
+Samsung Exynos3250 devfreq driver
+=================================
+
+The driver support changing frequencies and voltage for:
+ - memory controller and bus,
+ - peripheral buses (left and right).
+
+Memory controller and bus
+=========================
+Required properties:
+ - compatible : should be "samsung,exynos3250-busfreq-mif"
+ - reg : two sets (offset and length of the register) for PPMU registers
+	used by this devfreq driver
+ - clock-names : one clock of name "dmc" to manage frequency
+ - clocks : phandle and specifier for clock listed in clock-names property
+ - vdd_mif-supply : phandle to MIF voltage regulator
+
+Peripheral buses
+================
+Required properties:
+ - compatible : should be "samsung,exynos3250-busfreq-int"
+ - reg : two sets (offset and length of the register) for PPMU registers
+	used by this devfreq driver
+ - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
+	All following clock names (and corresponding phandles) must be
+	provided:
+	- "ppmu_left", "ppmu_right",
+	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
+ - clocks : phandles and specifiers for clocks listed in clock-names property
+ - vdd_mif-supply : phandle to INT voltage regulator
+
+Example
+=======
+	busfreq_mif: busfreq@106A0000 {
+		compatible = "samsung,exynos3250-busfreq-mif";
+		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
+		clocks = <&cmu_dmc CLK_DIV_DMC>;
+		clock-names = "dmc";
+		vdd_mif-supply = <&buck1_reg>;
+		status = "okay";
+	};
+
+	busfreq_int: busfreq@116A0000 {
+		compatible = "samsung,exynos3250-busfreq-int";
+		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
+		clocks = <&cmu CLK_PPMULEFT>,
+			<&cmu CLK_PPMURIGHT>,
+			<&cmu CLK_DIV_ACLK_400_MCUISP>,
+			<&cmu CLK_DIV_ACLK_266>,
+			<&cmu CLK_DIV_ACLK_200>,
+			<&cmu CLK_DIV_ACLK_160>,
+			<&cmu CLK_DIV_GDL>,
+			<&cmu CLK_DIV_GDR>,
+			<&cmu CLK_DIV_MFC>;
+		clock-names = "ppmuleft",
+			"ppmuright",
+			"aclk_400",
+			"aclk_266",
+			"aclk_200",
+			"aclk_160",
+			"aclk_gdl",
+			"aclk_gdr",
+			"mfc";
+		vdd_int-supply = <&buck3_reg>;
+		status = "okay";
+	};
-- 
1.9.1


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

* [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
@ 2014-12-05 16:46   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Add documentation for bindings used by Exynos3250 devfreq driver.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt

diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
new file mode 100644
index 000000000000..047955e9e371
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
@@ -0,0 +1,66 @@
+Samsung Exynos3250 devfreq driver
+=================================
+
+The driver support changing frequencies and voltage for:
+ - memory controller and bus,
+ - peripheral buses (left and right).
+
+Memory controller and bus
+=========================
+Required properties:
+ - compatible : should be "samsung,exynos3250-busfreq-mif"
+ - reg : two sets (offset and length of the register) for PPMU registers
+	used by this devfreq driver
+ - clock-names : one clock of name "dmc" to manage frequency
+ - clocks : phandle and specifier for clock listed in clock-names property
+ - vdd_mif-supply : phandle to MIF voltage regulator
+
+Peripheral buses
+================
+Required properties:
+ - compatible : should be "samsung,exynos3250-busfreq-int"
+ - reg : two sets (offset and length of the register) for PPMU registers
+	used by this devfreq driver
+ - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
+	All following clock names (and corresponding phandles) must be
+	provided:
+	- "ppmu_left", "ppmu_right",
+	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
+ - clocks : phandles and specifiers for clocks listed in clock-names property
+ - vdd_mif-supply : phandle to INT voltage regulator
+
+Example
+=======
+	busfreq_mif: busfreq at 106A0000 {
+		compatible = "samsung,exynos3250-busfreq-mif";
+		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
+		clocks = <&cmu_dmc CLK_DIV_DMC>;
+		clock-names = "dmc";
+		vdd_mif-supply = <&buck1_reg>;
+		status = "okay";
+	};
+
+	busfreq_int: busfreq at 116A0000 {
+		compatible = "samsung,exynos3250-busfreq-int";
+		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
+		clocks = <&cmu CLK_PPMULEFT>,
+			<&cmu CLK_PPMURIGHT>,
+			<&cmu CLK_DIV_ACLK_400_MCUISP>,
+			<&cmu CLK_DIV_ACLK_266>,
+			<&cmu CLK_DIV_ACLK_200>,
+			<&cmu CLK_DIV_ACLK_160>,
+			<&cmu CLK_DIV_GDL>,
+			<&cmu CLK_DIV_GDR>,
+			<&cmu CLK_DIV_MFC>;
+		clock-names = "ppmuleft",
+			"ppmuright",
+			"aclk_400",
+			"aclk_266",
+			"aclk_200",
+			"aclk_160",
+			"aclk_gdl",
+			"aclk_gdr",
+			"mfc";
+		vdd_int-supply = <&buck3_reg>;
+		status = "okay";
+	};
-- 
1.9.1

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

* [RFC 2/3] devfreq: exynos: Add driver for Exynos3250
  2014-12-05 16:46 ` Krzysztof Kozlowski
@ 2014-12-05 16:46   ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi
  Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Tomasz Figa,
	Krzysztof Kozlowski

Add new devfreq driver for Exynos3250. The driver utilizes existing PPMU
helpers and is multiplatform safe. Currently it does not support ASV
(Adaptive Supply Voltage).

Driver creates two devices:
 - Dynamic Memory Controller (DMC) and memory bus,
 - peripheral (left/right) buses.

For memory it changes the DMC clock from 50 MHz to 400 MHz and voltage
regulator from 800 mV to 875 mV.
As for peripheral it changes frequencies of multiple bus clocks and INT
voltage 850 mV to 950 mV.

Impact on performance (Rinato/Gear 2 board) calculated with:
$ perf bench mem memcpy -l 256MB -i 10
$ perf bench mem memset -l 256MB -i 10
$ dd if=/mmc of=file iflag=direct oflag=direct count=128 bs=1M

 type           | no devfreq [MB/s] | devfreq [MB/s] |  diff
============================================================
memcpy          | 156.253719        | 156.122788     | -0.1%
memcpy prefault | 166.789370        | 166.557580     | -0.1%
memset          | 134.094529        | 129.266162     | -3.6%
memset prefault | 168.584091        | 168.426261     | -0.1%
dd trabsfer     |  14.8             |  15.6          | -1.3%

Impact on energy consumption, system in idle (WFI), mA:
 no devfreq [mA] | devfreq [mA] |   diff
========================================
 29.0            | 19.2         | -33.8%

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 drivers/devfreq/Kconfig              |  12 +
 drivers/devfreq/Makefile             |   1 +
 drivers/devfreq/exynos/Makefile      |   1 +
 drivers/devfreq/exynos/exynos3_bus.c | 842 +++++++++++++++++++++++++++++++++++
 4 files changed, 856 insertions(+)
 create mode 100644 drivers/devfreq/exynos/exynos3_bus.c

diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index faf4e70c42e0..3fdd7cfebb6d 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -65,6 +65,18 @@ config DEVFREQ_GOV_USERSPACE
 
 comment "DEVFREQ Drivers"
 
+config ARM_EXYNOS3_BUS_DEVFREQ
+	bool "ARM Exynos3250 Memory and peripheral bus DEVFREQ Driver"
+	depends on SOC_EXYNOS3250
+	select DEVFREQ_GOV_SIMPLE_ONDEMAND
+	select PM_OPP
+	help
+	  This adds the DEVFREQ driver for Exynos3250 memory interface
+	  and peripheral bus (vdd_mif + vdd_int).
+	  It reads PPMU counters of memory controllers and adjusts
+	  the operating frequencies and voltages with OPP support.
+	  This does not yet operate with optimal voltages.
+
 config ARM_EXYNOS4_BUS_DEVFREQ
 	bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
 	depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 16138c9e0d58..d876fab4db21 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 
 # DEVFREQ Drivers
+obj-$(CONFIG_ARM_EXYNOS3_BUS_DEVFREQ)	+= exynos/
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos/
 obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos/
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
index 49bc9175f923..a4aa1ed474c9 100644
--- a/drivers/devfreq/exynos/Makefile
+++ b/drivers/devfreq/exynos/Makefile
@@ -1,3 +1,4 @@
 # Exynos DEVFREQ Drivers
+obj-$(CONFIG_ARM_EXYNOS3_BUS_DEVFREQ)	+= exynos_ppmu.o exynos3_bus.o
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos_ppmu.o exynos4_bus.o
 obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos_ppmu.o exynos5_bus.o
diff --git a/drivers/devfreq/exynos/exynos3_bus.c b/drivers/devfreq/exynos/exynos3_bus.c
new file mode 100644
index 000000000000..27370b97001b
--- /dev/null
+++ b/drivers/devfreq/exynos/exynos3_bus.c
@@ -0,0 +1,842 @@
+/*
+ * drivers/devfreq/exynos/exynos3_bus.c
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * based on drivers/devfreqw/exynos/exynos4_bus.c
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * EXYNOS3250 - Memory/Bus clock frequency scaling support in DEVFREQ framework
+ * This version supports EXYNOS3250 only.
+ *
+ * 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/clk.h>
+#include <linux/devfreq.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_opp.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+
+#include "exynos_ppmu.h"
+
+/*
+ * Assume that the bus is saturated if the utilization is 30%.
+ *
+ * Saturation ratio is less than that in exynos4_bus.c (40%) to boost
+ * ondemand governor early.
+ * Memory tests (memcpy, memory alloc, dmatest) shown that ratio of 40%
+ * triggers frequency increase sporadically.
+ */
+#define EXYNOS3_BUS_SATURATION_RATIO	30
+#define EXYNOS3_BUS_INT_REGULATOR_NAME	"vdd_int"
+#define EXYNOS3_BUS_MIF_REGULATOR_NAME	"vdd_mif"
+
+#define EXYNOS3_BUS_PPMU_NUM		2
+
+#define EXYNOS3_BUS_INTERVAL_SAFEVOLT	25000	/* 25mV */
+
+enum exynos3_busfreq_type {
+	TYPE_BUSFREQ_UNKNOWN = 0,
+	TYPE_BUSFREQ_EXYNOS3250_MIF,
+	TYPE_BUSFREQ_EXYNOS3250_INT,
+};
+
+enum exynos3_busfreq_level {
+	LV_0,
+	LV_1,
+	LV_2,
+	LV_3,
+	LV_4,
+	LV_5,
+
+	LV_END,
+};
+
+/*
+ * Clocks for INT PPMU.
+ * The clocks for DMC PPMU are not defined and by default are enabled.
+ */
+static const char * const exynos3_bus_int_ppmu_clk_name[] = {
+	"ppmu_left", "ppmu_right",
+};
+
+enum exynos3_bus_mif_clk {
+	DMC,
+	EXYNOS3_BUS_MIF_CLK_END,
+};
+
+enum exynos3_bus_int_clk {
+	ACLK_400,
+	ACLK_266,
+	ACLK_200,
+	ACLK_160,
+	ACLK_GDL,
+	ACLK_GDR,
+	MFC,
+	EXYNOS3_BUS_INT_CLK_END,
+};
+
+static const char * const exynos3_bus_mif_clk_name[] = {
+	[DMC]		= "dmc",
+};
+
+static const char * const exynos3_bus_int_clk_name[] = {
+	[ACLK_400]	= "aclk_400",
+	[ACLK_266]	= "aclk_266",
+	[ACLK_200]	= "aclk_200",
+	[ACLK_160]	= "aclk_160",
+	[ACLK_GDL]	= "aclk_gdl",
+	[ACLK_GDR]	= "aclk_gdr",
+	[MFC]		= "mfc",
+};
+
+/**
+ * struct busfreq_opp_info - opp information for bus
+ * @rate:	Frequency in hertz
+ * @volt:	Voltage in microvolts corresponding to this OPP
+ */
+struct busfreq_opp_info {
+	unsigned long rate;
+	unsigned long volt;
+};
+
+struct busfreq_data {
+	struct devfreq_dev_profile *profile;
+	enum exynos3_busfreq_type type;
+	struct device *dev;
+	struct devfreq *devfreq;
+	bool disabled;
+
+	struct busfreq_opp_info curr_opp_info;
+
+	struct regulator *regulator_vdd;
+	struct busfreq_ppmu_data ppmu;
+	struct clk **clk_ppmu;
+	struct clk **clk_bus;
+	unsigned int clk_bus_num;
+
+	const struct bus_opp_table *opp_table;
+	int opp_table_end;
+
+	struct notifier_block pm_notifier;
+	struct mutex lock;
+};
+
+static const struct bus_opp_table exynos3_bus_mif_clk_table[] = {
+	/*   DMC clock, MIF voltage */
+	{LV_0,	400000,	875000},
+	{LV_1,	200000,	800000},
+	{LV_2,	133000,	800000},
+	{LV_3,	100000,	800000},
+	{LV_4,	 50000,	800000},
+};
+
+/*
+ * The frequency for INT is an abstract clock, without real representation
+ * because INT actually changes multiple clocks. Values for this frequency
+ * match MIF/DMC clock (except one additional level: 80000).
+ */
+static const struct bus_opp_table exynos3_bus_int_clk_table[] = {
+	/* abstract clock, INT voltage */
+	{LV_0,	400000,	950000},
+	{LV_1,	200000,	950000},
+	{LV_2,	133000, 925000},
+	{LV_3,	100000, 850000},
+	{LV_4,	80000,  850000},
+	{LV_5,	50000,  850000},
+};
+
+static const unsigned int exynos3_bus_mif_clk_freq[][EXYNOS3_BUS_MIF_CLK_END] = {
+		/* DMC */
+	[LV_0] = { 400000000, },
+	[LV_1] = { 200000000, },
+	[LV_2] = { 133333334, },
+	[LV_3] = { 100000000, },
+	[LV_4] = {  50000000, },
+};
+
+static const unsigned int exynos3_bus_int_clk_freq[][EXYNOS3_BUS_INT_CLK_END] = {
+		/*  ACLK_400,  ACLK_266,  ACLK_200,  ACLK_160,  ACLK_GDL,  ACLK_GDR, MFC */
+	[LV_0] = { 400000000, 300000000, 200000000, 200000000, 200000000, 200000000, 200000000, },
+	[LV_1] = { 200000000, 200000000, 200000000, 133333334, 200000000, 200000000, 200000000, },
+	[LV_2] = {  50000000, 133333334, 100000000, 100000000, 133333334, 133333334, 200000000, },
+	[LV_3] = {  50000000,  50000000,  80000000,  80000000, 100000000, 100000000, 133333334, },
+	[LV_4] = {  50000000,  50000000,  50000000,  50000000, 100000000, 100000000, 100000000, },
+	[LV_5] = {  50000000,  50000000,  50000000,  50000000, 100000000, 100000000,  80000000, },
+};
+
+static int round_set_clk(struct device *dev, int id, struct clk *clk,
+		unsigned long rate)
+{
+	int ret;
+	long real_rate;
+
+	real_rate = clk_round_rate(clk, rate);
+	if (real_rate <= 0) {
+		dev_err(dev, "Cannot round clock rate %d to %lu: %ld\n",
+				id, rate, real_rate);
+		return -EINVAL;
+	}
+
+	ret = clk_set_rate(clk, real_rate);
+	if (ret) {
+		dev_err(dev, "Cannot set clock rate %d to %lu: %d",
+				id, real_rate, ret);
+		return ret;
+	}
+
+	dev_dbg(dev, "Clock %d to %lu/%lu\n", id, rate, real_rate);
+
+	return 0;
+}
+
+static int exynos3_bus_set_clk(struct busfreq_data *data,
+				  struct busfreq_opp_info *new_opp_info)
+{
+	int index, i, clk_num;
+	const unsigned int *clk_freq;
+
+	for (index = 0; index < data->opp_table_end; index++)
+		if (new_opp_info->rate == data->opp_table[index].clk)
+			break;
+
+	if (index == data->opp_table_end)
+		return -EINVAL;
+
+	switch (data->type) {
+	case TYPE_BUSFREQ_EXYNOS3250_MIF:
+		clk_num = EXYNOS3_BUS_MIF_CLK_END;
+		clk_freq = exynos3_bus_mif_clk_freq[index];
+		break;
+	case TYPE_BUSFREQ_EXYNOS3250_INT:
+		clk_num = EXYNOS3_BUS_INT_CLK_END;
+		clk_freq = exynos3_bus_int_clk_freq[index];
+		break;
+	default:
+		dev_err(data->dev, "Unknown device type %d\n", data->type);
+		return -EINVAL;
+	};
+
+	for (i = 0; i < clk_num; i++) {
+		int ret;
+
+		ret = round_set_clk(data->dev, i, data->clk_bus[i],
+				clk_freq[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int exynos3_bus_set_volt(struct busfreq_data *data,
+				struct busfreq_opp_info *new_opp_info,
+				struct busfreq_opp_info *old_opp_info)
+{
+	int ret;
+
+	ret = regulator_set_voltage(data->regulator_vdd, new_opp_info->volt,
+			new_opp_info->volt + EXYNOS3_BUS_INTERVAL_SAFEVOLT);
+	if (ret < 0) {
+		dev_err(data->dev, "Failed to set voltage %d\n", data->type);
+		regulator_set_voltage(data->regulator_vdd, old_opp_info->volt,
+			old_opp_info->volt + EXYNOS3_BUS_INTERVAL_SAFEVOLT);
+	}
+
+	return 0;
+}
+
+/*
+ * Define internal function of structure devfreq_dev_profile
+ */
+static int exynos3_bus_target(struct device *dev, unsigned long *_freq,
+			      u32 flags)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	struct busfreq_opp_info	new_opp_info;
+	unsigned long old_freq, new_freq;
+	struct dev_pm_opp *opp;
+	int ret = 0;
+
+	if (data->disabled)
+		goto out;
+
+	/* Get new opp-info instance according to new busfreq clock */
+	rcu_read_lock();
+	opp = devfreq_recommended_opp(dev, _freq, flags);
+	if (IS_ERR_OR_NULL(opp)) {
+		dev_err(dev, "Failed to get recommed opp instance\n");
+		rcu_read_unlock();
+		return PTR_ERR(opp);
+	}
+	new_opp_info.rate = dev_pm_opp_get_freq(opp);
+	new_opp_info.volt = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	old_freq = data->curr_opp_info.rate;
+	new_freq = new_opp_info.rate;
+	if (old_freq == new_freq)
+		return 0;
+
+	dev_dbg(dev, "%lu MHz, %ld mV --> %lu MHz, %ld mV\n",
+		old_freq / 1000, data->curr_opp_info.volt / 1000,
+		new_freq / 1000, new_opp_info.volt / 1000);
+
+	/* Change voltage/clock according to new busfreq level */
+	mutex_lock(&data->lock);
+
+	if (old_freq < new_freq) {
+		ret = exynos3_bus_set_volt(data, &new_opp_info,
+					   &data->curr_opp_info);
+		if (ret < 0) {
+			dev_err(dev, "Failed to set voltage %d\n", data->type);
+			goto out;
+		}
+	}
+
+	ret = exynos3_bus_set_clk(data, &new_opp_info);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set bus clock %d\n", data->type);
+		goto out;
+	}
+
+	if (old_freq > new_freq) {
+		ret = exynos3_bus_set_volt(data, &new_opp_info,
+					   &data->curr_opp_info);
+		if (ret < 0) {
+			dev_err(dev, "Failed to set voltage %d\n", data->type);
+			goto out;
+		}
+	}
+
+	data->curr_opp_info = new_opp_info;
+out:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int exynos3_bus_get_dev_status(struct device *dev,
+				      struct devfreq_dev_status *stat)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	int busier;
+
+	/* Read PPMU total cycle count and Read/Write count */
+	exynos_read_ppmu(&data->ppmu);
+
+	/* Get busier PPMU device among various PPMU */
+	busier = exynos_get_busier_ppmu(&data->ppmu);
+	stat->current_frequency = data->curr_opp_info.rate;
+
+	/* Number of cycles spent on memory access */
+	stat->busy_time = data->ppmu.ppmu[busier].count[PPMU_PMNCNT3];
+	stat->busy_time *= 100 / EXYNOS3_BUS_SATURATION_RATIO;
+	stat->total_time = data->ppmu.ppmu[busier].ccnt;
+
+	/* If the counters have overflown, retry */
+	if (data->ppmu.ppmu[busier].ccnt_overflow ||
+		data->ppmu.ppmu[busier].count_overflow[0])
+		return -EAGAIN;
+
+	return 0;
+}
+
+static void exynos3_bus_cleanup_iomap(struct busfreq_data *data)
+{
+	int i;
+
+	for (i = 0; i < data->ppmu.ppmu_end; i++) {
+		if (data->ppmu.ppmu[i].hw_base)
+			iounmap(data->ppmu.ppmu[i].hw_base);
+	}
+}
+
+static void exynos3_bus_cleanup_clocks(struct busfreq_data *data)
+{
+	int i;
+
+	for (i = 0; i < data->clk_bus_num; i++) {
+		if (data->clk_bus[i])
+			clk_disable_unprepare(data->clk_bus[i]);
+	}
+
+	for (i = 0; i < data->ppmu.ppmu_end; i++) {
+		if (data->clk_ppmu[i])
+			clk_disable_unprepare(data->clk_ppmu[i]);
+	}
+}
+
+static void exynos3_bus_exit(struct device *dev)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+
+	regulator_disable(data->regulator_vdd);
+	exynos3_bus_cleanup_clocks(data);
+	exynos3_bus_cleanup_iomap(data);
+}
+
+/* Define devfreq_dev_profile for MIF block */
+static struct devfreq_dev_profile exynos3_busfreq_mif_profile = {
+	.initial_freq	= 400000,
+	.polling_ms	= 100,
+	.target		= exynos3_bus_target,
+	.get_dev_status	= exynos3_bus_get_dev_status,
+	.exit		= exynos3_bus_exit,
+};
+
+/* Define devfreq_dev_profile for INT block */
+static struct devfreq_dev_profile exynos3_busfreq_int_profile = {
+	.initial_freq	= 400000,
+	.polling_ms	= 100,
+	.target		= exynos3_bus_target,
+	.get_dev_status	= exynos3_bus_get_dev_status,
+	.exit		= exynos3_bus_exit,
+};
+
+static int exynos3_bus_pm_notifier_event(struct notifier_block *this,
+					     unsigned long event, void *ptr)
+{
+	struct busfreq_data *data = container_of(this, struct busfreq_data,
+						 pm_notifier);
+	struct dev_pm_opp *opp;
+	struct busfreq_opp_info	new_opp_info;
+	unsigned long maxfreq = ULONG_MAX;
+	int err = 0;
+
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		mutex_lock(&data->lock);
+
+		data->disabled = true;
+
+		rcu_read_lock();
+		opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
+		if (IS_ERR(opp)) {
+			rcu_read_unlock();
+			dev_err(data->dev, "%s: unable to find a min freq\n",
+				__func__);
+			mutex_unlock(&data->lock);
+			return PTR_ERR(opp);
+		}
+		new_opp_info.rate = dev_pm_opp_get_freq(opp);
+		new_opp_info.volt = dev_pm_opp_get_voltage(opp);
+		rcu_read_unlock();
+
+		err = exynos3_bus_set_volt(data, &new_opp_info,
+					   &data->curr_opp_info);
+		if (err) {
+			mutex_unlock(&data->lock);
+			return err;
+		}
+
+		err = exynos3_bus_set_clk(data, &new_opp_info);
+		if (err) {
+			mutex_unlock(&data->lock);
+			return err;
+		}
+
+		data->curr_opp_info = new_opp_info;
+
+		mutex_unlock(&data->lock);
+		if (err)
+			return err;
+		return NOTIFY_OK;
+	case PM_POST_RESTORE:
+	case PM_POST_SUSPEND:
+		/* Reactivate */
+		mutex_lock(&data->lock);
+		data->disabled = false;
+		mutex_unlock(&data->lock);
+		return NOTIFY_OK;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int exynos3_bus_init_table(struct busfreq_data *data)
+{
+	int i, ret;
+
+	/* Add OPP entry including the voltage/clock of busfreq level */
+	for (i = 0; i < data->opp_table_end; i++) {
+		ret = dev_pm_opp_add(data->dev,
+			      data->opp_table[i].clk,
+			      data->opp_table[i].volt);
+		if (ret < 0) {
+			dev_err(data->dev, "Failed to add opp entry(%ld,%ld)\n",
+				data->opp_table[i].clk,
+				data->opp_table[i].volt);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int exynos3_bus_parse_dt(struct busfreq_data *data)
+{
+	struct device *dev = data->dev;
+	struct device_node *np = dev->of_node;
+	char regulator_name[DEVFREQ_NAME_LEN];
+	const char * const *ppmu_clk_name, * const *bus_clk_name;
+	int i, ret = 0;
+
+	data->ppmu.ppmu_end	= EXYNOS3_BUS_PPMU_NUM;
+	switch (data->type) {
+	case TYPE_BUSFREQ_EXYNOS3250_MIF:
+		data->profile		= &exynos3_busfreq_mif_profile;
+		data->opp_table		= exynos3_bus_mif_clk_table;
+		data->opp_table_end	= ARRAY_SIZE(exynos3_bus_mif_clk_table);
+
+		ppmu_clk_name		= NULL;
+		bus_clk_name		= exynos3_bus_mif_clk_name;
+		data->clk_bus_num	= ARRAY_SIZE(exynos3_bus_mif_clk_name);
+		strcpy(regulator_name,	EXYNOS3_BUS_MIF_REGULATOR_NAME);
+		break;
+	case TYPE_BUSFREQ_EXYNOS3250_INT:
+		data->profile		= &exynos3_busfreq_int_profile;
+		data->opp_table		= exynos3_bus_int_clk_table;
+		data->opp_table_end	= ARRAY_SIZE(exynos3_bus_int_clk_table);
+
+		ppmu_clk_name		= exynos3_bus_int_ppmu_clk_name;
+		bus_clk_name		= exynos3_bus_int_clk_name;
+		data->clk_bus_num	= ARRAY_SIZE(exynos3_bus_int_clk_name);
+		strcpy(regulator_name,	EXYNOS3_BUS_INT_REGULATOR_NAME);
+
+		break;
+	default:
+		dev_err(dev, "Unknown device id %d\n", data->type);
+		return -EINVAL;
+	};
+
+	/* Allocate memory for ppmu register/clock according to ppmu count */
+	data->ppmu.ppmu = devm_kzalloc(dev,
+			sizeof(struct exynos_ppmu) * data->ppmu.ppmu_end,
+			GFP_KERNEL);
+	if (!data->ppmu.ppmu) {
+		dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
+		return -ENOMEM;
+	}
+
+	data->clk_ppmu = devm_kzalloc(dev,
+				sizeof(struct clk *) * data->ppmu.ppmu_end,
+				GFP_KERNEL);
+	if (!data->clk_ppmu) {
+		dev_err(dev, "Failed to allocate memory for ppmu clock\n");
+		return -ENOMEM;
+	}
+
+	data->clk_bus = devm_kzalloc(dev,
+				sizeof(struct clk *) * data->clk_bus_num,
+				GFP_KERNEL);
+	if (!data->clk_bus)
+		return -ENOMEM;
+
+	/* Maps the memory mapped IO to control PPMU register */
+	for (i = 0; i < data->ppmu.ppmu_end; i++) {
+		data->ppmu.ppmu[i].hw_base = of_iomap(np, i);
+		if (IS_ERR_OR_NULL(data->ppmu.ppmu[i].hw_base)) {
+			dev_err(dev, "Failed to map memory region\n");
+			data->ppmu.ppmu[i].hw_base = NULL;
+			ret = -EINVAL;
+			goto err_iomap;
+		}
+	}
+
+	/*
+	 * Get PPMU's clocks to control them. But, if PPMU's clocks
+	 * is default 'pass' state, this driver don't need control
+	 * PPMU's clock.
+	 */
+	if (ppmu_clk_name) {
+		for (i = 0; i < data->ppmu.ppmu_end; i++) {
+			data->clk_ppmu[i] = devm_clk_get(dev, ppmu_clk_name[i]);
+			if (IS_ERR_OR_NULL(data->clk_ppmu[i])) {
+				dev_warn(dev, "Cannot get %s clock\n",
+						ppmu_clk_name[i]);
+				data->clk_ppmu[i] = NULL;
+			}
+
+			ret = clk_prepare_enable(data->clk_ppmu[i]);
+			if (ret < 0) {
+				dev_warn(dev, "Cannot enable %s clock\n",
+						ppmu_clk_name[i]);
+				data->clk_ppmu[i] = NULL;
+				goto err_clocks;
+			}
+		}
+	}
+
+	for (i = 0; i < data->clk_bus_num; i++) {
+		data->clk_bus[i] = devm_clk_get(dev, bus_clk_name[i]);
+		if (IS_ERR_OR_NULL(data->clk_bus[i])) {
+			dev_err(dev, "Cannot get %s clock: %ld\n",
+					bus_clk_name[i],
+					PTR_ERR(data->clk_bus[i]));
+			goto err_clocks;
+		}
+
+		ret = clk_prepare_enable(data->clk_bus[i]);
+		if (ret < 0) {
+			dev_err(dev, "Cannot enable %s clock: %d\n",
+						bus_clk_name[i], ret);
+			data->clk_bus[i] = NULL;
+			goto err_clocks;
+		}
+	}
+
+	/* Get regulators to control voltage of int/mif block */
+	data->regulator_vdd = devm_regulator_get(dev, regulator_name);
+	if (IS_ERR(data->regulator_vdd)) {
+		dev_err(dev, "Failed to get the regulator \"%s\": %ld\n",
+			regulator_name, PTR_ERR(data->regulator_vdd));
+		ret = -EINVAL;
+		goto err_clocks;
+	}
+
+	ret = regulator_enable(data->regulator_vdd);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulator: %d\n", ret);
+		goto err_clocks;
+	}
+
+	return 0;
+
+err_clocks:
+	exynos3_bus_cleanup_clocks(data);
+err_iomap:
+	exynos3_bus_cleanup_iomap(data);
+
+	return ret;
+}
+
+static struct of_device_id exynos3_busfreq_id_match[] = {
+	{
+		.compatible = "samsung,exynos3250-busfreq-mif",
+		.data = (void *)TYPE_BUSFREQ_EXYNOS3250_MIF,
+	}, {
+		.compatible = "samsung,exynos3250-busfreq-int",
+		.data = (void *)TYPE_BUSFREQ_EXYNOS3250_INT,
+	},
+	{},
+};
+
+static int exynos3_busfreq_get_driver_data(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *match;
+
+	match = of_match_node(exynos3_busfreq_id_match, dev->of_node);
+	if (!match)
+		return -ENODEV;
+
+	return (int)match->data;
+}
+
+static int exynos3_busfreq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct busfreq_data *data;
+	struct dev_pm_opp *opp;
+	int ret = 0;
+
+	if (!dev->of_node)
+		return -EINVAL;
+
+	data = devm_kzalloc(dev, sizeof(struct busfreq_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->type = exynos3_busfreq_get_driver_data(pdev);
+	data->dev = dev;
+	mutex_init(&data->lock);
+	platform_set_drvdata(pdev, data);
+
+	switch (data->type) {
+	case TYPE_BUSFREQ_EXYNOS3250_MIF:
+	case TYPE_BUSFREQ_EXYNOS3250_INT:
+		/* Parse dt data to get register/clock/regulator */
+		ret = exynos3_bus_parse_dt(data);
+		if (ret < 0) {
+			dev_err(dev, "Failed to parse dt for resource %d\n",
+				data->type);
+			return ret;
+		}
+
+		/* Initialize Memory Bus Voltage/Frequency table */
+		ret = exynos3_bus_init_table(data);
+		if (ret < 0) {
+			dev_err(dev, "Failed to initialze volt/freq table %d\n",
+				data->type);
+			return ret;
+		}
+		break;
+	default:
+		dev_err(dev, "Unknown device id %d\n", data->type);
+		return -EINVAL;
+	}
+
+	/* Find the proper opp instance according to initial bus frequency */
+	rcu_read_lock();
+	opp = dev_pm_opp_find_freq_floor(dev, &data->profile->initial_freq);
+	if (IS_ERR_OR_NULL(opp)) {
+		rcu_read_unlock();
+		dev_err(dev, "Failed to find initial frequency %lu kHz, %d\n",
+			      data->profile->initial_freq, data->type);
+		ret = PTR_ERR(opp);
+		goto err_opp;
+	}
+	data->curr_opp_info.rate = dev_pm_opp_get_freq(opp);
+	data->curr_opp_info.volt = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	/* Reigster Exynos3250's devfreq instance with 'simple_ondemand' gov */
+	data->devfreq = devfreq_add_device(dev, data->profile,
+					   "simple_ondemand", NULL);
+	if (IS_ERR_OR_NULL(data->devfreq)) {
+		dev_err(dev, "Failed to add devfreq device\n");
+		ret = PTR_ERR(data->devfreq);
+		goto err_opp;
+	}
+
+	/*
+	 * Start PPMU (Performance Profiling Monitoring Unit) to check
+	 * utilization of each IP in the Exynos3 SoC.
+	 */
+	busfreq_mon_reset(&data->ppmu);
+
+	/* Register opp_notifier for Exynos3 busfreq */
+	ret = devfreq_register_opp_notifier(dev, data->devfreq);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register opp notifier\n");
+		goto err_notifier_opp;
+	}
+
+	/* Register pm_notifier for Exynos3 busfreq */
+	data->pm_notifier.notifier_call = exynos3_bus_pm_notifier_event;
+	ret = register_pm_notifier(&data->pm_notifier);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register pm notifier\n");
+		goto err_notifier_pm;
+	}
+
+	return 0;
+
+err_notifier_pm:
+	devfreq_unregister_opp_notifier(dev, data->devfreq);
+err_notifier_opp:
+	devfreq_remove_device(data->devfreq);
+err_opp:
+	regulator_disable(data->regulator_vdd);
+	exynos3_bus_cleanup_clocks(data);
+	exynos3_bus_cleanup_iomap(data);
+
+	return ret;
+}
+
+static int exynos3_busfreq_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct busfreq_data *data = platform_get_drvdata(pdev);
+
+	/*
+	 * devfreq_dev_profile.exit() will disable regulator, unprepare
+	 * clocks and unmap memory.
+	 */
+
+	/* Unregister all of notifier chain */
+	unregister_pm_notifier(&data->pm_notifier);
+	devfreq_unregister_opp_notifier(dev, data->devfreq);
+
+	devfreq_remove_device(data->devfreq);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos3_busfreq_resume(struct device *dev)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	int i;
+
+	/* Enable clock after wake-up from suspend state */
+	for (i = 0; i < data->ppmu.ppmu_end; i++)
+		if (data->clk_ppmu[i])
+			clk_prepare_enable(data->clk_ppmu[i]);
+
+	/* Reset PPMU to check utilization again */
+	busfreq_mon_reset(&data->ppmu);
+
+	return 0;
+}
+
+static int exynos3_busfreq_suspend(struct device *dev)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	int i;
+
+	/*
+	 * Disable clock before entering suspend state
+	 * to reduce leakage power on suspend state.
+	 */
+	for (i = 0; i < data->ppmu.ppmu_end; i++)
+		if (data->clk_ppmu[i])
+			clk_disable_unprepare(data->clk_ppmu[i]);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos3_busfreq_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(exynos3_busfreq_suspend, exynos3_busfreq_resume)
+};
+
+static const struct platform_device_id exynos3_busfreq_id[] = {
+	{ "exynos3250-busf-mif", TYPE_BUSFREQ_EXYNOS3250_MIF },
+	{ "exynos3250-busf-int", TYPE_BUSFREQ_EXYNOS3250_INT },
+	{},
+};
+
+static struct platform_driver exynos3_busfreq_driver = {
+	.probe		= exynos3_busfreq_probe,
+	.remove		= exynos3_busfreq_remove,
+	.id_table	= exynos3_busfreq_id,
+	.driver		= {
+		.name		= "exynos3250-busfreq",
+		.owner		= THIS_MODULE,
+		.pm		= &exynos3_busfreq_pm,
+		.of_match_table	= exynos3_busfreq_id_match,
+	},
+};
+
+static int __init exynos3_busfreq_init(void)
+{
+	BUILD_BUG_ON(ARRAY_SIZE(exynos3_bus_mif_clk_name) !=
+					EXYNOS3_BUS_MIF_CLK_END);
+	BUILD_BUG_ON(ARRAY_SIZE(exynos3_bus_int_clk_name) !=
+					EXYNOS3_BUS_INT_CLK_END);
+
+	return platform_driver_register(&exynos3_busfreq_driver);
+}
+late_initcall(exynos3_busfreq_init);
+
+static void __exit exynos3_busfreq_exit(void)
+{
+	platform_driver_unregister(&exynos3_busfreq_driver);
+}
+module_exit(exynos3_busfreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EXYNOS3250 INT/MIF busfreq driver with devfreq framework");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-- 
1.9.1


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

* [RFC 2/3] devfreq: exynos: Add driver for Exynos3250
@ 2014-12-05 16:46   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Add new devfreq driver for Exynos3250. The driver utilizes existing PPMU
helpers and is multiplatform safe. Currently it does not support ASV
(Adaptive Supply Voltage).

Driver creates two devices:
 - Dynamic Memory Controller (DMC) and memory bus,
 - peripheral (left/right) buses.

For memory it changes the DMC clock from 50 MHz to 400 MHz and voltage
regulator from 800 mV to 875 mV.
As for peripheral it changes frequencies of multiple bus clocks and INT
voltage 850 mV to 950 mV.

Impact on performance (Rinato/Gear 2 board) calculated with:
$ perf bench mem memcpy -l 256MB -i 10
$ perf bench mem memset -l 256MB -i 10
$ dd if=/mmc of=file iflag=direct oflag=direct count=128 bs=1M

 type           | no devfreq [MB/s] | devfreq [MB/s] |  diff
============================================================
memcpy          | 156.253719        | 156.122788     | -0.1%
memcpy prefault | 166.789370        | 166.557580     | -0.1%
memset          | 134.094529        | 129.266162     | -3.6%
memset prefault | 168.584091        | 168.426261     | -0.1%
dd trabsfer     |  14.8             |  15.6          | -1.3%

Impact on energy consumption, system in idle (WFI), mA:
 no devfreq [mA] | devfreq [mA] |   diff
========================================
 29.0            | 19.2         | -33.8%

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 drivers/devfreq/Kconfig              |  12 +
 drivers/devfreq/Makefile             |   1 +
 drivers/devfreq/exynos/Makefile      |   1 +
 drivers/devfreq/exynos/exynos3_bus.c | 842 +++++++++++++++++++++++++++++++++++
 4 files changed, 856 insertions(+)
 create mode 100644 drivers/devfreq/exynos/exynos3_bus.c

diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index faf4e70c42e0..3fdd7cfebb6d 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -65,6 +65,18 @@ config DEVFREQ_GOV_USERSPACE
 
 comment "DEVFREQ Drivers"
 
+config ARM_EXYNOS3_BUS_DEVFREQ
+	bool "ARM Exynos3250 Memory and peripheral bus DEVFREQ Driver"
+	depends on SOC_EXYNOS3250
+	select DEVFREQ_GOV_SIMPLE_ONDEMAND
+	select PM_OPP
+	help
+	  This adds the DEVFREQ driver for Exynos3250 memory interface
+	  and peripheral bus (vdd_mif + vdd_int).
+	  It reads PPMU counters of memory controllers and adjusts
+	  the operating frequencies and voltages with OPP support.
+	  This does not yet operate with optimal voltages.
+
 config ARM_EXYNOS4_BUS_DEVFREQ
 	bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
 	depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 16138c9e0d58..d876fab4db21 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 
 # DEVFREQ Drivers
+obj-$(CONFIG_ARM_EXYNOS3_BUS_DEVFREQ)	+= exynos/
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos/
 obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos/
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
index 49bc9175f923..a4aa1ed474c9 100644
--- a/drivers/devfreq/exynos/Makefile
+++ b/drivers/devfreq/exynos/Makefile
@@ -1,3 +1,4 @@
 # Exynos DEVFREQ Drivers
+obj-$(CONFIG_ARM_EXYNOS3_BUS_DEVFREQ)	+= exynos_ppmu.o exynos3_bus.o
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos_ppmu.o exynos4_bus.o
 obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos_ppmu.o exynos5_bus.o
diff --git a/drivers/devfreq/exynos/exynos3_bus.c b/drivers/devfreq/exynos/exynos3_bus.c
new file mode 100644
index 000000000000..27370b97001b
--- /dev/null
+++ b/drivers/devfreq/exynos/exynos3_bus.c
@@ -0,0 +1,842 @@
+/*
+ * drivers/devfreq/exynos/exynos3_bus.c
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * based on drivers/devfreqw/exynos/exynos4_bus.c
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * EXYNOS3250 - Memory/Bus clock frequency scaling support in DEVFREQ framework
+ * This version supports EXYNOS3250 only.
+ *
+ * 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/clk.h>
+#include <linux/devfreq.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_opp.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+
+#include "exynos_ppmu.h"
+
+/*
+ * Assume that the bus is saturated if the utilization is 30%.
+ *
+ * Saturation ratio is less than that in exynos4_bus.c (40%) to boost
+ * ondemand governor early.
+ * Memory tests (memcpy, memory alloc, dmatest) shown that ratio of 40%
+ * triggers frequency increase sporadically.
+ */
+#define EXYNOS3_BUS_SATURATION_RATIO	30
+#define EXYNOS3_BUS_INT_REGULATOR_NAME	"vdd_int"
+#define EXYNOS3_BUS_MIF_REGULATOR_NAME	"vdd_mif"
+
+#define EXYNOS3_BUS_PPMU_NUM		2
+
+#define EXYNOS3_BUS_INTERVAL_SAFEVOLT	25000	/* 25mV */
+
+enum exynos3_busfreq_type {
+	TYPE_BUSFREQ_UNKNOWN = 0,
+	TYPE_BUSFREQ_EXYNOS3250_MIF,
+	TYPE_BUSFREQ_EXYNOS3250_INT,
+};
+
+enum exynos3_busfreq_level {
+	LV_0,
+	LV_1,
+	LV_2,
+	LV_3,
+	LV_4,
+	LV_5,
+
+	LV_END,
+};
+
+/*
+ * Clocks for INT PPMU.
+ * The clocks for DMC PPMU are not defined and by default are enabled.
+ */
+static const char * const exynos3_bus_int_ppmu_clk_name[] = {
+	"ppmu_left", "ppmu_right",
+};
+
+enum exynos3_bus_mif_clk {
+	DMC,
+	EXYNOS3_BUS_MIF_CLK_END,
+};
+
+enum exynos3_bus_int_clk {
+	ACLK_400,
+	ACLK_266,
+	ACLK_200,
+	ACLK_160,
+	ACLK_GDL,
+	ACLK_GDR,
+	MFC,
+	EXYNOS3_BUS_INT_CLK_END,
+};
+
+static const char * const exynos3_bus_mif_clk_name[] = {
+	[DMC]		= "dmc",
+};
+
+static const char * const exynos3_bus_int_clk_name[] = {
+	[ACLK_400]	= "aclk_400",
+	[ACLK_266]	= "aclk_266",
+	[ACLK_200]	= "aclk_200",
+	[ACLK_160]	= "aclk_160",
+	[ACLK_GDL]	= "aclk_gdl",
+	[ACLK_GDR]	= "aclk_gdr",
+	[MFC]		= "mfc",
+};
+
+/**
+ * struct busfreq_opp_info - opp information for bus
+ * @rate:	Frequency in hertz
+ * @volt:	Voltage in microvolts corresponding to this OPP
+ */
+struct busfreq_opp_info {
+	unsigned long rate;
+	unsigned long volt;
+};
+
+struct busfreq_data {
+	struct devfreq_dev_profile *profile;
+	enum exynos3_busfreq_type type;
+	struct device *dev;
+	struct devfreq *devfreq;
+	bool disabled;
+
+	struct busfreq_opp_info curr_opp_info;
+
+	struct regulator *regulator_vdd;
+	struct busfreq_ppmu_data ppmu;
+	struct clk **clk_ppmu;
+	struct clk **clk_bus;
+	unsigned int clk_bus_num;
+
+	const struct bus_opp_table *opp_table;
+	int opp_table_end;
+
+	struct notifier_block pm_notifier;
+	struct mutex lock;
+};
+
+static const struct bus_opp_table exynos3_bus_mif_clk_table[] = {
+	/*   DMC clock, MIF voltage */
+	{LV_0,	400000,	875000},
+	{LV_1,	200000,	800000},
+	{LV_2,	133000,	800000},
+	{LV_3,	100000,	800000},
+	{LV_4,	 50000,	800000},
+};
+
+/*
+ * The frequency for INT is an abstract clock, without real representation
+ * because INT actually changes multiple clocks. Values for this frequency
+ * match MIF/DMC clock (except one additional level: 80000).
+ */
+static const struct bus_opp_table exynos3_bus_int_clk_table[] = {
+	/* abstract clock, INT voltage */
+	{LV_0,	400000,	950000},
+	{LV_1,	200000,	950000},
+	{LV_2,	133000, 925000},
+	{LV_3,	100000, 850000},
+	{LV_4,	80000,  850000},
+	{LV_5,	50000,  850000},
+};
+
+static const unsigned int exynos3_bus_mif_clk_freq[][EXYNOS3_BUS_MIF_CLK_END] = {
+		/* DMC */
+	[LV_0] = { 400000000, },
+	[LV_1] = { 200000000, },
+	[LV_2] = { 133333334, },
+	[LV_3] = { 100000000, },
+	[LV_4] = {  50000000, },
+};
+
+static const unsigned int exynos3_bus_int_clk_freq[][EXYNOS3_BUS_INT_CLK_END] = {
+		/*  ACLK_400,  ACLK_266,  ACLK_200,  ACLK_160,  ACLK_GDL,  ACLK_GDR, MFC */
+	[LV_0] = { 400000000, 300000000, 200000000, 200000000, 200000000, 200000000, 200000000, },
+	[LV_1] = { 200000000, 200000000, 200000000, 133333334, 200000000, 200000000, 200000000, },
+	[LV_2] = {  50000000, 133333334, 100000000, 100000000, 133333334, 133333334, 200000000, },
+	[LV_3] = {  50000000,  50000000,  80000000,  80000000, 100000000, 100000000, 133333334, },
+	[LV_4] = {  50000000,  50000000,  50000000,  50000000, 100000000, 100000000, 100000000, },
+	[LV_5] = {  50000000,  50000000,  50000000,  50000000, 100000000, 100000000,  80000000, },
+};
+
+static int round_set_clk(struct device *dev, int id, struct clk *clk,
+		unsigned long rate)
+{
+	int ret;
+	long real_rate;
+
+	real_rate = clk_round_rate(clk, rate);
+	if (real_rate <= 0) {
+		dev_err(dev, "Cannot round clock rate %d to %lu: %ld\n",
+				id, rate, real_rate);
+		return -EINVAL;
+	}
+
+	ret = clk_set_rate(clk, real_rate);
+	if (ret) {
+		dev_err(dev, "Cannot set clock rate %d to %lu: %d",
+				id, real_rate, ret);
+		return ret;
+	}
+
+	dev_dbg(dev, "Clock %d to %lu/%lu\n", id, rate, real_rate);
+
+	return 0;
+}
+
+static int exynos3_bus_set_clk(struct busfreq_data *data,
+				  struct busfreq_opp_info *new_opp_info)
+{
+	int index, i, clk_num;
+	const unsigned int *clk_freq;
+
+	for (index = 0; index < data->opp_table_end; index++)
+		if (new_opp_info->rate == data->opp_table[index].clk)
+			break;
+
+	if (index == data->opp_table_end)
+		return -EINVAL;
+
+	switch (data->type) {
+	case TYPE_BUSFREQ_EXYNOS3250_MIF:
+		clk_num = EXYNOS3_BUS_MIF_CLK_END;
+		clk_freq = exynos3_bus_mif_clk_freq[index];
+		break;
+	case TYPE_BUSFREQ_EXYNOS3250_INT:
+		clk_num = EXYNOS3_BUS_INT_CLK_END;
+		clk_freq = exynos3_bus_int_clk_freq[index];
+		break;
+	default:
+		dev_err(data->dev, "Unknown device type %d\n", data->type);
+		return -EINVAL;
+	};
+
+	for (i = 0; i < clk_num; i++) {
+		int ret;
+
+		ret = round_set_clk(data->dev, i, data->clk_bus[i],
+				clk_freq[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int exynos3_bus_set_volt(struct busfreq_data *data,
+				struct busfreq_opp_info *new_opp_info,
+				struct busfreq_opp_info *old_opp_info)
+{
+	int ret;
+
+	ret = regulator_set_voltage(data->regulator_vdd, new_opp_info->volt,
+			new_opp_info->volt + EXYNOS3_BUS_INTERVAL_SAFEVOLT);
+	if (ret < 0) {
+		dev_err(data->dev, "Failed to set voltage %d\n", data->type);
+		regulator_set_voltage(data->regulator_vdd, old_opp_info->volt,
+			old_opp_info->volt + EXYNOS3_BUS_INTERVAL_SAFEVOLT);
+	}
+
+	return 0;
+}
+
+/*
+ * Define internal function of structure devfreq_dev_profile
+ */
+static int exynos3_bus_target(struct device *dev, unsigned long *_freq,
+			      u32 flags)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	struct busfreq_opp_info	new_opp_info;
+	unsigned long old_freq, new_freq;
+	struct dev_pm_opp *opp;
+	int ret = 0;
+
+	if (data->disabled)
+		goto out;
+
+	/* Get new opp-info instance according to new busfreq clock */
+	rcu_read_lock();
+	opp = devfreq_recommended_opp(dev, _freq, flags);
+	if (IS_ERR_OR_NULL(opp)) {
+		dev_err(dev, "Failed to get recommed opp instance\n");
+		rcu_read_unlock();
+		return PTR_ERR(opp);
+	}
+	new_opp_info.rate = dev_pm_opp_get_freq(opp);
+	new_opp_info.volt = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	old_freq = data->curr_opp_info.rate;
+	new_freq = new_opp_info.rate;
+	if (old_freq == new_freq)
+		return 0;
+
+	dev_dbg(dev, "%lu MHz, %ld mV --> %lu MHz, %ld mV\n",
+		old_freq / 1000, data->curr_opp_info.volt / 1000,
+		new_freq / 1000, new_opp_info.volt / 1000);
+
+	/* Change voltage/clock according to new busfreq level */
+	mutex_lock(&data->lock);
+
+	if (old_freq < new_freq) {
+		ret = exynos3_bus_set_volt(data, &new_opp_info,
+					   &data->curr_opp_info);
+		if (ret < 0) {
+			dev_err(dev, "Failed to set voltage %d\n", data->type);
+			goto out;
+		}
+	}
+
+	ret = exynos3_bus_set_clk(data, &new_opp_info);
+	if (ret < 0) {
+		dev_err(dev, "Failed to set bus clock %d\n", data->type);
+		goto out;
+	}
+
+	if (old_freq > new_freq) {
+		ret = exynos3_bus_set_volt(data, &new_opp_info,
+					   &data->curr_opp_info);
+		if (ret < 0) {
+			dev_err(dev, "Failed to set voltage %d\n", data->type);
+			goto out;
+		}
+	}
+
+	data->curr_opp_info = new_opp_info;
+out:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int exynos3_bus_get_dev_status(struct device *dev,
+				      struct devfreq_dev_status *stat)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	int busier;
+
+	/* Read PPMU total cycle count and Read/Write count */
+	exynos_read_ppmu(&data->ppmu);
+
+	/* Get busier PPMU device among various PPMU */
+	busier = exynos_get_busier_ppmu(&data->ppmu);
+	stat->current_frequency = data->curr_opp_info.rate;
+
+	/* Number of cycles spent on memory access */
+	stat->busy_time = data->ppmu.ppmu[busier].count[PPMU_PMNCNT3];
+	stat->busy_time *= 100 / EXYNOS3_BUS_SATURATION_RATIO;
+	stat->total_time = data->ppmu.ppmu[busier].ccnt;
+
+	/* If the counters have overflown, retry */
+	if (data->ppmu.ppmu[busier].ccnt_overflow ||
+		data->ppmu.ppmu[busier].count_overflow[0])
+		return -EAGAIN;
+
+	return 0;
+}
+
+static void exynos3_bus_cleanup_iomap(struct busfreq_data *data)
+{
+	int i;
+
+	for (i = 0; i < data->ppmu.ppmu_end; i++) {
+		if (data->ppmu.ppmu[i].hw_base)
+			iounmap(data->ppmu.ppmu[i].hw_base);
+	}
+}
+
+static void exynos3_bus_cleanup_clocks(struct busfreq_data *data)
+{
+	int i;
+
+	for (i = 0; i < data->clk_bus_num; i++) {
+		if (data->clk_bus[i])
+			clk_disable_unprepare(data->clk_bus[i]);
+	}
+
+	for (i = 0; i < data->ppmu.ppmu_end; i++) {
+		if (data->clk_ppmu[i])
+			clk_disable_unprepare(data->clk_ppmu[i]);
+	}
+}
+
+static void exynos3_bus_exit(struct device *dev)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+
+	regulator_disable(data->regulator_vdd);
+	exynos3_bus_cleanup_clocks(data);
+	exynos3_bus_cleanup_iomap(data);
+}
+
+/* Define devfreq_dev_profile for MIF block */
+static struct devfreq_dev_profile exynos3_busfreq_mif_profile = {
+	.initial_freq	= 400000,
+	.polling_ms	= 100,
+	.target		= exynos3_bus_target,
+	.get_dev_status	= exynos3_bus_get_dev_status,
+	.exit		= exynos3_bus_exit,
+};
+
+/* Define devfreq_dev_profile for INT block */
+static struct devfreq_dev_profile exynos3_busfreq_int_profile = {
+	.initial_freq	= 400000,
+	.polling_ms	= 100,
+	.target		= exynos3_bus_target,
+	.get_dev_status	= exynos3_bus_get_dev_status,
+	.exit		= exynos3_bus_exit,
+};
+
+static int exynos3_bus_pm_notifier_event(struct notifier_block *this,
+					     unsigned long event, void *ptr)
+{
+	struct busfreq_data *data = container_of(this, struct busfreq_data,
+						 pm_notifier);
+	struct dev_pm_opp *opp;
+	struct busfreq_opp_info	new_opp_info;
+	unsigned long maxfreq = ULONG_MAX;
+	int err = 0;
+
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		mutex_lock(&data->lock);
+
+		data->disabled = true;
+
+		rcu_read_lock();
+		opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
+		if (IS_ERR(opp)) {
+			rcu_read_unlock();
+			dev_err(data->dev, "%s: unable to find a min freq\n",
+				__func__);
+			mutex_unlock(&data->lock);
+			return PTR_ERR(opp);
+		}
+		new_opp_info.rate = dev_pm_opp_get_freq(opp);
+		new_opp_info.volt = dev_pm_opp_get_voltage(opp);
+		rcu_read_unlock();
+
+		err = exynos3_bus_set_volt(data, &new_opp_info,
+					   &data->curr_opp_info);
+		if (err) {
+			mutex_unlock(&data->lock);
+			return err;
+		}
+
+		err = exynos3_bus_set_clk(data, &new_opp_info);
+		if (err) {
+			mutex_unlock(&data->lock);
+			return err;
+		}
+
+		data->curr_opp_info = new_opp_info;
+
+		mutex_unlock(&data->lock);
+		if (err)
+			return err;
+		return NOTIFY_OK;
+	case PM_POST_RESTORE:
+	case PM_POST_SUSPEND:
+		/* Reactivate */
+		mutex_lock(&data->lock);
+		data->disabled = false;
+		mutex_unlock(&data->lock);
+		return NOTIFY_OK;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int exynos3_bus_init_table(struct busfreq_data *data)
+{
+	int i, ret;
+
+	/* Add OPP entry including the voltage/clock of busfreq level */
+	for (i = 0; i < data->opp_table_end; i++) {
+		ret = dev_pm_opp_add(data->dev,
+			      data->opp_table[i].clk,
+			      data->opp_table[i].volt);
+		if (ret < 0) {
+			dev_err(data->dev, "Failed to add opp entry(%ld,%ld)\n",
+				data->opp_table[i].clk,
+				data->opp_table[i].volt);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int exynos3_bus_parse_dt(struct busfreq_data *data)
+{
+	struct device *dev = data->dev;
+	struct device_node *np = dev->of_node;
+	char regulator_name[DEVFREQ_NAME_LEN];
+	const char * const *ppmu_clk_name, * const *bus_clk_name;
+	int i, ret = 0;
+
+	data->ppmu.ppmu_end	= EXYNOS3_BUS_PPMU_NUM;
+	switch (data->type) {
+	case TYPE_BUSFREQ_EXYNOS3250_MIF:
+		data->profile		= &exynos3_busfreq_mif_profile;
+		data->opp_table		= exynos3_bus_mif_clk_table;
+		data->opp_table_end	= ARRAY_SIZE(exynos3_bus_mif_clk_table);
+
+		ppmu_clk_name		= NULL;
+		bus_clk_name		= exynos3_bus_mif_clk_name;
+		data->clk_bus_num	= ARRAY_SIZE(exynos3_bus_mif_clk_name);
+		strcpy(regulator_name,	EXYNOS3_BUS_MIF_REGULATOR_NAME);
+		break;
+	case TYPE_BUSFREQ_EXYNOS3250_INT:
+		data->profile		= &exynos3_busfreq_int_profile;
+		data->opp_table		= exynos3_bus_int_clk_table;
+		data->opp_table_end	= ARRAY_SIZE(exynos3_bus_int_clk_table);
+
+		ppmu_clk_name		= exynos3_bus_int_ppmu_clk_name;
+		bus_clk_name		= exynos3_bus_int_clk_name;
+		data->clk_bus_num	= ARRAY_SIZE(exynos3_bus_int_clk_name);
+		strcpy(regulator_name,	EXYNOS3_BUS_INT_REGULATOR_NAME);
+
+		break;
+	default:
+		dev_err(dev, "Unknown device id %d\n", data->type);
+		return -EINVAL;
+	};
+
+	/* Allocate memory for ppmu register/clock according to ppmu count */
+	data->ppmu.ppmu = devm_kzalloc(dev,
+			sizeof(struct exynos_ppmu) * data->ppmu.ppmu_end,
+			GFP_KERNEL);
+	if (!data->ppmu.ppmu) {
+		dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
+		return -ENOMEM;
+	}
+
+	data->clk_ppmu = devm_kzalloc(dev,
+				sizeof(struct clk *) * data->ppmu.ppmu_end,
+				GFP_KERNEL);
+	if (!data->clk_ppmu) {
+		dev_err(dev, "Failed to allocate memory for ppmu clock\n");
+		return -ENOMEM;
+	}
+
+	data->clk_bus = devm_kzalloc(dev,
+				sizeof(struct clk *) * data->clk_bus_num,
+				GFP_KERNEL);
+	if (!data->clk_bus)
+		return -ENOMEM;
+
+	/* Maps the memory mapped IO to control PPMU register */
+	for (i = 0; i < data->ppmu.ppmu_end; i++) {
+		data->ppmu.ppmu[i].hw_base = of_iomap(np, i);
+		if (IS_ERR_OR_NULL(data->ppmu.ppmu[i].hw_base)) {
+			dev_err(dev, "Failed to map memory region\n");
+			data->ppmu.ppmu[i].hw_base = NULL;
+			ret = -EINVAL;
+			goto err_iomap;
+		}
+	}
+
+	/*
+	 * Get PPMU's clocks to control them. But, if PPMU's clocks
+	 * is default 'pass' state, this driver don't need control
+	 * PPMU's clock.
+	 */
+	if (ppmu_clk_name) {
+		for (i = 0; i < data->ppmu.ppmu_end; i++) {
+			data->clk_ppmu[i] = devm_clk_get(dev, ppmu_clk_name[i]);
+			if (IS_ERR_OR_NULL(data->clk_ppmu[i])) {
+				dev_warn(dev, "Cannot get %s clock\n",
+						ppmu_clk_name[i]);
+				data->clk_ppmu[i] = NULL;
+			}
+
+			ret = clk_prepare_enable(data->clk_ppmu[i]);
+			if (ret < 0) {
+				dev_warn(dev, "Cannot enable %s clock\n",
+						ppmu_clk_name[i]);
+				data->clk_ppmu[i] = NULL;
+				goto err_clocks;
+			}
+		}
+	}
+
+	for (i = 0; i < data->clk_bus_num; i++) {
+		data->clk_bus[i] = devm_clk_get(dev, bus_clk_name[i]);
+		if (IS_ERR_OR_NULL(data->clk_bus[i])) {
+			dev_err(dev, "Cannot get %s clock: %ld\n",
+					bus_clk_name[i],
+					PTR_ERR(data->clk_bus[i]));
+			goto err_clocks;
+		}
+
+		ret = clk_prepare_enable(data->clk_bus[i]);
+		if (ret < 0) {
+			dev_err(dev, "Cannot enable %s clock: %d\n",
+						bus_clk_name[i], ret);
+			data->clk_bus[i] = NULL;
+			goto err_clocks;
+		}
+	}
+
+	/* Get regulators to control voltage of int/mif block */
+	data->regulator_vdd = devm_regulator_get(dev, regulator_name);
+	if (IS_ERR(data->regulator_vdd)) {
+		dev_err(dev, "Failed to get the regulator \"%s\": %ld\n",
+			regulator_name, PTR_ERR(data->regulator_vdd));
+		ret = -EINVAL;
+		goto err_clocks;
+	}
+
+	ret = regulator_enable(data->regulator_vdd);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulator: %d\n", ret);
+		goto err_clocks;
+	}
+
+	return 0;
+
+err_clocks:
+	exynos3_bus_cleanup_clocks(data);
+err_iomap:
+	exynos3_bus_cleanup_iomap(data);
+
+	return ret;
+}
+
+static struct of_device_id exynos3_busfreq_id_match[] = {
+	{
+		.compatible = "samsung,exynos3250-busfreq-mif",
+		.data = (void *)TYPE_BUSFREQ_EXYNOS3250_MIF,
+	}, {
+		.compatible = "samsung,exynos3250-busfreq-int",
+		.data = (void *)TYPE_BUSFREQ_EXYNOS3250_INT,
+	},
+	{},
+};
+
+static int exynos3_busfreq_get_driver_data(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *match;
+
+	match = of_match_node(exynos3_busfreq_id_match, dev->of_node);
+	if (!match)
+		return -ENODEV;
+
+	return (int)match->data;
+}
+
+static int exynos3_busfreq_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct busfreq_data *data;
+	struct dev_pm_opp *opp;
+	int ret = 0;
+
+	if (!dev->of_node)
+		return -EINVAL;
+
+	data = devm_kzalloc(dev, sizeof(struct busfreq_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->type = exynos3_busfreq_get_driver_data(pdev);
+	data->dev = dev;
+	mutex_init(&data->lock);
+	platform_set_drvdata(pdev, data);
+
+	switch (data->type) {
+	case TYPE_BUSFREQ_EXYNOS3250_MIF:
+	case TYPE_BUSFREQ_EXYNOS3250_INT:
+		/* Parse dt data to get register/clock/regulator */
+		ret = exynos3_bus_parse_dt(data);
+		if (ret < 0) {
+			dev_err(dev, "Failed to parse dt for resource %d\n",
+				data->type);
+			return ret;
+		}
+
+		/* Initialize Memory Bus Voltage/Frequency table */
+		ret = exynos3_bus_init_table(data);
+		if (ret < 0) {
+			dev_err(dev, "Failed to initialze volt/freq table %d\n",
+				data->type);
+			return ret;
+		}
+		break;
+	default:
+		dev_err(dev, "Unknown device id %d\n", data->type);
+		return -EINVAL;
+	}
+
+	/* Find the proper opp instance according to initial bus frequency */
+	rcu_read_lock();
+	opp = dev_pm_opp_find_freq_floor(dev, &data->profile->initial_freq);
+	if (IS_ERR_OR_NULL(opp)) {
+		rcu_read_unlock();
+		dev_err(dev, "Failed to find initial frequency %lu kHz, %d\n",
+			      data->profile->initial_freq, data->type);
+		ret = PTR_ERR(opp);
+		goto err_opp;
+	}
+	data->curr_opp_info.rate = dev_pm_opp_get_freq(opp);
+	data->curr_opp_info.volt = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	/* Reigster Exynos3250's devfreq instance with 'simple_ondemand' gov */
+	data->devfreq = devfreq_add_device(dev, data->profile,
+					   "simple_ondemand", NULL);
+	if (IS_ERR_OR_NULL(data->devfreq)) {
+		dev_err(dev, "Failed to add devfreq device\n");
+		ret = PTR_ERR(data->devfreq);
+		goto err_opp;
+	}
+
+	/*
+	 * Start PPMU (Performance Profiling Monitoring Unit) to check
+	 * utilization of each IP in the Exynos3 SoC.
+	 */
+	busfreq_mon_reset(&data->ppmu);
+
+	/* Register opp_notifier for Exynos3 busfreq */
+	ret = devfreq_register_opp_notifier(dev, data->devfreq);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register opp notifier\n");
+		goto err_notifier_opp;
+	}
+
+	/* Register pm_notifier for Exynos3 busfreq */
+	data->pm_notifier.notifier_call = exynos3_bus_pm_notifier_event;
+	ret = register_pm_notifier(&data->pm_notifier);
+	if (ret < 0) {
+		dev_err(dev, "Failed to register pm notifier\n");
+		goto err_notifier_pm;
+	}
+
+	return 0;
+
+err_notifier_pm:
+	devfreq_unregister_opp_notifier(dev, data->devfreq);
+err_notifier_opp:
+	devfreq_remove_device(data->devfreq);
+err_opp:
+	regulator_disable(data->regulator_vdd);
+	exynos3_bus_cleanup_clocks(data);
+	exynos3_bus_cleanup_iomap(data);
+
+	return ret;
+}
+
+static int exynos3_busfreq_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct busfreq_data *data = platform_get_drvdata(pdev);
+
+	/*
+	 * devfreq_dev_profile.exit() will disable regulator, unprepare
+	 * clocks and unmap memory.
+	 */
+
+	/* Unregister all of notifier chain */
+	unregister_pm_notifier(&data->pm_notifier);
+	devfreq_unregister_opp_notifier(dev, data->devfreq);
+
+	devfreq_remove_device(data->devfreq);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos3_busfreq_resume(struct device *dev)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	int i;
+
+	/* Enable clock after wake-up from suspend state */
+	for (i = 0; i < data->ppmu.ppmu_end; i++)
+		if (data->clk_ppmu[i])
+			clk_prepare_enable(data->clk_ppmu[i]);
+
+	/* Reset PPMU to check utilization again */
+	busfreq_mon_reset(&data->ppmu);
+
+	return 0;
+}
+
+static int exynos3_busfreq_suspend(struct device *dev)
+{
+	struct busfreq_data *data = dev_get_drvdata(dev);
+	int i;
+
+	/*
+	 * Disable clock before entering suspend state
+	 * to reduce leakage power on suspend state.
+	 */
+	for (i = 0; i < data->ppmu.ppmu_end; i++)
+		if (data->clk_ppmu[i])
+			clk_disable_unprepare(data->clk_ppmu[i]);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos3_busfreq_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(exynos3_busfreq_suspend, exynos3_busfreq_resume)
+};
+
+static const struct platform_device_id exynos3_busfreq_id[] = {
+	{ "exynos3250-busf-mif", TYPE_BUSFREQ_EXYNOS3250_MIF },
+	{ "exynos3250-busf-int", TYPE_BUSFREQ_EXYNOS3250_INT },
+	{},
+};
+
+static struct platform_driver exynos3_busfreq_driver = {
+	.probe		= exynos3_busfreq_probe,
+	.remove		= exynos3_busfreq_remove,
+	.id_table	= exynos3_busfreq_id,
+	.driver		= {
+		.name		= "exynos3250-busfreq",
+		.owner		= THIS_MODULE,
+		.pm		= &exynos3_busfreq_pm,
+		.of_match_table	= exynos3_busfreq_id_match,
+	},
+};
+
+static int __init exynos3_busfreq_init(void)
+{
+	BUILD_BUG_ON(ARRAY_SIZE(exynos3_bus_mif_clk_name) !=
+					EXYNOS3_BUS_MIF_CLK_END);
+	BUILD_BUG_ON(ARRAY_SIZE(exynos3_bus_int_clk_name) !=
+					EXYNOS3_BUS_INT_CLK_END);
+
+	return platform_driver_register(&exynos3_busfreq_driver);
+}
+late_initcall(exynos3_busfreq_init);
+
+static void __exit exynos3_busfreq_exit(void)
+{
+	platform_driver_unregister(&exynos3_busfreq_driver);
+}
+module_exit(exynos3_busfreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EXYNOS3250 INT/MIF busfreq driver with devfreq framework");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-- 
1.9.1

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

* [RFC 3/3] ARM: dts: Add devfreq to Exynos3250 and Rinato board
  2014-12-05 16:46 ` Krzysztof Kozlowski
@ 2014-12-05 16:46   ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi
  Cc: Marek Szyprowski, Bartlomiej Zolnierkiewicz, Tomasz Figa,
	Krzysztof Kozlowski

Add devfreq to Exynos3250 common file and enable it for Rinato board.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 arch/arm/boot/dts/exynos3250-rinato.dts | 10 ++++++++++
 arch/arm/boot/dts/exynos3250.dtsi       | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 80aa8b4c4a3d..713b6a5c3f85 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -527,6 +527,16 @@
 	clock-frequency = <24000000>;
 };
 
+&busfreq_mif {
+	vdd_mif-supply = <&buck1_reg>;
+	status = "okay";
+};
+
+&busfreq_int {
+	vdd_int-supply = <&buck3_reg>;
+	status = "okay";
+};
+
 &pinctrl_0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sleep0>;
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 22465494b796..8f8d674a8748 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -175,6 +175,38 @@
 			#clock-cells = <1>;
 		};
 
+		busfreq_mif: busfreq@106A0000 {
+			compatible = "samsung,exynos3250-busfreq-mif";
+			reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
+			clocks = <&cmu_dmc CLK_DIV_DMC>;
+			clock-names = "dmc";
+			status = "disabled";
+		};
+
+		busfreq_int: busfreq@116A0000 {
+			compatible = "samsung,exynos3250-busfreq-int";
+			reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
+			clocks = <&cmu CLK_PPMULEFT>,
+				<&cmu CLK_PPMURIGHT>,
+				<&cmu CLK_DIV_ACLK_400_MCUISP>,
+				<&cmu CLK_DIV_ACLK_266>,
+				<&cmu CLK_DIV_ACLK_200>,
+				<&cmu CLK_DIV_ACLK_160>,
+				<&cmu CLK_DIV_GDL>,
+				<&cmu CLK_DIV_GDR>,
+				<&cmu CLK_DIV_MFC>;
+			clock-names = "ppmu_left",
+				"ppmu_right",
+				"aclk_400",
+				"aclk_266",
+				"aclk_200",
+				"aclk_160",
+				"aclk_gdl",
+				"aclk_gdr",
+				"mfc";
+			status = "disabled";
+		};
+
 		rtc: rtc@10070000 {
 			compatible = "samsung,exynos3250-rtc";
 			reg = <0x10070000 0x100>;
-- 
1.9.1


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

* [RFC 3/3] ARM: dts: Add devfreq to Exynos3250 and Rinato board
@ 2014-12-05 16:46   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-05 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Add devfreq to Exynos3250 common file and enable it for Rinato board.

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 arch/arm/boot/dts/exynos3250-rinato.dts | 10 ++++++++++
 arch/arm/boot/dts/exynos3250.dtsi       | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 80aa8b4c4a3d..713b6a5c3f85 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -527,6 +527,16 @@
 	clock-frequency = <24000000>;
 };
 
+&busfreq_mif {
+	vdd_mif-supply = <&buck1_reg>;
+	status = "okay";
+};
+
+&busfreq_int {
+	vdd_int-supply = <&buck3_reg>;
+	status = "okay";
+};
+
 &pinctrl_0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sleep0>;
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 22465494b796..8f8d674a8748 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -175,6 +175,38 @@
 			#clock-cells = <1>;
 		};
 
+		busfreq_mif: busfreq at 106A0000 {
+			compatible = "samsung,exynos3250-busfreq-mif";
+			reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
+			clocks = <&cmu_dmc CLK_DIV_DMC>;
+			clock-names = "dmc";
+			status = "disabled";
+		};
+
+		busfreq_int: busfreq at 116A0000 {
+			compatible = "samsung,exynos3250-busfreq-int";
+			reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
+			clocks = <&cmu CLK_PPMULEFT>,
+				<&cmu CLK_PPMURIGHT>,
+				<&cmu CLK_DIV_ACLK_400_MCUISP>,
+				<&cmu CLK_DIV_ACLK_266>,
+				<&cmu CLK_DIV_ACLK_200>,
+				<&cmu CLK_DIV_ACLK_160>,
+				<&cmu CLK_DIV_GDL>,
+				<&cmu CLK_DIV_GDR>,
+				<&cmu CLK_DIV_MFC>;
+			clock-names = "ppmu_left",
+				"ppmu_right",
+				"aclk_400",
+				"aclk_266",
+				"aclk_200",
+				"aclk_160",
+				"aclk_gdl",
+				"aclk_gdr",
+				"mfc";
+			status = "disabled";
+		};
+
 		rtc: rtc at 10070000 {
 			compatible = "samsung,exynos3250-rtc";
 			reg = <0x10070000 0x100>;
-- 
1.9.1

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

* Re: [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
  2014-12-05 16:46   ` Krzysztof Kozlowski
  (?)
@ 2014-12-05 16:53     ` Mark Rutland
  -1 siblings, 0 replies; 14+ messages in thread
From: Mark Rutland @ 2014-12-05 16:53 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi, Marek Szyprowski, Bartlomiej Zolnierkiewicz,
	Tomasz Figa

On Fri, Dec 05, 2014 at 04:46:26PM +0000, Krzysztof Kozlowski wrote:
> Add documentation for bindings used by Exynos3250 devfreq driver.
> 
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> new file mode 100644
> index 000000000000..047955e9e371
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> @@ -0,0 +1,66 @@
> +Samsung Exynos3250 devfreq driver

The binding should describe the hardware, not a particular driver of
that hardware. Please write the binding (and its documentation) with
that in mind, and drop references to the driver and "busfreq".

With an adequate binding we can probe the device and forward the
information to relevant driver(s) as necessary.

> +=================================
> +
> +The driver support changing frequencies and voltage for:
> + - memory controller and bus,
> + - peripheral buses (left and right).


What do left and right mean in this context?

> +
> +Memory controller and bus
> +=========================
> +Required properties:
> + - compatible : should be "samsung,exynos3250-busfreq-mif"
> + - reg : two sets (offset and length of the register) for PPMU registers
> +	used by this devfreq driver
> + - clock-names : one clock of name "dmc" to manage frequency
> + - clocks : phandle and specifier for clock listed in clock-names property
> + - vdd_mif-supply : phandle to MIF voltage regulator

s/_/-/ in property names please.

> +
> +Peripheral buses
> +================
> +Required properties:
> + - compatible : should be "samsung,exynos3250-busfreq-int"

What does "int" mean here?

> + - reg : two sets (offset and length of the register) for PPMU registers
> +	used by this devfreq driver
> + - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
> +	All following clock names (and corresponding phandles) must be
> +	provided:
> +	- "ppmu_left", "ppmu_right",
> +	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
> + - clocks : phandles and specifiers for clocks listed in clock-names property
> + - vdd_mif-supply : phandle to INT voltage regulator

s/_/-/ here too.

Thanks,
Mark.

> +
> +Example
> +=======
> +	busfreq_mif: busfreq@106A0000 {
> +		compatible = "samsung,exynos3250-busfreq-mif";
> +		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
> +		clocks = <&cmu_dmc CLK_DIV_DMC>;
> +		clock-names = "dmc";
> +		vdd_mif-supply = <&buck1_reg>;
> +		status = "okay";
> +	};
> +
> +	busfreq_int: busfreq@116A0000 {
> +		compatible = "samsung,exynos3250-busfreq-int";
> +		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
> +		clocks = <&cmu CLK_PPMULEFT>,
> +			<&cmu CLK_PPMURIGHT>,
> +			<&cmu CLK_DIV_ACLK_400_MCUISP>,
> +			<&cmu CLK_DIV_ACLK_266>,
> +			<&cmu CLK_DIV_ACLK_200>,
> +			<&cmu CLK_DIV_ACLK_160>,
> +			<&cmu CLK_DIV_GDL>,
> +			<&cmu CLK_DIV_GDR>,
> +			<&cmu CLK_DIV_MFC>;
> +		clock-names = "ppmuleft",
> +			"ppmuright",
> +			"aclk_400",
> +			"aclk_266",
> +			"aclk_200",
> +			"aclk_160",
> +			"aclk_gdl",
> +			"aclk_gdr",
> +			"mfc";
> +		vdd_int-supply = <&buck3_reg>;
> +		status = "okay";
> +	};
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 14+ messages in thread

* Re: [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
@ 2014-12-05 16:53     ` Mark Rutland
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Rutland @ 2014-12-05 16:53 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi, Marek Szyprowski, Bartlomiej Zolnierkiewicz,
	Tomasz Figa

On Fri, Dec 05, 2014 at 04:46:26PM +0000, Krzysztof Kozlowski wrote:
> Add documentation for bindings used by Exynos3250 devfreq driver.
> 
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> new file mode 100644
> index 000000000000..047955e9e371
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> @@ -0,0 +1,66 @@
> +Samsung Exynos3250 devfreq driver

The binding should describe the hardware, not a particular driver of
that hardware. Please write the binding (and its documentation) with
that in mind, and drop references to the driver and "busfreq".

With an adequate binding we can probe the device and forward the
information to relevant driver(s) as necessary.

> +=================================
> +
> +The driver support changing frequencies and voltage for:
> + - memory controller and bus,
> + - peripheral buses (left and right).


What do left and right mean in this context?

> +
> +Memory controller and bus
> +=========================
> +Required properties:
> + - compatible : should be "samsung,exynos3250-busfreq-mif"
> + - reg : two sets (offset and length of the register) for PPMU registers
> +	used by this devfreq driver
> + - clock-names : one clock of name "dmc" to manage frequency
> + - clocks : phandle and specifier for clock listed in clock-names property
> + - vdd_mif-supply : phandle to MIF voltage regulator

s/_/-/ in property names please.

> +
> +Peripheral buses
> +================
> +Required properties:
> + - compatible : should be "samsung,exynos3250-busfreq-int"

What does "int" mean here?

> + - reg : two sets (offset and length of the register) for PPMU registers
> +	used by this devfreq driver
> + - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
> +	All following clock names (and corresponding phandles) must be
> +	provided:
> +	- "ppmu_left", "ppmu_right",
> +	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
> + - clocks : phandles and specifiers for clocks listed in clock-names property
> + - vdd_mif-supply : phandle to INT voltage regulator

s/_/-/ here too.

Thanks,
Mark.

> +
> +Example
> +=======
> +	busfreq_mif: busfreq@106A0000 {
> +		compatible = "samsung,exynos3250-busfreq-mif";
> +		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
> +		clocks = <&cmu_dmc CLK_DIV_DMC>;
> +		clock-names = "dmc";
> +		vdd_mif-supply = <&buck1_reg>;
> +		status = "okay";
> +	};
> +
> +	busfreq_int: busfreq@116A0000 {
> +		compatible = "samsung,exynos3250-busfreq-int";
> +		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
> +		clocks = <&cmu CLK_PPMULEFT>,
> +			<&cmu CLK_PPMURIGHT>,
> +			<&cmu CLK_DIV_ACLK_400_MCUISP>,
> +			<&cmu CLK_DIV_ACLK_266>,
> +			<&cmu CLK_DIV_ACLK_200>,
> +			<&cmu CLK_DIV_ACLK_160>,
> +			<&cmu CLK_DIV_GDL>,
> +			<&cmu CLK_DIV_GDR>,
> +			<&cmu CLK_DIV_MFC>;
> +		clock-names = "ppmuleft",
> +			"ppmuright",
> +			"aclk_400",
> +			"aclk_266",
> +			"aclk_200",
> +			"aclk_160",
> +			"aclk_gdl",
> +			"aclk_gdr",
> +			"mfc";
> +		vdd_int-supply = <&buck3_reg>;
> +		status = "okay";
> +	};
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 14+ messages in thread

* [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
@ 2014-12-05 16:53     ` Mark Rutland
  0 siblings, 0 replies; 14+ messages in thread
From: Mark Rutland @ 2014-12-05 16:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Dec 05, 2014 at 04:46:26PM +0000, Krzysztof Kozlowski wrote:
> Add documentation for bindings used by Exynos3250 devfreq driver.
> 
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> new file mode 100644
> index 000000000000..047955e9e371
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> @@ -0,0 +1,66 @@
> +Samsung Exynos3250 devfreq driver

The binding should describe the hardware, not a particular driver of
that hardware. Please write the binding (and its documentation) with
that in mind, and drop references to the driver and "busfreq".

With an adequate binding we can probe the device and forward the
information to relevant driver(s) as necessary.

> +=================================
> +
> +The driver support changing frequencies and voltage for:
> + - memory controller and bus,
> + - peripheral buses (left and right).


What do left and right mean in this context?

> +
> +Memory controller and bus
> +=========================
> +Required properties:
> + - compatible : should be "samsung,exynos3250-busfreq-mif"
> + - reg : two sets (offset and length of the register) for PPMU registers
> +	used by this devfreq driver
> + - clock-names : one clock of name "dmc" to manage frequency
> + - clocks : phandle and specifier for clock listed in clock-names property
> + - vdd_mif-supply : phandle to MIF voltage regulator

s/_/-/ in property names please.

> +
> +Peripheral buses
> +================
> +Required properties:
> + - compatible : should be "samsung,exynos3250-busfreq-int"

What does "int" mean here?

> + - reg : two sets (offset and length of the register) for PPMU registers
> +	used by this devfreq driver
> + - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
> +	All following clock names (and corresponding phandles) must be
> +	provided:
> +	- "ppmu_left", "ppmu_right",
> +	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
> + - clocks : phandles and specifiers for clocks listed in clock-names property
> + - vdd_mif-supply : phandle to INT voltage regulator

s/_/-/ here too.

Thanks,
Mark.

> +
> +Example
> +=======
> +	busfreq_mif: busfreq at 106A0000 {
> +		compatible = "samsung,exynos3250-busfreq-mif";
> +		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
> +		clocks = <&cmu_dmc CLK_DIV_DMC>;
> +		clock-names = "dmc";
> +		vdd_mif-supply = <&buck1_reg>;
> +		status = "okay";
> +	};
> +
> +	busfreq_int: busfreq at 116A0000 {
> +		compatible = "samsung,exynos3250-busfreq-int";
> +		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
> +		clocks = <&cmu CLK_PPMULEFT>,
> +			<&cmu CLK_PPMURIGHT>,
> +			<&cmu CLK_DIV_ACLK_400_MCUISP>,
> +			<&cmu CLK_DIV_ACLK_266>,
> +			<&cmu CLK_DIV_ACLK_200>,
> +			<&cmu CLK_DIV_ACLK_160>,
> +			<&cmu CLK_DIV_GDL>,
> +			<&cmu CLK_DIV_GDR>,
> +			<&cmu CLK_DIV_MFC>;
> +		clock-names = "ppmuleft",
> +			"ppmuright",
> +			"aclk_400",
> +			"aclk_266",
> +			"aclk_200",
> +			"aclk_160",
> +			"aclk_gdl",
> +			"aclk_gdr",
> +			"mfc";
> +		vdd_int-supply = <&buck3_reg>;
> +		status = "okay";
> +	};
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 14+ messages in thread

* Re: [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
  2014-12-05 16:53     ` Mark Rutland
  (?)
@ 2014-12-08  9:09       ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-08  9:09 UTC (permalink / raw)
  To: Mark Rutland
  Cc: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi, Marek Szyprowski, Bartlomiej Zolnierkiewicz,
	Tomasz Figa

On pią, 2014-12-05 at 16:53 +0000, Mark Rutland wrote:
> On Fri, Dec 05, 2014 at 04:46:26PM +0000, Krzysztof Kozlowski wrote:
> > Add documentation for bindings used by Exynos3250 devfreq driver.
> > 
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> > ---
> >  .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
> >  1 file changed, 66 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > new file mode 100644
> > index 000000000000..047955e9e371
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > @@ -0,0 +1,66 @@
> > +Samsung Exynos3250 devfreq driver
> 
> The binding should describe the hardware, not a particular driver of
> that hardware. Please write the binding (and its documentation) with
> that in mind, and drop references to the driver and "busfreq".
> 
> With an adequate binding we can probe the device and forward the
> information to relevant driver(s) as necessary.

OK

> 
> > +=================================
> > +
> > +The driver support changing frequencies and voltage for:
> > + - memory controller and bus,
> > + - peripheral buses (left and right).
> 
> 
> What do left and right mean in this context?

These are names for clock domains associated with buses between memory
controller and peripherals. They're called "leftbus" and "rightbus" in
documentation.

> 
> > +
> > +Memory controller and bus
> > +=========================
> > +Required properties:
> > + - compatible : should be "samsung,exynos3250-busfreq-mif"
> > + - reg : two sets (offset and length of the register) for PPMU registers
> > +	used by this devfreq driver
> > + - clock-names : one clock of name "dmc" to manage frequency
> > + - clocks : phandle and specifier for clock listed in clock-names property
> > + - vdd_mif-supply : phandle to MIF voltage regulator
> 
> s/_/-/ in property names please.

Sure.

> 
> > +
> > +Peripheral buses
> > +================
> > +Required properties:
> > + - compatible : should be "samsung,exynos3250-busfreq-int"
> 
> What does "int" mean here?

It is the name of power source (VDD_INT) and regulator supplying certain
power domains in SoC. However I have no clue what engineers meant by
this abbreviation.

> 
> > + - reg : two sets (offset and length of the register) for PPMU registers
> > +	used by this devfreq driver
> > + - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
> > +	All following clock names (and corresponding phandles) must be
> > +	provided:
> > +	- "ppmu_left", "ppmu_right",
> > +	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
> > + - clocks : phandles and specifiers for clocks listed in clock-names property
> > + - vdd_mif-supply : phandle to INT voltage regulator
> 
> s/_/-/ here too.

OK

Thanks for feedback.

Best regards,
Krzysztof


> Thanks,
> Mark.
> 
> > +
> > +Example
> > +=======
> > +	busfreq_mif: busfreq@106A0000 {
> > +		compatible = "samsung,exynos3250-busfreq-mif";
> > +		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
> > +		clocks = <&cmu_dmc CLK_DIV_DMC>;
> > +		clock-names = "dmc";
> > +		vdd_mif-supply = <&buck1_reg>;
> > +		status = "okay";
> > +	};
> > +
> > +	busfreq_int: busfreq@116A0000 {
> > +		compatible = "samsung,exynos3250-busfreq-int";
> > +		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
> > +		clocks = <&cmu CLK_PPMULEFT>,
> > +			<&cmu CLK_PPMURIGHT>,
> > +			<&cmu CLK_DIV_ACLK_400_MCUISP>,
> > +			<&cmu CLK_DIV_ACLK_266>,
> > +			<&cmu CLK_DIV_ACLK_200>,
> > +			<&cmu CLK_DIV_ACLK_160>,
> > +			<&cmu CLK_DIV_GDL>,
> > +			<&cmu CLK_DIV_GDR>,
> > +			<&cmu CLK_DIV_MFC>;
> > +		clock-names = "ppmuleft",
> > +			"ppmuright",
> > +			"aclk_400",
> > +			"aclk_266",
> > +			"aclk_200",
> > +			"aclk_160",
> > +			"aclk_gdl",
> > +			"aclk_gdr",
> > +			"mfc";
> > +		vdd_int-supply = <&buck3_reg>;
> > +		status = "okay";
> > +	};
> > -- 
> > 1.9.1
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 14+ messages in thread

* Re: [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
@ 2014-12-08  9:09       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-08  9:09 UTC (permalink / raw)
  To: Mark Rutland
  Cc: MyungJoo Ham, Kyungmin Park, Kukjin Kim, linux-kernel, linux-pm,
	linux-arm-kernel, linux-samsung-soc, devicetree, Russell King,
	Chanwoo Choi, Marek Szyprowski, Bartlomiej Zolnierkiewicz,
	Tomasz Figa

On pią, 2014-12-05 at 16:53 +0000, Mark Rutland wrote:
> On Fri, Dec 05, 2014 at 04:46:26PM +0000, Krzysztof Kozlowski wrote:
> > Add documentation for bindings used by Exynos3250 devfreq driver.
> > 
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> > ---
> >  .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
> >  1 file changed, 66 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > new file mode 100644
> > index 000000000000..047955e9e371
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > @@ -0,0 +1,66 @@
> > +Samsung Exynos3250 devfreq driver
> 
> The binding should describe the hardware, not a particular driver of
> that hardware. Please write the binding (and its documentation) with
> that in mind, and drop references to the driver and "busfreq".
> 
> With an adequate binding we can probe the device and forward the
> information to relevant driver(s) as necessary.

OK

> 
> > +=================================
> > +
> > +The driver support changing frequencies and voltage for:
> > + - memory controller and bus,
> > + - peripheral buses (left and right).
> 
> 
> What do left and right mean in this context?

These are names for clock domains associated with buses between memory
controller and peripherals. They're called "leftbus" and "rightbus" in
documentation.

> 
> > +
> > +Memory controller and bus
> > +=========================
> > +Required properties:
> > + - compatible : should be "samsung,exynos3250-busfreq-mif"
> > + - reg : two sets (offset and length of the register) for PPMU registers
> > +	used by this devfreq driver
> > + - clock-names : one clock of name "dmc" to manage frequency
> > + - clocks : phandle and specifier for clock listed in clock-names property
> > + - vdd_mif-supply : phandle to MIF voltage regulator
> 
> s/_/-/ in property names please.

Sure.

> 
> > +
> > +Peripheral buses
> > +================
> > +Required properties:
> > + - compatible : should be "samsung,exynos3250-busfreq-int"
> 
> What does "int" mean here?

It is the name of power source (VDD_INT) and regulator supplying certain
power domains in SoC. However I have no clue what engineers meant by
this abbreviation.

> 
> > + - reg : two sets (offset and length of the register) for PPMU registers
> > +	used by this devfreq driver
> > + - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
> > +	All following clock names (and corresponding phandles) must be
> > +	provided:
> > +	- "ppmu_left", "ppmu_right",
> > +	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
> > + - clocks : phandles and specifiers for clocks listed in clock-names property
> > + - vdd_mif-supply : phandle to INT voltage regulator
> 
> s/_/-/ here too.

OK

Thanks for feedback.

Best regards,
Krzysztof


> Thanks,
> Mark.
> 
> > +
> > +Example
> > +=======
> > +	busfreq_mif: busfreq@106A0000 {
> > +		compatible = "samsung,exynos3250-busfreq-mif";
> > +		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
> > +		clocks = <&cmu_dmc CLK_DIV_DMC>;
> > +		clock-names = "dmc";
> > +		vdd_mif-supply = <&buck1_reg>;
> > +		status = "okay";
> > +	};
> > +
> > +	busfreq_int: busfreq@116A0000 {
> > +		compatible = "samsung,exynos3250-busfreq-int";
> > +		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
> > +		clocks = <&cmu CLK_PPMULEFT>,
> > +			<&cmu CLK_PPMURIGHT>,
> > +			<&cmu CLK_DIV_ACLK_400_MCUISP>,
> > +			<&cmu CLK_DIV_ACLK_266>,
> > +			<&cmu CLK_DIV_ACLK_200>,
> > +			<&cmu CLK_DIV_ACLK_160>,
> > +			<&cmu CLK_DIV_GDL>,
> > +			<&cmu CLK_DIV_GDR>,
> > +			<&cmu CLK_DIV_MFC>;
> > +		clock-names = "ppmuleft",
> > +			"ppmuright",
> > +			"aclk_400",
> > +			"aclk_266",
> > +			"aclk_200",
> > +			"aclk_160",
> > +			"aclk_gdl",
> > +			"aclk_gdr",
> > +			"mfc";
> > +		vdd_int-supply = <&buck3_reg>;
> > +		status = "okay";
> > +	};
> > -- 
> > 1.9.1
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 14+ messages in thread

* [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver
@ 2014-12-08  9:09       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 14+ messages in thread
From: Krzysztof Kozlowski @ 2014-12-08  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On pi?, 2014-12-05 at 16:53 +0000, Mark Rutland wrote:
> On Fri, Dec 05, 2014 at 04:46:26PM +0000, Krzysztof Kozlowski wrote:
> > Add documentation for bindings used by Exynos3250 devfreq driver.
> > 
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> > ---
> >  .../bindings/arm/samsung/exynos3250-devfreq.txt    | 66 ++++++++++++++++++++++
> >  1 file changed, 66 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > new file mode 100644
> > index 000000000000..047955e9e371
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/samsung/exynos3250-devfreq.txt
> > @@ -0,0 +1,66 @@
> > +Samsung Exynos3250 devfreq driver
> 
> The binding should describe the hardware, not a particular driver of
> that hardware. Please write the binding (and its documentation) with
> that in mind, and drop references to the driver and "busfreq".
> 
> With an adequate binding we can probe the device and forward the
> information to relevant driver(s) as necessary.

OK

> 
> > +=================================
> > +
> > +The driver support changing frequencies and voltage for:
> > + - memory controller and bus,
> > + - peripheral buses (left and right).
> 
> 
> What do left and right mean in this context?

These are names for clock domains associated with buses between memory
controller and peripherals. They're called "leftbus" and "rightbus" in
documentation.

> 
> > +
> > +Memory controller and bus
> > +=========================
> > +Required properties:
> > + - compatible : should be "samsung,exynos3250-busfreq-mif"
> > + - reg : two sets (offset and length of the register) for PPMU registers
> > +	used by this devfreq driver
> > + - clock-names : one clock of name "dmc" to manage frequency
> > + - clocks : phandle and specifier for clock listed in clock-names property
> > + - vdd_mif-supply : phandle to MIF voltage regulator
> 
> s/_/-/ in property names please.

Sure.

> 
> > +
> > +Peripheral buses
> > +================
> > +Required properties:
> > + - compatible : should be "samsung,exynos3250-busfreq-int"
> 
> What does "int" mean here?

It is the name of power source (VDD_INT) and regulator supplying certain
power domains in SoC. However I have no clue what engineers meant by
this abbreviation.

> 
> > + - reg : two sets (offset and length of the register) for PPMU registers
> > +	used by this devfreq driver
> > + - clock-names : names for PPMU clocks and bus clocks to manage frequencies;
> > +	All following clock names (and corresponding phandles) must be
> > +	provided:
> > +	- "ppmu_left", "ppmu_right",
> > +	- "aclk_400", "aclk_266", "aclk_200", "aclk_160", "aclk_gdl", "aclk_gdr", "mfc";
> > + - clocks : phandles and specifiers for clocks listed in clock-names property
> > + - vdd_mif-supply : phandle to INT voltage regulator
> 
> s/_/-/ here too.

OK

Thanks for feedback.

Best regards,
Krzysztof


> Thanks,
> Mark.
> 
> > +
> > +Example
> > +=======
> > +	busfreq_mif: busfreq at 106A0000 {
> > +		compatible = "samsung,exynos3250-busfreq-mif";
> > +		reg = <0x106A0000 0x2000>, <0x106B0000 0x2000>;
> > +		clocks = <&cmu_dmc CLK_DIV_DMC>;
> > +		clock-names = "dmc";
> > +		vdd_mif-supply = <&buck1_reg>;
> > +		status = "okay";
> > +	};
> > +
> > +	busfreq_int: busfreq at 116A0000 {
> > +		compatible = "samsung,exynos3250-busfreq-int";
> > +		reg = <0x116A0000 0x2000>, <0x112A0000 0x2000>;
> > +		clocks = <&cmu CLK_PPMULEFT>,
> > +			<&cmu CLK_PPMURIGHT>,
> > +			<&cmu CLK_DIV_ACLK_400_MCUISP>,
> > +			<&cmu CLK_DIV_ACLK_266>,
> > +			<&cmu CLK_DIV_ACLK_200>,
> > +			<&cmu CLK_DIV_ACLK_160>,
> > +			<&cmu CLK_DIV_GDL>,
> > +			<&cmu CLK_DIV_GDR>,
> > +			<&cmu CLK_DIV_MFC>;
> > +		clock-names = "ppmuleft",
> > +			"ppmuright",
> > +			"aclk_400",
> > +			"aclk_266",
> > +			"aclk_200",
> > +			"aclk_160",
> > +			"aclk_gdl",
> > +			"aclk_gdr",
> > +			"mfc";
> > +		vdd_int-supply = <&buck3_reg>;
> > +		status = "okay";
> > +	};
> > -- 
> > 1.9.1
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe devicetree" 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] 14+ messages in thread

end of thread, other threads:[~2014-12-08  9:09 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-05 16:46 [RFC 0/3] devfreq: exynos: Add driver for Exynos3250 Krzysztof Kozlowski
2014-12-05 16:46 ` Krzysztof Kozlowski
2014-12-05 16:46 ` [RFC 1/3] devfreq: dt-bindings: Document Exynos3250 devfreq driver Krzysztof Kozlowski
2014-12-05 16:46   ` Krzysztof Kozlowski
2014-12-05 16:53   ` Mark Rutland
2014-12-05 16:53     ` Mark Rutland
2014-12-05 16:53     ` Mark Rutland
2014-12-08  9:09     ` Krzysztof Kozlowski
2014-12-08  9:09       ` Krzysztof Kozlowski
2014-12-08  9:09       ` Krzysztof Kozlowski
2014-12-05 16:46 ` [RFC 2/3] devfreq: exynos: Add driver for Exynos3250 Krzysztof Kozlowski
2014-12-05 16:46   ` Krzysztof Kozlowski
2014-12-05 16:46 ` [RFC 3/3] ARM: dts: Add devfreq to Exynos3250 and Rinato board Krzysztof Kozlowski
2014-12-05 16:46   ` Krzysztof Kozlowski

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.