[U-Boot] [PATCH v1 2/7] clk: at91: Improve the clock implementation

Wenyou Yang wenyou.yang at atmel.com
Tue Sep 13 03:54:44 CEST 2016


For the peripheral clock, provide the clock ops for the clock
provider, such as spi0_clk. The .of_xlate is to get the clk->id,
the .enable is to enable the spi0 peripheral clock, the .get_rate
is to get the clock frequency.

The driver for periph32ck node is responsible for recursively
binding its children as clk devices, not provide the clock ops.

So do the generated clock and system clock.

Signed-off-by: Wenyou Yang <wenyou.yang at atmel.com>
---

 drivers/clk/at91/clk-generated.c  | 141 ++++++++++++++++++++++++++++----------
 drivers/clk/at91/clk-peripheral.c | 139 ++++++++++++++++++++++++++++++-------
 drivers/clk/at91/clk-system.c     | 117 +++++++++++++++++++++++++------
 drivers/clk/at91/pmc.c            |  28 --------
 drivers/clk/at91/pmc.h            |   1 -
 5 files changed, 316 insertions(+), 110 deletions(-)

diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
index f6164cc..923ffbb 100644
--- a/drivers/clk/at91/clk-generated.c
+++ b/drivers/clk/at91/clk-generated.c
@@ -8,22 +8,97 @@
 #include <common.h>
 #include <clk-uclass.h>
 #include <dm/device.h>
+#include <dm/lists.h>
 #include <linux/io.h>
 #include <mach/at91_pmc.h>
-#include "pmc.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #define GENERATED_SOURCE_MAX	6
 #define GENERATED_MAX_DIV	255
 
-struct generated_clk_priv {
+/**
+ * generated_clk_bind() - for the generated clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int generated_clk_bind(struct udevice *dev)
+{
+	const void *fdt = gd->fdt_blob;
+	int offset = dev->of_offset;
+	bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+	const char *name;
+	int ret;
+
+	for (offset = fdt_first_subnode(fdt, offset);
+	     offset > 0;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		if (pre_reloc_only &&
+		    !fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL))
+			continue;
+		/*
+		 * If this node has "compatible" property, this is not
+		 * a pin configuration node, but a normal device. skip.
+		 */
+		fdt_get_property(fdt, offset, "compatible", &ret);
+		if (ret >= 0)
+			continue;
+
+		if (ret != -FDT_ERR_NOTFOUND)
+			return ret;
+
+		name = fdt_get_name(fdt, offset, NULL);
+		if (!name)
+			return -EINVAL;
+		ret = device_bind_driver_to_node(dev, "generic-clk", name,
+						 offset, NULL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id generated_clk_match[] = {
+	{ .compatible = "atmel,sama5d2-clk-generated" },
+	{}
+};
+
+U_BOOT_DRIVER(generated_clk) = {
+	.name = "generated-clk",
+	.id = UCLASS_CLK,
+	.of_match = generated_clk_match,
+	.bind = generated_clk_bind,
+};
+
+/*-------------------------------------------------------------*/
+
+struct generic_clk_platdata {
+	struct at91_pmc *reg_base;
+};
+
+struct generic_clk_priv {
 	u32 num_parents;
 };
 
-static ulong generated_clk_get_rate(struct clk *clk)
+static int generic_clk_of_xlate(struct clk *clk,
+			       struct fdtdec_phandle_args *args)
 {
-	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+	int periph;
+
+	periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
+	if (periph < 0)
+		return -EINVAL;
+
+	clk->id = periph;
+
+	return 0;
+}
+
+static ulong generic_clk_get_rate(struct clk *clk)
+{
+	struct generic_clk_platdata *plat = dev_get_platdata(clk->dev);
 	struct at91_pmc *pmc = plat->reg_base;
 	struct clk parent;
 	u32 tmp, gckdiv;
@@ -36,18 +111,18 @@ static ulong generated_clk_get_rate(struct clk *clk)
 		    AT91_PMC_PCR_GCKCSS_MASK;
 	gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
 
-	ret = clk_get_by_index(clk->dev, parent_id, &parent);
+	ret = clk_get_by_index(dev_get_parent(clk->dev), parent_id, &parent);
 	if (ret)
 		return 0;
 
 	return clk_get_rate(&parent) / (gckdiv + 1);
 }
 
-static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
+static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
 {
-	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+	struct generic_clk_platdata *plat = dev_get_platdata(clk->dev);
 	struct at91_pmc *pmc = plat->reg_base;
-	struct generated_clk_priv *priv = dev_get_priv(clk->dev);
+	struct generic_clk_priv *priv = dev_get_priv(clk->dev);
 	struct clk parent, best_parent;
 	ulong tmp_rate, best_rate = rate, parent_rate;
 	int tmp_diff, best_diff = -1;
@@ -58,7 +133,7 @@ static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
 	int ret;
 
 	for (i = 0; i < priv->num_parents; i++) {
-		ret = clk_get_by_index(clk->dev, i, &parent);
+		ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
 		if (ret)
 			return ret;
 
@@ -111,18 +186,20 @@ static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
 	return 0;
 }
 
-static struct clk_ops generated_clk_ops = {
-	.get_rate = generated_clk_get_rate,
-	.set_rate = generated_clk_set_rate,
+static struct clk_ops generic_clk_ops = {
+	.of_xlate = generic_clk_of_xlate,
+	.get_rate = generic_clk_get_rate,
+	.set_rate = generic_clk_set_rate,
 };
 
-static int generated_clk_ofdata_to_platdata(struct udevice *dev)
+static int generic_clk_ofdata_to_platdata(struct udevice *dev)
 {
-	struct generated_clk_priv *priv = dev_get_priv(dev);
+	struct generic_clk_priv *priv = dev_get_priv(dev);
 	u32 cells[GENERATED_SOURCE_MAX];
 	u32 num_parents;
 
-	num_parents = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
+	num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
+						 dev_get_parent(dev)->of_offset,
 						 "clocks", cells,
 						 GENERATED_SOURCE_MAX);
 
@@ -134,29 +211,23 @@ static int generated_clk_ofdata_to_platdata(struct udevice *dev)
 	return 0;
 }
 
-static int generated_clk_bind(struct udevice *dev)
+static int generic_clk_probe(struct udevice *dev)
 {
-	return at91_pmc_clk_node_bind(dev);
-}
+	struct generic_clk_platdata *plat = dev_get_platdata(dev);
 
-static int generated_clk_probe(struct udevice *dev)
-{
-	return at91_pmc_core_probe(dev);
-}
+	dev = dev_get_parent(dev);
+	dev = dev_get_parent(dev);
+	plat->reg_base = (struct at91_pmc *)dev_get_addr_ptr(dev);
 
-static const struct udevice_id generated_clk_match[] = {
-	{ .compatible = "atmel,sama5d2-clk-generated" },
-	{}
-};
+	return 0;
+}
 
-U_BOOT_DRIVER(generated_clk) = {
-	.name = "generated-clk",
+U_BOOT_DRIVER(generic_clk) = {
+	.name = "generic-clk",
 	.id = UCLASS_CLK,
-	.of_match = generated_clk_match,
-	.bind = generated_clk_bind,
-	.probe = generated_clk_probe,
-	.ofdata_to_platdata = generated_clk_ofdata_to_platdata,
-	.priv_auto_alloc_size = sizeof(struct generated_clk_priv),
-	.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
-	.ops = &generated_clk_ops,
+	.probe = generic_clk_probe,
+	.ofdata_to_platdata = generic_clk_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct generic_clk_priv),
+	.platdata_auto_alloc_size = sizeof(struct generic_clk_platdata),
+	.ops = &generic_clk_ops,
 };
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index 16688e9..a7091c1 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -8,17 +8,94 @@
 #include <common.h>
 #include <clk-uclass.h>
 #include <dm/device.h>
+#include <dm/lists.h>
 #include <linux/io.h>
 #include <mach/at91_pmc.h>
-#include "pmc.h"
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #define PERIPHERAL_ID_MIN	2
 #define PERIPHERAL_ID_MAX	31
 #define PERIPHERAL_MASK(id)	(1 << ((id) & PERIPHERAL_ID_MAX))
 
-static int sam9x5_periph_clk_enable(struct clk *clk)
+struct periph_clk_platdata {
+	struct at91_pmc *reg_base;
+};
+
+/**
+ * sam9x5_periph_clk_bind() - for the periph clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int sam9x5_periph_clk_bind(struct udevice *dev)
+{
+	const void *fdt = gd->fdt_blob;
+	int offset = dev->of_offset;
+	bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+	const char *name;
+	int ret;
+
+	for (offset = fdt_first_subnode(fdt, offset);
+	     offset > 0;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		if (pre_reloc_only &&
+		    !fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL))
+			continue;
+		/*
+		 * If this node has "compatible" property, this is not
+		 * a pin configuration node, but a normal device. skip.
+		 */
+		fdt_get_property(fdt, offset, "compatible", &ret);
+		if (ret >= 0)
+			continue;
+
+		if (ret != -FDT_ERR_NOTFOUND)
+			return ret;
+
+		name = fdt_get_name(fdt, offset, NULL);
+		if (!name)
+			return -EINVAL;
+		ret = device_bind_driver_to_node(dev, "periph-clk", name,
+						 offset, NULL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id sam9x5_periph_clk_match[] = {
+	{ .compatible = "atmel,at91sam9x5-clk-peripheral" },
+	{}
+};
+
+U_BOOT_DRIVER(sam9x5_periph_clk) = {
+	.name = "sam9x5-periph-clk",
+	.id = UCLASS_CLK,
+	.of_match = sam9x5_periph_clk_match,
+	.bind = sam9x5_periph_clk_bind,
+};
+
+/*---------------------------------------------------------*/
+
+static int periph_clk_of_xlate(struct clk *clk,
+			       struct fdtdec_phandle_args *args)
 {
-	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+	int periph;
+
+	periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
+	if (periph < 0)
+		return -EINVAL;
+
+	clk->id = periph;
+
+	return 0;
+}
+
+static int periph_clk_enable(struct clk *clk)
+{
+	struct periph_clk_platdata *plat = dev_get_platdata(clk->dev);
 	struct at91_pmc *pmc = plat->reg_base;
 
 	if (clk->id < PERIPHERAL_ID_MIN)
@@ -30,31 +107,45 @@ static int sam9x5_periph_clk_enable(struct clk *clk)
 	return 0;
 }
 
-static struct clk_ops sam9x5_periph_clk_ops = {
-	.enable = sam9x5_periph_clk_enable,
-};
-
-static int sam9x5_periph_clk_bind(struct udevice *dev)
+static ulong periph_get_rate(struct clk *clk)
 {
-	return at91_pmc_clk_node_bind(dev);
-}
+	struct udevice *dev;
+	struct clk clk_dev;
+	int ret;
 
-static int sam9x5_periph_clk_probe(struct udevice *dev)
-{
-	return at91_pmc_core_probe(dev);
+	dev = dev_get_parent(clk->dev);
+	ret = clk_request(dev, &clk_dev);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 0, &clk_dev);
+	if (ret)
+		return ret;
+
+	return clk_get_rate(&clk_dev);
 }
 
-static const struct udevice_id sam9x5_periph_clk_match[] = {
-	{ .compatible = "atmel,at91sam9x5-clk-peripheral" },
-	{}
+static struct clk_ops periph_clk_ops = {
+	.of_xlate = periph_clk_of_xlate,
+	.enable = periph_clk_enable,
+	.get_rate = periph_get_rate,
 };
 
-U_BOOT_DRIVER(sam9x5_periph_clk) = {
-	.name = "sam9x5-periph-clk",
-	.id = UCLASS_CLK,
-	.of_match = sam9x5_periph_clk_match,
-	.bind = sam9x5_periph_clk_bind,
-	.probe = sam9x5_periph_clk_probe,
-	.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
-	.ops = &sam9x5_periph_clk_ops,
+static int periph_clk_probe(struct udevice *dev)
+{
+	struct periph_clk_platdata *plat = dev_get_platdata(dev);
+
+	dev = dev_get_parent(dev);
+	dev = dev_get_parent(dev);
+	plat->reg_base = (struct at91_pmc *)dev_get_addr_ptr(dev);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(clk_periph) = {
+	.name	= "periph-clk",
+	.id	= UCLASS_CLK,
+	.platdata_auto_alloc_size = sizeof(struct periph_clk_platdata),
+	.probe = periph_clk_probe,
+	.ops	= &periph_clk_ops,
 };
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index fa80bad..149f45c 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -8,20 +8,98 @@
 #include <common.h>
 #include <clk-uclass.h>
 #include <dm/device.h>
+#include <dm/lists.h>
 #include <linux/io.h>
 #include <mach/at91_pmc.h>
 #include "pmc.h"
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #define SYSTEM_MAX_ID		31
 
+/**
+ * at91_system_clk_bind() - for the system clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int at91_system_clk_bind(struct udevice *dev)
+{
+	const void *fdt = gd->fdt_blob;
+	int offset = dev->of_offset;
+	bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+	const char *name;
+	int ret;
+
+	for (offset = fdt_first_subnode(fdt, offset);
+	     offset > 0;
+	     offset = fdt_next_subnode(fdt, offset)) {
+		if (pre_reloc_only &&
+		    !fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL))
+			continue;
+		/*
+		 * If this node has "compatible" property, this is not
+		 * a pin configuration node, but a normal device. skip.
+		 */
+		fdt_get_property(fdt, offset, "compatible", &ret);
+		if (ret >= 0)
+			continue;
+
+		if (ret != -FDT_ERR_NOTFOUND)
+			return ret;
+
+		name = fdt_get_name(fdt, offset, NULL);
+		if (!name)
+			return -EINVAL;
+		ret = device_bind_driver_to_node(dev, "system-clk", name,
+						 offset, NULL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id at91_system_clk_match[] = {
+	{ .compatible = "atmel,at91rm9200-clk-system" },
+	{}
+};
+
+U_BOOT_DRIVER(at91_system_clk) = {
+	.name = "at91-system-clk",
+	.id = UCLASS_CLK,
+	.of_match = at91_system_clk_match,
+	.bind = at91_system_clk_bind,
+};
+
+/*----------------------------------------------------------*/
+
+struct system_clk_platdata {
+	struct at91_pmc *reg_base;
+};
+
+static int system_clk_of_xlate(struct clk *clk,
+			       struct fdtdec_phandle_args *args)
+{
+	int periph;
+
+	periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
+	if (periph < 0)
+		return -EINVAL;
+
+	clk->id = periph;
+
+	return 0;
+}
+
 static inline int is_pck(int id)
 {
 	return (id >= 8) && (id <= 15);
 }
 
-static int at91_system_clk_enable(struct clk *clk)
+static int system_clk_enable(struct clk *clk)
 {
-	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+	struct system_clk_platdata *plat = dev_get_platdata(clk->dev);
 	struct at91_pmc *pmc = plat->reg_base;
 	u32 mask;
 
@@ -46,31 +124,26 @@ static int at91_system_clk_enable(struct clk *clk)
 	return 0;
 }
 
-static struct clk_ops at91_system_clk_ops = {
-	.enable = at91_system_clk_enable,
+static struct clk_ops system_clk_ops = {
+	.of_xlate = system_clk_of_xlate,
+	.enable = system_clk_enable,
 };
 
-static int at91_system_clk_bind(struct udevice *dev)
+static int system_clk_probe(struct udevice *dev)
 {
-	return at91_pmc_clk_node_bind(dev);
-}
+	struct system_clk_platdata *plat = dev_get_platdata(dev);
 
-static int at91_system_clk_probe(struct udevice *dev)
-{
-	return at91_pmc_core_probe(dev);
-}
+	dev = dev_get_parent(dev);
+	dev = dev_get_parent(dev);
+	plat->reg_base = (struct at91_pmc *)dev_get_addr_ptr(dev);
 
-static const struct udevice_id at91_system_clk_match[] = {
-	{ .compatible = "atmel,at91rm9200-clk-system" },
-	{}
-};
+	return 0;
+}
 
-U_BOOT_DRIVER(at91_system_clk) = {
-	.name = "at91-system-clk",
+U_BOOT_DRIVER(system_clk) = {
+	.name = "system-clk",
 	.id = UCLASS_CLK,
-	.of_match = at91_system_clk_match,
-	.bind = at91_system_clk_bind,
-	.probe = at91_system_clk_probe,
-	.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
-	.ops = &at91_system_clk_ops,
+	.probe = system_clk_probe,
+	.platdata_auto_alloc_size = sizeof(struct system_clk_platdata),
+	.ops = &system_clk_ops,
 };
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 76ff387..b666caf 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -35,31 +35,3 @@ int at91_pmc_core_probe(struct udevice *dev)
 
 	return 0;
 }
-
-int at91_pmc_clk_node_bind(struct udevice *dev)
-{
-	const void *fdt = gd->fdt_blob;
-	int offset = dev->of_offset;
-	const char *name;
-	int ret;
-
-	for (offset = fdt_first_subnode(fdt, offset);
-	     offset > 0;
-	     offset = fdt_next_subnode(fdt, offset)) {
-		name = fdt_get_name(fdt, offset, NULL);
-		if (!name)
-			return -EINVAL;
-
-		ret = device_bind_driver_to_node(dev, "clk", name,
-						 offset, NULL);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-U_BOOT_DRIVER(clk_generic) = {
-	.id	= UCLASS_CLK,
-	.name	= "clk",
-};
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 5444c84..201dad8 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -13,6 +13,5 @@ struct pmc_platdata {
 };
 
 int at91_pmc_core_probe(struct udevice *dev);
-int at91_pmc_clk_node_bind(struct udevice *dev);
 
 #endif
-- 
2.7.4



More information about the U-Boot mailing list