[U-Boot] [PATCH v2 6/6] clk: add device tree support for clock framework

Masahiro Yamada yamada.masahiro at socionext.com
Wed Jan 13 05:16:13 CET 2016


Add device tree binding support for the clock uclass.  This allows
clock consumers to get the peripheral ID based on the "clocks"
property in the device tree.

Usage:
Assume the following device tree:

  clk: myclock {
          compatible = "myclocktype";
          #clock-cells = <1>;
  };

  uart {
          compatible = "myuart";
          clocks = <&clk 3>;
  };

  i2c {
          compatible = "myi2c";
          clocks = <&clk 5>;
  };

In this example, the UART, I2C driver can get the peripheral ID 3, 5,
respectively by calling fdt_clk_get().

By default, fdt_clk_get() returns the value of the first cell, or
zero if #clock-cells == <0>.  This should work for most of the cases,
but you can still override this behavior by implementing .fdt_xlate
callback in your driver.

Signed-off-by: Masahiro Yamada <yamada.masahiro at socionext.com>
---

Changes in v2:
  - Change the arguments of fdt_clk_get() as Simon mentioned
  - rename .get_id() to .fdt_xlate(), which seems a more suitable name

 drivers/clk/clk-uclass.c | 33 +++++++++++++++++++++++++++++++++
 include/clk.h            | 29 +++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index ac3909d..81ef526 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -62,6 +62,39 @@ long clk_set_periph_rate(struct udevice *dev, int periph, ulong rate)
 	return ops->set_periph_rate(dev, periph, rate);
 }
 
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+int fdt_clk_get(struct udevice *dev, int index, struct udevice **clkdevp)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	struct fdtdec_phandle_args clkspec;
+	struct clk_ops *ops;
+	struct udevice *clkdev;
+	int rc;
+
+	rc = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+					    "clocks", "#clock-cells", 0, index,
+					    &clkspec);
+	if (rc)
+		return rc;
+
+	rc = uclass_get_device_by_of_offset(UCLASS_CLK, clkspec.node, &clkdev);
+	if (rc)
+		return rc;
+
+	ops = clk_get_ops(clkdev);
+
+	if (ops->fdt_xlate)
+		rc = ops->fdt_xlate(clkdev, &clkspec);
+	else
+		rc = clkspec.args_count > 0 ? clkspec.args[0] : 0;
+
+	if (clkdevp)
+		*clkdevp = clkdev;
+
+	return rc;
+}
+#endif
+
 UCLASS_DRIVER(clk) = {
 	.id		= UCLASS_CLK,
 	.name		= "clk",
diff --git a/include/clk.h b/include/clk.h
index de15999..3f95395 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 
+struct fdtdec_phandle_args;
 struct udevice;
 
 int soc_clk_dump(void);
@@ -58,6 +59,16 @@ struct clk_ops {
 	 * @return new clock rate in Hz, or -ve error code
 	 */
 	long (*set_periph_rate)(struct udevice *dev, int periph, ulong rate);
+
+	/**
+	 * fdt_xlate() - translate DT arguments into peripheral ID
+	 *
+	 * @dev:	clock provider
+	 * @clkspec:	arguments taken from the device tree
+	 * @return peripheral ID, or -ve error code
+	 */
+	int (*fdt_xlate)(struct udevice *dev,
+			 struct fdtdec_phandle_args *clkspec);
 };
 
 #define clk_get_ops(dev)	((struct clk_ops *)(dev)->driver->ops)
@@ -105,4 +116,22 @@ long clk_get_periph_rate(struct udevice *dev, int periph);
  */
 long clk_set_periph_rate(struct udevice *dev, int periph, ulong rate);
 
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+/**
+ * fdt_clk_get() - Get peripheral ID from device tree
+ *
+ * @dev:	Peripheral device
+ * @index:	index of a phandle to parse out in "clocks" property
+ * @clkdevp:	if not NULL, filled with pointer of clock provider
+ * @return peripheral ID, or -ve error code
+ */
+int fdt_clk_get(struct udevice *dev, int index, struct udevice **clkdevp);
+#else
+static inline int fdt_clk_get(struct udevice *dev, int index,
+			      struct udevice **clkdevp);
+{
+	return -ENOSYS;
+}
+#endif
+
 #endif /* _CLK_H_ */
-- 
1.9.1



More information about the U-Boot mailing list