devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/5] ARM: sun9i: Add Allwinner A80 PRCM clock/reset support
@ 2015-11-29  3:03 Chen-Yu Tsai
       [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
  0 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29  3:03 UTC (permalink / raw)
  To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai

Hi everyone,

(resent with mailing lists CC-ed)

This is v4 of the Allwinner A80 PRCM support series. Since v4, the
series moved away from the mfd approach, and just lists the various
controls directly under the "clocks" and "soc" nodes.

Changes since v3:

    - Only build new clock drivers for CONFIG_MACH_SUN9I

    - Refactor sun8i-a23-apb0-clk driver to share common clock
      registering code

Changes since v2:

    - Move away from mfd approach and directly list the clock and
      reset controls as first class devices.

    - Use the new clk-simple-gates driver for the apbs clock gates.

    - Update clk code to use struct clk_request.

    - Add 1wire clk node.

    - Use GENMASK and always use shifted bitmasks in cpus clk driver.

Changes since v1:

    - Added missing clock gates based on updated documents

    - Added new cpus clock driver based on updated documents

    - Added pll3 clock placeholder

    - Added comments about 24M & 32k oscillators

The series adds support for the Power Reset and Clock Management
module on Allwinner's A80 SoC. The PRCM manages clocks and resets
for the "special" block of peripherals, or the R/RTC block in
earlier SoCs, as well as power domain and resets for various parts
of the SoC, such as the 2 processor clusters, the GPU and others.

The special peripherals include a standby processor core, a timer
block, a watchdog, pin controller, 1 wire interface, PS/2 interface,
a UART, the RSB controller, a DMA controller, a consumer IR receiver
block, 2 I2C controllers, and 2 I2S controllers. We do not have
documents for all the peripherals. Support will be added where
possible.

Patch 1 adds CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver.
This driver was used with the mfd approach for the A23/A33 PRCM. As
such it is a platform device driver.

Patch 2 adds a new compatible string for the apbs gates to the
clk-simple-gates driver.

Patch 3 adds a new driver for the cpus clock.

Patch 4 adds the various supported clock and reset control device nodes
to the A80 dtsi.

Patch 5 adds some TODO comments regarding the 2 system oscillators.

Regards
ChenYu

Chen-Yu Tsai (5):
  clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
  clk: sunxi: Add sun9i A80 apbs gates support
  clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
  ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes
  ARM: dts: sun9i: Add TODO comments for the main and low power clocks

 Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
 arch/arm/boot/dts/sun9i-a80.dtsi                  |  97 ++++++++-
 drivers/clk/sunxi/Makefile                        |   6 +-
 drivers/clk/sunxi/clk-simple-gates.c              |   2 +
 drivers/clk/sunxi/clk-sun8i-apb0.c                |  71 +++++--
 drivers/clk/sunxi/clk-sun9i-cpus.c                | 240 ++++++++++++++++++++++
 6 files changed, 403 insertions(+), 15 deletions(-)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-cpus.c

-- 
2.6.2

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

* [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
       [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
@ 2015-11-29  3:03   ` Chen-Yu Tsai
  2015-12-01 10:04     ` Maxime Ripard
  2015-11-29  3:03   ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29  3:03 UTC (permalink / raw)
  To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai

The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
instead of through a PRCM mfd device and subdevices for each clock
and reset control. As such we need a CLK_OF_DECLARE version of
the sun8i-a23-apb0-clk driver.

Also, build it for sun9i/A80, and not just for configurations with
MFD_SUN6I_PRCM enabled.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 drivers/clk/sunxi/Makefile         |  5 +--
 drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
 2 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index cb4c299214ce..c55d5cd1c0e5 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
 obj-y += clk-sun9i-mmc.o
 obj-y += clk-usb.o
 
+obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
+
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
-	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
-	clk-sun8i-apb0.o
+	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
--- a/drivers/clk/sunxi/clk-sun8i-apb0.c
+++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
@@ -17,13 +17,68 @@
 #include <linux/clk-provider.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 
+static struct clk *sun8i_a23_apb0_register(struct device_node *node,
+					   void __iomem *reg)
+{
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	struct clk *clk;
+	int ret;
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+	if (!clk_parent)
+		return ERR_PTR(-EINVAL);
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	/* The A23 APB0 clock is a standard 2 bit wide divider clock */
+	clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
+				   0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+	if (IS_ERR(clk))
+		return clk;
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (ret)
+		goto err_unregister;
+
+	return clk;
+
+err_unregister:
+	clk_unregister_divider(clk);
+
+	return ERR_PTR(ret);
+}
+
+static void sun8i_a23_apb0_setup(struct device_node *node)
+{
+	void __iomem *reg;
+	struct resource res;
+	struct clk *clk;
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg))
+		return;
+
+	clk = sun8i_a23_apb0_register(node, reg);
+	if (IS_ERR(clk))
+		goto err_unmap;
+
+	return;
+
+err_unmap:
+	iounmap(reg);
+	of_address_to_resource(node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+}
+CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
+	       sun8i_a23_apb0_setup);
+
 static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	const char *clk_name = np->name;
-	const char *clk_parent;
 	struct resource *r;
 	void __iomem *reg;
 	struct clk *clk;
@@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
 	if (IS_ERR(reg))
 		return PTR_ERR(reg);
 
-	clk_parent = of_clk_get_parent_name(np, 0);
-	if (!clk_parent)
-		return -EINVAL;
-
-	of_property_read_string(np, "clock-output-names", &clk_name);
-
-	/* The A23 APB0 clock is a standard 2 bit wide divider clock */
-	clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
-				   0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+	clk = sun8i_a23_apb0_register(np, reg);
 	if (IS_ERR(clk))
 		return PTR_ERR(clk);
 
-	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return 0;
 }
 
 static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
-- 
2.6.2

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

* [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support
       [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
  2015-11-29  3:03   ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
@ 2015-11-29  3:03   ` Chen-Yu Tsai
  2015-11-30 17:14     ` Rob Herring
  2015-11-29  3:03   ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29  3:03 UTC (permalink / raw)
  To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai

This patch adds support for the PRCM apbs clock gates found on the
Allwinner A80 SoC.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
 drivers/clk/sunxi/clk-simple-gates.c              | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index a94bb56a0e9e..b6859ed6913f 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -55,6 +55,7 @@ Required properties:
 	"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
 	"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
 	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
+	"allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
 	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
 	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
 	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
index 0214c6548afd..c8acc0612c15 100644
--- a/drivers/clk/sunxi/clk-simple-gates.c
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -140,6 +140,8 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
 	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
 	       sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
+	       sunxi_simple_gates_init);
 
 static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
 	14,	/* ahb_sdram */
-- 
2.6.2

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

* [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
       [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
  2015-11-29  3:03   ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
  2015-11-29  3:03   ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
@ 2015-11-29  3:03   ` Chen-Yu Tsai
  2015-11-30 17:13     ` Rob Herring
  2015-11-29  3:03   ` [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes Chen-Yu Tsai
  2015-11-29  3:03   ` [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks Chen-Yu Tsai
  4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29  3:03 UTC (permalink / raw)
  To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai

The "cpus" clock is the clock for the embedded processor in the A80.
It is also part of the PRCM clock tree. This clock includes a pre-
divider on one of its inputs. For now we are using a custom clock
driver for it. In the future we may want to develop a generalized
driver for these types of clocks, which also includes the AHB clock
driver on sun[5678]i.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun9i-cpus.c                | 240 ++++++++++++++++++++++
 3 files changed, 242 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun9i-cpus.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index b6859ed6913f..153ac72869e8 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -27,6 +27,7 @@ Required properties:
 	"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
 	"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
 	"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
+	"allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
 	"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
 	"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
 	"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index c55d5cd1c0e5..f7d439fa9980 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -16,6 +16,7 @@ obj-y += clk-sun9i-mmc.o
 obj-y += clk-usb.o
 
 obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
+obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
 
 obj-$(CONFIG_MFD_SUN6I_PRCM) += \
 	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
diff --git a/drivers/clk/sunxi/clk-sun9i-cpus.c b/drivers/clk/sunxi/clk-sun9i-cpus.c
new file mode 100644
index 000000000000..7626d2194b96
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-cpus.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
+ *
+ * Allwinner A80 CPUS clock driver
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
+
+/**
+ * sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
+ */
+
+#define SUN9I_CPUS_MAX_PARENTS		4
+#define SUN9I_CPUS_MUX_PARENT_PLL4	3
+#define SUN9I_CPUS_MUX_SHIFT		16
+#define SUN9I_CPUS_MUX_MASK		GENMASK(17, 16)
+#define SUN9I_CPUS_MUX_GET_PARENT(reg)	((reg & SUN9I_CPUS_MUX_MASK) >> \
+						SUN9I_CPUS_MUX_SHIFT)
+
+#define SUN9I_CPUS_DIV_SHIFT		4
+#define SUN9I_CPUS_DIV_MASK		GENMASK(5, 4)
+#define SUN9I_CPUS_DIV_GET(reg)		((reg & SUN9I_CPUS_DIV_MASK) >> \
+						SUN9I_CPUS_DIV_SHIFT)
+#define SUN9I_CPUS_DIV_SET(reg, div)	((reg & ~SUN9I_CPUS_DIV_MASK) | \
+						(div << SUN9I_CPUS_DIV_SHIFT))
+#define SUN9I_CPUS_PLL4_DIV_SHIFT	8
+#define SUN9I_CPUS_PLL4_DIV_MASK	GENMASK(12, 8)
+#define SUN9I_CPUS_PLL4_DIV_GET(reg)	((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
+						SUN9I_CPUS_PLL4_DIV_SHIFT)
+#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
+						(div << SUN9I_CPUS_PLL4_DIV_SHIFT))
+
+struct sun9i_a80_cpus_clk {
+	struct clk_hw hw;
+	void __iomem *reg;
+};
+
+#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
+
+static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
+						    unsigned long parent_rate)
+{
+	struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+	unsigned long rate;
+	u32 reg;
+
+	/* Fetch the register value */
+	reg = readl(cpus->reg);
+
+	/* apply pre-divider first if parent is pll4 */
+	if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
+		parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
+
+	/* clk divider */
+	rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
+
+	return rate;
+}
+
+static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+				     u8 parent, unsigned long parent_rate)
+{
+	u8 div, pre_div = 1;
+
+	/*
+	 * clock can only divide, so we will never be able to achieve
+	 * frequencies higher than the parent frequency
+	 */
+	if (parent_rate && rate > parent_rate)
+		rate = parent_rate;
+
+	div = DIV_ROUND_UP(parent_rate, rate);
+
+	/* calculate pre-divider if parent is pll4 */
+	if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
+		/* pre-divider is 1 ~ 32 */
+		if (div < 32) {
+			pre_div = div;
+			div = 1;
+		} else if (div < 64) {
+			pre_div = DIV_ROUND_UP(div, 2);
+			div = 2;
+		} else if (div < 96) {
+			pre_div = DIV_ROUND_UP(div, 3);
+			div = 3;
+		} else {
+			pre_div = DIV_ROUND_UP(div, 4);
+			div = 4;
+		}
+	}
+
+	/* we were asked to pass back divider values */
+	if (divp) {
+		*divp = div - 1;
+		*pre_divp = pre_div - 1;
+	}
+
+	return parent_rate / pre_div / div;
+}
+
+static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
+					     struct clk_rate_request *req)
+{
+	struct clk_hw *parent, *best_parent = NULL;
+	int i, num_parents;
+	unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+	unsigned long rate = req->rate;
+
+	/* find the parent that can help provide the fastest rate <= rate */
+	num_parents = clk_hw_get_num_parents(clk);
+	for (i = 0; i < num_parents; i++) {
+		parent = clk_hw_get_parent_by_index(clk, i);
+		if (!parent)
+			continue;
+		if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
+			parent_rate = clk_hw_round_rate(parent, rate);
+		else
+			parent_rate = clk_hw_get_rate(parent);
+
+		child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
+						      parent_rate);
+
+		if (child_rate <= rate && child_rate > best_child_rate) {
+			best_parent = parent;
+			best = parent_rate;
+			best_child_rate = child_rate;
+		}
+	}
+
+	if (!best_parent)
+		return -EINVAL;
+
+	req->best_parent_hw = best_parent;
+	req->best_parent_rate = best;
+	req->rate = best_child_rate;
+
+	return 0;
+}
+
+static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
+	unsigned long flags;
+	u8 div, pre_div, parent;
+	u32 reg;
+
+	spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
+
+	reg = readl(cpus->reg);
+
+	/* need to know which parent is used to apply pre-divider */
+	parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
+	sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+	reg = SUN9I_CPUS_DIV_SET(reg, div);
+	reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
+	writel(reg, cpus->reg);
+
+	spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
+
+	return 0;
+}
+
+static const struct clk_ops sun9i_a80_cpus_clk_ops = {
+	.determine_rate	= sun9i_a80_cpus_clk_determine_rate,
+	.recalc_rate	= sun9i_a80_cpus_clk_recalc_rate,
+	.set_rate	= sun9i_a80_cpus_clk_set_rate,
+};
+
+static void sun9i_a80_cpus_setup(struct device_node *node)
+{
+	const char *clk_name = node->name;
+	const char *parents[SUN9I_CPUS_MAX_PARENTS];
+	struct resource res;
+	struct sun9i_a80_cpus_clk *cpus;
+	struct clk_mux *mux;
+	struct clk *clk;
+	int ret;
+
+	cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
+	if (!cpus)
+		return;
+
+	cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(cpus->reg))
+		goto err_free_cpus;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	/* we have a mux, we will have >1 parents */
+	ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		goto err_unmap;
+
+	/* set up clock properties */
+	mux->reg = cpus->reg;
+	mux->shift = SUN9I_CPUS_MUX_SHIFT;
+	/* un-shifted mask is what mux_clk expects */
+	mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
+	mux->lock = &sun9i_a80_cpus_lock;
+
+	clk = clk_register_composite(NULL, clk_name, parents, ret,
+				     &mux->hw, &clk_mux_ops,
+				     &cpus->hw, &sun9i_a80_cpus_clk_ops,
+				     NULL, NULL, 0);
+	if (IS_ERR(clk))
+		goto err_free_mux;
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (ret)
+		goto err_unregister;
+
+	return;
+
+err_unregister:
+	clk_unregister(clk);
+err_free_mux:
+	kfree(mux);
+err_unmap:
+	iounmap(cpus->reg);
+	of_address_to_resource(node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+err_free_cpus:
+	kfree(cpus);
+}
+CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
+	       sun9i_a80_cpus_setup);
-- 
2.6.2

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

* [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes
       [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
                     ` (2 preceding siblings ...)
  2015-11-29  3:03   ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
@ 2015-11-29  3:03   ` Chen-Yu Tsai
  2015-11-29  3:03   ` [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks Chen-Yu Tsai
  4 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29  3:03 UTC (permalink / raw)
  To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai

This adds the supported PRCM clocks and reset controls to the A80 dtsi.
The DAUDIO module clocks are not supported yet.

Also update clock and reset phandles for r_uart.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 79 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 1118bf5cc4fb..a4ce348c0831 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -164,6 +164,14 @@
 					     "usb_phy2", "usb_hsic_12M";
 		};
 
+		pll3: clk@06000008 {
+			/* placeholder until implemented */
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-rate = <0>;
+			clock-output-names = "pll3";
+		};
+
 		pll4: clk@0600000c {
 			#clock-cells = <0>;
 			compatible = "allwinner,sun9i-a80-pll4-clk";
@@ -350,6 +358,68 @@
 					"apb1_uart2", "apb1_uart3",
 					"apb1_uart4", "apb1_uart5";
 		};
+
+		cpus_clk: clk@08001410 {
+			compatible = "allwinner,sun9i-a80-cpus-clk";
+			reg = <0x08001410 0x4>;
+			#clock-cells = <0>;
+			clocks = <&osc32k>, <&osc24M>, <&pll4>, <&pll3>;
+			clock-output-names = "cpus";
+		};
+
+		ahbs: ahbs_clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <1>;
+			clocks = <&cpus_clk>;
+			clock-output-names = "ahbs";
+		};
+
+		apbs: clk@0800141c {
+			compatible = "allwinner,sun8i-a23-apb0-clk";
+			reg = <0x0800141c 0x4>;
+			#clock-cells = <0>;
+			clocks = <&ahbs>;
+			clock-output-names = "apbs";
+		};
+
+		apbs_gates: clk@08001428 {
+			compatible = "allwinner,sun9i-a80-apbs-gates-clk";
+			reg = <0x08001428 0x4>;
+			#clock-cells = <1>;
+			clocks = <&apbs>;
+			clock-indices = <0>, <1>,
+					<2>, <3>,
+					<4>, <5>,
+					<6>, <7>,
+					<12>, <13>,
+					<16>, <17>,
+					<18>, <20>;
+			clock-output-names = "apbs_pio", "apbs_ir",
+					"apbs_timer", "apbs_rsb",
+					"apbs_uart", "apbs_1wire",
+					"apbs_i2c0", "apbs_i2c1",
+					"apbs_ps2_0", "apbs_ps2_1",
+					"apbs_dma", "apbs_i2s0",
+					"apbs_i2s1", "apbs_twd";
+		};
+
+		r_1wire_clk: clk@08001450 {
+			reg = <0x08001450 0x4>;
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			clocks = <&osc32k>, <&osc24M>;
+			clock-output-names = "r_1wire";
+		};
+
+		r_ir_clk: clk@08001454 {
+			reg = <0x08001454 0x4>;
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			clocks = <&osc32k>, <&osc24M>;
+			clock-output-names = "r_ir";
+		};
 	};
 
 	soc {
@@ -764,13 +834,20 @@
 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		apbs_rst: reset@080014b0 {
+			reg = <0x080014b0 0x4>;
+			compatible = "allwinner,sun6i-a31-clock-reset";
+			#reset-cells = <1>;
+		};
+
 		r_uart: serial@08002800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x08002800 0x400>;
 			interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
-			clocks = <&osc24M>;
+			clocks = <&apbs_gates 4>;
+			resets = <&apbs_rst 4>;
 			status = "disabled";
 		};
 	};
-- 
2.6.2

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

* [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks
       [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
                     ` (3 preceding siblings ...)
  2015-11-29  3:03   ` [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes Chen-Yu Tsai
@ 2015-11-29  3:03   ` Chen-Yu Tsai
       [not found]     ` <1448766190-11345-6-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
  4 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-11-29  3:03 UTC (permalink / raw)
  To: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala
  Cc: linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Chen-Yu Tsai

The main (24MHz) clock on the A80 is configurable via the PRCM address
space. The low power/speed (32kHz) clock is from an external chip, the
AC100.

Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index a4ce348c0831..eb69a62f6bc4 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -128,6 +128,17 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		/*
+		 * This clock is actually configurable from the PRCM address
+		 * space. The external 24M oscillator can be turned off, and
+		 * the clock switched to an internal 16M RC oscillator. Under
+		 * normal operation there's no reason to do this, and the
+		 * default is to use the external good one, so just model this
+		 * as a fixed clock. Also it is not entirely clear if the
+		 * osc24M mux in the PRCM affects the entire clock tree, which
+		 * would also throw all the PLL clock rates off, or just the
+		 * downstream clocks in the PRCM.
+		 */
 		osc24M: osc24M_clk {
 			#clock-cells = <0>;
 			compatible = "fixed-clock";
@@ -135,6 +146,13 @@
 			clock-output-names = "osc24M";
 		};
 
+		/*
+		 * The 32k clock is from an external source, normally the
+		 * AC100 codec/RTC chip. This clock is by default enabled
+		 * and clocked at 32768 Hz, from the oscillator connected
+		 * to the AC100. It is configurable, but no such driver or
+		 * bindings exist yet.
+		 */
 		osc32k: osc32k_clk {
 			#clock-cells = <0>;
 			compatible = "fixed-clock";
-- 
2.6.2

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

* Re: [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
  2015-11-29  3:03   ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
@ 2015-11-30 17:13     ` Rob Herring
  2015-12-01 13:07       ` Maxime Ripard
  0 siblings, 1 reply; 16+ messages in thread
From: Rob Herring @ 2015-11-30 17:13 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
	linux-arm-kernel, linux-kernel, devicetree, linux-sunxi

On Sun, Nov 29, 2015 at 11:03:08AM +0800, Chen-Yu Tsai wrote:
> The "cpus" clock is the clock for the embedded processor in the A80.
> It is also part of the PRCM clock tree. This clock includes a pre-
> divider on one of its inputs. For now we are using a custom clock
> driver for it. In the future we may want to develop a generalized
> driver for these types of clocks, which also includes the AHB clock
> driver on sun[5678]i.
> 
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |   1 +

For the binding:

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/sunxi/Makefile                        |   1 +
>  drivers/clk/sunxi/clk-sun9i-cpus.c                | 240 ++++++++++++++++++++++
>  3 files changed, 242 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun9i-cpus.c
> 
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index b6859ed6913f..153ac72869e8 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -27,6 +27,7 @@ Required properties:
>  	"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
>  	"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
>  	"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
> +	"allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
>  	"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
>  	"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
>  	"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index c55d5cd1c0e5..f7d439fa9980 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -16,6 +16,7 @@ obj-y += clk-sun9i-mmc.o
>  obj-y += clk-usb.o
>  
>  obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
> +obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
>  
>  obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>  	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
> diff --git a/drivers/clk/sunxi/clk-sun9i-cpus.c b/drivers/clk/sunxi/clk-sun9i-cpus.c
> new file mode 100644
> index 000000000000..7626d2194b96
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun9i-cpus.c
> @@ -0,0 +1,240 @@
> +/*
> + * Copyright (C) 2015 Chen-Yu Tsai
> + *
> + * Chen-Yu Tsai <wens@csie.org>
> + *
> + * Allwinner A80 CPUS clock driver
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +
> +static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
> +
> +/**
> + * sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
> + */
> +
> +#define SUN9I_CPUS_MAX_PARENTS		4
> +#define SUN9I_CPUS_MUX_PARENT_PLL4	3
> +#define SUN9I_CPUS_MUX_SHIFT		16
> +#define SUN9I_CPUS_MUX_MASK		GENMASK(17, 16)
> +#define SUN9I_CPUS_MUX_GET_PARENT(reg)	((reg & SUN9I_CPUS_MUX_MASK) >> \
> +						SUN9I_CPUS_MUX_SHIFT)
> +
> +#define SUN9I_CPUS_DIV_SHIFT		4
> +#define SUN9I_CPUS_DIV_MASK		GENMASK(5, 4)
> +#define SUN9I_CPUS_DIV_GET(reg)		((reg & SUN9I_CPUS_DIV_MASK) >> \
> +						SUN9I_CPUS_DIV_SHIFT)
> +#define SUN9I_CPUS_DIV_SET(reg, div)	((reg & ~SUN9I_CPUS_DIV_MASK) | \
> +						(div << SUN9I_CPUS_DIV_SHIFT))
> +#define SUN9I_CPUS_PLL4_DIV_SHIFT	8
> +#define SUN9I_CPUS_PLL4_DIV_MASK	GENMASK(12, 8)
> +#define SUN9I_CPUS_PLL4_DIV_GET(reg)	((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
> +						SUN9I_CPUS_PLL4_DIV_SHIFT)
> +#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
> +						(div << SUN9I_CPUS_PLL4_DIV_SHIFT))
> +
> +struct sun9i_a80_cpus_clk {
> +	struct clk_hw hw;
> +	void __iomem *reg;
> +};
> +
> +#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
> +
> +static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
> +						    unsigned long parent_rate)
> +{
> +	struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
> +	unsigned long rate;
> +	u32 reg;
> +
> +	/* Fetch the register value */
> +	reg = readl(cpus->reg);
> +
> +	/* apply pre-divider first if parent is pll4 */
> +	if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
> +		parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
> +
> +	/* clk divider */
> +	rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
> +
> +	return rate;
> +}
> +
> +static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
> +				     u8 parent, unsigned long parent_rate)
> +{
> +	u8 div, pre_div = 1;
> +
> +	/*
> +	 * clock can only divide, so we will never be able to achieve
> +	 * frequencies higher than the parent frequency
> +	 */
> +	if (parent_rate && rate > parent_rate)
> +		rate = parent_rate;
> +
> +	div = DIV_ROUND_UP(parent_rate, rate);
> +
> +	/* calculate pre-divider if parent is pll4 */
> +	if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
> +		/* pre-divider is 1 ~ 32 */
> +		if (div < 32) {
> +			pre_div = div;
> +			div = 1;
> +		} else if (div < 64) {
> +			pre_div = DIV_ROUND_UP(div, 2);
> +			div = 2;
> +		} else if (div < 96) {
> +			pre_div = DIV_ROUND_UP(div, 3);
> +			div = 3;
> +		} else {
> +			pre_div = DIV_ROUND_UP(div, 4);
> +			div = 4;
> +		}
> +	}
> +
> +	/* we were asked to pass back divider values */
> +	if (divp) {
> +		*divp = div - 1;
> +		*pre_divp = pre_div - 1;
> +	}
> +
> +	return parent_rate / pre_div / div;
> +}
> +
> +static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
> +					     struct clk_rate_request *req)
> +{
> +	struct clk_hw *parent, *best_parent = NULL;
> +	int i, num_parents;
> +	unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
> +	unsigned long rate = req->rate;
> +
> +	/* find the parent that can help provide the fastest rate <= rate */
> +	num_parents = clk_hw_get_num_parents(clk);
> +	for (i = 0; i < num_parents; i++) {
> +		parent = clk_hw_get_parent_by_index(clk, i);
> +		if (!parent)
> +			continue;
> +		if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
> +			parent_rate = clk_hw_round_rate(parent, rate);
> +		else
> +			parent_rate = clk_hw_get_rate(parent);
> +
> +		child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
> +						      parent_rate);
> +
> +		if (child_rate <= rate && child_rate > best_child_rate) {
> +			best_parent = parent;
> +			best = parent_rate;
> +			best_child_rate = child_rate;
> +		}
> +	}
> +
> +	if (!best_parent)
> +		return -EINVAL;
> +
> +	req->best_parent_hw = best_parent;
> +	req->best_parent_rate = best;
> +	req->rate = best_child_rate;
> +
> +	return 0;
> +}
> +
> +static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
> +				       unsigned long parent_rate)
> +{
> +	struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
> +	unsigned long flags;
> +	u8 div, pre_div, parent;
> +	u32 reg;
> +
> +	spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
> +
> +	reg = readl(cpus->reg);
> +
> +	/* need to know which parent is used to apply pre-divider */
> +	parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
> +	sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
> +
> +	reg = SUN9I_CPUS_DIV_SET(reg, div);
> +	reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
> +	writel(reg, cpus->reg);
> +
> +	spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
> +
> +	return 0;
> +}
> +
> +static const struct clk_ops sun9i_a80_cpus_clk_ops = {
> +	.determine_rate	= sun9i_a80_cpus_clk_determine_rate,
> +	.recalc_rate	= sun9i_a80_cpus_clk_recalc_rate,
> +	.set_rate	= sun9i_a80_cpus_clk_set_rate,
> +};
> +
> +static void sun9i_a80_cpus_setup(struct device_node *node)
> +{
> +	const char *clk_name = node->name;
> +	const char *parents[SUN9I_CPUS_MAX_PARENTS];
> +	struct resource res;
> +	struct sun9i_a80_cpus_clk *cpus;
> +	struct clk_mux *mux;
> +	struct clk *clk;
> +	int ret;
> +
> +	cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
> +	if (!cpus)
> +		return;
> +
> +	cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> +	if (IS_ERR(cpus->reg))
> +		goto err_free_cpus;
> +
> +	of_property_read_string(node, "clock-output-names", &clk_name);
> +
> +	/* we have a mux, we will have >1 parents */
> +	ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
> +
> +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		goto err_unmap;
> +
> +	/* set up clock properties */
> +	mux->reg = cpus->reg;
> +	mux->shift = SUN9I_CPUS_MUX_SHIFT;
> +	/* un-shifted mask is what mux_clk expects */
> +	mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
> +	mux->lock = &sun9i_a80_cpus_lock;
> +
> +	clk = clk_register_composite(NULL, clk_name, parents, ret,
> +				     &mux->hw, &clk_mux_ops,
> +				     &cpus->hw, &sun9i_a80_cpus_clk_ops,
> +				     NULL, NULL, 0);
> +	if (IS_ERR(clk))
> +		goto err_free_mux;
> +
> +	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +	if (ret)
> +		goto err_unregister;
> +
> +	return;
> +
> +err_unregister:
> +	clk_unregister(clk);
> +err_free_mux:
> +	kfree(mux);
> +err_unmap:
> +	iounmap(cpus->reg);
> +	of_address_to_resource(node, 0, &res);
> +	release_mem_region(res.start, resource_size(&res));
> +err_free_cpus:
> +	kfree(cpus);
> +}
> +CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
> +	       sun9i_a80_cpus_setup);
> -- 
> 2.6.2
> 

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

* Re: [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support
  2015-11-29  3:03   ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
@ 2015-11-30 17:14     ` Rob Herring
  2015-12-01 11:16       ` Maxime Ripard
  0 siblings, 1 reply; 16+ messages in thread
From: Rob Herring @ 2015-11-30 17:14 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
	linux-arm-kernel, linux-kernel, devicetree, linux-sunxi

On Sun, Nov 29, 2015 at 11:03:07AM +0800, Chen-Yu Tsai wrote:
> This patch adds support for the PRCM apbs clock gates found on the
> Allwinner A80 SoC.
> 
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>

Acked-by: Rob Herring <robh@kernel.org>

> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
>  drivers/clk/sunxi/clk-simple-gates.c              | 2 ++
>  2 files changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index a94bb56a0e9e..b6859ed6913f 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -55,6 +55,7 @@ Required properties:
>  	"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
>  	"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
>  	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
> +	"allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
>  	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
>  	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
>  	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
> index 0214c6548afd..c8acc0612c15 100644
> --- a/drivers/clk/sunxi/clk-simple-gates.c
> +++ b/drivers/clk/sunxi/clk-simple-gates.c
> @@ -140,6 +140,8 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
>  	       sunxi_simple_gates_init);
>  CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
>  	       sunxi_simple_gates_init);
> +CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
> +	       sunxi_simple_gates_init);
>  
>  static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
>  	14,	/* ahb_sdram */
> -- 
> 2.6.2
> 

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

* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
  2015-11-29  3:03   ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
@ 2015-12-01 10:04     ` Maxime Ripard
  2015-12-01 11:54       ` Chen-Yu Tsai
  0 siblings, 1 reply; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 10:04 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Emilio Lopez, Michael Turquette, Stephen Boyd, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
	linux-arm-kernel, linux-kernel, devicetree, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 4556 bytes --]

Hi,

On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
> instead of through a PRCM mfd device and subdevices for each clock
> and reset control. As such we need a CLK_OF_DECLARE version of
> the sun8i-a23-apb0-clk driver.
> 
> Also, build it for sun9i/A80, and not just for configurations with
> MFD_SUN6I_PRCM enabled.
> 
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
>  drivers/clk/sunxi/Makefile         |  5 +--
>  drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>  2 files changed, 62 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index cb4c299214ce..c55d5cd1c0e5 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>  obj-y += clk-sun9i-mmc.o
>  obj-y += clk-usb.o
>  
> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
> +

So sun8i doesn't use it?

>  obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> -	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> -	clk-sun8i-apb0.o
> +	clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
> @@ -17,13 +17,68 @@
>  #include <linux/clk-provider.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_address.h>
>  #include <linux/platform_device.h>
>  
> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
> +					   void __iomem *reg)
> +{
> +	const char *clk_name = node->name;
> +	const char *clk_parent;
> +	struct clk *clk;
> +	int ret;
> +
> +	clk_parent = of_clk_get_parent_name(node, 0);
> +	if (!clk_parent)
> +		return ERR_PTR(-EINVAL);
> +
> +	of_property_read_string(node, "clock-output-names", &clk_name);
> +
> +	/* The A23 APB0 clock is a standard 2 bit wide divider clock */
> +	clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
> +				   0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> +	if (IS_ERR(clk))
> +		return clk;
> +
> +	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +	if (ret)
> +		goto err_unregister;
> +
> +	return clk;
> +
> +err_unregister:
> +	clk_unregister_divider(clk);
> +
> +	return ERR_PTR(ret);
> +}
> +
> +static void sun8i_a23_apb0_setup(struct device_node *node)
> +{
> +	void __iomem *reg;
> +	struct resource res;
> +	struct clk *clk;
> +
> +	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> +	if (IS_ERR(reg))
> +		return;
> +
> +	clk = sun8i_a23_apb0_register(node, reg);
> +	if (IS_ERR(clk))
> +		goto err_unmap;
> +
> +	return;
> +
> +err_unmap:
> +	iounmap(reg);
> +	of_address_to_resource(node, 0, &res);
> +	release_mem_region(res.start, resource_size(&res));
> +}
> +CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
> +	       sun8i_a23_apb0_setup);
> +
>  static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>  {
>  	struct device_node *np = pdev->dev.of_node;
> -	const char *clk_name = np->name;
> -	const char *clk_parent;
>  	struct resource *r;
>  	void __iomem *reg;
>  	struct clk *clk;
> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>  	if (IS_ERR(reg))
>  		return PTR_ERR(reg);
>  
> -	clk_parent = of_clk_get_parent_name(np, 0);
> -	if (!clk_parent)
> -		return -EINVAL;
> -
> -	of_property_read_string(np, "clock-output-names", &clk_name);
> -
> -	/* The A23 APB0 clock is a standard 2 bit wide divider clock */
> -	clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
> -				   0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> +	clk = sun8i_a23_apb0_register(np, reg);
>  	if (IS_ERR(clk))
>  		return PTR_ERR(clk);
>  
> -	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +	return 0;
>  }

Won't this probe twice now? First the CLK_OF_DECLARE will register a
clock, and then the device model will call probe a second time.

I guess then request_mem_region will catch it, but then you return an
error code, which is probably an error success, since the clock is
registered :)

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support
  2015-11-30 17:14     ` Rob Herring
@ 2015-12-01 11:16       ` Maxime Ripard
  0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 11:16 UTC (permalink / raw)
  To: Rob Herring
  Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw

[-- Attachment #1: Type: text/plain, Size: 499 bytes --]

On Mon, Nov 30, 2015 at 11:14:06AM -0600, Rob Herring wrote:
> On Sun, Nov 29, 2015 at 11:03:07AM +0800, Chen-Yu Tsai wrote:
> > This patch adds support for the PRCM apbs clock gates found on the
> > Allwinner A80 SoC.
> > 
> > Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> 
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Applied, thanks!

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
  2015-12-01 10:04     ` Maxime Ripard
@ 2015-12-01 11:54       ` Chen-Yu Tsai
  2015-12-01 12:50         ` Maxime Ripard
  0 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-12-01 11:54 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	linux-clk, linux-arm-kernel, linux-kernel, devicetree,
	linux-sunxi

On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
>> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
>> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
>> instead of through a PRCM mfd device and subdevices for each clock
>> and reset control. As such we need a CLK_OF_DECLARE version of
>> the sun8i-a23-apb0-clk driver.
>>
>> Also, build it for sun9i/A80, and not just for configurations with
>> MFD_SUN6I_PRCM enabled.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>> ---
>>  drivers/clk/sunxi/Makefile         |  5 +--
>>  drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>>  2 files changed, 62 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
>> index cb4c299214ce..c55d5cd1c0e5 100644
>> --- a/drivers/clk/sunxi/Makefile
>> +++ b/drivers/clk/sunxi/Makefile
>> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>>  obj-y += clk-sun9i-mmc.o
>>  obj-y += clk-usb.o
>>
>> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
>> +
>
> So sun8i doesn't use it?

Shit... I messed up. clk-sun8i-apb0.o should also be under
CONFIG_MFD_SUN6I_PRCM.

I'll send a new version of this patch. No need to keep spamming
people with the whole series.

>>  obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>> -     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
>> -     clk-sun8i-apb0.o
>> +     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
>> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
>> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
>> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> @@ -17,13 +17,68 @@
>>  #include <linux/clk-provider.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/of_address.h>
>>  #include <linux/platform_device.h>
>>
>> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
>> +                                        void __iomem *reg)
>> +{
>> +     const char *clk_name = node->name;
>> +     const char *clk_parent;
>> +     struct clk *clk;
>> +     int ret;
>> +
>> +     clk_parent = of_clk_get_parent_name(node, 0);
>> +     if (!clk_parent)
>> +             return ERR_PTR(-EINVAL);
>> +
>> +     of_property_read_string(node, "clock-output-names", &clk_name);
>> +
>> +     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> +     clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
>> +                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> +     if (IS_ERR(clk))
>> +             return clk;
>> +
>> +     ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> +     if (ret)
>> +             goto err_unregister;
>> +
>> +     return clk;
>> +
>> +err_unregister:
>> +     clk_unregister_divider(clk);
>> +
>> +     return ERR_PTR(ret);
>> +}
>> +
>> +static void sun8i_a23_apb0_setup(struct device_node *node)
>> +{
>> +     void __iomem *reg;
>> +     struct resource res;
>> +     struct clk *clk;
>> +
>> +     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>> +     if (IS_ERR(reg))
>> +             return;
>> +
>> +     clk = sun8i_a23_apb0_register(node, reg);
>> +     if (IS_ERR(clk))
>> +             goto err_unmap;
>> +
>> +     return;
>> +
>> +err_unmap:
>> +     iounmap(reg);
>> +     of_address_to_resource(node, 0, &res);
>> +     release_mem_region(res.start, resource_size(&res));
>> +}
>> +CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
>> +            sun8i_a23_apb0_setup);
>> +
>>  static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>>  {
>>       struct device_node *np = pdev->dev.of_node;
>> -     const char *clk_name = np->name;
>> -     const char *clk_parent;
>>       struct resource *r;
>>       void __iomem *reg;
>>       struct clk *clk;
>> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>>       if (IS_ERR(reg))
>>               return PTR_ERR(reg);
>>
>> -     clk_parent = of_clk_get_parent_name(np, 0);
>> -     if (!clk_parent)
>> -             return -EINVAL;
>> -
>> -     of_property_read_string(np, "clock-output-names", &clk_name);
>> -
>> -     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> -     clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
>> -                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> +     clk = sun8i_a23_apb0_register(np, reg);
>>       if (IS_ERR(clk))
>>               return PTR_ERR(clk);
>>
>> -     return of_clk_add_provider(np, of_clk_src_simple_get, clk);
>> +     return 0;
>>  }
>
> Won't this probe twice now? First the CLK_OF_DECLARE will register a
> clock, and then the device model will call probe a second time.

AFAIK it will.

> I guess then request_mem_region will catch it, but then you return an
> error code, which is probably an error success, since the clock is
> registered :)

Indeed. clk-mod0.c actually has a comment block explaining this.
I didn't want to repeat the whole thing though.

Regards
ChenYu

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

* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
  2015-12-01 11:54       ` Chen-Yu Tsai
@ 2015-12-01 12:50         ` Maxime Ripard
  2015-12-01 14:19           ` Chen-Yu Tsai
  0 siblings, 1 reply; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 12:50 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Emilio Lopez, Michael Turquette, Stephen Boyd, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, linux-clk,
	linux-arm-kernel, linux-kernel, devicetree, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 5946 bytes --]

On Tue, Dec 01, 2015 at 07:54:06PM +0800, Chen-Yu Tsai wrote:
> On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > Hi,
> >
> > On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
> >> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
> >> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
> >> instead of through a PRCM mfd device and subdevices for each clock
> >> and reset control. As such we need a CLK_OF_DECLARE version of
> >> the sun8i-a23-apb0-clk driver.
> >>
> >> Also, build it for sun9i/A80, and not just for configurations with
> >> MFD_SUN6I_PRCM enabled.
> >>
> >> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> >> ---
> >>  drivers/clk/sunxi/Makefile         |  5 +--
> >>  drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
> >>  2 files changed, 62 insertions(+), 14 deletions(-)
> >>
> >> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> >> index cb4c299214ce..c55d5cd1c0e5 100644
> >> --- a/drivers/clk/sunxi/Makefile
> >> +++ b/drivers/clk/sunxi/Makefile
> >> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
> >>  obj-y += clk-sun9i-mmc.o
> >>  obj-y += clk-usb.o
> >>
> >> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
> >> +
> >
> > So sun8i doesn't use it?
> 
> Shit... I messed up. clk-sun8i-apb0.o should also be under
> CONFIG_MFD_SUN6I_PRCM.
> 
> I'll send a new version of this patch. No need to keep spamming
> people with the whole series.

Ok.

> >>  obj-$(CONFIG_MFD_SUN6I_PRCM) += \
> >> -     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
> >> -     clk-sun8i-apb0.o
> >> +     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
> >> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
> >> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
> >> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
> >> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
> >> @@ -17,13 +17,68 @@
> >>  #include <linux/clk-provider.h>
> >>  #include <linux/module.h>
> >>  #include <linux/of.h>
> >> +#include <linux/of_address.h>
> >>  #include <linux/platform_device.h>
> >>
> >> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
> >> +                                        void __iomem *reg)
> >> +{
> >> +     const char *clk_name = node->name;
> >> +     const char *clk_parent;
> >> +     struct clk *clk;
> >> +     int ret;
> >> +
> >> +     clk_parent = of_clk_get_parent_name(node, 0);
> >> +     if (!clk_parent)
> >> +             return ERR_PTR(-EINVAL);
> >> +
> >> +     of_property_read_string(node, "clock-output-names", &clk_name);
> >> +
> >> +     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
> >> +     clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
> >> +                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> >> +     if (IS_ERR(clk))
> >> +             return clk;
> >> +
> >> +     ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> >> +     if (ret)
> >> +             goto err_unregister;
> >> +
> >> +     return clk;
> >> +
> >> +err_unregister:
> >> +     clk_unregister_divider(clk);
> >> +
> >> +     return ERR_PTR(ret);
> >> +}
> >> +
> >> +static void sun8i_a23_apb0_setup(struct device_node *node)
> >> +{
> >> +     void __iomem *reg;
> >> +     struct resource res;
> >> +     struct clk *clk;
> >> +
> >> +     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> >> +     if (IS_ERR(reg))
> >> +             return;
> >> +
> >> +     clk = sun8i_a23_apb0_register(node, reg);
> >> +     if (IS_ERR(clk))
> >> +             goto err_unmap;
> >> +
> >> +     return;
> >> +
> >> +err_unmap:
> >> +     iounmap(reg);
> >> +     of_address_to_resource(node, 0, &res);
> >> +     release_mem_region(res.start, resource_size(&res));
> >> +}
> >> +CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
> >> +            sun8i_a23_apb0_setup);
> >> +
> >>  static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
> >>  {
> >>       struct device_node *np = pdev->dev.of_node;
> >> -     const char *clk_name = np->name;
> >> -     const char *clk_parent;
> >>       struct resource *r;
> >>       void __iomem *reg;
> >>       struct clk *clk;
> >> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
> >>       if (IS_ERR(reg))
> >>               return PTR_ERR(reg);
> >>
> >> -     clk_parent = of_clk_get_parent_name(np, 0);
> >> -     if (!clk_parent)
> >> -             return -EINVAL;
> >> -
> >> -     of_property_read_string(np, "clock-output-names", &clk_name);
> >> -
> >> -     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
> >> -     clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
> >> -                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> >> +     clk = sun8i_a23_apb0_register(np, reg);
> >>       if (IS_ERR(clk))
> >>               return PTR_ERR(clk);
> >>
> >> -     return of_clk_add_provider(np, of_clk_src_simple_get, clk);
> >> +     return 0;
> >>  }
> >
> > Won't this probe twice now? First the CLK_OF_DECLARE will register a
> > clock, and then the device model will call probe a second time.
> 
> AFAIK it will.
> 
> > I guess then request_mem_region will catch it, but then you return an
> > error code, which is probably an error success, since the clock is
> > registered :)
> 
> Indeed. clk-mod0.c actually has a comment block explaining this.
> I didn't want to repeat the whole thing though.

I guess, we can simply return 0 if of_io_request_and_map returns
EBUSY, since it would simply mean that we already probed.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support
  2015-11-30 17:13     ` Rob Herring
@ 2015-12-01 13:07       ` Maxime Ripard
  0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 13:07 UTC (permalink / raw)
  To: Rob Herring
  Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw

[-- Attachment #1: Type: text/plain, Size: 880 bytes --]

On Mon, Nov 30, 2015 at 11:13:25AM -0600, Rob Herring wrote:
> On Sun, Nov 29, 2015 at 11:03:08AM +0800, Chen-Yu Tsai wrote:
> > The "cpus" clock is the clock for the embedded processor in the A80.
> > It is also part of the PRCM clock tree. This clock includes a pre-
> > divider on one of its inputs. For now we are using a custom clock
> > driver for it. In the future we may want to develop a generalized
> > driver for these types of clocks, which also includes the AHB clock
> > driver on sun[5678]i.
> > 
> > Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> > ---
> >  Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
> 
> For the binding:
> 
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Applied, thanks!

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

* Re: [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks
       [not found]     ` <1448766190-11345-6-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
@ 2015-12-01 13:08       ` Maxime Ripard
  0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2015-12-01 13:08 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Emilio Lopez, Michael Turquette, Stephen Boyd, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw

[-- Attachment #1: Type: text/plain, Size: 426 bytes --]

On Sun, Nov 29, 2015 at 11:03:10AM +0800, Chen-Yu Tsai wrote:
> The main (24MHz) clock on the A80 is configurable via the PRCM address
> space. The low power/speed (32kHz) clock is from an external chip, the
> AC100.
> 
> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>

Applied 4 and 5, thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

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

* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
  2015-12-01 12:50         ` Maxime Ripard
@ 2015-12-01 14:19           ` Chen-Yu Tsai
  2015-12-01 14:39             ` Chen-Yu Tsai
  0 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-12-01 14:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	linux-clk, linux-arm-kernel, linux-kernel, devicetree,
	linux-sunxi

On Tue, Dec 1, 2015 at 8:50 PM, Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> On Tue, Dec 01, 2015 at 07:54:06PM +0800, Chen-Yu Tsai wrote:
>> On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
>> <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
>> > Hi,
>> >
>> > On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
>> >> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
>> >> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
>> >> instead of through a PRCM mfd device and subdevices for each clock
>> >> and reset control. As such we need a CLK_OF_DECLARE version of
>> >> the sun8i-a23-apb0-clk driver.
>> >>
>> >> Also, build it for sun9i/A80, and not just for configurations with
>> >> MFD_SUN6I_PRCM enabled.
>> >>
>> >> Signed-off-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>> >> ---
>> >>  drivers/clk/sunxi/Makefile         |  5 +--
>> >>  drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>> >>  2 files changed, 62 insertions(+), 14 deletions(-)
>> >>
>> >> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
>> >> index cb4c299214ce..c55d5cd1c0e5 100644
>> >> --- a/drivers/clk/sunxi/Makefile
>> >> +++ b/drivers/clk/sunxi/Makefile
>> >> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>> >>  obj-y += clk-sun9i-mmc.o
>> >>  obj-y += clk-usb.o
>> >>
>> >> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
>> >> +
>> >
>> > So sun8i doesn't use it?
>>
>> Shit... I messed up. clk-sun8i-apb0.o should also be under
>> CONFIG_MFD_SUN6I_PRCM.
>>
>> I'll send a new version of this patch. No need to keep spamming
>> people with the whole series.
>
> Ok.
>
>> >>  obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>> >> -     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
>> >> -     clk-sun8i-apb0.o
>> >> +     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
>> >> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> >> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
>> >> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
>> >> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
>> >> @@ -17,13 +17,68 @@
>> >>  #include <linux/clk-provider.h>
>> >>  #include <linux/module.h>
>> >>  #include <linux/of.h>
>> >> +#include <linux/of_address.h>
>> >>  #include <linux/platform_device.h>
>> >>
>> >> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
>> >> +                                        void __iomem *reg)
>> >> +{
>> >> +     const char *clk_name = node->name;
>> >> +     const char *clk_parent;
>> >> +     struct clk *clk;
>> >> +     int ret;
>> >> +
>> >> +     clk_parent = of_clk_get_parent_name(node, 0);
>> >> +     if (!clk_parent)
>> >> +             return ERR_PTR(-EINVAL);
>> >> +
>> >> +     of_property_read_string(node, "clock-output-names", &clk_name);
>> >> +
>> >> +     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> >> +     clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
>> >> +                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> >> +     if (IS_ERR(clk))
>> >> +             return clk;
>> >> +
>> >> +     ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>> >> +     if (ret)
>> >> +             goto err_unregister;
>> >> +
>> >> +     return clk;
>> >> +
>> >> +err_unregister:
>> >> +     clk_unregister_divider(clk);
>> >> +
>> >> +     return ERR_PTR(ret);
>> >> +}
>> >> +
>> >> +static void sun8i_a23_apb0_setup(struct device_node *node)
>> >> +{
>> >> +     void __iomem *reg;
>> >> +     struct resource res;
>> >> +     struct clk *clk;
>> >> +
>> >> +     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>> >> +     if (IS_ERR(reg))
>> >> +             return;
>> >> +
>> >> +     clk = sun8i_a23_apb0_register(node, reg);
>> >> +     if (IS_ERR(clk))
>> >> +             goto err_unmap;
>> >> +
>> >> +     return;
>> >> +
>> >> +err_unmap:
>> >> +     iounmap(reg);
>> >> +     of_address_to_resource(node, 0, &res);
>> >> +     release_mem_region(res.start, resource_size(&res));
>> >> +}
>> >> +CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
>> >> +            sun8i_a23_apb0_setup);
>> >> +
>> >>  static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>> >>  {
>> >>       struct device_node *np = pdev->dev.of_node;
>> >> -     const char *clk_name = np->name;
>> >> -     const char *clk_parent;
>> >>       struct resource *r;
>> >>       void __iomem *reg;
>> >>       struct clk *clk;
>> >> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>> >>       if (IS_ERR(reg))
>> >>               return PTR_ERR(reg);
>> >>
>> >> -     clk_parent = of_clk_get_parent_name(np, 0);
>> >> -     if (!clk_parent)
>> >> -             return -EINVAL;
>> >> -
>> >> -     of_property_read_string(np, "clock-output-names", &clk_name);
>> >> -
>> >> -     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>> >> -     clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
>> >> -                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>> >> +     clk = sun8i_a23_apb0_register(np, reg);
>> >>       if (IS_ERR(clk))
>> >>               return PTR_ERR(clk);
>> >>
>> >> -     return of_clk_add_provider(np, of_clk_src_simple_get, clk);
>> >> +     return 0;
>> >>  }
>> >
>> > Won't this probe twice now? First the CLK_OF_DECLARE will register a
>> > clock, and then the device model will call probe a second time.
>>
>> AFAIK it will.
>>
>> > I guess then request_mem_region will catch it, but then you return an
>> > error code, which is probably an error success, since the clock is
>> > registered :)
>>
>> Indeed. clk-mod0.c actually has a comment block explaining this.
>> I didn't want to repeat the whole thing though.
>
> I guess, we can simply return 0 if of_io_request_and_map returns
> EBUSY, since it would simply mean that we already probed.

I think CLK_OF_DECLARE gets probed first, then platform devices.
of_io_request_and_map fails for mfd cells, which have no DT reg
properties. So we should be ignoring -EINVAL instead of -EBUSY.
But yeah, I'll have it return 0 in this case, and add a brief
comment.

ChenYu

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

* Re: [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
  2015-12-01 14:19           ` Chen-Yu Tsai
@ 2015-12-01 14:39             ` Chen-Yu Tsai
  0 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2015-12-01 14:39 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Maxime Ripard, Emilio Lopez, Michael Turquette, Stephen Boyd,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	linux-clk, linux-arm-kernel, linux-kernel, devicetree,
	linux-sunxi

On Tue, Dec 1, 2015 at 10:19 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Tue, Dec 1, 2015 at 8:50 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> On Tue, Dec 01, 2015 at 07:54:06PM +0800, Chen-Yu Tsai wrote:
>>> On Tue, Dec 1, 2015 at 6:04 PM, Maxime Ripard
>>> <maxime.ripard@free-electrons.com> wrote:
>>> > Hi,
>>> >
>>> > On Sun, Nov 29, 2015 at 11:03:06AM +0800, Chen-Yu Tsai wrote:
>>> >> The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
>>> >> sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
>>> >> instead of through a PRCM mfd device and subdevices for each clock
>>> >> and reset control. As such we need a CLK_OF_DECLARE version of
>>> >> the sun8i-a23-apb0-clk driver.
>>> >>
>>> >> Also, build it for sun9i/A80, and not just for configurations with
>>> >> MFD_SUN6I_PRCM enabled.
>>> >>
>>> >> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>>> >> ---
>>> >>  drivers/clk/sunxi/Makefile         |  5 +--
>>> >>  drivers/clk/sunxi/clk-sun8i-apb0.c | 71 +++++++++++++++++++++++++++++++-------
>>> >>  2 files changed, 62 insertions(+), 14 deletions(-)
>>> >>
>>> >> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
>>> >> index cb4c299214ce..c55d5cd1c0e5 100644
>>> >> --- a/drivers/clk/sunxi/Makefile
>>> >> +++ b/drivers/clk/sunxi/Makefile
>>> >> @@ -15,6 +15,7 @@ obj-y += clk-sun9i-core.o
>>> >>  obj-y += clk-sun9i-mmc.o
>>> >>  obj-y += clk-usb.o
>>> >>
>>> >> +obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
>>> >> +
>>> >
>>> > So sun8i doesn't use it?
>>>
>>> Shit... I messed up. clk-sun8i-apb0.o should also be under
>>> CONFIG_MFD_SUN6I_PRCM.
>>>
>>> I'll send a new version of this patch. No need to keep spamming
>>> people with the whole series.
>>
>> Ok.
>>
>>> >>  obj-$(CONFIG_MFD_SUN6I_PRCM) += \
>>> >> -     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
>>> >> -     clk-sun8i-apb0.o
>>> >> +     clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
>>> >> diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c
>>> >> index 7ae5d2c2cde1..c1e2ac8f4b0d 100644
>>> >> --- a/drivers/clk/sunxi/clk-sun8i-apb0.c
>>> >> +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c
>>> >> @@ -17,13 +17,68 @@
>>> >>  #include <linux/clk-provider.h>
>>> >>  #include <linux/module.h>
>>> >>  #include <linux/of.h>
>>> >> +#include <linux/of_address.h>
>>> >>  #include <linux/platform_device.h>
>>> >>
>>> >> +static struct clk *sun8i_a23_apb0_register(struct device_node *node,
>>> >> +                                        void __iomem *reg)
>>> >> +{
>>> >> +     const char *clk_name = node->name;
>>> >> +     const char *clk_parent;
>>> >> +     struct clk *clk;
>>> >> +     int ret;
>>> >> +
>>> >> +     clk_parent = of_clk_get_parent_name(node, 0);
>>> >> +     if (!clk_parent)
>>> >> +             return ERR_PTR(-EINVAL);
>>> >> +
>>> >> +     of_property_read_string(node, "clock-output-names", &clk_name);
>>> >> +
>>> >> +     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>>> >> +     clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
>>> >> +                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>>> >> +     if (IS_ERR(clk))
>>> >> +             return clk;
>>> >> +
>>> >> +     ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
>>> >> +     if (ret)
>>> >> +             goto err_unregister;
>>> >> +
>>> >> +     return clk;
>>> >> +
>>> >> +err_unregister:
>>> >> +     clk_unregister_divider(clk);
>>> >> +
>>> >> +     return ERR_PTR(ret);
>>> >> +}
>>> >> +
>>> >> +static void sun8i_a23_apb0_setup(struct device_node *node)
>>> >> +{
>>> >> +     void __iomem *reg;
>>> >> +     struct resource res;
>>> >> +     struct clk *clk;
>>> >> +
>>> >> +     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
>>> >> +     if (IS_ERR(reg))
>>> >> +             return;
>>> >> +
>>> >> +     clk = sun8i_a23_apb0_register(node, reg);
>>> >> +     if (IS_ERR(clk))
>>> >> +             goto err_unmap;
>>> >> +
>>> >> +     return;
>>> >> +
>>> >> +err_unmap:
>>> >> +     iounmap(reg);
>>> >> +     of_address_to_resource(node, 0, &res);
>>> >> +     release_mem_region(res.start, resource_size(&res));
>>> >> +}
>>> >> +CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
>>> >> +            sun8i_a23_apb0_setup);
>>> >> +
>>> >>  static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>>> >>  {
>>> >>       struct device_node *np = pdev->dev.of_node;
>>> >> -     const char *clk_name = np->name;
>>> >> -     const char *clk_parent;
>>> >>       struct resource *r;
>>> >>       void __iomem *reg;
>>> >>       struct clk *clk;
>>> >> @@ -33,19 +88,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
>>> >>       if (IS_ERR(reg))
>>> >>               return PTR_ERR(reg);
>>> >>
>>> >> -     clk_parent = of_clk_get_parent_name(np, 0);
>>> >> -     if (!clk_parent)
>>> >> -             return -EINVAL;
>>> >> -
>>> >> -     of_property_read_string(np, "clock-output-names", &clk_name);
>>> >> -
>>> >> -     /* The A23 APB0 clock is a standard 2 bit wide divider clock */
>>> >> -     clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
>>> >> -                                0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
>>> >> +     clk = sun8i_a23_apb0_register(np, reg);
>>> >>       if (IS_ERR(clk))
>>> >>               return PTR_ERR(clk);
>>> >>
>>> >> -     return of_clk_add_provider(np, of_clk_src_simple_get, clk);
>>> >> +     return 0;
>>> >>  }
>>> >
>>> > Won't this probe twice now? First the CLK_OF_DECLARE will register a
>>> > clock, and then the device model will call probe a second time.
>>>
>>> AFAIK it will.
>>>
>>> > I guess then request_mem_region will catch it, but then you return an
>>> > error code, which is probably an error success, since the clock is
>>> > registered :)
>>>
>>> Indeed. clk-mod0.c actually has a comment block explaining this.
>>> I didn't want to repeat the whole thing though.
>>
>> I guess, we can simply return 0 if of_io_request_and_map returns
>> EBUSY, since it would simply mean that we already probed.
>
> I think CLK_OF_DECLARE gets probed first, then platform devices.
> of_io_request_and_map fails for mfd cells, which have no DT reg
> properties. So we should be ignoring -EINVAL instead of -EBUSY.

Right... I misread your comment. You're talking about the platform device
part. About ignoring the error here: normally we use CLK_OF_DECLARE with
clocks under the "clocks" node, which don't get registered as platform
device. (Or is this not so common?) So if one does get probed twice, I
think we shouldn't ignore the error. It's likely the DT has a problem
and the probe error will let the user know.

What do you think?

ChenYu

> But yeah, I'll have it return 0 in this case, and add a brief
> comment.

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

end of thread, other threads:[~2015-12-01 14:39 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-29  3:03 [PATCH v4 0/5] ARM: sun9i: Add Allwinner A80 PRCM clock/reset support Chen-Yu Tsai
     [not found] ` <1448766190-11345-1-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-11-29  3:03   ` [PATCH v4 1/5] clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver Chen-Yu Tsai
2015-12-01 10:04     ` Maxime Ripard
2015-12-01 11:54       ` Chen-Yu Tsai
2015-12-01 12:50         ` Maxime Ripard
2015-12-01 14:19           ` Chen-Yu Tsai
2015-12-01 14:39             ` Chen-Yu Tsai
2015-11-29  3:03   ` [PATCH v4 2/5] clk: sunxi: Add sun9i A80 apbs gates support Chen-Yu Tsai
2015-11-30 17:14     ` Rob Herring
2015-12-01 11:16       ` Maxime Ripard
2015-11-29  3:03   ` [PATCH v4 3/5] clk: sunxi: Add sun9i A80 cpus (cpu special) clock support Chen-Yu Tsai
2015-11-30 17:13     ` Rob Herring
2015-12-01 13:07       ` Maxime Ripard
2015-11-29  3:03   ` [PATCH v4 4/5] ARM: dts: sun9i: Add A80 PRCM clocks and reset control nodes Chen-Yu Tsai
2015-11-29  3:03   ` [PATCH v4 5/5] ARM: dts: sun9i: Add TODO comments for the main and low power clocks Chen-Yu Tsai
     [not found]     ` <1448766190-11345-6-git-send-email-wens-jdAy2FN1RRM@public.gmane.org>
2015-12-01 13:08       ` Maxime Ripard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).