diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-28 12:38:06 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-28 12:38:06 -0700 |
commit | 735e941caa9a35f933297af0ab1e0ad6447411c4 (patch) | |
tree | ad05f19a0e748061d743f9f4d99cde9923b192c2 /include | |
parent | 09893ee84591b0417a9186a7e7cf1503ccf99ac2 (diff) | |
parent | 8fb61e33507e5d76b69467b4f96290338e96b733 (diff) |
Merge tag 'common-clk-api' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull "drivers/clk: common clock framework" from Olof Johansson:
"This branch contains patches from Mike Turquette adding a common clock
framework to be shared across platforms. This is part of the work
towards building a common zImage for several ARM platforms."
* tag 'common-clk-api' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc:
clk: make CONFIG_COMMON_CLK invisible
clk: basic clock hardware types
clk: introduce the common clock framework
Documentation: common clk API
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/clk-private.h | 196 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 300 | ||||
-rw-r--r-- | include/linux/clk.h | 68 |
3 files changed, 559 insertions, 5 deletions
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h new file mode 100644 index 00000000000..5e4312b6f5c --- /dev/null +++ b/include/linux/clk-private.h @@ -0,0 +1,196 @@ +/* + * linux/include/linux/clk-private.h + * + * Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com> + * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org> + * + * 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. + */ +#ifndef __LINUX_CLK_PRIVATE_H +#define __LINUX_CLK_PRIVATE_H + +#include <linux/clk-provider.h> +#include <linux/list.h> + +/* + * WARNING: Do not include clk-private.h from any file that implements struct + * clk_ops. Doing so is a layering violation! + * + * This header exists only to allow for statically initialized clock data. Any + * static clock data must be defined in a separate file from the logic that + * implements the clock operations for that same data. + */ + +#ifdef CONFIG_COMMON_CLK + +struct clk { + const char *name; + const struct clk_ops *ops; + struct clk_hw *hw; + struct clk *parent; + char **parent_names; + struct clk **parents; + u8 num_parents; + unsigned long rate; + unsigned long new_rate; + unsigned long flags; + unsigned int enable_count; + unsigned int prepare_count; + struct hlist_head children; + struct hlist_node child_node; + unsigned int notifier_count; +#ifdef CONFIG_COMMON_CLK_DEBUG + struct dentry *dentry; +#endif +}; + +/* + * DOC: Basic clock implementations common to many platforms + * + * Each basic clock hardware type is comprised of a structure describing the + * clock hardware, implementations of the relevant callbacks in struct clk_ops, + * unique flags for that hardware type, a registration function and an + * alternative macro for static initialization + */ + +extern struct clk_ops clk_fixed_rate_ops; + +#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ + _fixed_rate_flags) \ + static struct clk _name; \ + static char *_name##_parent_names[] = {}; \ + static struct clk_fixed_rate _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .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, \ + }; + +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 char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_gate _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .reg = _reg, \ + .bit_idx = _bit_idx, \ + .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, \ + }; + +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 char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_divider _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .reg = _reg, \ + .shift = _shift, \ + .width = _width, \ + .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, \ + }; + +extern struct clk_ops clk_mux_ops; + +#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ + _reg, _shift, _width, \ + _mux_flags, _lock) \ + static struct clk _name; \ + static struct clk_mux _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .reg = _reg, \ + .shift = _shift, \ + .width = _width, \ + .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, \ + }; + +/** + * __clk_init - initialize the data structures in a struct clk + * @dev: device initializing this clk, placeholder for now + * @clk: clk being initialized + * + * 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 + * + * It is not necessary to call clk_register if __clk_init is used directly with + * statically initialized clock data. + */ +void __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 new file mode 100644 index 00000000000..5508897ad37 --- /dev/null +++ b/include/linux/clk-provider.h @@ -0,0 +1,300 @@ +/* + * linux/include/linux/clk-provider.h + * + * Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com> + * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org> + * + * 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. + */ +#ifndef __LINUX_CLK_PROVIDER_H +#define __LINUX_CLK_PROVIDER_H + +#include <linux/clk.h> + +#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 + * belong in struct clk_foo + */ +#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */ +#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */ +#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */ +#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_ops - Callback operations for hardware clocks; these are to + * be provided by the clock implementation, and will be called by drivers + * through the clk_* api. + * + * @prepare: Prepare the clock for enabling. This must not return until + * the clock is fully prepared, and it's safe to call clk_enable. + * This callback is intended to allow clock implementations to + * do any initialisation that may sleep. Called with + * prepare_lock held. + * + * @unprepare: Release the clock from its prepared state. This will typically + * undo any work done in the @prepare callback. Called with + * prepare_lock held. + * + * @enable: Enable the clock atomically. This must not return until the + * clock is generating a valid clock signal, usable by consumer + * devices. Called with enable_lock held. This function must not + * sleep. + * + * @disable: Disable the clock atomically. Called with enable_lock held. + * This function must not sleep. + * + * @recalc_rate Recalculate the rate of this clock, by quering hardware. The + * parent rate is an input parameter. It is up to the caller to + * insure that the prepare_mutex is held across this call. + * Returns the calculated rate. Optional, but recommended - if + * this op is not set then clock rate will be initialized to 0. + * + * @round_rate: Given a target rate as input, returns the closest rate actually + * supported by the clock. + * + * @get_parent: Queries the hardware to determine the parent of a clock. The + * return value is a u8 which specifies the index corresponding to + * the parent clock. This index can be applied to either the + * .parent_names or .parents arrays. In short, this function + * translates the parent value read from hardware into an array + * index. Currently only called when the clock is initialized by + * __clk_init. This callback is mandatory for clocks with + * multiple parents. It is optional (and unnecessary) for clocks + * with 0 or 1 parents. + * + * @set_parent: Change the input source of this clock; for clocks with multiple + * possible parents specify a new parent by passing in the index + * as a u8 corresponding to the parent in either the .parent_names + * or .parents arrays. This function in affect translates an + * 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. + * + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow + * implementations to split any work between atomic (enable) and sleepable + * (prepare) contexts. If enabling a clock requires code that might sleep, + * this must be done in clk_prepare. Clock enable code that will never be + * called in a sleepable context may be implement in clk_enable. + * + * Typically, drivers will call clk_prepare when a clock may be needed later + * (eg. when a device is opened), and clk_enable when the clock is actually + * required (eg. from an interrupt). Note that clk_prepare MUST have been + * called before clk_enable. + */ +struct clk_ops { + int (*prepare)(struct clk_hw *hw); + void (*unprepare)(struct clk_hw *hw); + int (*enable)(struct clk_hw *hw); + void (*disable)(struct clk_hw *hw); + int (*is_enabled)(struct clk_hw *hw); + unsigned long (*recalc_rate)(struct clk_hw *hw, + unsigned long parent_rate); + long (*round_rate)(struct clk_hw *hw, unsigned long, + 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); + void (*init)(struct clk_hw *hw); +}; + +/* + * DOC: Basic clock implementations common to many platforms + * + * Each basic clock hardware type is comprised of a structure describing the + * clock hardware, implementations of the relevant callbacks in struct clk_ops, + * unique flags for that hardware type, a registration function and an + * alternative macro for static initialization + */ + +/** + * struct clk_fixed_rate - fixed-rate clock + * @hw: handle between common and hardware-specific interfaces + * @fixed_rate: constant frequency of clock + */ +struct clk_fixed_rate { + struct clk_hw hw; + unsigned long fixed_rate; + u8 flags; +}; + +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_gate - gating clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling gate + * @bit_idx: single bit controlling gate + * @flags: hardware-specific flags + * @lock: register lock + * + * 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 + * enable the clock. Setting this flag does the opposite: setting the bit + * disable the clock and clearing it enables the clock + */ +struct clk_gate { + struct clk_hw hw; + void __iomem *reg; + u8 bit_idx; + u8 flags; + spinlock_t *lock; + char *parent[1]; +}; + +#define CLK_GATE_SET_TO_DISABLE BIT(0) + +struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + +/** + * struct clk_divider - adjustable divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @lock: register lock + * + * Clock with an adjustable divider affecting its output frequency. Implements + * .recalc_rate, .set_rate and .round_rate + * + * Flags: + * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the + * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is + * the raw value read from the register, with the value of zero considered + * invalid + * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from + * the hardware register + */ +struct clk_divider { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + 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) + +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, + u8 clk_divider_flags, spinlock_t *lock); + +/** + * struct clk_mux - multiplexer clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register controlling multiplexer + * @shift: shift to multiplexer bit field + * @width: width of mutliplexer bit field + * @num_clks: number of parent clocks + * @lock: register lock + * + * Clock with multiple selectable parents. Implements .get_parent, .set_parent + * and .recalc_rate + * + * 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) + */ +struct clk_mux { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + u8 width; + u8 flags; + spinlock_t *lock; +}; + +#define CLK_MUX_INDEX_ONE BIT(0) +#define CLK_MUX_INDEX_BIT BIT(1) + +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, + u8 clk_mux_flags, spinlock_t *lock); + +/** + * 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. + */ +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); +struct clk_hw *__clk_get_hw(struct clk *clk); +u8 __clk_get_num_parents(struct clk *clk); +struct clk *__clk_get_parent(struct clk *clk); +inline int __clk_get_enable_count(struct clk *clk); +inline int __clk_get_prepare_count(struct clk *clk); +unsigned long __clk_get_rate(struct clk *clk); +unsigned long __clk_get_flags(struct clk *clk); +int __clk_is_enabled(struct clk *clk); +struct clk *__clk_lookup(const char *name); + +/* + * FIXME clock api without lock protection + */ +int __clk_prepare(struct clk *clk); +void __clk_unprepare(struct clk *clk); +void __clk_reparent(struct clk *clk, struct clk *new_parent); +unsigned long __clk_round_rate(struct clk *clk, unsigned long rate); + +#endif /* CONFIG_COMMON_CLK */ +#endif /* CLK_PROVIDER_H */ diff --git a/include/linux/clk.h b/include/linux/clk.h index b9d46fa154b..b0252726df6 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -3,6 +3,7 @@ * * Copyright (C) 2004 ARM Limited. * Written by Deep Blue Solutions Limited. + * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org> * * 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 @@ -12,18 +13,75 @@ #define __LINUX_CLK_H #include <linux/kernel.h> +#include <linux/notifier.h> struct device; -/* - * The base API. +struct clk; + +#ifdef CONFIG_COMMON_CLK + +/** + * DOC: clk notifier callback types + * + * PRE_RATE_CHANGE - called immediately before the clk rate is changed, + * to indicate that the rate change will proceed. Drivers must + * immediately terminate any operations that will be affected by the + * rate change. Callbacks may either return NOTIFY_DONE or + * NOTIFY_STOP. + * + * ABORT_RATE_CHANGE: called if the rate change failed for some reason + * after PRE_RATE_CHANGE. In this case, all registered notifiers on + * the clk will be called with ABORT_RATE_CHANGE. Callbacks must + * always return NOTIFY_DONE. + * + * POST_RATE_CHANGE - called after the clk rate change has successfully + * completed. Callbacks must always return NOTIFY_DONE. + * */ +#define PRE_RATE_CHANGE BIT(0) +#define POST_RATE_CHANGE BIT(1) +#define ABORT_RATE_CHANGE BIT(2) +/** + * struct clk_notifier - associate a clk with a notifier + * @clk: struct clk * to associate the notifier with + * @notifier_head: a blocking_notifier_head for this clk + * @node: linked list pointers + * + * A list of struct clk_notifier is maintained by the notifier code. + * An entry is created whenever code registers the first notifier on a + * particular @clk. Future notifiers on that @clk are added to the + * @notifier_head. + */ +struct clk_notifier { + struct clk *clk; + struct srcu_notifier_head notifier_head; + struct list_head node; +}; -/* - * struct clk - an machine class defined object / cookie. +/** + * struct clk_notifier_data - rate data to pass to the notifier callback + * @clk: struct clk * being changed + * @old_rate: previous rate of this clk + * @new_rate: new rate of this clk + * + * For a pre-notifier, old_rate is the clk's rate before this rate + * change, and new_rate is what the rate will be in the future. For a + * post-notifier, old_rate and new_rate are both set to the clk's + * current rate (this was done to optimize the implementation). */ -struct clk; +struct clk_notifier_data { + struct clk *clk; + unsigned long old_rate; + unsigned long new_rate; +}; + +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 */ /** * clk_get - lookup and obtain a reference to a clock producer. |