From 277f1944b3bbcd67e23b806a2e99efe8862167d7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 7 Mar 2012 09:30:06 +0100 Subject: [PATCH] --- yaml --- r: 308221 b: refs/heads/master c: 7560e3f3581ed415828d3f431b8622fa38c2d133 h: refs/heads/master i: 308219: f762b469754c9bec5d5471750c4a231017037931 v: v3 --- [refs] | 2 +- trunk/Documentation/driver-model/devres.txt | 4 - trunk/MAINTAINERS | 10 - trunk/drivers/clk/Kconfig | 12 +- trunk/drivers/clk/Makefile | 2 +- trunk/drivers/clk/clk-divider.c | 68 ++--- trunk/drivers/clk/clk-fixed-factor.c | 95 ------- trunk/drivers/clk/clk-fixed-rate.c | 49 ++-- trunk/drivers/clk/clk-gate.c | 104 ++++---- trunk/drivers/clk/clk-mux.c | 27 +- trunk/drivers/clk/clk.c | 270 +++++++------------- trunk/drivers/clk/clkdev.c | 142 +--------- trunk/drivers/dma/imx-sdma.c | 40 ++- trunk/include/linux/clk-private.h | 99 +++---- trunk/include/linux/clk-provider.h | 118 +++------ trunk/include/linux/clk.h | 38 +-- trunk/include/linux/clkdev.h | 3 - 17 files changed, 362 insertions(+), 721 deletions(-) delete mode 100644 trunk/drivers/clk/clk-fixed-factor.c diff --git a/[refs] b/[refs] index 1306c9a35b0f..e311c514241b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e12ff34402bd3a6cbeab0423012066874bb10f4b +refs/heads/master: 7560e3f3581ed415828d3f431b8622fa38c2d133 diff --git a/trunk/Documentation/driver-model/devres.txt b/trunk/Documentation/driver-model/devres.txt index 9faac6ae3525..2a596a4fc23e 100644 --- a/trunk/Documentation/driver-model/devres.txt +++ b/trunk/Documentation/driver-model/devres.txt @@ -276,7 +276,3 @@ REGULATOR devm_regulator_get() devm_regulator_put() devm_regulator_bulk_get() - -CLOCK - devm_clk_get() - devm_clk_put() diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 164e9a1df0f6..1a2f8f5823e0 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -1882,16 +1882,6 @@ F: Documentation/filesystems/coda.txt F: fs/coda/ F: include/linux/coda*.h -COMMON CLK FRAMEWORK -M: Mike Turquette -M: Mike Turquette -L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV) -T: git git://git.linaro.org/people/mturquette/linux.git -S: Maintained -F: drivers/clk/clk.c -F: drivers/clk/clk-* -F: include/linux/clk-pr* - COMMON INTERNET FILE SYSTEM (CIFS) M: Steve French L: linux-cifs@vger.kernel.org diff --git a/trunk/drivers/clk/Kconfig b/trunk/drivers/clk/Kconfig index 4864407e3fc4..165e1febae53 100644 --- a/trunk/drivers/clk/Kconfig +++ b/trunk/drivers/clk/Kconfig @@ -12,7 +12,6 @@ config HAVE_MACH_CLKDEV config COMMON_CLK bool select HAVE_CLK_PREPARE - select CLKDEV_LOOKUP ---help--- The common clock framework is a single definition of struct clk, useful across many platforms, as well as an @@ -23,6 +22,17 @@ config COMMON_CLK menu "Common Clock Framework" depends on COMMON_CLK +config COMMON_CLK_DISABLE_UNUSED + bool "Disabled unused clocks at boot" + depends on COMMON_CLK + ---help--- + Traverses the entire clock tree and disables any clocks that are + enabled in hardware but have not been enabled by any device drivers. + This saves power and keeps the software model of the clock in line + with reality. + + If in doubt, say "N". + config COMMON_CLK_DEBUG bool "DebugFS representation of clock tree" depends on COMMON_CLK diff --git a/trunk/drivers/clk/Makefile b/trunk/drivers/clk/Makefile index 24aa7144811b..1f736bc11c4b 100644 --- a/trunk/drivers/clk/Makefile +++ b/trunk/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-fixed-factor.o + clk-mux.o clk-divider.o diff --git a/trunk/drivers/clk/clk-divider.c b/trunk/drivers/clk/clk-divider.c index 8ea11b444528..d5ac6a75ea57 100644 --- a/trunk/drivers/clk/clk-divider.c +++ b/trunk/drivers/clk/clk-divider.c @@ -45,6 +45,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, return parent_rate / div; } +EXPORT_SYMBOL_GPL(clk_divider_recalc_rate); /* * The reverse of DIV_ROUND_UP: The maximum number which @@ -67,8 +68,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_ONE_BASED) maxdiv--; - if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { - parent_rate = *best_parent_rate; + if (!best_parent_rate) { + parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); bestdiv = DIV_ROUND_UP(parent_rate, rate); bestdiv = bestdiv == 0 ? 1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; @@ -108,18 +109,24 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, int div; div = clk_divider_bestdiv(hw, rate, prate); - return *prate / div; + if (prate) + return *prate / div; + else { + unsigned long r; + r = __clk_get_rate(__clk_get_parent(hw->clk)); + return r / div; + } } +EXPORT_SYMBOL_GPL(clk_divider_round_rate); -static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) { struct clk_divider *divider = to_clk_divider(hw); unsigned int div; unsigned long flags = 0; u32 val; - div = parent_rate / rate; + div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) div--; @@ -140,26 +147,15 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +EXPORT_SYMBOL_GPL(clk_divider_set_rate); -const struct clk_ops clk_divider_ops = { +struct clk_ops clk_divider_ops = { .recalc_rate = clk_divider_recalc_rate, .round_rate = clk_divider_round_rate, .set_rate = clk_divider_set_rate, }; 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, @@ -167,34 +163,38 @@ 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); + if (!div) { pr_err("%s: could not allocate divider clk\n", __func__); - return ERR_PTR(-ENOMEM); + return NULL; } - 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, &div->hw); + if (parent_name) { + div->parent[0] = kstrdup(parent_name, GFP_KERNEL); + if (!div->parent[0]) + goto out; + } + + clk = clk_register(dev, name, + &clk_divider_ops, &div->hw, + div->parent, + (parent_name ? 1 : 0), + flags); + if (clk) + return clk; - if (IS_ERR(clk)) - kfree(div); +out: + kfree(div->parent[0]); + kfree(div); - return clk; + return NULL; } diff --git a/trunk/drivers/clk/clk-fixed-factor.c b/trunk/drivers/clk/clk-fixed-factor.c deleted file mode 100644 index c8c003e217ad..000000000000 --- a/trunk/drivers/clk/clk-fixed-factor.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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/trunk/drivers/clk/clk-fixed-rate.c b/trunk/drivers/clk/clk-fixed-rate.c index cbd246229786..90c79fb5d1bd 100644 --- a/trunk/drivers/clk/clk-fixed-rate.c +++ b/trunk/drivers/clk/clk-fixed-rate.c @@ -32,50 +32,51 @@ static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, { return to_clk_fixed_rate(hw)->fixed_rate; } +EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate); -const struct clk_ops clk_fixed_rate_ops = { +struct clk_ops clk_fixed_rate_ops = { .recalc_rate = clk_fixed_rate_recalc_rate, }; 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; - struct clk *clk; - struct clk_init_data init; + char **parent_names = NULL; + u8 len; - /* 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); } - 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, &fixed->hw); + if (parent_name) { + parent_names = kmalloc(sizeof(char *), GFP_KERNEL); + + if (! parent_names) + goto out; - if (IS_ERR(clk)) - kfree(fixed); + 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); + } - return clk; +out: + return clk_register(dev, name, + &clk_fixed_rate_ops, &fixed->hw, + parent_names, + (parent_name ? 1 : 0), + flags); } diff --git a/trunk/drivers/clk/clk-gate.c b/trunk/drivers/clk/clk-gate.c index 578465e04be6..b5902e2ef2fd 100644 --- a/trunk/drivers/clk/clk-gate.c +++ b/trunk/drivers/clk/clk-gate.c @@ -28,38 +28,32 @@ #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) -/* - * It works on following logic: - * - * For enabling clock, enable = 1 - * set2dis = 1 -> clear bit -> set = 0 - * set2dis = 0 -> set bit -> set = 1 - * - * For disabling clock, enable = 0 - * set2dis = 1 -> set bit -> set = 1 - * set2dis = 0 -> clear bit -> set = 0 - * - * So, result is always: enable xor set2dis. - */ -static void clk_gate_endisable(struct clk_hw *hw, int enable) +static void clk_gate_set_bit(struct clk_gate *gate) { - struct clk_gate *gate = to_clk_gate(hw); - int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; - unsigned long flags = 0; u32 reg; - - set ^= enable; + unsigned long flags = 0; if (gate->lock) spin_lock_irqsave(gate->lock, flags); reg = readl(gate->reg); + reg |= BIT(gate->bit_idx); + writel(reg, gate->reg); - if (set) - reg |= BIT(gate->bit_idx); - else - reg &= ~BIT(gate->bit_idx); + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); +} + +static void clk_gate_clear_bit(struct clk_gate *gate) +{ + u32 reg; + unsigned long flags = 0; + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg &= ~BIT(gate->bit_idx); writel(reg, gate->reg); if (gate->lock) @@ -68,15 +62,27 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) static int clk_gate_enable(struct clk_hw *hw) { - clk_gate_endisable(hw, 1); + struct clk_gate *gate = to_clk_gate(hw); + + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + clk_gate_clear_bit(gate); + else + clk_gate_set_bit(gate); return 0; } +EXPORT_SYMBOL_GPL(clk_gate_enable); static void clk_gate_disable(struct clk_hw *hw) { - clk_gate_endisable(hw, 0); + struct clk_gate *gate = to_clk_gate(hw); + + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + clk_gate_set_bit(gate); + else + clk_gate_clear_bit(gate); } +EXPORT_SYMBOL_GPL(clk_gate_disable); static int clk_gate_is_enabled(struct clk_hw *hw) { @@ -93,25 +99,15 @@ static int clk_gate_is_enabled(struct clk_hw *hw) return reg ? 1 : 0; } +EXPORT_SYMBOL_GPL(clk_gate_is_enabled); -const struct clk_ops clk_gate_ops = { +struct clk_ops clk_gate_ops = { .enable = clk_gate_enable, .disable = clk_gate_disable, .is_enabled = clk_gate_is_enabled, }; 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, @@ -119,32 +115,36 @@ 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); + if (!gate) { pr_err("%s: could not allocate gated clk\n", __func__); - return ERR_PTR(-ENOMEM); + return NULL; } - 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; - clk = clk_register(dev, &gate->hw); - - if (IS_ERR(clk)) - kfree(gate); + if (parent_name) { + gate->parent[0] = kstrdup(parent_name, GFP_KERNEL); + if (!gate->parent[0]) + goto out; + } - return clk; + clk = clk_register(dev, name, + &clk_gate_ops, &gate->hw, + gate->parent, + (parent_name ? 1 : 0), + flags); + if (clk) + return clk; +out: + kfree(gate->parent[0]); + kfree(gate); + + return NULL; } diff --git a/trunk/drivers/clk/clk-mux.c b/trunk/drivers/clk/clk-mux.c index fd36a8ea73d9..c71ad1f41a97 100644 --- a/trunk/drivers/clk/clk-mux.c +++ b/trunk/drivers/clk/clk-mux.c @@ -55,6 +55,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) return val; } +EXPORT_SYMBOL_GPL(clk_mux_get_parent); static int clk_mux_set_parent(struct clk_hw *hw, u8 index) { @@ -81,47 +82,35 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) return 0; } +EXPORT_SYMBOL_GPL(clk_mux_set_parent); -const struct clk_ops clk_mux_ops = { +struct clk_ops clk_mux_ops = { .get_parent = clk_mux_get_parent, .set_parent = clk_mux_set_parent, }; EXPORT_SYMBOL_GPL(clk_mux_ops); struct clk *clk_register_mux(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned long flags, + char **parent_names, u8 num_parents, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u8 clk_mux_flags, spinlock_t *lock) { struct clk_mux *mux; - struct clk *clk; - struct clk_init_data init; - /* allocate the mux */ - mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); + mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL); + if (!mux) { pr_err("%s: could not allocate mux clk\n", __func__); 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; mux->width = width; mux->flags = clk_mux_flags; mux->lock = lock; - mux->hw.init = &init; - - clk = clk_register(dev, &mux->hw); - - if (IS_ERR(clk)) - kfree(mux); - return clk; + return clk_register(dev, name, &clk_mux_ops, &mux->hw, + parent_names, num_parents, flags); } diff --git a/trunk/drivers/clk/clk.c b/trunk/drivers/clk/clk.c index e5d5dc13bcfd..9cf6f59e3e19 100644 --- a/trunk/drivers/clk/clk.c +++ b/trunk/drivers/clk/clk.c @@ -194,8 +194,9 @@ static int __init clk_debug_init(void) late_initcall(clk_debug_init); #else static inline int clk_debug_register(struct clk *clk) { return 0; } -#endif +#endif /* CONFIG_COMMON_CLK_DEBUG */ +#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED /* caller must hold prepare_lock */ static void clk_disable_unused_subtree(struct clk *clk) { @@ -245,6 +246,9 @@ static int clk_disable_unused(void) return 0; } late_initcall(clk_disable_unused); +#else +static inline int clk_disable_unused(struct clk *clk) { return 0; } +#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */ /*** helper functions ***/ @@ -283,7 +287,7 @@ unsigned long __clk_get_rate(struct clk *clk) unsigned long ret; if (!clk) { - ret = 0; + ret = -EINVAL; goto out; } @@ -293,7 +297,7 @@ unsigned long __clk_get_rate(struct clk *clk) goto out; if (!clk->parent) - ret = 0; + ret = -ENODEV; out: return ret; @@ -558,7 +562,7 @@ EXPORT_SYMBOL_GPL(clk_enable); * @clk: the clk whose rate is being returned * * Simply returns the cached rate of the clk. Does not query the hardware. If - * clk is NULL then returns 0. + * clk is NULL then returns -EINVAL. */ unsigned long clk_get_rate(struct clk *clk) { @@ -580,22 +584,18 @@ EXPORT_SYMBOL_GPL(clk_get_rate); */ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { - unsigned long parent_rate = 0; + unsigned long unused; if (!clk) return -EINVAL; - if (!clk->ops->round_rate) { - if (clk->flags & CLK_SET_RATE_PARENT) - return __clk_round_rate(clk->parent, rate); - else - return clk->rate; - } + if (!clk->ops->round_rate) + return clk->rate; - if (clk->parent) - parent_rate = clk->parent->rate; - - return clk->ops->round_rate(clk->hw, rate, &parent_rate); + if (clk->flags & CLK_SET_RATE_PARENT) + return clk->ops->round_rate(clk->hw, rate, &unused); + else + return clk->ops->round_rate(clk->hw, rate, NULL); } /** @@ -765,41 +765,25 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate) static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) { struct clk *top = clk; - unsigned long best_parent_rate = 0; + unsigned long best_parent_rate = clk->parent->rate; unsigned long new_rate; - /* sanity */ - if (IS_ERR_OR_NULL(clk)) + if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) { + clk->new_rate = clk->rate; return NULL; - - /* save parent rate, if it exists */ - if (clk->parent) - best_parent_rate = clk->parent->rate; - - /* never propagate up to the parent */ - if (!(clk->flags & CLK_SET_RATE_PARENT)) { - if (!clk->ops->round_rate) { - clk->new_rate = clk->rate; - return NULL; - } - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); - goto out; } - /* need clk->parent from here on out */ - if (!clk->parent) { - pr_debug("%s: %s has NULL parent\n", __func__, clk->name); - return NULL; - } - - if (!clk->ops->round_rate) { + if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) { top = clk_calc_new_rates(clk->parent, rate); - new_rate = clk->parent->new_rate; + new_rate = clk->new_rate = clk->parent->new_rate; goto out; } - new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); + if (clk->flags & CLK_SET_RATE_PARENT) + new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); + else + new_rate = clk->ops->round_rate(clk->hw, rate, NULL); if (best_parent_rate != clk->parent->rate) { top = clk_calc_new_rates(clk->parent, best_parent_rate); @@ -855,7 +839,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->parent->rate); + clk->ops->set_rate(clk->hw, clk->new_rate); if (clk->ops->recalc_rate) clk->rate = clk->ops->recalc_rate(clk->hw, @@ -875,19 +859,38 @@ static void clk_change_rate(struct clk *clk) * @clk: the clk whose rate is being changed * @rate: the new rate for clk * - * In the simplest case clk_set_rate will only adjust the rate of clk. + * In the simplest case clk_set_rate will only change the rate of clk. * - * Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to - * propagate up to clk's parent; whether or not this happens depends on the - * outcome of clk's .round_rate implementation. If *parent_rate is unchanged - * after calling .round_rate then upstream parent propagation is ignored. If - * *parent_rate comes back with a new rate for clk's parent then we propagate - * up to clk's parent and set it's rate. Upward propagation will continue - * until either a clk does not support the CLK_SET_RATE_PARENT flag or - * .round_rate stops requesting changes to clk's parent_rate. + * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call + * will fail; only when the clk is disabled will it be able to change + * its rate. * - * Rate changes are accomplished via tree traversal that also recalculates the - * rates for the clocks and fires off POST_RATE_CHANGE notifiers. + * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to + * recursively propagate up to clk's parent; whether or not this happens + * depends on the outcome of clk's .round_rate implementation. If + * *parent_rate is 0 after calling .round_rate then upstream parent + * propagation is ignored. If *parent_rate comes back with a new rate + * for clk's parent then we propagate up to clk's parent and set it's + * rate. Upward propagation will continue until either a clk does not + * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting + * changes to clk's parent_rate. If there is a failure during upstream + * propagation then clk_set_rate will unwind and restore each clk's rate + * that had been successfully changed. Afterwards a rate change abort + * notification will be propagated downstream, starting from the clk + * that failed. + * + * At the end of all of the rate setting, clk_set_rate internally calls + * __clk_recalc_rates and propagates the rate changes downstream, + * starting from the highest clk whose rate was changed. This has the + * added benefit of propagating post-rate change notifiers. + * + * Note that while post-rate change and rate change abort notifications + * are guaranteed to be sent to a clk only once per call to + * clk_set_rate, pre-change notifications will be sent for every clk + * whose rate is changed. Stacking pre-change notifications is noisy + * for the drivers subscribed to them, but this allows drivers to react + * to intermediate clk rate changes up until the point where the final + * rate is achieved at the end of upstream propagation. * * Returns 0 on success, -EERROR otherwise. */ @@ -903,11 +906,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate) if (rate == clk->rate) goto out; - if ((clk->flags & CLK_SET_RATE_GATE) && __clk_is_enabled(clk)) { - ret = -EBUSY; - goto out; - } - /* calculate new rates and get the topmost changed clock */ top = clk_calc_new_rates(clk, rate); if (!top) { @@ -1177,41 +1175,40 @@ 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. */ -int __clk_init(struct device *dev, struct clk *clk) +void __clk_init(struct device *dev, struct clk *clk) { - int i, ret = 0; + int i; struct clk *orphan; struct hlist_node *tmp, *tmp2; if (!clk) - return -EINVAL; + return; mutex_lock(&prepare_lock); /* check to see if a clock with this name is already registered */ - 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; + if (__clk_lookup(clk->name)) 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; - } /* throw a WARN if any entries in parent_names are NULL */ for (i = 0; i < clk->num_parents; i++) @@ -1305,118 +1302,45 @@ int __clk_init(struct device *dev, struct clk *clk) out: mutex_unlock(&prepare_lock); - 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; + return; } -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 * cannot be dereferenced by driver code but may be used in conjuction with the - * 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. + * rest of the clock API. */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw) +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) { - int i, ret; struct clk *clk; clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) { - pr_err("%s: could not allocate clk\n", __func__); - ret = -ENOMEM; - goto fail_out; - } + if (!clk) + return NULL; - 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->name = name; + clk->ops = ops; clk->hw = hw; - clk->flags = hw->init->flags; - clk->num_parents = hw->init->num_parents; + clk->flags = flags; + clk->parent_names = parent_names; + clk->num_parents = num_parents; hw->clk = clk; - /* allocate local copy in case parent_names is __initdata */ - clk->parent_names = kzalloc((sizeof(char*) * clk->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 < 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; - goto fail_parent_names_copy; - } - } + __clk_init(dev, clk); - ret = __clk_init(dev, clk); - if (!ret) - return clk; - -fail_parent_names_copy: - while (--i >= 0) - 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); + return clk; } EXPORT_SYMBOL_GPL(clk_register); diff --git a/trunk/drivers/clk/clkdev.c b/trunk/drivers/clk/clkdev.c index c535cf8c5770..6db161f64ae0 100644 --- a/trunk/drivers/clk/clkdev.c +++ b/trunk/drivers/clk/clkdev.c @@ -35,12 +35,7 @@ static DEFINE_MUTEX(clocks_mutex); static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { struct clk_lookup *p, *cl = NULL; - int match, best_found = 0, best_possible = 0; - - if (dev_id) - best_possible += 2; - if (con_id) - best_possible += 1; + int match, best = 0; list_for_each_entry(p, &clocks, node) { match = 0; @@ -55,10 +50,10 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) match += 1; } - if (match > best_found) { + if (match > best) { cl = p; - if (match != best_possible) - best_found = match; + if (match != 3) + best = match; else break; } @@ -94,51 +89,6 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); -static void devm_clk_release(struct device *dev, void *res) -{ - clk_put(*(struct clk **)res); -} - -struct clk *devm_clk_get(struct device *dev, const char *id) -{ - struct clk **ptr, *clk; - - ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - clk = clk_get(dev, id); - if (!IS_ERR(clk)) { - *ptr = clk; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return clk; -} -EXPORT_SYMBOL(devm_clk_get); - -static int devm_clk_match(struct device *dev, void *res, void *data) -{ - struct clk **c = res; - if (!c || !*c) { - WARN_ON(!c || !*c); - return 0; - } - return *c == data; -} - -void devm_clk_put(struct device *dev, struct clk *clk) -{ - int ret; - - ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); - - WARN_ON(ret); -} -EXPORT_SYMBOL(devm_clk_put); - void clkdev_add(struct clk_lookup *cl) { mutex_lock(&clocks_mutex); @@ -166,9 +116,8 @@ struct clk_lookup_alloc { char con_id[MAX_CON_ID]; }; -static struct clk_lookup * __init_refok -vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, - va_list ap) +struct clk_lookup * __init_refok +clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) { struct clk_lookup_alloc *cla; @@ -183,25 +132,16 @@ vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, } if (dev_fmt) { + va_list ap; + + va_start(ap, dev_fmt); vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); cla->cl.dev_id = cla->dev_id; + va_end(ap); } return &cla->cl; } - -struct clk_lookup * __init_refok -clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) -{ - struct clk_lookup *cl; - va_list ap; - - va_start(ap, dev_fmt); - cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); - va_end(ap); - - return cl; -} EXPORT_SYMBOL(clkdev_alloc); int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, @@ -233,65 +173,3 @@ void clkdev_drop(struct clk_lookup *cl) kfree(cl); } EXPORT_SYMBOL(clkdev_drop); - -/** - * clk_register_clkdev - register one clock lookup for a struct clk - * @clk: struct clk to associate with all clk_lookups - * @con_id: connection ID string on device - * @dev_id: format string describing device name - * - * con_id or dev_id may be NULL as a wildcard, just as in the rest of - * clkdev. - * - * To make things easier for mass registration, we detect error clks - * from a previous clk_register() call, and return the error code for - * those. This is to permit this function to be called immediately - * after clk_register(). - */ -int clk_register_clkdev(struct clk *clk, const char *con_id, - const char *dev_fmt, ...) -{ - struct clk_lookup *cl; - va_list ap; - - if (IS_ERR(clk)) - return PTR_ERR(clk); - - va_start(ap, dev_fmt); - cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); - va_end(ap); - - if (!cl) - return -ENOMEM; - - clkdev_add(cl); - - return 0; -} - -/** - * clk_register_clkdevs - register a set of clk_lookup for a struct clk - * @clk: struct clk to associate with all clk_lookups - * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized - * @num: number of clk_lookup structures to register - * - * To make things easier for mass registration, we detect error clks - * from a previous clk_register() call, and return the error code for - * those. This is to permit this function to be called immediately - * after clk_register(). - */ -int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num) -{ - unsigned i; - - if (IS_ERR(clk)) - return PTR_ERR(clk); - - for (i = 0; i < num; i++, cl++) { - cl->clk = clk; - clkdev_add(cl); - } - - return 0; -} -EXPORT_SYMBOL(clk_register_clkdevs); diff --git a/trunk/drivers/dma/imx-sdma.c b/trunk/drivers/dma/imx-sdma.c index d3e38e28bb6b..fddccae6b476 100644 --- a/trunk/drivers/dma/imx-sdma.c +++ b/trunk/drivers/dma/imx-sdma.c @@ -322,7 +322,8 @@ struct sdma_engine { struct sdma_context_data *context; dma_addr_t context_phys; struct dma_device dma_device; - struct clk *clk; + struct clk *clk_ipg; + struct clk *clk_ahb; struct mutex channel_0_lock; struct sdma_script_start_addrs *script_addrs; }; @@ -859,7 +860,8 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) sdmac->peripheral_type = data->peripheral_type; sdmac->event_id0 = data->dma_request; - clk_enable(sdmac->sdma->clk); + clk_enable(sdmac->sdma->clk_ipg); + clk_enable(sdmac->sdma->clk_ahb); ret = sdma_request_channel(sdmac); if (ret) @@ -896,7 +898,8 @@ static void sdma_free_chan_resources(struct dma_chan *chan) dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); } static struct dma_async_tx_descriptor *sdma_prep_slave_sg( @@ -1169,12 +1172,14 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) addr = (void *)header + header->script_addrs_start; ram_code = (void *)header + header->ram_code_start; - clk_enable(sdma->clk); + clk_enable(sdma->clk_ipg); + clk_enable(sdma->clk_ahb); /* download the RAM image for SDMA */ sdma_load_script(sdma, ram_code, header->ram_code_size, addr->ram_code_start_addr); - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); sdma_add_scripts(sdma, addr); @@ -1216,7 +1221,8 @@ static int __init sdma_init(struct sdma_engine *sdma) return -ENODEV; } - clk_enable(sdma->clk); + clk_enable(sdma->clk_ipg); + clk_enable(sdma->clk_ahb); /* Be sure SDMA has not started yet */ writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); @@ -1269,12 +1275,14 @@ static int __init sdma_init(struct sdma_engine *sdma) /* Initializes channel's priorities */ sdma_set_channel_priority(&sdma->channel[0], 7); - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); return 0; err_dma_alloc: - clk_disable(sdma->clk); + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); dev_err(sdma->dev, "initialisation failed with %d\n", ret); return ret; } @@ -1313,12 +1321,21 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_request_region; } - sdma->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(sdma->clk)) { - ret = PTR_ERR(sdma->clk); + sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(sdma->clk_ipg)) { + ret = PTR_ERR(sdma->clk_ipg); goto err_clk; } + sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sdma->clk_ahb)) { + ret = PTR_ERR(sdma->clk_ahb); + goto err_clk; + } + + clk_prepare(sdma->clk_ipg); + clk_prepare(sdma->clk_ahb); + sdma->regs = ioremap(iores->start, resource_size(iores)); if (!sdma->regs) { ret = -ENOMEM; @@ -1426,7 +1443,6 @@ static int __init sdma_probe(struct platform_device *pdev) err_request_irq: iounmap(sdma->regs); err_ioremap: - clk_put(sdma->clk); err_clk: release_mem_region(iores->start, resource_size(iores)); err_request_region: diff --git a/trunk/include/linux/clk-private.h b/trunk/include/linux/clk-private.h index eb3f84bc5325..5e4312b6f5cc 100644 --- a/trunk/include/linux/clk-private.h +++ b/trunk/include/linux/clk-private.h @@ -30,7 +30,7 @@ struct clk { const struct clk_ops *ops; struct clk_hw *hw; struct clk *parent; - const char **parent_names; + char **parent_names; struct clk **parents; u8 num_parents; unsigned long rate; @@ -55,22 +55,12 @@ 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, \ - } +extern struct clk_ops clk_fixed_rate_ops; #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ _fixed_rate_flags) \ static struct clk _name; \ - static const char *_name##_parent_names[] = {}; \ + static char *_name##_parent_names[] = {}; \ static struct clk_fixed_rate _name##_hw = { \ .hw = { \ .clk = &_name, \ @@ -78,14 +68,23 @@ struct clk { .fixed_rate = _rate, \ .flags = _fixed_rate_flags, \ }; \ - DEFINE_CLK(_name, clk_fixed_rate_ops, _flags, \ - _name##_parent_names, NULL); + 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, \ + }; + +extern struct clk_ops clk_gate_ops; #define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr, \ _flags, _reg, _bit_idx, \ _gate_flags, _lock) \ static struct clk _name; \ - static const char *_name##_parent_names[] = { \ + static char *_name##_parent_names[] = { \ _parent_name, \ }; \ static struct clk *_name##_parents[] = { \ @@ -100,14 +99,24 @@ struct clk { .flags = _gate_flags, \ .lock = _lock, \ }; \ - DEFINE_CLK(_name, clk_gate_ops, _flags, \ - _name##_parent_names, _name##_parents); + 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, \ + }; + +extern struct clk_ops clk_divider_ops; #define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ _flags, _reg, _shift, _width, \ _divider_flags, _lock) \ static struct clk _name; \ - static const char *_name##_parent_names[] = { \ + static char *_name##_parent_names[] = { \ _parent_name, \ }; \ static struct clk *_name##_parents[] = { \ @@ -123,8 +132,18 @@ struct clk { .flags = _divider_flags, \ .lock = _lock, \ }; \ - DEFINE_CLK(_name, clk_divider_ops, _flags, \ - _name##_parent_names, _name##_parents); + 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, \ + }; + +extern struct clk_ops clk_mux_ops; #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ _reg, _shift, _width, \ @@ -140,28 +159,16 @@ struct clk { .flags = _mux_flags, \ .lock = _lock, \ }; \ - 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); + 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, \ + }; /** * __clk_init - initialize the data structures in a struct clk @@ -182,12 +189,8 @@ 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. */ -int __clk_init(struct device *dev, struct clk *clk); - -struct clk *__clk_register(struct device *dev, struct clk_hw *hw); +void __clk_init(struct device *dev, struct clk *clk); #endif /* CONFIG_COMMON_CLK */ #endif /* CLK_PRIVATE_H */ diff --git a/trunk/include/linux/clk-provider.h b/trunk/include/linux/clk-provider.h index c1c23b9ec368..5508897ad376 100644 --- a/trunk/include/linux/clk-provider.h +++ b/trunk/include/linux/clk-provider.h @@ -15,6 +15,19 @@ #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 @@ -26,8 +39,6 @@ #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 @@ -77,11 +88,19 @@ 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. 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. + * @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. * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable @@ -106,46 +125,10 @@ 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, - unsigned long); + int (*set_rate)(struct clk_hw *hw, unsigned long); 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 * @@ -166,7 +149,6 @@ 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); @@ -183,7 +165,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_TO_DISABLE - by default this clock sets the bit at bit_idx to + * CLK_GATE_SET_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 */ @@ -193,11 +175,11 @@ struct clk_gate { u8 bit_idx; u8 flags; spinlock_t *lock; + char *parent[1]; }; #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, @@ -230,12 +212,12 @@ struct clk_divider { u8 width; u8 flags; spinlock_t *lock; + char *parent[1]; }; #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, @@ -256,7 +238,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_BIT - register index is a single bit (power of two) + * CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two) */ struct clk_mux { struct clk_hw hw; @@ -270,47 +252,29 @@ 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, - const char **parent_names, u8 num_parents, unsigned long flags, + char **parent_names, u8 num_parents, unsigned long flags, 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 + * @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 * cannot be dereferenced by driver code but may be used in conjuction with the - * 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. + * rest of the clock API. */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw); +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); /* helper functions */ const char *__clk_get_name(struct clk *clk); diff --git a/trunk/include/linux/clk.h b/trunk/include/linux/clk.h index ad5c43e8ae8a..b0252726df61 100644 --- a/trunk/include/linux/clk.h +++ b/trunk/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 +#endif /* !CONFIG_COMMON_CLK */ /** * clk_get - lookup and obtain a reference to a clock producer. @@ -100,26 +100,6 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); */ struct clk *clk_get(struct device *dev, const char *id); -/** - * devm_clk_get - lookup and obtain a managed reference to a clock producer. - * @dev: device for clock "consumer" - * @id: clock comsumer ID - * - * Returns a struct clk corresponding to the clock producer, or - * valid IS_ERR() condition containing errno. The implementation - * uses @dev and @id to determine the clock consumer, and thereby - * the clock producer. (IOW, @id may be identical strings, but - * clk_get may return different clock producers depending on @dev.) - * - * Drivers must assume that the clock source is not enabled. - * - * devm_clk_get should not be called from within interrupt context. - * - * The clock will automatically be freed when the device is unbound - * from the bus. - */ -struct clk *devm_clk_get(struct device *dev, const char *id); - /** * clk_prepare - prepare a clock source * @clk: clock source @@ -226,18 +206,6 @@ unsigned long clk_get_rate(struct clk *clk); */ void clk_put(struct clk *clk); -/** - * devm_clk_put - "free" a managed clock source - * @dev: device used to acuqire the clock - * @clk: clock source acquired with devm_clk_get() - * - * Note: drivers must ensure that all clk_enable calls made on this - * clock source are balanced by clk_disable calls prior to calling - * this function. - * - * clk_put should not be called from within interrupt context. - */ -void devm_clk_put(struct device *dev, struct clk *clk); /* * The remaining APIs are optional for machine class support. @@ -252,7 +220,7 @@ void devm_clk_put(struct device *dev, 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 @@ -261,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 diff --git a/trunk/include/linux/clkdev.h b/trunk/include/linux/clkdev.h index a6a6f603103b..d9a4fd028c9d 100644 --- a/trunk/include/linux/clkdev.h +++ b/trunk/include/linux/clkdev.h @@ -40,7 +40,4 @@ void clkdev_drop(struct clk_lookup *cl); void clkdev_add_table(struct clk_lookup *, size_t); int clk_add_alias(const char *, const char *, char *, struct device *); -int clk_register_clkdev(struct clk *, const char *, const char *, ...); -int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); - #endif