diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/clk-provider.h | 43 | ||||
-rw-r--r-- | include/linux/clk.h | 62 | ||||
-rw-r--r-- | include/linux/clkdev.h | 7 | ||||
-rw-r--r-- | include/linux/platform_data/si5351.h | 2 |
4 files changed, 107 insertions, 7 deletions
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 7c925e6211f1..f711be6e8c44 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -20,6 +20,8 @@ * 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 + * + * Please update clk_flags[] in drivers/clk/clk.c when making changes here! */ #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 */ @@ -412,7 +414,7 @@ extern const struct clk_ops clk_divider_ro_ops; unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned int val, const struct clk_div_table *table, - unsigned long flags); + unsigned long flags, unsigned long width); long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *prate, const struct clk_div_table *table, @@ -744,6 +746,7 @@ unsigned long clk_hw_get_rate(const struct clk_hw *hw); unsigned long __clk_get_flags(struct clk *clk); unsigned long clk_hw_get_flags(const struct clk_hw *hw); bool clk_hw_is_prepared(const struct clk_hw *hw); +bool clk_hw_rate_is_protected(const struct clk_hw *hw); bool clk_hw_is_enabled(const struct clk_hw *hw); bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); @@ -806,6 +809,44 @@ extern struct of_device_id __clk_of_table; } \ OF_DECLARE_1(clk, name, compat, name##_of_clk_init_driver) +#define CLK_HW_INIT(_name, _parent, _ops, _flags) \ + (&(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .ops = _ops, \ + }) + +#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \ + (&(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .ops = _ops, \ + }) + +#define CLK_HW_INIT_NO_PARENT(_name, _ops, _flags) \ + (&(struct clk_init_data) { \ + .flags = _flags, \ + .name = _name, \ + .parent_names = NULL, \ + .num_parents = 0, \ + .ops = _ops, \ + }) + +#define CLK_FIXED_FACTOR(_struct, _name, _parent, \ + _div, _mult, _flags) \ + struct clk_fixed_factor _struct = { \ + .div = _div, \ + .mult = _mult, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &clk_fixed_factor_ops, \ + _flags), \ + } + #ifdef CONFIG_OF int of_clk_add_provider(struct device_node *np, struct clk *(*clk_src_get)(struct of_phandle_args *args, diff --git a/include/linux/clk.h b/include/linux/clk.h index 12c96d94d1fa..4c4ef9f34db3 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -331,6 +331,38 @@ struct clk *devm_clk_get(struct device *dev, const char *id); */ struct clk *devm_get_clk_from_child(struct device *dev, struct device_node *np, const char *con_id); +/** + * clk_rate_exclusive_get - get exclusivity over the rate control of a + * producer + * @clk: clock source + * + * This function allows drivers to get exclusive control over the rate of a + * provider. It prevents any other consumer to execute, even indirectly, + * opereation which could alter the rate of the provider or cause glitches + * + * If exlusivity is claimed more than once on clock, even by the same driver, + * the rate effectively gets locked as exclusivity can't be preempted. + * + * Must not be called from within atomic context. + * + * Returns success (0) or negative errno. + */ +int clk_rate_exclusive_get(struct clk *clk); + +/** + * clk_rate_exclusive_put - release exclusivity over the rate control of a + * producer + * @clk: clock source + * + * This function allows drivers to release the exclusivity it previously got + * from clk_rate_exclusive_get() + * + * The caller must balance the number of clk_rate_exclusive_get() and + * clk_rate_exclusive_put() calls. + * + * Must not be called from within atomic context. + */ +void clk_rate_exclusive_put(struct clk *clk); /** * clk_enable - inform the system when the clock source should be running. @@ -473,6 +505,23 @@ long clk_round_rate(struct clk *clk, unsigned long rate); int clk_set_rate(struct clk *clk, unsigned long rate); /** + * clk_set_rate_exclusive- set the clock rate and claim exclusivity over + * clock source + * @clk: clock source + * @rate: desired clock rate in Hz + * + * This helper function allows drivers to atomically set the rate of a producer + * and claim exclusivity over the rate control of the producer. + * + * It is essentially a combination of clk_set_rate() and + * clk_rate_exclusite_get(). Caller must balance this call with a call to + * clk_rate_exclusive_put() + * + * Returns success (0) or negative errno. + */ +int clk_set_rate_exclusive(struct clk *clk, unsigned long rate); + +/** * clk_has_parent - check if a clock is a possible parent for another * @clk: clock source * @parent: parent clock source @@ -583,6 +632,14 @@ static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {} static inline void devm_clk_put(struct device *dev, struct clk *clk) {} + +static inline int clk_rate_exclusive_get(struct clk *clk) +{ + return 0; +} + +static inline void clk_rate_exclusive_put(struct clk *clk) {} + static inline int clk_enable(struct clk *clk) { return 0; @@ -609,6 +666,11 @@ static inline int clk_set_rate(struct clk *clk, unsigned long rate) return 0; } +static inline int clk_set_rate_exclusive(struct clk *clk, unsigned long rate) +{ + return 0; +} + static inline long clk_round_rate(struct clk *clk, unsigned long rate) { return 0; diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index 2eabc862abdb..4890ff033220 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -12,7 +12,7 @@ #ifndef __CLKDEV_H #define __CLKDEV_H -#include <asm/clkdev.h> +#include <linux/slab.h> struct clk; struct clk_hw; @@ -52,9 +52,4 @@ int clk_add_alias(const char *, const char *, const char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *); int clk_hw_register_clkdev(struct clk_hw *, const char *, const char *); -#ifdef CONFIG_COMMON_CLK -int __clk_get(struct clk *clk); -void __clk_put(struct clk *clk); -#endif - #endif diff --git a/include/linux/platform_data/si5351.h b/include/linux/platform_data/si5351.h index 818c5c6e203f..c71a2dd66143 100644 --- a/include/linux/platform_data/si5351.h +++ b/include/linux/platform_data/si5351.h @@ -86,6 +86,7 @@ enum si5351_disable_state { * @multisynth_src: multisynth source clock * @clkout_src: clkout source clock * @pll_master: if true, clkout can also change pll rate + * @pll_reset: if true, clkout can reset its pll * @drive: output drive strength * @rate: initial clkout rate, or default if 0 */ @@ -95,6 +96,7 @@ struct si5351_clkout_config { enum si5351_drive_strength drive; enum si5351_disable_state disable_state; bool pll_master; + bool pll_reset; unsigned long rate; }; |