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.masah...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot