clk-uclass.c contains all of the UCLASS_CLK specific code but it also contains common clk functionality which is generic between UCLASS_CLK and CCF.
Split this functionality out so that we can reuse it with CCF and avoid building clk-uclass.c entirely. Signed-off-by: Casey Connolly <[email protected]> --- drivers/clk/Makefile | 8 +- drivers/clk/clk-common.c | 220 +++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clk-common.h | 45 +++++++++ drivers/clk/clk-uclass.c | 175 ++-------------------------------- include/linux/clk-provider.h | 3 + 5 files changed, 278 insertions(+), 173 deletions(-) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index dd71d005aada..ee06bffaef72 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -4,19 +4,19 @@ # Wolfgang Denk, DENX Software Engineering, [email protected]. # obj-$(CONFIG_$(PHASE_)CLK) += clk-uclass.o +obj-$(CONFIG_$(PHASE_)CLK) += clk-common.o obj-$(CONFIG_$(PHASE_)CLK_GPIO) += clk-gpio.o obj-$(CONFIG_$(PHASE_)CLK_STUB) += clk-stub.o # Full Linux CCF support -obj-$(CONFIG_$(PHASE_)CLK_CCF_FULL) += ccf/ - +ifdef CONFIG_CLK_CCF_FULL +obj-y += ccf/ +else # U-Boot basic fixed clocks, full CCF has a # different and incompatible implementation -ifndef CONFIG_CLK_CCF_FULL obj-y += basic/ - # U-Boot/IMX "micro" CCF port obj-$(CONFIG_$(PHASE_)CLK_CCF) += uccf/ endif diff --git a/drivers/clk/clk-common.c b/drivers/clk/clk-common.c new file mode 100644 index 000000000000..7f30ad496da2 --- /dev/null +++ b/drivers/clk/clk-common.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass <[email protected]> + * Copyright (c) 2016, NVIDIA CORPORATION. + * Copyright (c) 2018, Theobroma Systems Design und Consulting GmbH + * + * Common clock support code shared between CCF_FULL and UCLASS_CLK + */ + +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dt-structs.h> +#include <log.h> +#include <malloc.h> +#include <asm/global_data.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/devres.h> +#include <dm/read.h> +#include <linux/bug.h> +#include <linux/clk-provider.h> +#include <linux/err.h> + +#include "clk-common.h" + +#if CONFIG_IS_ENABLED(OF_REAL) +int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) +{ + return clk_get_by_index_nodev(dev_ofnode(dev), index, clk); +} + +int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk) +{ + struct ofnode_phandle_args args; + int ret; + + ret = ofnode_parse_phandle_with_args(node, "clocks", "#clock-cells", 0, + index, &args); + + return clk_get_by_index_tail(ret, node, &args, "clocks", + index, clk); +} + +int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk) +{ + int i, ret, err, count; + + bulk->count = 0; + + count = dev_count_phandle_with_args(dev, "clocks", "#clock-cells", 0); + if (count < 1) + return count; + + bulk->clks = devm_kcalloc(dev, count, sizeof(struct clk), GFP_KERNEL); + if (!bulk->clks) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = clk_get_by_index(dev, i, &bulk->clks[i]); + if (ret < 0) + goto bulk_get_err; + + ++bulk->count; + } + + return 0; + +bulk_get_err: + err = clk_release_all(bulk->clks, bulk->count); + if (err) + debug("%s: could not release all clocks for %s\n", + __func__, dev_read_name(dev)); + + return ret; +} + +int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) +{ + return clk_get_by_name_nodev(dev_ofnode(dev), name, clk); +} +#endif /* OF_REAL */ + +int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk) +{ + int index = 0; + + debug("%s(node=%s, name=%s, clk=%p)\n", __func__, + ofnode_get_name(node), name, clk); + clk->dev = NULL; + + if (name) { + index = ofnode_stringlist_search(node, "clock-names", name); + if (index < 0) { + debug("fdt_stringlist_search() failed: %d\n", index); + return index; + } + } + + return clk_get_by_index_nodev(node, index, clk); +} + +int clk_release_all(struct clk *clk, unsigned int count) +{ + unsigned int i; + int ret; + + for (i = 0; i < count; i++) { + debug("%s(clk[%u]=%p)\n", __func__, i, &clk[i]); + + /* check if clock has been previously requested */ + if (!clk[i].dev) + continue; + + ret = clk_disable(&clk[i]); + if (ret && ret != -ENOSYS) + return ret; + } + + return 0; +} + + +int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage) +{ + int ret; + + if (!dev_has_ofnode(dev)) + return 0; + + /* + * To avoid setting defaults twice, don't set them before relocation. + * However, still set them for SPL. And still set them if explicitly + * asked. + */ + if (!(IS_ENABLED(CONFIG_XPL_BUILD) || (gd->flags & GD_FLG_RELOC))) + if (stage != CLK_DEFAULTS_POST_FORCE) + return 0; + + debug("%s(%s)\n", __func__, dev_read_name(dev)); + + ret = clk_set_default_parents(dev, stage); + if (ret) + return ret; + + ret = clk_set_default_rates(dev, stage); + if (ret < 0) + return ret; + + return 0; +} + +struct clk *devm_clk_get(struct udevice *dev, const char *id) +{ + int rc; + struct clk *clk; + + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (unlikely(!clk)) + return ERR_PTR(-ENOMEM); + + rc = clk_get_by_name(dev, id, clk); + if (rc) + return ERR_PTR(rc); + + return clk; +} + +int clk_prepare_bulk(struct clk_bulk *bulk) +{ + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = clk_prepare(&bulk->clks[i]); + if (ret < 0 && ret != -ENOSYS) + return ret; + } + + return 0; +} + +int clk_unprepare_bulk(struct clk_bulk *bulk) +{ + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = clk_prepare(&bulk->clks[i]); + if (ret < 0 && ret != -ENOSYS) + return ret; + } + + return 0; +} + +int clk_enable_bulk(struct clk_bulk *bulk) +{ + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = clk_enable(&bulk->clks[i]); + if (ret < 0 && ret != -ENOSYS) + return ret; + } + + return 0; +} + +int clk_disable_bulk(struct clk_bulk *bulk) +{ + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = clk_disable(&bulk->clks[i]); + if (ret < 0 && ret != -ENOSYS) + return ret; + } + + return 0; +} diff --git a/drivers/clk/clk-common.h b/drivers/clk/clk-common.h new file mode 100644 index 000000000000..fbb1bd5b3ba0 --- /dev/null +++ b/drivers/clk/clk-common.h @@ -0,0 +1,45 @@ + +#include <dm/ofnode.h> +#include <clk.h> + +#ifndef __CLK_COMMON_H__ +#define __CLK_COMMON_H__ + +/* These functions are unused with CCF_FULL */ + +#if !CONFIG_IS_ENABLED(CLK_CCF_FULL) +int clk_get_by_index_tail(int ret, ofnode node, + struct ofnode_phandle_args *args, + const char *list_name, int index, + struct clk *clk); + +int clk_set_default_parents(struct udevice *dev, + enum clk_defaults_stage stage); + + +int clk_set_default_rates(struct udevice *dev, + enum clk_defaults_stage stage); +#else +int clk_get_by_index_tail(int ret, ofnode node, + struct ofnode_phandle_args *args, + const char *list_name, int index, + struct clk *clk) +{ + return -ENOSYS; +} + +int clk_set_default_parents(struct udevice *dev, + enum clk_defaults_stage stage) +{ + return -ENOSYS; +} + +int clk_set_default_rates(struct udevice *dev, + enum clk_defaults_stage stage) +{ + return -ENOSYS; +} + +#endif /* CONFIG_CLK_CCF_FULL */ + +#endif /* __CLK_COMMON_H__ */ diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index e960d2ad2383..e6036d880cb7 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -23,8 +23,10 @@ #include <linux/bug.h> #include <linux/clk-provider.h> #include <linux/err.h> +#include "clk-common.h" + static inline const struct clk_ops_uboot *clk_dev_ops(struct udevice *dev) { return (const struct clk_ops_uboot *)dev->driver->ops; } @@ -74,9 +76,9 @@ static int clk_of_xlate_default(struct clk *clk, return 0; } -static int clk_get_by_index_tail(int ret, ofnode node, +int clk_get_by_index_tail(int ret, ofnode node, struct ofnode_phandle_args *args, const char *list_name, int index, struct clk *clk) { @@ -114,8 +116,9 @@ err: __func__, ofnode_get_name(node), list_name, index, ret); return log_msg_ret("prop", ret); } +#endif /* OF_REAL */ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name, int index, struct clk *clk) { @@ -139,58 +142,8 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name, return clk_get_by_index_tail(ret, dev_ofnode(dev), &args, "clocks", index, clk); } -int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) -{ - return clk_get_by_index_nodev(dev_ofnode(dev), index, clk); -} - -int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk) -{ - struct ofnode_phandle_args args; - int ret; - - ret = ofnode_parse_phandle_with_args(node, "clocks", "#clock-cells", 0, - index, &args); - - return clk_get_by_index_tail(ret, node, &args, "clocks", - index, clk); -} - -int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk) -{ - int i, ret, err, count; - - bulk->count = 0; - - count = dev_count_phandle_with_args(dev, "clocks", "#clock-cells", 0); - if (count < 1) - return count; - - bulk->clks = devm_kcalloc(dev, count, sizeof(struct clk), GFP_KERNEL); - if (!bulk->clks) - return -ENOMEM; - - for (i = 0; i < count; i++) { - ret = clk_get_by_index(dev, i, &bulk->clks[i]); - if (ret < 0) - goto bulk_get_err; - - ++bulk->count; - } - - return 0; - -bulk_get_err: - err = clk_release_all(bulk->clks, bulk->count); - if (err) - debug("%s: could not release all clocks for %s\n", - __func__, dev_read_name(dev)); - - return ret; -} - static struct clk *clk_set_default_get_by_id(struct clk *clk) { struct clk *c = clk; @@ -206,9 +159,9 @@ static struct clk *clk_set_default_get_by_id(struct clk *clk) return c; } -static int clk_set_default_parents(struct udevice *dev, +int clk_set_default_parents(struct udevice *dev, enum clk_defaults_stage stage) { struct clk clk, parent_clk, *c, *p; int index; @@ -289,9 +242,9 @@ static int clk_set_default_parents(struct udevice *dev, return 0; } -static int clk_set_default_rates(struct udevice *dev, +int clk_set_default_rates(struct udevice *dev, enum clk_defaults_stage stage) { struct clk clk, *c; int index; @@ -371,62 +324,8 @@ fail: free(rates); return ret; } -int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage) -{ - int ret; - - if (!dev_has_ofnode(dev)) - return 0; - - /* - * To avoid setting defaults twice, don't set them before relocation. - * However, still set them for SPL. And still set them if explicitly - * asked. - */ - if (!(IS_ENABLED(CONFIG_XPL_BUILD) || (gd->flags & GD_FLG_RELOC))) - if (stage != CLK_DEFAULTS_POST_FORCE) - return 0; - - debug("%s(%s)\n", __func__, dev_read_name(dev)); - - ret = clk_set_default_parents(dev, stage); - if (ret) - return ret; - - ret = clk_set_default_rates(dev, stage); - if (ret < 0) - return ret; - - return 0; -} - -int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) -{ - return clk_get_by_name_nodev(dev_ofnode(dev), name, clk); -} -#endif /* OF_REAL */ - -int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk) -{ - int index = 0; - - debug("%s(node=%s, name=%s, clk=%p)\n", __func__, - ofnode_get_name(node), name, clk); - clk->dev = NULL; - - if (name) { - index = ofnode_stringlist_search(node, "clock-names", name); - if (index < 0) { - debug("fdt_stringlist_search() failed: %d\n", index); - return index; - } - } - - return clk_get_by_index_nodev(node, index, clk); -} - const char * clk_resolve_parent_clk(struct udevice *dev, const char *name) { struct udevice *parent; @@ -443,28 +342,8 @@ clk_resolve_parent_clk(struct udevice *dev, const char *name) return clk.dev->name; } -int clk_release_all(struct clk *clk, unsigned int count) -{ - unsigned int i; - int ret; - - for (i = 0; i < count; i++) { - debug("%s(clk[%u]=%p)\n", __func__, i, &clk[i]); - - /* check if clock has been previously requested */ - if (!clk[i].dev) - continue; - - ret = clk_disable(&clk[i]); - if (ret && ret != -ENOSYS) - return ret; - } - - return 0; -} - int clk_request(struct udevice *dev, struct clk *clk) { const struct clk_ops_uboot *ops; @@ -704,21 +583,8 @@ int clk_enable(struct clk *clk) return 0; } -int clk_enable_bulk(struct clk_bulk *bulk) -{ - int i, ret; - - for (i = 0; i < bulk->count; i++) { - ret = clk_enable(&bulk->clks[i]); - if (ret < 0 && ret != -ENOSYS) - return ret; - } - - return 0; -} - int clk_disable(struct clk *clk) { const struct clk_ops_uboot *ops; struct clk *clkp = NULL; @@ -769,21 +635,8 @@ int clk_disable(struct clk *clk) return 0; } -int clk_disable_bulk(struct clk_bulk *bulk) -{ - int i, ret; - - for (i = 0; i < bulk->count; i++) { - ret = clk_disable(&bulk->clks[i]); - if (ret < 0 && ret != -ENOSYS) - return ret; - } - - return 0; -} - int clk_get_by_id(ulong id, struct clk **clkp) { struct udevice *dev; struct uclass *uc; @@ -821,24 +674,8 @@ bool clk_is_match(const struct clk *p, const struct clk *q) return false; } -struct clk *devm_clk_get(struct udevice *dev, const char *id) -{ - int rc; - struct clk *clk; - - clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); - if (unlikely(!clk)) - return ERR_PTR(-ENOMEM); - - rc = clk_get_by_name(dev, id, clk); - if (rc) - return ERR_PTR(rc); - - return clk; -} - int clk_prepare(struct clk *clk) { return 0; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 4fcdb5a86799..17d6190134dd 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -39,8 +39,11 @@ */ #if CONFIG_IS_ENABLED(CLK_CCF_FULL) #include "clk-provider-ccf_full.h" #else +/* Forward-declare clk_hw so we can compile code that references it even though it's unused*/ +struct clk_hw; + #include "clk-provider-uccf.h" #endif #endif /* __LINUX_CLK_PROVIDER_H */ -- 2.55.0
