From 822c250e154cd44cf60a4f0d647aa70abea09520 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 27 Mar 2012 15:23:22 +0800 Subject: clk: add "const" for clk_ops of basic clks The clk_ops of basic clks should have "const" to match the definition in "struct clk" and clk_register prototype. Signed-off-by: Shawn Guo Signed-off-by: Mike Turquette --- include/linux/clk-private.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 5e4312b6f5cc..5f4ccd7cd761 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -55,7 +55,7 @@ struct clk { * alternative macro for static initialization */ -extern struct clk_ops clk_fixed_rate_ops; +extern const struct clk_ops clk_fixed_rate_ops; #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ _fixed_rate_flags) \ @@ -78,7 +78,7 @@ extern struct clk_ops clk_fixed_rate_ops; .flags = _flags, \ }; -extern struct clk_ops clk_gate_ops; +extern const struct clk_ops clk_gate_ops; #define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \ _flags, _reg, _bit_idx, \ @@ -110,7 +110,7 @@ extern struct clk_ops clk_gate_ops; .flags = _flags, \ }; -extern struct clk_ops clk_divider_ops; +extern const struct clk_ops clk_divider_ops; #define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ _flags, _reg, _shift, _width, \ @@ -143,7 +143,7 @@ extern struct clk_ops clk_divider_ops; .flags = _flags, \ }; -extern struct clk_ops clk_mux_ops; +extern const struct clk_ops clk_mux_ops; #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ _reg, _shift, _width, \ -- cgit v1.2.3 From bffad66e31fe9d94cd096f2e4de7c683e1ae32ef Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 27 Mar 2012 15:23:23 +0800 Subject: clk: declare clk_ops of basic clks in clk-provider.h Besides the static initialization, the clk_ops of basic clks could also be used by particular clk type being subclass of the basic clks. For example, clk_busy_divider has the same clk_ops as clk_divider, except it has to wait for a busy bit before return success with .set_rate. clk_busy_divider will somehow reuse clk_ops of clk_divider. Since clk-provider.h is included by clk-private.h, it's safe to move those clk_ops declaration of basic clks form clk-private.h into clk-provider.h, so that implementation of clks like clk_busy_divider above do not need to include clk-private.h to access those clk_ops. Signed-off-by: Shawn Guo Signed-off-by: Mike Turquette --- include/linux/clk-private.h | 8 -------- include/linux/clk-provider.h | 4 ++++ 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 5f4ccd7cd761..f19fee0190cb 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -55,8 +55,6 @@ struct clk { * alternative macro for static initialization */ -extern const struct clk_ops clk_fixed_rate_ops; - #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ _fixed_rate_flags) \ static struct clk _name; \ @@ -78,8 +76,6 @@ extern const struct clk_ops clk_fixed_rate_ops; .flags = _flags, \ }; -extern const struct clk_ops clk_gate_ops; - #define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \ _flags, _reg, _bit_idx, \ _gate_flags, _lock) \ @@ -110,8 +106,6 @@ extern const struct clk_ops clk_gate_ops; .flags = _flags, \ }; -extern const struct clk_ops clk_divider_ops; - #define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ _flags, _reg, _shift, _width, \ _divider_flags, _lock) \ @@ -143,8 +137,6 @@ extern const struct clk_ops clk_divider_ops; .flags = _flags, \ }; -extern const struct clk_ops clk_mux_ops; - #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ _reg, _shift, _width, \ _mux_flags, _lock) \ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5508897ad376..6eb8e5da788e 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -149,6 +149,7 @@ struct clk_fixed_rate { u8 flags; }; +extern const struct clk_ops clk_fixed_rate_ops; struct clk *clk_register_fixed_rate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate); @@ -180,6 +181,7 @@ struct clk_gate { #define CLK_GATE_SET_TO_DISABLE BIT(0) +extern const struct clk_ops clk_gate_ops; struct clk *clk_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, @@ -218,6 +220,7 @@ struct clk_divider { #define CLK_DIVIDER_ONE_BASED BIT(0) #define CLK_DIVIDER_POWER_OF_TWO BIT(1) +extern const struct clk_ops clk_divider_ops; struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -252,6 +255,7 @@ struct clk_mux { #define CLK_MUX_INDEX_ONE BIT(0) #define CLK_MUX_INDEX_BIT BIT(1) +extern const struct clk_ops clk_mux_ops; struct clk *clk_register_mux(struct device *dev, const char *name, char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, -- cgit v1.2.3 From 7e87aed965fa7a642fc299af96d370dad7b5b814 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Apr 2012 15:31:23 +0100 Subject: clk: Remove comment for end of CONFIG_COMMON_CLK section The comment is inaccurate (it actually ends the CONFIG_COMMON_CLK section, there's no else) and given that we've just got a single level of ifdef isn't really needed anyway. Signed-off-by: Mark Brown Signed-off-by: Mike Turquette --- include/linux/clk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/clk.h b/include/linux/clk.h index b0252726df61..c9547d99e52c 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -81,7 +81,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb); int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); -#endif /* !CONFIG_COMMON_CLK */ +#endif /** * clk_get - lookup and obtain a reference to a clock producer. -- cgit v1.2.3 From d305fb78f31209596c9135d396a0d3af7ac86947 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 21 Mar 2012 20:01:20 +0000 Subject: clk: Constify parent name arrays Drivers should be able to declare their arrays of parent names as const so the APIs need to accept const arguments. Signed-off-by: Mark Brown [mturquette@linaro.org: constified gate] Signed-off-by: Mike Turquette --- drivers/clk/clk-mux.c | 2 +- drivers/clk/clk.c | 2 +- include/linux/clk-private.h | 2 +- include/linux/clk-provider.h | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 54244889a948..bd5e598b9f1e 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -89,7 +89,7 @@ const struct clk_ops clk_mux_ops = { EXPORT_SYMBOL_GPL(clk_mux_ops); struct clk *clk_register_mux(struct device *dev, const char *name, - char **parent_names, u8 num_parents, unsigned long flags, + const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock) { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a24b121747ac..ddade8759ea9 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1328,7 +1328,7 @@ out: */ struct clk *clk_register(struct device *dev, const char *name, const struct clk_ops *ops, struct clk_hw *hw, - char **parent_names, u8 num_parents, unsigned long flags) + const char **parent_names, u8 num_parents, unsigned long flags) { struct clk *clk; diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index f19fee0190cb..e9c8b9841b16 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -30,7 +30,7 @@ struct clk { const struct clk_ops *ops; struct clk_hw *hw; struct clk *parent; - char **parent_names; + const char **parent_names; struct clk **parents; u8 num_parents; unsigned long rate; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 6eb8e5da788e..8981435f9064 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -176,7 +176,7 @@ struct clk_gate { u8 bit_idx; u8 flags; spinlock_t *lock; - char *parent[1]; + const char *parent[1]; }; #define CLK_GATE_SET_TO_DISABLE BIT(0) @@ -214,7 +214,7 @@ struct clk_divider { u8 width; u8 flags; spinlock_t *lock; - char *parent[1]; + const char *parent[1]; }; #define CLK_DIVIDER_ONE_BASED BIT(0) @@ -257,7 +257,7 @@ struct clk_mux { extern const struct clk_ops clk_mux_ops; struct clk *clk_register_mux(struct device *dev, const char *name, - char **parent_names, u8 num_parents, unsigned long flags, + const char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock); @@ -278,7 +278,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name, */ struct clk *clk_register(struct device *dev, const char *name, const struct clk_ops *ops, struct clk_hw *hw, - char **parent_names, u8 num_parents, unsigned long flags); + const char **parent_names, u8 num_parents, unsigned long flags); /* helper functions */ const char *__clk_get_name(struct clk *clk); -- cgit v1.2.3 From d1302a36a7f1c33d1a8babc6a510e1401a5e5aed Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Thu, 29 Mar 2012 14:30:40 -0700 Subject: clk: core: copy parent_names & return error codes This patch cleans up clk_register and solves a few bugs by teaching clk_register and __clk_init to return error codes (instead of just NULL) to better align with the existing clk.h api. Along with that change this patch also introduces a new behavior whereby clk_register copies the parent_names array, thus allowing platforms to declare their parent_names arrays as __initdata. Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 65 ++++++++++++++++++++++++++++++++++++-------- include/linux/clk-private.h | 4 ++- include/linux/clk-provider.h | 3 +- 3 files changed, 58 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ddade8759ea9..8f7c3849c8f6 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1185,34 +1185,41 @@ EXPORT_SYMBOL_GPL(clk_set_parent); * very large numbers of clocks that need to be statically initialized. It is * a layering violation to include clk-private.h from any code which implements * a clock's .ops; as such any statically initialized clock data MUST be in a - * separate C file from the logic that implements it's operations. + * separate C file from the logic that implements it's operations. Returns 0 + * on success, otherwise an error code. */ -void __clk_init(struct device *dev, struct clk *clk) +int __clk_init(struct device *dev, struct clk *clk) { - int i; + int i, ret = 0; struct clk *orphan; struct hlist_node *tmp, *tmp2; if (!clk) - return; + return -EINVAL; mutex_lock(&prepare_lock); /* check to see if a clock with this name is already registered */ - if (__clk_lookup(clk->name)) + if (__clk_lookup(clk->name)) { + pr_debug("%s: clk %s already initialized\n", + __func__, clk->name); + ret = -EEXIST; goto out; + } /* check that clk_ops are sane. See Documentation/clk.txt */ if (clk->ops->set_rate && !(clk->ops->round_rate && clk->ops->recalc_rate)) { pr_warning("%s: %s must implement .round_rate & .recalc_rate\n", __func__, clk->name); + ret = -EINVAL; goto out; } if (clk->ops->set_parent && !clk->ops->get_parent) { pr_warning("%s: %s must implement .get_parent & .set_parent\n", __func__, clk->name); + ret = -EINVAL; goto out; } @@ -1308,7 +1315,7 @@ void __clk_init(struct device *dev, struct clk *clk) out: mutex_unlock(&prepare_lock); - return; + return ret; } /** @@ -1324,29 +1331,63 @@ out: * clk_register is the primary interface for populating the clock tree with new * clock nodes. It returns a pointer to the newly allocated struct clk which * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. */ struct clk *clk_register(struct device *dev, const char *name, const struct clk_ops *ops, struct clk_hw *hw, const char **parent_names, u8 num_parents, unsigned long flags) { + int i, ret; struct clk *clk; clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) - return NULL; + if (!clk) { + pr_err("%s: could not allocate clk\n", __func__); + ret = -ENOMEM; + goto fail_out; + } clk->name = name; clk->ops = ops; clk->hw = hw; clk->flags = flags; - clk->parent_names = parent_names; clk->num_parents = num_parents; hw->clk = clk; - __clk_init(dev, clk); + /* allocate local copy in case parent_names is __initdata */ + clk->parent_names = kzalloc((sizeof(char*) * num_parents), + GFP_KERNEL); + + if (!clk->parent_names) { + pr_err("%s: could not allocate clk->parent_names\n", __func__); + ret = -ENOMEM; + goto fail_parent_names; + } + + + /* copy each string name in case parent_names is __initdata */ + for (i = 0; i < num_parents; i++) { + clk->parent_names[i] = kstrdup(parent_names[i], GFP_KERNEL); + if (!clk->parent_names[i]) { + pr_err("%s: could not copy parent_names\n", __func__); + ret = -ENOMEM; + goto fail_parent_names_copy; + } + } + + ret = __clk_init(dev, clk); + if (!ret) + return clk; - return clk; +fail_parent_names_copy: + while (--i >= 0) + kfree(clk->parent_names[i]); + kfree(clk->parent_names); +fail_parent_names: + kfree(clk); +fail_out: + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(clk_register); diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index e9c8b9841b16..e7032fdd45eb 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -181,8 +181,10 @@ struct clk { * * It is not necessary to call clk_register if __clk_init is used directly with * statically initialized clock data. + * + * Returns 0 on success, otherwise an error code. */ -void __clk_init(struct device *dev, struct clk *clk); +int __clk_init(struct device *dev, struct clk *clk); #endif /* CONFIG_COMMON_CLK */ #endif /* CLK_PRIVATE_H */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 8981435f9064..97f9fabf3be2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -274,7 +274,8 @@ struct clk *clk_register_mux(struct device *dev, const char *name, * clk_register is the primary interface for populating the clock tree with new * clock nodes. It returns a pointer to the newly allocated struct clk which * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. */ struct clk *clk_register(struct device *dev, const char *name, const struct clk_ops *ops, struct clk_hw *hw, -- cgit v1.2.3 From 27d545915fd49cbe18a3877d82359896e9851efb Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Mon, 26 Mar 2012 17:51:03 -0700 Subject: clk: basic: improve parent_names & return errors This patch is the basic clk version of 'clk: core: copy parent_names & return error codes'. The registration functions are changed to allow the core code to copy the array of strings and allow platforms to declare those arrays as __initdata. This patch also converts all of the basic clk registration functions to return error codes which better aligns them with the existing clk.h api. Signed-off-by: Mike Turquette --- drivers/clk/clk-divider.c | 34 +++++++++++++++++++--------------- drivers/clk/clk-fixed-rate.c | 40 ++++++++++++++++++---------------------- drivers/clk/clk-gate.c | 34 +++++++++++++++++++--------------- drivers/clk/clk-mux.c | 10 ++++++++-- include/linux/clk-provider.h | 2 -- 5 files changed, 64 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index b1c4b02aaaf1..5fc541d017f1 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -153,6 +153,18 @@ const struct clk_ops clk_divider_ops = { }; EXPORT_SYMBOL_GPL(clk_divider_ops); +/** + * clk_register_divider - register a divider clock with the clock framework + * @dev: device registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @reg: register address to adjust divider + * @shift: number of bits to shift the bitfield + * @width: width of the bitfield + * @clk_divider_flags: divider-specific flags for this clock + * @lock: shared register lock for this clock + */ struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -161,11 +173,11 @@ struct clk *clk_register_divider(struct device *dev, const char *name, struct clk_divider *div; struct clk *clk; + /* allocate the divider */ div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); - if (!div) { pr_err("%s: could not allocate divider clk\n", __func__); - return NULL; + return ERR_PTR(-ENOMEM); } /* struct clk_divider assignments */ @@ -175,23 +187,15 @@ struct clk *clk_register_divider(struct device *dev, const char *name, div->flags = clk_divider_flags; div->lock = lock; - if (parent_name) { - div->parent[0] = kstrdup(parent_name, GFP_KERNEL); - if (!div->parent[0]) - goto out; - } - + /* register the clock */ clk = clk_register(dev, name, &clk_divider_ops, &div->hw, - div->parent, + (parent_name ? &parent_name: NULL), (parent_name ? 1 : 0), flags); - if (clk) - return clk; -out: - kfree(div->parent[0]); - kfree(div); + if (IS_ERR(clk)) + kfree(div); - return NULL; + return clk; } diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 027e47704de9..b555a04c8df8 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -38,16 +38,23 @@ const struct clk_ops clk_fixed_rate_ops = { }; EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); +/** + * clk_register_fixed_rate - register fixed-rate clock with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @flags: framework-specific flags + * @fixed_rate: non-adjustable clock rate + */ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate) { struct clk_fixed_rate *fixed; - char **parent_names = NULL; - u8 len; + struct clk *clk; + /* allocate fixed-rate clock */ fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); - if (!fixed) { pr_err("%s: could not allocate fixed clk\n", __func__); return ERR_PTR(-ENOMEM); @@ -56,26 +63,15 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, /* struct clk_fixed_rate assignments */ fixed->fixed_rate = fixed_rate; - if (parent_name) { - parent_names = kmalloc(sizeof(char *), GFP_KERNEL); - - if (! parent_names) - goto out; - - len = sizeof(char) * strlen(parent_name); - - parent_names[0] = kmalloc(len, GFP_KERNEL); - - if (!parent_names[0]) - goto out; - - strncpy(parent_names[0], parent_name, len); - } - -out: - return clk_register(dev, name, + /* register the clock */ + clk = clk_register(dev, name, &clk_fixed_rate_ops, &fixed->hw, - parent_names, + (parent_name ? &parent_name : NULL), (parent_name ? 1 : 0), flags); + + if (IS_ERR(clk)) + kfree(fixed); + + return clk; } diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index fe2ff9e774c2..42a4b941b6e7 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -105,6 +105,17 @@ const struct clk_ops clk_gate_ops = { }; EXPORT_SYMBOL_GPL(clk_gate_ops); +/** + * clk_register_gate - register a gate clock with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @flags: framework-specific flags for this clock + * @reg: register address to control gating of this clock + * @bit_idx: which bit in the register controls gating of this clock + * @clk_gate_flags: gate-specific flags for this clock + * @lock: shared register lock for this clock + */ struct clk *clk_register_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, @@ -113,11 +124,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name, struct clk_gate *gate; struct clk *clk; + /* allocate the gate */ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); - if (!gate) { pr_err("%s: could not allocate gated clk\n", __func__); - return NULL; + return ERR_PTR(-ENOMEM); } /* struct clk_gate assignments */ @@ -126,22 +137,15 @@ struct clk *clk_register_gate(struct device *dev, const char *name, gate->flags = clk_gate_flags; gate->lock = lock; - if (parent_name) { - gate->parent[0] = kstrdup(parent_name, GFP_KERNEL); - if (!gate->parent[0]) - goto out; - } - + /* register the clock */ clk = clk_register(dev, name, &clk_gate_ops, &gate->hw, - gate->parent, + (parent_name ? &parent_name : NULL), (parent_name ? 1 : 0), flags); - if (clk) - return clk; -out: - kfree(gate->parent[0]); - kfree(gate); - return NULL; + if (IS_ERR(clk)) + kfree(gate); + + return clk; } diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index bd5e598b9f1e..6e58f11ab81f 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -94,9 +94,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name, u8 clk_mux_flags, spinlock_t *lock) { struct clk_mux *mux; + struct clk *clk; + /* allocate the mux */ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); - if (!mux) { pr_err("%s: could not allocate mux clk\n", __func__); return ERR_PTR(-ENOMEM); @@ -109,6 +110,11 @@ struct clk *clk_register_mux(struct device *dev, const char *name, mux->flags = clk_mux_flags; mux->lock = lock; - return clk_register(dev, name, &clk_mux_ops, &mux->hw, + clk = clk_register(dev, name, &clk_mux_ops, &mux->hw, parent_names, num_parents, flags); + + if (IS_ERR(clk)) + kfree(mux); + + return clk; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 97f9fabf3be2..3323d24a7be4 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -176,7 +176,6 @@ struct clk_gate { u8 bit_idx; u8 flags; spinlock_t *lock; - const char *parent[1]; }; #define CLK_GATE_SET_TO_DISABLE BIT(0) @@ -214,7 +213,6 @@ struct clk_divider { u8 width; u8 flags; spinlock_t *lock; - const char *parent[1]; }; #define CLK_DIVIDER_ONE_BASED BIT(0) -- cgit v1.2.3 From 1c0035d710dd3bfa86d58f851b8737c7f11a9bbc Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 12 Apr 2012 20:50:18 +0800 Subject: clk: pass parent_rate into .set_rate For most of .set_rate implementation, parent_rate will be used, so just like passing parent_rate into .recalc_rate, let's pass parent_rate into .set_rate too. It also updates the kernel doc for .set_rate ops. Signed-off-by: Shawn Guo Signed-off-by: Mike Turquette --- drivers/clk/clk-divider.c | 5 +++-- drivers/clk/clk.c | 2 +- include/linux/clk-provider.h | 21 +++++++-------------- 3 files changed, 11 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 03b127c0313b..90627e4069af 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -111,14 +111,15 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, return *prate / div; } -static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { struct clk_divider *divider = to_clk_divider(hw); unsigned int div; unsigned long flags = 0; u32 val; - div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; + div = parent_rate / rate; if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) div--; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1ab4f7e5c7ef..62ecac53b0a2 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -848,7 +848,7 @@ static void clk_change_rate(struct clk *clk) old_rate = clk->rate; if (clk->ops->set_rate) - clk->ops->set_rate(clk->hw, clk->new_rate); + clk->ops->set_rate(clk->hw, clk->new_rate, clk->parent->rate); if (clk->ops->recalc_rate) clk->rate = clk->ops->recalc_rate(clk->hw, diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 3323d24a7be4..cb82918d8fe0 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -88,19 +88,11 @@ struct clk_hw { * array index into the value programmed into the hardware. * Returns 0 on success, -EERROR otherwise. * - * @set_rate: Change the rate of this clock. If this callback returns - * CLK_SET_RATE_PARENT, the rate change will be propagated to the - * parent clock (which may propagate again if the parent clock - * also sets this flag). The requested rate of the parent is - * passed back from the callback in the second 'unsigned long *' - * argument. Note that it is up to the hardware clock's set_rate - * implementation to insure that clocks do not run out of spec - * when propgating the call to set_rate up to the parent. One way - * to do this is to gate the clock (via clk_disable and/or - * clk_unprepare) before calling clk_set_rate, then ungating it - * afterward. If your clock also has the CLK_GATE_SET_RATE flag - * set then this will insure safety. Returns 0 on success, - * -EERROR otherwise. + * @set_rate: Change the rate of this clock. The requested rate is specified + * by the second argument, which should typically be the return + * of .round_rate call. The third argument gives the parent rate + * which is likely helpful for most .set_rate implementation. + * Returns 0 on success, -EERROR otherwise. * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable @@ -125,7 +117,8 @@ struct clk_ops { unsigned long *); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); - int (*set_rate)(struct clk_hw *hw, unsigned long); + int (*set_rate)(struct clk_hw *hw, unsigned long, + unsigned long); void (*init)(struct clk_hw *hw); }; -- cgit v1.2.3 From 1f73f31ad6e37df0679f6842b7405d96515ec8b1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 17 Apr 2012 16:45:35 +0530 Subject: clk: Fix typo in comment CLK_MUX_INDEX_BIT is mistakenly written as CLK_MUX_INDEX_BITWISE in comment. Fix it. CLK_GATE_SET_TO_DISABLE is mistakenly written as CLK_GATE_SET_DISABLE in comment. Fix it. Signed-off-by: Viresh Kumar Signed-off-by: Mike Turquette --- include/linux/clk-provider.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index cb82918d8fe0..8f2148942b87 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -159,7 +159,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, * Clock which can gate its output. Implements .enable & .disable * * Flags: - * CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to + * CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to * enable the clock. Setting this flag does the opposite: setting the bit * disable the clock and clearing it enables the clock */ @@ -232,7 +232,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, * * Flags: * CLK_MUX_INDEX_ONE - register index starts at 1, not 0 - * CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two) + * CLK_MUX_INDEX_BIT - register index is a single bit (power of two) */ struct clk_mux { struct clk_hw hw; -- cgit v1.2.3 From 182f9e8cd5e451911a37f121f942409205ede0d6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 17 Apr 2012 16:45:36 +0530 Subject: clk: clk-private: Add DEFINE_CLK macro All macros used for creating different kind of clocks have similar code for initializing struct clk. This patch removes those redundant lines and create another macro DEFINE_CLK. Signed-off-by: Viresh Kumar Signed-off-by: Mike Turquette --- include/linux/clk-private.h | 59 +++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index e7032fdd45eb..eeae7a3cfc45 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -55,6 +55,18 @@ struct clk { * alternative macro for static initialization */ +#define DEFINE_CLK(_name, _ops, _flags, _parent_names, \ + _parents) \ + static struct clk _name = { \ + .name = #_name, \ + .ops = &_ops, \ + .hw = &_name##_hw.hw, \ + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .parents = _parents, \ + .flags = _flags, \ + } + #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ _fixed_rate_flags) \ static struct clk _name; \ @@ -66,15 +78,8 @@ struct clk { .fixed_rate = _rate, \ .flags = _fixed_rate_flags, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_fixed_rate_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _name##_parent_names, \ - .num_parents = \ - ARRAY_SIZE(_name##_parent_names), \ - .flags = _flags, \ - }; + DEFINE_CLK(_name, clk_fixed_rate_ops, _flags, \ + _name##_parent_names, NULL); #define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \ _flags, _reg, _bit_idx, \ @@ -95,16 +100,8 @@ struct clk { .flags = _gate_flags, \ .lock = _lock, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_gate_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _name##_parent_names, \ - .num_parents = \ - ARRAY_SIZE(_name##_parent_names), \ - .parents = _name##_parents, \ - .flags = _flags, \ - }; + DEFINE_CLK(_name, clk_gate_ops, _flags, \ + _name##_parent_names, _name##_parents); #define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ _flags, _reg, _shift, _width, \ @@ -126,16 +123,8 @@ struct clk { .flags = _divider_flags, \ .lock = _lock, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_divider_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _name##_parent_names, \ - .num_parents = \ - ARRAY_SIZE(_name##_parent_names), \ - .parents = _name##_parents, \ - .flags = _flags, \ - }; + DEFINE_CLK(_name, clk_divider_ops, _flags, \ + _name##_parent_names, _name##_parents); #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ _reg, _shift, _width, \ @@ -151,16 +140,8 @@ struct clk { .flags = _mux_flags, \ .lock = _lock, \ }; \ - static struct clk _name = { \ - .name = #_name, \ - .ops = &clk_mux_ops, \ - .hw = &_name##_hw.hw, \ - .parent_names = _parent_names, \ - .num_parents = \ - ARRAY_SIZE(_parent_names), \ - .parents = _parents, \ - .flags = _flags, \ - }; + DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \ + _parents); /** * __clk_init - initialize the data structures in a struct clk -- cgit v1.2.3 From 8b7730ddff5affd623bed2affa0d0fa47ebbad3b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 9 Apr 2012 15:24:59 -0500 Subject: clk: remove trailing whitespace from clk.h Remove trailing whitespace from 2 lines. Signed-off-by: Rob Herring --- include/linux/clk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk.h b/include/linux/clk.h index c9547d99e52c..0e078bdec09f 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -220,7 +220,7 @@ void clk_put(struct clk *clk); * Returns rounded clock rate in Hz, or negative errno. */ long clk_round_rate(struct clk *clk, unsigned long rate); - + /** * clk_set_rate - set the clock rate for a clock source * @clk: clock source @@ -229,7 +229,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate); * Returns success (0) or negative errno. */ int clk_set_rate(struct clk *clk, unsigned long rate); - + /** * clk_set_parent - set the parent clock source for this clock * @clk: clock source -- cgit v1.2.3 From e447c50e3af5dcad3075c80bd1bdc4e2024b8186 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 27 Apr 2012 17:58:13 +0530 Subject: clk: constify parent name arrays in macros parent name array is now expected to be const char *, make the relevent changes in the clk macros which define default clock types. Signed-off-by: Rajendra Nayak Signed-off-by: Mike Turquette --- include/linux/clk-private.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index eeae7a3cfc45..6ebec83f1a77 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -70,7 +70,7 @@ struct clk { #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ _fixed_rate_flags) \ static struct clk _name; \ - static char *_name##_parent_names[] = {}; \ + static const char *_name##_parent_names[] = {}; \ static struct clk_fixed_rate _name##_hw = { \ .hw = { \ .clk = &_name, \ @@ -85,7 +85,7 @@ struct clk { _flags, _reg, _bit_idx, \ _gate_flags, _lock) \ static struct clk _name; \ - static char *_name##_parent_names[] = { \ + static const char *_name##_parent_names[] = { \ _parent_name, \ }; \ static struct clk *_name##_parents[] = { \ @@ -107,7 +107,7 @@ struct clk { _flags, _reg, _shift, _width, \ _divider_flags, _lock) \ static struct clk _name; \ - static char *_name##_parent_names[] = { \ + static const char *_name##_parent_names[] = { \ _parent_name, \ }; \ static struct clk *_name##_parents[] = { \ -- cgit v1.2.3 From 0197b3ea0f66cd2a11417f58fe1812858ea77908 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 25 Apr 2012 22:58:56 -0700 Subject: clk: Use a separate struct for holding init data. Create a struct clk_init_data to hold all data that needs to be passed from the platfrom specific driver to the common clock framework during clock registration. Add a pointer to this struct inside clk_hw. This has several advantages: * Completely hides struct clk from many clock platform drivers and static clock initialization code that don't care for static initialization of the struct clks. * For platforms that want to do complete static initialization, it removed the need to directly mess with the struct clk's fields while still allowing to statically allocate struct clk. This keeps the code more future proof even if they include clk-private.h. * Simplifies the generic clk_register() function and allows adding optional fields in the future without modifying the function signature. * Simplifies the static initialization of clocks on all platforms by removing the need for forward delcarations or convoluted macros. Signed-off-by: Saravana Kannan [mturquette@linaro.org: kept DEFINE_CLK_* macros and __clk_init] Signed-off-by: Mike Turquette Cc: Andrew Lunn Cc: Rob Herring Cc: Russell King Cc: Jeremy Kerr Cc: Thomas Gleixner Cc: Arnd Bergman Cc: Paul Walmsley Cc: Shawn Guo Cc: Sascha Hauer Cc: Jamie Iles Cc: Richard Zhao Cc: Saravana Kannan Cc: Magnus Damm Cc: Mark Brown Cc: Linus Walleij Cc: Stephen Boyd Cc: Amit Kucheria Cc: Deepak Saxena Cc: Grant Likely --- drivers/clk/clk-divider.c | 14 ++++--- drivers/clk/clk-fixed-rate.c | 14 ++++--- drivers/clk/clk-gate.c | 15 +++++--- drivers/clk/clk-mux.c | 10 ++++- drivers/clk/clk.c | 89 +++++++++++++++++++++++++++----------------- include/linux/clk-private.h | 2 + include/linux/clk-provider.h | 59 ++++++++++++++++++----------- 7 files changed, 129 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 90627e4069af..8ea11b444528 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -167,6 +167,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, { struct clk_divider *div; struct clk *clk; + struct clk_init_data init; /* allocate the divider */ div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); @@ -175,19 +176,22 @@ struct clk *clk_register_divider(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_divider_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + /* struct clk_divider assignments */ div->reg = reg; div->shift = shift; div->width = width; div->flags = clk_divider_flags; div->lock = lock; + div->hw.init = &init; /* register the clock */ - clk = clk_register(dev, name, - &clk_divider_ops, &div->hw, - (parent_name ? &parent_name: NULL), - (parent_name ? 1 : 0), - flags); + clk = clk_register(dev, &div->hw); if (IS_ERR(clk)) kfree(div); diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index b555a04c8df8..cbd246229786 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -52,6 +52,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, { struct clk_fixed_rate *fixed; struct clk *clk; + struct clk_init_data init; /* allocate fixed-rate clock */ fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); @@ -60,15 +61,18 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_fixed_rate_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + /* struct clk_fixed_rate assignments */ fixed->fixed_rate = fixed_rate; + fixed->hw.init = &init; /* register the clock */ - clk = clk_register(dev, name, - &clk_fixed_rate_ops, &fixed->hw, - (parent_name ? &parent_name : NULL), - (parent_name ? 1 : 0), - flags); + clk = clk_register(dev, &fixed->hw); if (IS_ERR(clk)) kfree(fixed); diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 00216164fb9d..578465e04be6 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -119,6 +119,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name, { struct clk_gate *gate; struct clk *clk; + struct clk_init_data init; /* allocate the gate */ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); @@ -127,18 +128,20 @@ struct clk *clk_register_gate(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_gate_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + /* struct clk_gate assignments */ gate->reg = reg; gate->bit_idx = bit_idx; gate->flags = clk_gate_flags; gate->lock = lock; + gate->hw.init = &init; - /* register the clock */ - clk = clk_register(dev, name, - &clk_gate_ops, &gate->hw, - (parent_name ? &parent_name : NULL), - (parent_name ? 1 : 0), - flags); + clk = clk_register(dev, &gate->hw); if (IS_ERR(clk)) kfree(gate); diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 6e58f11ab81f..8e97491902e7 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -95,6 +95,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name, { struct clk_mux *mux; struct clk *clk; + struct clk_init_data init; /* allocate the mux */ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); @@ -103,6 +104,12 @@ struct clk *clk_register_mux(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); } + init.name = name; + init.ops = &clk_mux_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + /* struct clk_mux assignments */ mux->reg = reg; mux->shift = shift; @@ -110,8 +117,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name, mux->flags = clk_mux_flags; mux->lock = lock; - clk = clk_register(dev, name, &clk_mux_ops, &mux->hw, - parent_names, num_parents, flags); + clk = clk_register(dev, &mux->hw); if (IS_ERR(clk)) kfree(mux); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2dd20c01134d..c81803b9ba35 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1169,26 +1169,6 @@ EXPORT_SYMBOL_GPL(clk_set_parent); * * Initializes the lists in struct clk, queries the hardware for the * parent and rate and sets them both. - * - * Any struct clk passed into __clk_init must have the following members - * populated: - * .name - * .ops - * .hw - * .parent_names - * .num_parents - * .flags - * - * Essentially, everything that would normally be passed into clk_register is - * assumed to be initialized already in __clk_init. The other members may be - * populated, but are optional. - * - * __clk_init is only exposed via clk-private.h and is intended for use with - * very large numbers of clocks that need to be statically initialized. It is - * a layering violation to include clk-private.h from any code which implements - * a clock's .ops; as such any statically initialized clock data MUST be in a - * separate C file from the logic that implements it's operations. Returns 0 - * on success, otherwise an error code. */ int __clk_init(struct device *dev, struct clk *clk) { @@ -1320,15 +1300,48 @@ out: return ret; } +/** + * __clk_register - register a clock and return a cookie. + * + * Same as clk_register, except that the .clk field inside hw shall point to a + * preallocated (generally statically allocated) struct clk. None of the fields + * of the struct clk need to be initialized. + * + * The data pointed to by .init and .clk field shall NOT be marked as init + * data. + * + * __clk_register is only exposed via clk-private.h and is intended for use with + * very large numbers of clocks that need to be statically initialized. It is + * a layering violation to include clk-private.h from any code which implements + * a clock's .ops; as such any statically initialized clock data MUST be in a + * separate C file from the logic that implements it's operations. Returns 0 + * on success, otherwise an error code. + */ +struct clk *__clk_register(struct device *dev, struct clk_hw *hw) +{ + int ret; + struct clk *clk; + + clk = hw->clk; + clk->name = hw->init->name; + clk->ops = hw->init->ops; + clk->hw = hw; + clk->flags = hw->init->flags; + clk->parent_names = hw->init->parent_names; + clk->num_parents = hw->init->num_parents; + + ret = __clk_init(dev, clk); + if (ret) + return ERR_PTR(ret); + + return clk; +} +EXPORT_SYMBOL_GPL(__clk_register); + /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock - * @name: clock name - * @ops: operations this clock supports * @hw: link to hardware-specific clock data - * @parent_names: array of string names for all possible parents - * @num_parents: number of possible parents - * @flags: framework-level hints and quirks * * clk_register is the primary interface for populating the clock tree with new * clock nodes. It returns a pointer to the newly allocated struct clk which @@ -1336,9 +1349,7 @@ out: * rest of the clock API. In the event of an error clk_register will return an * error code; drivers must test for an error code after calling clk_register. */ -struct clk *clk_register(struct device *dev, const char *name, - const struct clk_ops *ops, struct clk_hw *hw, - const char **parent_names, u8 num_parents, unsigned long flags) +struct clk *clk_register(struct device *dev, struct clk_hw *hw) { int i, ret; struct clk *clk; @@ -1350,15 +1361,20 @@ struct clk *clk_register(struct device *dev, const char *name, goto fail_out; } - clk->name = name; - clk->ops = ops; + clk->name = kstrdup(hw->init->name, GFP_KERNEL); + if (!clk->name) { + pr_err("%s: could not allocate clk->name\n", __func__); + ret = -ENOMEM; + goto fail_name; + } + clk->ops = hw->init->ops; clk->hw = hw; - clk->flags = flags; - clk->num_parents = num_parents; + clk->flags = hw->init->flags; + clk->num_parents = hw->init->num_parents; hw->clk = clk; /* allocate local copy in case parent_names is __initdata */ - clk->parent_names = kzalloc((sizeof(char*) * num_parents), + clk->parent_names = kzalloc((sizeof(char*) * clk->num_parents), GFP_KERNEL); if (!clk->parent_names) { @@ -1369,8 +1385,9 @@ struct clk *clk_register(struct device *dev, const char *name, /* copy each string name in case parent_names is __initdata */ - for (i = 0; i < num_parents; i++) { - clk->parent_names[i] = kstrdup(parent_names[i], GFP_KERNEL); + for (i = 0; i < clk->num_parents; i++) { + clk->parent_names[i] = kstrdup(hw->init->parent_names[i], + GFP_KERNEL); if (!clk->parent_names[i]) { pr_err("%s: could not copy parent_names\n", __func__); ret = -ENOMEM; @@ -1387,6 +1404,8 @@ fail_parent_names_copy: kfree(clk->parent_names[i]); kfree(clk->parent_names); fail_parent_names: + kfree(clk->name); +fail_name: kfree(clk); fail_out: return ERR_PTR(ret); diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 6ebec83f1a77..b258532162b8 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -167,5 +167,7 @@ struct clk { */ int __clk_init(struct device *dev, struct clk *clk); +struct clk *__clk_register(struct device *dev, struct clk_hw *hw); + #endif /* CONFIG_COMMON_CLK */ #endif /* CLK_PRIVATE_H */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 8f2148942b87..5db3412106b3 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -15,19 +15,6 @@ #ifdef CONFIG_COMMON_CLK -/** - * struct clk_hw - handle for traversing from a struct clk to its corresponding - * hardware-specific structure. struct clk_hw should be declared within struct - * clk_foo and then referenced by the struct clk instance that uses struct - * clk_foo's clk_ops - * - * clk: pointer to the struct clk instance that points back to this struct - * clk_hw instance - */ -struct clk_hw { - struct clk *clk; -}; - /* * flags used across common struct clk. these flags should only affect the * top-level framework. custom flags for dealing with hardware specifics @@ -39,6 +26,8 @@ struct clk_hw { #define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ #define CLK_IS_ROOT BIT(4) /* root clk, has no parent */ +struct clk_hw; + /** * struct clk_ops - Callback operations for hardware clocks; these are to * be provided by the clock implementation, and will be called by drivers @@ -122,6 +111,41 @@ struct clk_ops { void (*init)(struct clk_hw *hw); }; +/** + * struct clk_init_data - holds init data that's common to all clocks and is + * shared between the clock provider and the common clock framework. + * + * @name: clock name + * @ops: operations this clock supports + * @parent_names: array of string names for all possible parents + * @num_parents: number of possible parents + * @flags: framework-level hints and quirks + */ +struct clk_init_data { + const char *name; + const struct clk_ops *ops; + const char **parent_names; + u8 num_parents; + unsigned long flags; +}; + +/** + * struct clk_hw - handle for traversing from a struct clk to its corresponding + * hardware-specific structure. struct clk_hw should be declared within struct + * clk_foo and then referenced by the struct clk instance that uses struct + * clk_foo's clk_ops + * + * @clk: pointer to the struct clk instance that points back to this struct + * clk_hw instance + * + * @init: pointer to struct clk_init_data that contains the init data shared + * with the common clock framework. + */ +struct clk_hw { + struct clk *clk; + struct clk_init_data *init; +}; + /* * DOC: Basic clock implementations common to many platforms * @@ -255,12 +279,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name, /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock - * @name: clock name - * @ops: operations this clock supports * @hw: link to hardware-specific clock data - * @parent_names: array of string names for all possible parents - * @num_parents: number of possible parents - * @flags: framework-level hints and quirks * * clk_register is the primary interface for populating the clock tree with new * clock nodes. It returns a pointer to the newly allocated struct clk which @@ -268,9 +287,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name, * rest of the clock API. In the event of an error clk_register will return an * error code; drivers must test for an error code after calling clk_register. */ -struct clk *clk_register(struct device *dev, const char *name, - const struct clk_ops *ops, struct clk_hw *hw, - const char **parent_names, u8 num_parents, unsigned long flags); +struct clk *clk_register(struct device *dev, struct clk_hw *hw); /* helper functions */ const char *__clk_get_name(struct clk *clk); -- cgit v1.2.3 From f0948f59dbc8e725a96ba16da666e8f5cdd43ba8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 3 May 2012 15:36:14 +0530 Subject: clk: add a fixed factor clock Having fixed factors/dividers in hardware is a common pattern, so add a basic clock type doing this. It basically describes a fixed factor clock using a nominator and a denominator. Signed-off-by: Sascha Hauer Reviewed-by: Viresh Kumar Tested-by: Shawn Guo [mturquette@linaro.org: constify parent_names in static init macro] [mturquette@linaro.org: copy/paste bug from mux in static init macro] [mturquette@linaro.org: fix error handling in clk_register_fixed_factor] [mturquette@linaro.org: improve division accuracy; thanks to Saravana] Signed-off-by: Mike Turquette --- drivers/clk/Makefile | 2 +- drivers/clk/clk-fixed-factor.c | 95 ++++++++++++++++++++++++++++++++++++++++++ include/linux/clk-private.h | 20 +++++++++ include/linux/clk-provider.h | 23 ++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/clk-fixed-factor.c (limited to 'include/linux') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1f736bc11c4b..24aa7144811b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ - clk-mux.o clk-divider.o + clk-mux.o clk-divider.o clk-fixed-factor.o diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c new file mode 100644 index 000000000000..c8c003e217ad --- /dev/null +++ b/drivers/clk/clk-fixed-factor.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Standard functionality for the common clock API. + */ +#include +#include +#include +#include + +/* + * DOC: basic fixed multiplier and divider clock that cannot gate + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is fixed. clk->rate = parent->rate / div * mult + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw) + +static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + return parent_rate * fix->mult / fix->div; +} + +static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { + unsigned long best_parent; + + best_parent = (rate / fix->mult) * fix->div; + *prate = __clk_round_rate(__clk_get_parent(hw->clk), + best_parent); + } + + return (*prate / fix->div) * fix->mult; +} + +static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} + +struct clk_ops clk_fixed_factor_ops = { + .round_rate = clk_factor_round_rate, + .set_rate = clk_factor_set_rate, + .recalc_rate = clk_factor_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); + +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + struct clk_fixed_factor *fix; + struct clk_init_data init; + struct clk *clk; + + fix = kmalloc(sizeof(*fix), GFP_KERNEL); + if (!fix) { + pr_err("%s: could not allocate fixed factor clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_fixed_factor assignments */ + fix->mult = mult; + fix->div = div; + fix->hw.init = &init; + + init.name = name; + init.ops = &clk_fixed_factor_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(dev, &fix->hw); + + if (IS_ERR(clk)) + kfree(fix); + + return clk; +} diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index b258532162b8..eb3f84bc5325 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -143,6 +143,26 @@ struct clk { DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \ _parents); +#define DEFINE_CLK_FIXED_FACTOR(_name, _parent_name, \ + _parent_ptr, _flags, \ + _mult, _div) \ + static struct clk _name; \ + static const char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_fixed_factor _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .mult = _mult, \ + .div = _div, \ + }; \ + DEFINE_CLK(_name, clk_fixed_factor_ops, _flags, \ + _name##_parent_names, _name##_parents); + /** * __clk_init - initialize the data structures in a struct clk * @dev: device initializing this clk, placeholder for now diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5db3412106b3..c1c23b9ec368 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -276,6 +276,29 @@ struct clk *clk_register_mux(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock); +/** + * struct clk_fixed_factor - fixed multiplier and divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @mult: multiplier + * @div: divider + * + * Clock with a fixed multiplier and divider. The output frequency is the + * parent clock rate divided by div and multiplied by mult. + * Implements .recalc_rate, .set_rate and .round_rate + */ + +struct clk_fixed_factor { + struct clk_hw hw; + unsigned int mult; + unsigned int div; +}; + +extern struct clk_ops clk_fixed_factor_ops; +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div); + /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock -- cgit v1.2.3 From 4574b886698dfad6209102fed6136622b5fe1c21 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 6 Apr 2012 17:17:26 +0200 Subject: ARM: Orion: SPI: Add clk/clkdev support. Remove now redundant tclk from SPI platform data. This makes the platform data empty, so remove it. Signed-off-by: Andrew Lunn Tested-by: Jamie Lentin Signed-off-by: Mike Turquette --- arch/arm/mach-dove/common.c | 6 ++-- arch/arm/mach-dove/dove-db-setup.c | 1 - arch/arm/mach-kirkwood/board-dreamplug.c | 1 - arch/arm/mach-kirkwood/common.c | 10 +++++-- arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c | 1 - arch/arm/mach-kirkwood/rd88f6192-nas-setup.c | 1 - arch/arm/mach-kirkwood/t5325-setup.c | 1 - arch/arm/mach-kirkwood/tsx1x-common.c | 1 - arch/arm/mach-mv78xx0/common.c | 2 ++ arch/arm/mach-orion5x/common.c | 4 ++- arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c | 1 - arch/arm/plat-orion/common.c | 38 ++++++++++++++++---------- arch/arm/plat-orion/include/plat/common.h | 11 +++++--- drivers/spi/spi-orion.c | 30 +++++++++++++++----- include/linux/spi/orion_spi.h | 17 ------------ 15 files changed, 70 insertions(+), 55 deletions(-) delete mode 100644 include/linux/spi/orion_spi.h (limited to 'include/linux') diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index 63fe6e612e98..da5b4047464d 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -76,6 +76,8 @@ static void __init clk_init(void) { tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, get_tclk()); + + orion_clkdev_init(tclk); } /***************************************************************************** @@ -162,12 +164,12 @@ void __init dove_uart3_init(void) ****************************************************************************/ void __init dove_spi0_init(void) { - orion_spi_init(DOVE_SPI0_PHYS_BASE, get_tclk()); + orion_spi_init(DOVE_SPI0_PHYS_BASE); } void __init dove_spi1_init(void) { - orion_spi_1_init(DOVE_SPI1_PHYS_BASE, get_tclk()); + orion_spi_1_init(DOVE_SPI1_PHYS_BASE); } /***************************************************************************** diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index ea77ae430b2d..bc2867f11346 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-kirkwood/board-dreamplug.c b/arch/arm/mach-kirkwood/board-dreamplug.c index 985453994dd3..55e357ab2923 100644 --- a/arch/arm/mach-kirkwood/board-dreamplug.c +++ b/arch/arm/mach-kirkwood/board-dreamplug.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index 57b8d1ef3093..476e0b941db7 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -86,10 +86,12 @@ static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx) void __init kirkwood_clk_init(void) { + struct clk *runit; + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, kirkwood_tclk); - kirkwood_register_gate("runit", CGC_BIT_RUNIT); + runit = kirkwood_register_gate("runit", CGC_BIT_RUNIT); kirkwood_register_gate("ge0", CGC_BIT_GE0); kirkwood_register_gate("ge1", CGC_BIT_GE1); kirkwood_register_gate("sata0", CGC_BIT_SATA0); @@ -104,6 +106,10 @@ void __init kirkwood_clk_init(void) kirkwood_register_gate("audio", CGC_BIT_AUDIO); kirkwood_register_gate("tdm", CGC_BIT_TDM); kirkwood_register_gate("tsu", CGC_BIT_TSU); + + /* clkdev entries, mapping clks to devices */ + orion_clkdev_add(NULL, "orion_spi.0", runit); + orion_clkdev_add(NULL, "orion_spi.1", runit); } /***************************************************************************** @@ -270,7 +276,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) void __init kirkwood_spi_init() { kirkwood_clk_ctrl |= CGC_RUNIT; - orion_spi_init(SPI_PHYS_BASE, kirkwood_tclk); + orion_spi_init(SPI_PHYS_BASE); } diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c index 85f6169c2484..6d8364a97810 100644 --- a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c +++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c index fd2c9c8b6831..f742a66a7045 100644 --- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c +++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c index f9d2a11b7f96..bad738e44044 100644 --- a/arch/arm/mach-kirkwood/t5325-setup.c +++ b/arch/arm/mach-kirkwood/t5325-setup.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-kirkwood/tsx1x-common.c b/arch/arm/mach-kirkwood/tsx1x-common.c index 24294b2bc469..8943ede29b44 100644 --- a/arch/arm/mach-kirkwood/tsx1x-common.c +++ b/arch/arm/mach-kirkwood/tsx1x-common.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include "common.h" diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index 73733207f5a9..4c24b46520aa 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -175,6 +175,8 @@ static void __init clk_init(void) { tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, get_tclk()); + + orion_clkdev_init(tclk); } /***************************************************************************** diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 81660522c6b4..2ef82e2f511d 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -79,6 +79,8 @@ static void __init clk_init(void) { tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, orion5x_tclk); + + orion_clkdev_init(tclk); } /***************************************************************************** @@ -144,7 +146,7 @@ void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) ****************************************************************************/ void __init orion5x_spi_init() { - orion_spi_init(SPI_PHYS_BASE, orion5x_tclk); + orion_spi_init(SPI_PHYS_BASE); } diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c index 2c5fab00d205..7b97a9a211ed 100644 --- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 4fdd2e7e74a1..bbe50a948710 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -19,12 +19,32 @@ #include #include #include -#include #include #include #include #include +/* Create a clkdev entry for a given device/clk */ +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk) +{ + struct clk_lookup *cl; + + cl = clkdev_alloc(clk, con_id, dev_id); + if (cl) + clkdev_add(cl); +} + +/* Create clkdev entries for all orion platforms except kirkwood. + Kirkwood has gated clocks for some of its peripherals, so creates + its own clkdev entries. For all the other orion devices, create + clkdev entries to the tclk. */ +void __init orion_clkdev_init(struct clk *tclk) +{ + orion_clkdev_add(NULL, "orion_spi.0", tclk); + orion_clkdev_add(NULL, "orion_spi.1", tclk); +} + /* Fill in the resources structure and link it into the platform device structure. There is always a memory region, and nearly always an interrupt.*/ @@ -523,44 +543,32 @@ void __init orion_i2c_1_init(unsigned long mapbase, /***************************************************************************** * SPI ****************************************************************************/ -static struct orion_spi_info orion_spi_plat_data; static struct resource orion_spi_resources; static struct platform_device orion_spi = { .name = "orion_spi", .id = 0, - .dev = { - .platform_data = &orion_spi_plat_data, - }, }; -static struct orion_spi_info orion_spi_1_plat_data; static struct resource orion_spi_1_resources; static struct platform_device orion_spi_1 = { .name = "orion_spi", .id = 1, - .dev = { - .platform_data = &orion_spi_1_plat_data, - }, }; /* Note: The SPI silicon core does have interrupts. However the * current Linux software driver does not use interrupts. */ -void __init orion_spi_init(unsigned long mapbase, - unsigned long tclk) +void __init orion_spi_init(unsigned long mapbase) { - orion_spi_plat_data.tclk = tclk; fill_resources(&orion_spi, &orion_spi_resources, mapbase, SZ_512 - 1, NO_IRQ); platform_device_register(&orion_spi); } -void __init orion_spi_1_init(unsigned long mapbase, - unsigned long tclk) +void __init orion_spi_1_init(unsigned long mapbase) { - orion_spi_1_plat_data.tclk = tclk; fill_resources(&orion_spi_1, &orion_spi_1_resources, mapbase, SZ_512 - 1, NO_IRQ); platform_device_register(&orion_spi_1); diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h index a7fa005a5a0e..d188a1aa6f56 100644 --- a/arch/arm/plat-orion/include/plat/common.h +++ b/arch/arm/plat-orion/include/plat/common.h @@ -70,11 +70,9 @@ void __init orion_i2c_1_init(unsigned long mapbase, unsigned long irq, unsigned long freq_m); -void __init orion_spi_init(unsigned long mapbase, - unsigned long tclk); +void __init orion_spi_init(unsigned long mapbase); -void __init orion_spi_1_init(unsigned long mapbase, - unsigned long tclk); +void __init orion_spi_1_init(unsigned long mapbase); void __init orion_wdt_init(unsigned long tclk); @@ -106,4 +104,9 @@ void __init orion_crypto_init(unsigned long mapbase, unsigned long srambase, unsigned long sram_size, unsigned long irq); + +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk); + +void __init orion_clkdev_init(struct clk *tclk); #endif diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index e496f799b7a9..dfd04e91fa6d 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -16,8 +16,8 @@ #include #include #include -#include #include +#include #include #define DRIVER_NAME "orion_spi" @@ -46,6 +46,7 @@ struct orion_spi { unsigned int max_speed; unsigned int min_speed; struct orion_spi_info *spi_info; + struct clk *clk; }; static struct workqueue_struct *orion_spi_wq; @@ -104,7 +105,7 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) orion_spi = spi_master_get_devdata(spi->master); - tclk_hz = orion_spi->spi_info->tclk; + tclk_hz = clk_get_rate(orion_spi->clk); /* * the supported rates are: 4,6,8...30 @@ -450,6 +451,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) struct orion_spi *spi; struct resource *r; struct orion_spi_info *spi_info; + unsigned long tclk_hz; int status = 0; spi_info = pdev->dev.platform_data; @@ -476,19 +478,28 @@ static int __init orion_spi_probe(struct platform_device *pdev) spi->master = master; spi->spi_info = spi_info; - spi->max_speed = DIV_ROUND_UP(spi_info->tclk, 4); - spi->min_speed = DIV_ROUND_UP(spi_info->tclk, 30); + spi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(spi->clk)) { + status = PTR_ERR(spi->clk); + goto out; + } + + clk_prepare(spi->clk); + clk_enable(spi->clk); + tclk_hz = clk_get_rate(spi->clk); + spi->max_speed = DIV_ROUND_UP(tclk_hz, 4); + spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { status = -ENODEV; - goto out; + goto out_rel_clk; } if (!request_mem_region(r->start, resource_size(r), dev_name(&pdev->dev))) { status = -EBUSY; - goto out; + goto out_rel_clk; } spi->base = ioremap(r->start, SZ_1K); @@ -508,7 +519,9 @@ static int __init orion_spi_probe(struct platform_device *pdev) out_rel_mem: release_mem_region(r->start, resource_size(r)); - +out_rel_clk: + clk_disable_unprepare(spi->clk); + clk_put(spi->clk); out: spi_master_put(master); return status; @@ -526,6 +539,9 @@ static int __exit orion_spi_remove(struct platform_device *pdev) cancel_work_sync(&spi->work); + clk_disable_unprepare(spi->clk); + clk_put(spi->clk); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(r->start, resource_size(r)); diff --git a/include/linux/spi/orion_spi.h b/include/linux/spi/orion_spi.h deleted file mode 100644 index b4d9fa6f797c..000000000000 --- a/include/linux/spi/orion_spi.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * orion_spi.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __LINUX_SPI_ORION_SPI_H -#define __LINUX_SPI_ORION_SPI_H - -struct orion_spi_info { - u32 tclk; /* no support yet */ -}; - - -#endif -- cgit v1.2.3 From 452503ebc7cc4cce5b9e52cf2f03255365a53234 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 24 Dec 2011 01:24:24 +0100 Subject: ARM: Orion: Eth: Add clk/clkdev support. The t_clk is moved from the shared part of the ethernet driver into the per port section. Each port can have its own gated clock, which it needs to enable/disable, as oppossed to there being one clock shared by all ports. In practice, only kirkwood supports this at the moment. Signed-off-by: Andrew Lunn Tested-by: Jamie Lentin Signed-off-by: Mike Turquette --- arch/arm/mach-dove/common.c | 3 +-- arch/arm/mach-kirkwood/common.c | 12 +++++---- arch/arm/mach-mv78xx0/common.c | 8 +++--- arch/arm/mach-orion5x/common.c | 2 +- arch/arm/plat-orion/common.c | 26 +++++++++--------- arch/arm/plat-orion/include/plat/common.h | 13 ++++----- drivers/net/ethernet/marvell/mv643xx_eth.c | 42 ++++++++++++++++++++++-------- include/linux/mv643xx_eth.h | 1 - 8 files changed, 61 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index da5b4047464d..02766960480d 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -102,8 +102,7 @@ void __init dove_ehci1_init(void) void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, - DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, - 0, get_tclk()); + DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, 0); } /***************************************************************************** diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index 476e0b941db7..c22354405297 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -86,14 +86,14 @@ static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx) void __init kirkwood_clk_init(void) { - struct clk *runit; + struct clk *runit, *ge0, *ge1; tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, kirkwood_tclk); runit = kirkwood_register_gate("runit", CGC_BIT_RUNIT); - kirkwood_register_gate("ge0", CGC_BIT_GE0); - kirkwood_register_gate("ge1", CGC_BIT_GE1); + ge0 = kirkwood_register_gate("ge0", CGC_BIT_GE0); + ge1 = kirkwood_register_gate("ge1", CGC_BIT_GE1); kirkwood_register_gate("sata0", CGC_BIT_SATA0); kirkwood_register_gate("sata1", CGC_BIT_SATA1); kirkwood_register_gate("usb0", CGC_BIT_USB0); @@ -110,6 +110,8 @@ void __init kirkwood_clk_init(void) /* clkdev entries, mapping clks to devices */ orion_clkdev_add(NULL, "orion_spi.0", runit); orion_clkdev_add(NULL, "orion_spi.1", runit); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", ge0); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", ge1); } /***************************************************************************** @@ -131,7 +133,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM, - IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk); + IRQ_KIRKWOOD_GE00_ERR); } @@ -145,7 +147,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data) orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM, - IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk); + IRQ_KIRKWOOD_GE01_ERR); } diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index 4c24b46520aa..ad4d037bbcd3 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -213,7 +213,7 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM, - IRQ_MV78XX0_GE_ERR, get_tclk()); + IRQ_MV78XX0_GE_ERR); } @@ -224,7 +224,7 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } @@ -248,7 +248,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data) orion_ge10_init(eth_data, GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } @@ -272,7 +272,7 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data) orion_ge11_init(eth_data, GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } /***************************************************************************** diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 2ef82e2f511d..3fc731824e9c 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -109,7 +109,7 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM, - IRQ_ORION5X_ETH_ERR, orion5x_tclk); + IRQ_ORION5X_ETH_ERR); } diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index bbe50a948710..a33733bb380d 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -43,6 +43,10 @@ void __init orion_clkdev_init(struct clk *tclk) { orion_clkdev_add(NULL, "orion_spi.0", tclk); orion_clkdev_add(NULL, "orion_spi.1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".2", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".3", tclk); } /* Fill in the resources structure and link it into the platform @@ -225,13 +229,11 @@ void __init orion_rtc_init(unsigned long mapbase, ****************************************************************************/ static __init void ge_complete( struct mv643xx_eth_shared_platform_data *orion_ge_shared_data, - int tclk, struct resource *orion_ge_resource, unsigned long irq, struct platform_device *orion_ge_shared, struct mv643xx_eth_platform_data *eth_data, struct platform_device *orion_ge) { - orion_ge_shared_data->t_clk = tclk; orion_ge_resource->start = irq; orion_ge_resource->end = irq; eth_data->shared = orion_ge_shared; @@ -282,12 +284,11 @@ static struct platform_device orion_ge00 = { void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge00_shared_data, tclk, + ge_complete(&orion_ge00_shared_data, orion_ge00_resources, irq, &orion_ge00_shared, eth_data, &orion_ge00); } @@ -335,12 +336,11 @@ static struct platform_device orion_ge01 = { void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge01_shared_data, tclk, + ge_complete(&orion_ge01_shared_data, orion_ge01_resources, irq, &orion_ge01_shared, eth_data, &orion_ge01); } @@ -388,12 +388,11 @@ static struct platform_device orion_ge10 = { void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge10_shared, orion_ge10_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge10_shared_data, tclk, + ge_complete(&orion_ge10_shared_data, orion_ge10_resources, irq, &orion_ge10_shared, eth_data, &orion_ge10); } @@ -441,12 +440,11 @@ static struct platform_device orion_ge11 = { void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge11_shared, orion_ge11_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge11_shared_data, tclk, + ge_complete(&orion_ge11_shared_data, orion_ge11_resources, irq, &orion_ge11_shared, eth_data, &orion_ge11); } diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h index d188a1aa6f56..00d8761c7d28 100644 --- a/arch/arm/plat-orion/include/plat/common.h +++ b/arch/arm/plat-orion/include/plat/common.h @@ -39,29 +39,26 @@ void __init orion_rtc_init(unsigned long mapbase, void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq); + void __init orion_i2c_init(unsigned long mapbase, unsigned long irq, unsigned long freq_m); diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 5e1ca0f05090..99cd233266ac 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -57,6 +57,7 @@ #include #include #include +#include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -289,10 +290,10 @@ struct mv643xx_eth_shared_private { /* * Hardware-specific parameters. */ - unsigned int t_clk; int extended_rx_coal_limit; int tx_bw_control; int tx_csum_limit; + }; #define TX_BW_CONTROL_ABSENT 0 @@ -431,6 +432,12 @@ struct mv643xx_eth_private { int tx_desc_sram_size; int txq_count; struct tx_queue txq[8]; + + /* + * Hardware-specific parameters. + */ + struct clk *clk; + unsigned int t_clk; }; @@ -1010,7 +1017,7 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) int mtu; int bucket_size; - token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); + token_rate = ((rate / 1000) * 64) / (mp->t_clk / 1000); if (token_rate > 1023) token_rate = 1023; @@ -1042,7 +1049,7 @@ static void txq_set_rate(struct tx_queue *txq, int rate, int burst) int token_rate; int bucket_size; - token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); + token_rate = ((rate / 1000) * 64) / (mp->t_clk / 1000); if (token_rate > 1023) token_rate = 1023; @@ -1309,7 +1316,7 @@ static unsigned int get_rx_coal(struct mv643xx_eth_private *mp) temp = (val & 0x003fff00) >> 8; temp *= 64000000; - do_div(temp, mp->shared->t_clk); + do_div(temp, mp->t_clk); return (unsigned int)temp; } @@ -1319,7 +1326,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec) u64 temp; u32 val; - temp = (u64)usec * mp->shared->t_clk; + temp = (u64)usec * mp->t_clk; temp += 31999999; do_div(temp, 64000000); @@ -1345,7 +1352,7 @@ static unsigned int get_tx_coal(struct mv643xx_eth_private *mp) temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4; temp *= 64000000; - do_div(temp, mp->shared->t_clk); + do_div(temp, mp->t_clk); return (unsigned int)temp; } @@ -1354,7 +1361,7 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec) { u64 temp; - temp = (u64)usec * mp->shared->t_clk; + temp = (u64)usec * mp->t_clk; temp += 31999999; do_div(temp, 64000000); @@ -2662,10 +2669,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) if (dram) mv643xx_eth_conf_mbus_windows(msp, dram); - /* - * Detect hardware parameters. - */ - msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000; msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ? pd->tx_csum_limit : 9 * 1024; infer_hw_params(msp); @@ -2890,6 +2893,18 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mp->dev = dev; + /* + * Get the clk rate, if there is one, otherwise use the default. + */ + mp->clk = clk_get(&pdev->dev, (pdev->id ? "1" : "0")); + if (!IS_ERR(mp->clk)) { + clk_prepare_enable(mp->clk); + mp->t_clk = clk_get_rate(mp->clk); + } else { + mp->t_clk = 133000000; + printk(KERN_WARNING "Unable to get clock"); + } + set_params(mp, pd); netif_set_real_num_tx_queues(dev, mp->txq_count); netif_set_real_num_rx_queues(dev, mp->rxq_count); @@ -2978,6 +2993,11 @@ static int mv643xx_eth_remove(struct platform_device *pdev) if (mp->phy != NULL) phy_detach(mp->phy); cancel_work_sync(&mp->tx_timeout_task); + + if (!IS_ERR(mp->clk)) { + clk_disable_unprepare(mp->clk); + clk_put(mp->clk); + } free_netdev(mp->dev); platform_set_drvdata(pdev, NULL); diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h index 30b0c4e78f91..51bf8ada6dc0 100644 --- a/include/linux/mv643xx_eth.h +++ b/include/linux/mv643xx_eth.h @@ -18,7 +18,6 @@ struct mv643xx_eth_shared_platform_data { struct mbus_dram_target_info *dram; struct platform_device *shared_smi; - unsigned int t_clk; /* * Max packet size for Tx IP/Layer 4 checksum, when set to 0, default * limit of 9KiB will be used. -- cgit v1.2.3 From 1df5c939f6d9dff7dfbe108d93133b9636baa607 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 18 Apr 2012 09:07:12 +0100 Subject: clk: Provide dummy clk_unregister() While there's no actual implementation behind it having the call to use in drivers makes them feel neater from a driver author point of view. An actual implementation can wait for someone who needs to use the function in a real system. Signed-off-by: Mark Brown [mturquette@linaro.org: void return type instead of int -EINVAL] Signed-off-by: Mike Turquette --- drivers/clk/clk.c | 9 +++++++++ include/linux/clk-provider.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'include/linux') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index e5d5dc13bcfd..a7e5dd59e19d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1420,6 +1420,15 @@ fail_out: } EXPORT_SYMBOL_GPL(clk_register); +/** + * clk_unregister - unregister a currently registered clock + * @clk: clock to unregister + * + * Currently unimplemented. + */ +void clk_unregister(struct clk *clk) {} +EXPORT_SYMBOL_GPL(clk_unregister); + /*** clk rate change notifiers ***/ /** diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index c1c23b9ec368..4a0b483986c3 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -312,6 +312,8 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, */ struct clk *clk_register(struct device *dev, struct clk_hw *hw); +void clk_unregister(struct clk *clk); + /* helper functions */ const char *__clk_get_name(struct clk *clk); struct clk_hw *__clk_get_hw(struct clk *clk); -- cgit v1.2.3