diff options
Diffstat (limited to 'include/linux/clk.h')
-rw-r--r-- | include/linux/clk.h | 835 |
1 files changed, 717 insertions, 118 deletions
diff --git a/include/linux/clk.h b/include/linux/clk.h index c3aeea80dd..7ba0679d03 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -1,20 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2004 ARM Limited */ + /* * linux/include/linux/clk.h * - * Copyright (C) 2004 ARM Limited. * Written by Deep Blue Solutions Limited. - * - * 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_H #define __LINUX_CLK_H #include <linux/err.h> +#include <linux/spinlock.h> #include <linux/stringify.h> +#include <linux/container_of.h> +#include <deep-probe.h> +#include <xfuncs.h> -struct device_d; +struct device; /* * The base API. @@ -24,6 +27,7 @@ struct device_d; * struct clk - an machine class defined object / cookie. */ struct clk; +struct clk_hw; /** * struct clk_bulk_data - Data used for bulk clk operations. @@ -58,30 +62,7 @@ struct clk_bulk_data { * * clk_get should not be called from within interrupt context. */ -struct clk *clk_get(struct device_d *dev, const char *id); - -/** - * clk_bulk_get - lookup and obtain a number of references to clock producer. - * @dev: device for clock "consumer" - * @num_clks: the number of clk_bulk_data - * @clks: the clk_bulk_data table of consumer - * - * This helper function allows drivers to get several clk consumers in one - * operation. If any of the clk cannot be acquired then any clks - * that were obtained will be freed before returning to the caller. - * - * Returns 0 if all clocks specified in clk_bulk_data table are obtained - * successfully, or valid IS_ERR() condition containing errno. - * The implementation uses @dev and @clk_bulk_data.id to determine the - * clock consumer, and thereby the clock producer. - * The clock returned is stored in each @clk_bulk_data.clk field. - * - * Drivers must assume that the clock source is not enabled. - * - * clk_bulk_get should not be called from within interrupt context. - */ -int __must_check clk_bulk_get(struct device_d *dev, int num_clks, - struct clk_bulk_data *clks); +struct clk *clk_get(struct device *dev, const char *id); /** * clk_enable - inform the system when the clock source should be running. @@ -94,18 +75,6 @@ int __must_check clk_bulk_get(struct device_d *dev, int num_clks, int clk_enable(struct clk *clk); /** - * clk_bulk_enable - inform the system when the set of clks should be running. - * @num_clks: the number of clk_bulk_data - * @clks: the clk_bulk_data table of consumer - * - * May be called from atomic contexts. - * - * Returns success (0) or negative errno. - */ -int __must_check clk_bulk_enable(int num_clks, - const struct clk_bulk_data *clks); - -/** * clk_disable - inform the system when the clock source is no longer required. * @clk: clock source * @@ -120,42 +89,12 @@ int __must_check clk_bulk_enable(int num_clks, void clk_disable(struct clk *clk); /** - * clk_bulk_disable - inform the system when the set of clks is no - * longer required. - * @num_clks: the number of clk_bulk_data - * @clks: the clk_bulk_data table of consumer - * - * Inform the system that a set of clks is no longer required by - * a driver and may be shut down. - * - * May be called from atomic contexts. - * - * Implementation detail: if the set of clks is shared between - * multiple drivers, clk_bulk_enable() calls must be balanced by the - * same number of clk_bulk_disable() calls for the clock source to be - * disabled. - */ -void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); - -/** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. * @clk: clock source */ unsigned long clk_get_rate(struct clk *clk); - -/** - * clk_bulk_put - "free" the clock source - * @num_clks: the number of clk_bulk_data - * @clks: the clk_bulk_data table of consumer - * - * Note: drivers must ensure that all clk_bulk_enable calls made on this - * clock source are balanced by clk_bulk_disable calls prior to calling - * this function. - * - * clk_bulk_put should not be called from within interrupt context. - */ -void clk_bulk_put(int num_clks, struct clk_bulk_data *clks); +unsigned long clk_hw_get_rate(struct clk_hw *hw); /* * The remaining APIs are optional for machine class support. @@ -170,7 +109,7 @@ void clk_bulk_put(int num_clks, struct clk_bulk_data *clks); * Returns rounded clock rate in Hz, or negative errno. */ long clk_round_rate(struct clk *clk, unsigned long rate); - +long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate); /** * clk_set_rate - set the clock rate for a clock source * @clk: clock source @@ -179,6 +118,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); +int clk_hw_set_rate(struct clk_hw *hw, unsigned long rate); /** * clk_set_parent - set the parent clock source for this clock @@ -188,6 +128,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate); * Returns success (0) or negative errno. */ int clk_set_parent(struct clk *clk, struct clk *parent); +int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *hwp); +struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, unsigned int idx); /** * clk_get_parent - get the parent clock source for this clock @@ -197,6 +139,11 @@ int clk_set_parent(struct clk *clk, struct clk *parent); * valid IS_ERR() condition containing errno. */ struct clk *clk_get_parent(struct clk *clk); +struct clk_hw *clk_hw_get_parent(struct clk_hw *hw); +int clk_hw_get_parent_index(struct clk_hw *hw); + +int clk_set_phase(struct clk *clk, int degrees); +int clk_get_phase(struct clk *clk); /** * clk_get_sys - get a clock based upon the device name @@ -226,29 +173,26 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id); * Assumes clkdev, see clkdev.h for more info. */ int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, - struct device_d *dev); + struct device *dev); #else -static inline struct clk *clk_get(struct device_d *dev, const char *id) +static inline struct clk *clk_get(struct device *dev, const char *id) { return NULL; } -static inline int __must_check clk_bulk_get(struct device_d *dev, int num_clks, - struct clk_bulk_data *clks) +static inline struct clk *clk_get_parent(struct clk *clk) { - return 0; + return NULL; } -static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {} - -static inline int clk_enable(struct clk *clk) +static inline int clk_hw_get_parent_index(struct clk_hw *hw) { - return 0; + return -EINVAL; } -static inline int __must_check clk_bulk_enable(int num_clks, struct clk_bulk_data *clks) +static inline int clk_enable(struct clk *clk) { return 0; } @@ -257,9 +201,6 @@ static inline void clk_disable(struct clk *clk) { } -static inline void clk_bulk_disable(int num_clks, - struct clk_bulk_data *clks) {} - static inline unsigned long clk_get_rate(struct clk *clk) { return 0; @@ -276,6 +217,9 @@ static inline int clk_set_rate(struct clk *clk, unsigned long rate) } #endif +#define clk_prepare_enable(clk) clk_enable(clk) +#define clk_disable_unprepare(clk) clk_disable(clk) + static inline void clk_put(struct clk *clk) { } @@ -286,26 +230,122 @@ static inline void clk_put(struct clk *clk) #define CLK_SET_RATE_PARENT (1 << 0) /* propagate rate change up one level */ #define CLK_IGNORE_UNUSED (1 << 3) /* do not gate even if unused */ +#define CLK_GET_RATE_NOCACHE (1 << 6) /* do not use the cached clk rate */ #define CLK_SET_RATE_NO_REPARENT (1 << 7) /* don't re-parent on rate change */ +#define CLK_SET_RATE_UNGATE (1 << 10) /* clock needs to run to set rate */ #define CLK_IS_CRITICAL (1 << 11) /* do not gate, ever */ /* parents need enable during gate/ungate, set rate and re-parent */ #define CLK_OPS_PARENT_ENABLE (1 << 12) -#define CLK_GATE_INVERTED (1 << 0) +#define CLK_GATE_SET_TO_DISABLE (1 << 0) #define CLK_GATE_HIWORD_MASK (1 << 1) +/* Ignored sanity checking flags */ +#define CLK_SET_RATE_GATE 0 /* must be gated across rate change */ +#define CLK_SET_PARENT_GATE 0 /* must be gated across re-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. + * + * @init: Perform platform-specific initialization magic. + * This is not used by any of the basic clock types. + * This callback exist for HW which needs to perform some + * initialisation magic for CCF to get an accurate view of the + * clock. It may also be used dynamic resource allocation is + * required. It shall not used to deal with clock parameters, + * such as rate or parents. + * Returns 0 on success, -EERROR otherwise. + * + * @enable: Prepare and enable the clock atomically. This must not return + * until the clock is generating a valid clock signal, usable by + * consumer devices. + * + * @disable: Unprepare and disable the clock atomically. + * + * @is_enabled: Queries the hardware to determine if the clock is enabled. + * Optional, if this op is not set then the enable count will be + * used. + * + * @recalc_rate Recalculate the rate of this clock, by querying hardware. The + * parent rate is an input parameter. If the driver cannot figure + * out a rate for this clock, it must return 0. 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. The parent rate is an input/output + * parameter. + * + * @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. + * + * @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. + * + * @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_phase: Shift the phase this clock signal in degrees specified + * by the second argument. Valid values for degrees are + * 0-359. Return 0 on success, otherwise -EERROR. + * + * @get_phase: Queries the hardware to get the current phase of a clock. + * Returned values are 0-359 degrees on success, negative + * error codes on failure. + * + * Unlike Linux, there is no differentiation between clk_prepare/clk_enable + * and clk_unprepare/clk_disable in barebox as all work is atomic. + */ struct clk_ops { - int (*enable)(struct clk *clk); - void (*disable)(struct clk *clk); - int (*is_enabled)(struct clk *clk); - unsigned long (*recalc_rate)(struct clk *clk, + int (*init)(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 *clk, unsigned long, + long (*round_rate)(struct clk_hw *hw, unsigned long, unsigned long *); - int (*set_parent)(struct clk *clk, u8 index); - int (*get_parent)(struct clk *clk); - int (*set_rate)(struct clk *clk, unsigned long, + int (*set_parent)(struct clk_hw *hw, u8 index); + int (*get_parent)(struct clk_hw *hw); + int (*set_rate)(struct clk_hw *hw, unsigned long, unsigned long); + int (*set_phase)(struct clk_hw *hw, int degrees); + int (*get_phase)(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 + * @parent_hws: array of pointers to all possible parents (when all parents + * are internal to the clk controller) + * @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 * const *parent_names; + const struct clk_hw **parent_hws; + unsigned int num_parents; + unsigned long flags; }; struct clk { @@ -320,15 +360,56 @@ struct clk { 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 per-user struct clk instance that can be used to call + * into the clk API + * + * @init: pointer to struct clk_init_data that contains the init data shared + * with the common clock framework. + */ +struct clk_hw { + struct clk clk; + const struct clk_init_data *init; +}; + +static inline struct clk *clk_hw_to_clk(const struct clk_hw *hw) +{ + return IS_ERR(hw) ? ERR_CAST(hw) : (struct clk *)&hw->clk; +} + +static inline struct clk_hw *clk_to_clk_hw(const struct clk *clk) +{ + return container_of_safe(clk, struct clk_hw, clk); +} +#define __clk_get_hw(clk) clk_to_clk_hw(clk) + struct clk_div_table { unsigned int val; unsigned int div; }; -struct clk *clk_fixed(const char *name, int rate); +struct clk *clk_register_fixed_rate(const char *name, + const char *parent_name, unsigned long flags, + unsigned long fixed_rate); + +struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + unsigned long rate); + +static inline struct clk *clk_fixed(const char *name, int rate) +{ + return clk_register_fixed_rate(name, NULL, 0, rate); +} struct clk_divider { - struct clk clk; + struct clk_hw hw; u8 shift; u8 width; void __iomem *reg; @@ -338,18 +419,33 @@ struct clk_divider { const struct clk_div_table *table; int max_div_index; int table_size; + spinlock_t *lock; }; +#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) + #define clk_div_mask(width) ((1 << (width)) - 1) #define CLK_DIVIDER_POWER_OF_TWO (1 << 1) +#define CLK_DIVIDER_ALLOW_ZERO (1 << 2) #define CLK_DIVIDER_HIWORD_MASK (1 << 3) #define CLK_DIVIDER_READ_ONLY (1 << 5) #define CLK_MUX_HIWORD_MASK (1 << 2) #define CLK_MUX_READ_ONLY (1 << 3) /* mux can't be changed */ -extern struct clk_ops clk_divider_ops; +extern const struct clk_ops clk_divider_ops; +extern const struct clk_ops clk_divider_ro_ops; + +static inline void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent) +{ + /* clk_get_parent always reads from HW, so nothing to update here */ +} + +static inline int __clk_get_enable_count(struct clk *clk) +{ + return !clk ? 0 : clk->enable_count; +} unsigned long divider_recalc_rate(struct clk *clk, unsigned long parent_rate, unsigned int val, @@ -371,6 +467,10 @@ void clk_divider_free(struct clk *clk_divider); struct clk *clk_divider(const char *name, const char *parent, unsigned clk_flags, void __iomem *reg, u8 shift, u8 width, unsigned div_flags); +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 *clk_divider_one_based(const char *name, const char *parent, unsigned clk_flags, void __iomem *reg, u8 shift, u8 width, unsigned div_flags); @@ -378,9 +478,99 @@ struct clk *clk_divider_table(const char *name, const char *parent, unsigned clk_flags, void __iomem *reg, u8 shift, u8 width, const struct clk_div_table *table, unsigned div_flags); +struct clk *clk_register_divider_table(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock); + +struct clk_hw *clk_hw_register_divider_table(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *reg, u8 shift, + u8 width, + u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock); + +struct clk_hw *clk_hw_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_fixed_factor { + struct clk_hw hw; + int mult; + int div; + const char *parent; +}; + +static inline struct clk_fixed_factor *to_clk_fixed_factor(struct clk_hw *hw) +{ + return container_of(hw, struct clk_fixed_factor, hw); +} + +extern struct clk_ops clk_fixed_factor_ops; + struct clk *clk_fixed_factor(const char *name, const char *parent, unsigned int mult, unsigned int div, unsigned flags); +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_hw *clk_hw_register_fixed_factor(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + unsigned int mult, + unsigned int div); + +/** + * struct clk_fractional_divider - adjustable fractional divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the divider + * @mshift: shift to the numerator bit field + * @mwidth: width of the numerator bit field + * @nshift: shift to the denominator bit field + * @nwidth: width of the denominator bit field + * + * Clock with adjustable fractional divider affecting its output frequency. + * + * Flags: + * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator + * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED + * is set then the numerator and denominator are both the value read + * plus one. + * CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are + * used for the divider register. Setting this flag makes the register + * accesses big endian. + */ +struct clk_fractional_divider { + struct clk_hw hw; + void __iomem *reg; + u8 mshift; + u8 mwidth; + u32 mmask; + u8 nshift; + u8 nwidth; + u32 nmask; + u8 flags; + void (*approximation)(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate, + unsigned long *m, unsigned long *n); + spinlock_t *lock; +}; + +#define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0) +#define CLK_FRAC_DIVIDER_BIG_ENDIAN BIT(1) + struct clk *clk_fractional_divider_alloc( const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, @@ -391,17 +581,24 @@ struct clk *clk_fractional_divider( u8 clk_divider_flags); void clk_fractional_divider_free(struct clk *clk_fd); +#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) + +extern const struct clk_ops clk_fractional_divider_ops; + struct clk_mux { - struct clk clk; + struct clk_hw hw; void __iomem *reg; int shift; int width; unsigned flags; + u32 *table; + spinlock_t *lock; }; -#define to_clk_mux(_clk) container_of(_clk, struct clk_mux, clk) +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) -extern struct clk_ops clk_mux_ops; +extern const struct clk_ops clk_mux_ops; +extern const struct clk_ops clk_mux_ro_ops; struct clk *clk_mux_alloc(const char *name, unsigned clk_flags, void __iomem *reg, u8 shift, u8 width, @@ -411,18 +608,55 @@ void clk_mux_free(struct clk *clk_mux); struct clk *clk_mux(const char *name, unsigned clk_flags, void __iomem *reg, u8 shift, u8 width, const char * const *parents, u8 num_parents, unsigned mux_flags); +struct clk *clk_register_mux(struct device *dev, const char *name, + const char * const *parent_names, u8 num_parents, + unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_mux_flags, spinlock_t *lock); + +struct clk_hw *__clk_hw_register_mux(struct device *dev, + const char *name, u8 num_parents, + const char * const *parent_names, + unsigned long flags, void __iomem *reg, + u8 shift, u32 mask, + u8 clk_mux_flags, u32 *table, + spinlock_t *lock); + +#define clk_hw_register_mux(dev, name, parent_names, \ + num_parents, flags, reg, shift, mask, \ + clk_mux_flags, lock) \ + __clk_hw_register_mux((dev), (name), (num_parents), \ + (parent_names), \ + (flags), (reg), (shift), (mask), \ + (clk_mux_flags), NULL, (lock)) + +#define clk_hw_register_mux_table(dev, name, parent_names, num_parents, \ + flags, reg, shift, mask, clk_mux_flags, \ + table, lock) \ + __clk_hw_register_mux((dev), (name), (num_parents), \ + (parent_names), (flags), (reg), \ + (shift), (mask), (clk_mux_flags), (table), \ + (lock)) + +int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, + unsigned int val); +unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index); + +long clk_mux_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate); struct clk_gate { - struct clk clk; + struct clk_hw hw; void __iomem *reg; int shift; const char *parent; unsigned flags; + spinlock_t *lock; }; -int clk_gate_is_enabled(struct clk *clk); +int clk_gate_is_enabled(struct clk_hw *hw); -#define to_clk_gate(_clk) container_of(_clk, struct clk_gate, clk) +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) extern struct clk_ops clk_gate_ops; @@ -436,20 +670,46 @@ struct clk *clk_gate_inverted(const char *name, const char *parent, void __iomem u8 shift, unsigned flags); struct clk *clk_gate_shared(const char *name, const char *parent, const char *shared, unsigned flags); +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); + +static inline struct clk_hw *clk_hw_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) +{ + return clk_to_clk_hw(clk_register_gate(dev, xstrdup(name), xstrdup(parent_name), + flags, reg, bit_idx, + clk_gate_flags, lock)); +} int clk_is_enabled(struct clk *clk); +int clk_hw_is_enabled(struct clk_hw *hw); -int clk_is_enabled_always(struct clk *clk); -long clk_parent_round_rate(struct clk *clk, unsigned long rate, +int clk_is_enabled_always(struct clk_hw *hw); +long clk_parent_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate); -int clk_parent_set_rate(struct clk *clk, unsigned long rate, +int clk_parent_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); -int clk_register(struct clk *clk); +int bclk_register(struct clk *clk); +struct clk *clk_register(struct device *dev, struct clk_hw *hw); + +static inline int clk_hw_register(struct device *dev, struct clk_hw *hw) +{ + return PTR_ERR_OR_ZERO(clk_register(dev, hw)); +} struct clk *clk_lookup(const char *name); void clk_dump(int verbose); +void clk_dump_one(struct clk *clk, int verbose); struct clk *clk_register_composite(const char *name, const char * const *parent_names, int num_parents, @@ -457,6 +717,37 @@ struct clk *clk_register_composite(const char *name, struct clk *rate_clk, struct clk *gate_clk, unsigned long flags); + +struct clk_hw *clk_hw_register_composite(struct device *dev, + const char *name, + const char * const *parent_names, + int num_parents, + struct clk_hw *mux_hw, + const struct clk_ops *mux_ops, + struct clk_hw *rate_hw, + const struct clk_ops *rate_ops, + struct clk_hw *gate_hw, + const struct clk_ops *gate_ops, + unsigned long flags); + +static inline const char *clk_hw_get_name(struct clk_hw *hw) +{ + return hw->clk.name; +} + +static inline unsigned int clk_hw_get_num_parents(const struct clk_hw *hw) +{ + return hw->clk.num_parents; +} + +static inline unsigned long clk_hw_get_flags(const struct clk_hw *hw) +{ + return hw->clk.flags; +} + +int clk_name_set_parent(const char *clkname, const char *clkparentname); +int clk_name_set_rate(const char *clkname, unsigned long rate); + #endif struct device_node; @@ -468,11 +759,16 @@ struct clk_onecell_data { unsigned int clk_num; }; +struct clk_hw_onecell_data { + unsigned int num; + struct clk_hw *hws[]; +}; + #if defined(CONFIG_COMMON_CLK_OF_PROVIDER) #define CLK_OF_DECLARE(name, compat, fn) \ const struct of_device_id __clk_of_table_##name \ -__attribute__ ((unused,section (".__clk_of_table"))) \ + __ll_elem(.__clk_of_table) \ = { .compatible = compat, .data = fn } void of_clk_del_provider(struct device_node *np); @@ -481,6 +777,8 @@ typedef int (*of_clk_init_cb_t)(struct device_node *); struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data); struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, void *data); +struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data); +struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data); struct clk *of_clk_get(struct device_node *np, int index); struct clk *of_clk_get_by_name(struct device_node *np, const char *name); @@ -488,16 +786,17 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec); unsigned int of_clk_get_parent_count(struct device_node *np); int of_clk_parent_fill(struct device_node *np, const char **parents, unsigned int size); -int of_clk_init(struct device_node *root, const struct of_device_id *matches); +int of_clk_init(void); int of_clk_add_provider(struct device_node *np, struct clk *(*clk_src_get)(struct of_phandle_args *args, void *data), void *data); -static inline unsigned int clk_get_num_parents(const struct clk *hw) -{ - return hw->num_parents; -} +int of_clk_add_hw_provider(struct device_node *np, + struct clk_hw *(*clk_hw_src_get)(struct of_phandle_args *clkspec, + void *data), + void *data); + #else @@ -515,11 +814,21 @@ static inline struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec { return ERR_PTR(-ENOENT); } +static inline struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec, + void *data) +{ + return ERR_PTR(-ENOENT); +} static inline struct clk * of_clk_src_simple_get(struct of_phandle_args *clkspec, void *data) { return ERR_PTR(-ENOENT); } +static inline struct clk_hw * +of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data) +{ + return ERR_PTR(-ENOENT); +} static inline struct clk *of_clk_get(struct device_node *np, int index) { return ERR_PTR(-ENOENT); @@ -529,8 +838,12 @@ static inline struct clk *of_clk_get_by_name(struct device_node *np, { return ERR_PTR(-ENOENT); } -static inline int of_clk_init(struct device_node *root, - const struct of_device_id *matches) +static inline unsigned int of_clk_get_parent_count(struct device_node *np) +{ + return 0; +} + +static inline int of_clk_init(void) { return 0; } @@ -541,6 +854,14 @@ static inline int of_clk_add_provider(struct device_node *np, { return 0; } + +static inline int of_clk_add_hw_provider(struct device_node *np, + struct clk_hw *(*clk_hw_src_get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + return 0; +} #endif #define CLK_OF_DECLARE_DRIVER(name, compat, fn) CLK_OF_DECLARE(name, compat, fn) @@ -549,6 +870,284 @@ struct string_list; int clk_name_complete(struct string_list *sl, char *instr); -char *of_clk_get_parent_name(struct device_node *np, unsigned int index); +char *of_clk_get_parent_name(const struct device_node *np, int index); + +static inline void clk_unregister(struct clk *clk) +{ +} + +static inline void clk_hw_unregister(struct clk_hw *hw) +{ +} + +#ifdef CONFIG_COMMON_CLK + +/** + * clk_bulk_get - lookup and obtain a number of references to clock producer. + * @dev: device for clock "consumer" + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * This helper function allows drivers to get several clk consumers in one + * operation. If any of the clk cannot be acquired then any clks + * that were obtained will be freed before returning to the caller. + * + * Returns 0 if all clocks specified in clk_bulk_data table are obtained + * successfully, or valid IS_ERR() condition containing errno. + * The implementation uses @dev and @clk_bulk_data.id to determine the + * clock consumer, and thereby the clock producer. + * The clock returned is stored in each @clk_bulk_data.clk field. + * + * Drivers must assume that the clock source is not enabled. + * + * clk_bulk_get should not be called from within interrupt context. + */ +int __must_check clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks); + +/** + * clk_bulk_get_optional - lookup and obtain a number of references to clock producer + * @dev: device for clock "consumer" + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * Behaves the same as clk_bulk_get() except where there is no clock producer. + * In this case, instead of returning -ENOENT, the function returns 0 and + * NULL for a clk for which a clock producer could not be determined. + */ +int __must_check clk_bulk_get_optional(struct device *dev, int num_clks, + struct clk_bulk_data *clks); + +/** + * clk_bulk_get_all - lookup and obtain all available references to clock + * producer. + * @dev: device for clock "consumer" + * @clks: pointer to the clk_bulk_data table of consumer + * + * This helper function allows drivers to get all clk consumers in one + * operation. If any of the clk cannot be acquired then any clks + * that were obtained will be freed before returning to the caller. + * + * Returns a positive value for the number of clocks obtained while the + * clock references are stored in the clk_bulk_data table in @clks field. + * Returns 0 if there're none and a negative value if something failed. + * + * Drivers must assume that the clock source is not enabled. + * + * clk_bulk_get should not be called from within interrupt context. + */ +int __must_check clk_bulk_get_all(struct device *dev, + struct clk_bulk_data **clks); + +/** + * clk_bulk_put - "free" the clock source + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * Note: drivers must ensure that all clk_bulk_enable calls made on this + * clock source are balanced by clk_bulk_disable calls prior to calling + * this function. + * + * clk_bulk_put should not be called from within interrupt context. + */ +void clk_bulk_put(int num_clks, struct clk_bulk_data *clks); + +/** + * clk_bulk_put_all - "free" all the clock source + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * Note: drivers must ensure that all clk_bulk_enable calls made on this + * clock source are balanced by clk_bulk_disable calls prior to calling + * this function. + * + * clk_bulk_put_all should not be called from within interrupt context. + */ +void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks); + +/** + * clk_bulk_enable - inform the system when the set of clks should be running. + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * May be called from atomic contexts. + * + * Returns success (0) or negative errno. + */ +int __must_check clk_bulk_enable(int num_clks, + const struct clk_bulk_data *clks); + +/** + * clk_bulk_disable - inform the system when the set of clks is no + * longer required. + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * Inform the system that a set of clks is no longer required by + * a driver and may be shut down. + * + * May be called from atomic contexts. + * + * Implementation detail: if the set of clks is shared between + * multiple drivers, clk_bulk_enable() calls must be balanced by the + * same number of clk_bulk_disable() calls for the clock source to be + * disabled. + */ +void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); + +#else +static inline int __must_check clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks) +{ + return 0; +} + +static inline int __must_check clk_bulk_get_optional(struct device *dev, + int num_clks, + struct clk_bulk_data *clks) +{ + return 0; +} + +static inline int __must_check clk_bulk_get_all(struct device *dev, + struct clk_bulk_data **clks) +{ + return 0; +} + +static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {} + +static inline void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks) {} + +static inline int __must_check clk_bulk_enable(int num_clks, struct clk_bulk_data *clks) +{ + return 0; +} + +static inline void clk_bulk_disable(int num_clks, + struct clk_bulk_data *clks) {} + +#endif + +/** + * clk_hw_register_fixed_rate_with_accuracy - 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 + * @fixed_accuracy: non-adjustable clock accuracy (ignored) + */ +#define clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name, \ + flags, fixed_rate, \ + fixed_accuracy) \ + clk_hw_register_fixed_rate((dev), (name), (parent_name), (flags), (fixed_rate)) + +#define clk_bulk_prepare_enable clk_bulk_enable +#define clk_bulk_disable_unprepare clk_bulk_disable + +/** + * clk_get_optional - lookup and obtain a reference to an optional clock + * producer. + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Behaves the same as clk_get() except where there is no clock producer. In + * this case, instead of returning -ENOENT, the function returns NULL. + */ +static inline struct clk *clk_get_optional(struct device *dev, const char *id) +{ + struct clk *clk = clk_get(dev, id); + + if (clk == ERR_PTR(-ENOENT)) + return NULL; + + return clk; +} + +/** + * clk_get_enabled - clk_get() + clk_prepare_enable() + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Return: 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.) + * + * The returned clk (if valid) is enabled. + */ +static inline struct clk *clk_get_enabled(struct device *dev, const char *id) +{ + struct clk *clk; + int ret; + + clk = clk_get(dev, id); + if (IS_ERR(clk)) + return clk; + + ret = clk_enable(clk); + if (ret) { + clk_put(clk); + return ERR_PTR(ret); + } + + return clk; +} + +/** + * clk_get_optional_enabled - clk_get_optional() + + * clk_prepare_enable() + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Return: 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. If no such clk is found, it returns NULL + * which serves as a dummy clk. That's the only difference compared + * to clk_get_enabled(). + * + * The returned clk (if valid) is enabled. + */ +static inline struct clk *clk_get_optional_enabled(struct device *dev, const char *id) +{ + struct clk *clk; + int ret; + + clk = clk_get_optional(dev, id); + if (IS_ERR_OR_NULL(clk)) + return clk; + + ret = clk_enable(clk); + if (ret) { + clk_put(clk); + return ERR_PTR(ret); + } + + return clk; +} + +/** + * clk_get_if_available - get clock, ignoring known unavailable clock controller + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Return: a struct clk corresponding to the clock producer, a + * valid IS_ERR() condition containing errno or NULL if it could + * be determined that the clock producer will never be probed in + * absence of modules. + */ +static inline struct clk *clk_get_if_available(struct device *dev, const char *id) +{ + struct clk *clk = clk_get(dev, id); + + if (clk == ERR_PTR(-EPROBE_DEFER) && deep_probe_is_supported()) + return NULL; + + return clk; +} #endif |