Clock API
A clock is a hardware signal that oscillates autonomously at a specific frequency and duty cycle. Most hardware modules require one or more clock signal to drive their operation. Clock signals are typically generated externally to the HW module consuming them, by an entity this API calls a clock provider. This API provides a standard means for drivers to enable and disable clocks, and to set the rate at which they oscillate.
A driver that implements UCLASS_CLK is a clock provider. A provider will often implement multiple separate clocks, since the hardware it manages often has this capability. clk-uclass.h describes the interface which clock providers must implement.
Clock consumers/clients are the HW modules driven by the clock signals. This header file describes the API used by drivers for those HW modules.
Client API
-
structclk
A handle to (allowing control of) a single clock.
Definition
struct clk { struct udevice *dev; long long rate; u32 flags; int enable_count; unsigned long id; unsigned long data; };
Members
dev
The device which implements the clock signal.
rate
The clock rate (in HZ).
flags
Flags used across common clock structure (e.g.
CLK_
) Clock IP blocks specific flags (i.e. mux, div, gate, etc) are defined in struct’s for those devices (e.g.struct clk_mux
).enable_count
The number of times this clock has been enabled.
id
The clock signal ID within the provider.
data
An optional data field for scenarios where a single integer ID is not sufficient. If used, it can be populated through an .of_xlate op and processed during the various clock ops.
Description
Clients provide storage for clock handles. The content of the structure is managed solely by the clock API and clock drivers. A clock struct is initialized by "get"ing the clock struct. The clock struct is passed to all other clock APIs to identify which clock signal to operate upon.
Should additional information to identify and configure any clock signal for any provider be required in the future, the struct could be expanded to either (a) add more fields to allow clock providers to store additional information, or (b) replace the id field with an opaque pointer, which the provider would dynamically allocated during its .of_xlate op, and process during is .request op. This may require the addition of an extra op to clean up the allocation.
-
structclk_bulk
A handle to (allowing control of) a bulk of clocks.
Definition
struct clk_bulk { struct clk *clks; unsigned int count; };
Members
clks
An array of clock handles.
count
The number of clock handles in the clks array.
Description
Clients provide storage for the clock bulk. The content of the structure is managed solely by the clock API. A clock bulk struct is initialized by "get"ing the clock bulk struct. The clock bulk struct is passed to all other bulk clock APIs to apply the API to all the clock in the bulk struct.
-
intclk_get_by_phandle(structudevice *dev, conststructphandle_1_arg*cells, structclk *clk)
Get a clock by its phandle information (of-platadata)
Parameters
struct udevice *dev
Device containing the phandle
const struct phandle_1_arg *cells
Phandle info
struct clk *clk
A pointer to a clock struct to initialise
Description
This function is used when of-platdata is enabled.
This looks up a clock using the phandle info. With dtoc, each phandle in the ‘clocks’ property is transformed into an idx representing the device. For example:
clocks = <&dpll_mpu_ck 23>;
might result in:
.clocks = {1, {23}},},
indicating that the clock is udevice idx 1 in dt-plat.c with an argument of 23. This function can return a valid clock given the above information. In this example it would return a clock containing the ‘dpll_mpu_ck’ device and the clock ID 23.
Return
0 if OK, or a negative error code.
-
intclk_get_by_index(structudevice *dev, intindex, structclk *clk)
Get/request a clock by integer index.
Parameters
struct udevice *dev
The client device.
int index
The index of the clock to request, within the client’s list of clocks.
struct clk *clk
A pointer to a clock struct to initialize.
Description
This looks up and requests a clock. The index is relative to the client device; each device is assumed to have n clocks associated with it somehow, and this function finds and requests one of them. The mapping of client device clock indices to provider clocks may be via device-tree properties, board-provided mapping tables, or some other mechanism.
Return
0 if OK, or a negative error code.
-
intclk_get_by_index_nodev(ofnodenode, intindex, structclk *clk)
Get/request a clock by integer index without a device.
Parameters
ofnode node
The client ofnode.
int index
The index of the clock to request, within the client’s list of clocks.
struct clk *clk
A pointer to a clock struct to initialize.
Return
0 if OK, or a negative error code.
Parameters
struct udevice *dev
The client device.
struct clk_bulk *bulk
A pointer to a clock bulk struct to initialize.
Description
This looks up and requests all clocks of the client device; each device is assumed to have n clocks associated with it somehow, and this function finds and requests all of them in a separate structure. The mapping of client device clock indices to provider clocks may be via device-tree properties, board-provided mapping tables, or some other mechanism.
Return
0 if OK, or a negative error code.
-
intclk_get_by_name(structudevice *dev, constchar*name, structclk *clk)
Get/request a clock by name.
Parameters
struct udevice *dev
The client device.
const char *name
The name of the clock to request, within the client’s list of clocks, or NULL to request the first clock in the list.
struct clk *clk
A pointer to a clock struct to initialize.
Description
This looks up and requests a clock. The name is relative to the client device; each device is assumed to have n clocks associated with it somehow, and this function finds and requests one of them. The mapping of client device clock names to provider clocks may be via device-tree properties, board-provided mapping tables, or some other mechanism.
Return
0 if OK, or a negative error code.
-
intclk_get_by_name_nodev(ofnodenode, constchar*name, structclk *clk)
Get/request a clock by name without a device.
Parameters
ofnode node
The client ofnode.
const char *name
The name of the clock to request, within the client’s list of clocks, or NULL to request the first clock in the list.
struct clk *clk
A pointer to a clock struct to initialize.
Return
0 if OK, or a negative error code.
-
structclk *devm_clk_get(structudevice *dev, constchar*id)
lookup and obtain a managed reference to a clock producer.
Parameters
struct udevice *dev
device for clock "consumer"
const char *id
clock consumer ID
Description
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.
The clock will automatically be freed when the device is unbound from the bus.
Return
a struct clk corresponding to the clock producer, or valid IS_ERR() condition containing errno
-
structclk *devm_clk_get_optional(structudevice *dev, constchar*id)
lookup and obtain a managed reference to an optional clock producer.
Parameters
struct udevice *dev
device for clock "consumer"
const char *id
clock consumer ID
Description
Behaves the same as devm_clk_get() except where there is no clock producer.
In this case, instead of returning -ENOENT
, the function returns NULL.
-
intclk_release_all(structclk *clk, unsignedintcount)
Disable (turn off)/Free an array of previously requested clocks.
Parameters
struct clk *clk
A clock struct array that was previously successfully requested by clk_request/get_by_*().
unsigned int count
Number of clock contained in the array
Description
For each clock contained in the clock array, this function will check if clock has been previously requested and then will disable and free it.
Return
zero on success, or -ve error code.
-
intclk_get_by_name_optional(structudevice *dev, constchar*name, structclk *clk)
Get/request a optional clock by name.
Parameters
struct udevice *dev
The client device.
const char *name
The name of the clock to request, within the client’s list of clocks.
struct clk *clk
A pointer to a clock struct to initialize.
Description
Behaves the same as clk_get_by_name(), except when there is no clock provider. In the latter case, return 0.
Return
0 if OK, or a negative error code.
-
intclk_get_by_name_nodev_optional(ofnodenode, constchar*name, structclk *clk)
Get/request an optinonal clock by name without a device.
Parameters
ofnode node
The client ofnode.
const char *name
The name of the clock to request, within the client’s list of clocks.
struct clk *clk
A pointer to a clock struct to initialize.
Description
Behaves the same as clk_get_by_name_nodev() except where there is
no clock producer, in this case, skip the error number -ENODATA
, and
the function returns 0.
-
constchar*clk_resolve_parent_clk(structudevice *dev, constchar*name)
Determine name of clock udevice based on clock-names
Parameters
struct udevice *dev
The client udevice.
const char *name
The name of the clock to look up.
Description
Return name of the clock udevice which represents clock with clock-names name.
-
enumclk_defaults_stage
What stage clk_set_defaults() is called at
Constants
CLK_DEFAULTS_PRE
Called before probe. Setting of defaults for clocks owned by this clock driver will be defered until after probing.
CLK_DEFAULTS_POST
Called after probe. Only defaults for clocks owned by this clock driver will be set.
CLK_DEFAULTS_POST_FORCE
Called after probe, and always set defaults, even before relocation. Usually, defaults are not set pre-relocation to avoid setting them twice (when the device is probed again post-relocation). This may incur a performance cost as device tree properties must be parsed for a second time. However, when not using SPL, pre-relocation may be the only time we can set defaults for some clocks (such as those used for the RAM we will relocate into).
-
intclk_set_defaults(structudevice *dev, enumclk_defaults_stage stage)
Process
assigned-{clocks/clock-parents/clock-rates}
properties to configure clocks
Parameters
struct udevice *dev
A device to process (the ofnode associated with this device will be processed).
enum clk_defaults_stage stage
The stage of the probing process this function is called during.
Return
zero on success, or -ve error code.
-
intclk_release_bulk(structclk_bulk *bulk)
Disable (turn off)/Free an array of previously requested clocks in a clock bulk struct.
Parameters
struct clk_bulk *bulk
A clock bulk struct that was previously successfully requested by clk_get_bulk().
Description
For each clock contained in the clock bulk struct, this function will check if clock has been previously requested and then will disable and free it.
Return
zero on success, or -ve error code.
Parameters
struct udevice *dev
The clock provider device.
struct clk *clk
A pointer to a clock struct to initialize. The caller must have already initialized any field in this struct which the clock provider uses to identify the clock.
Description
This requests a clock using a provider-specific ID. Generally, this function should not be used, since clk_get_by_index/name() provide an interface that better separates clients from intimate knowledge of clock providers. However, this function may be useful in core SoC-specific code.
Return
0 if OK, or a negative error code.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
Return
- clock rate in Hz on success, 0 for invalid clock, or -ve error code
for other errors.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
Return
pointer to parent’s struct clk, or error code passed as pointer
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
Return
clock rate in Hz, or -ve error code.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
ulong rate
desired clock rate in Hz.
Description
This answers the question "if I were to pass rate to clk_set_rate(), what clock rate would I end up with?" without changing the hardware in any way. In other words:
rate = clk_round_rate(clk, r);
and:
rate = clk_set_rate(clk, r);
are equivalent except the former does not modify the clock hardware in any way.
Return
rounded rate in Hz, or -ve error code.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
ulong rate
New clock rate in Hz.
Return
new rate, or -ve error code.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
struct clk *parent
A clock struct that was previously successfully requested by clk_request/get_by_*().
Return
new rate, or -ve error code.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
Return
zero on success, or -ve error code.
Parameters
struct clk_bulk *bulk
A clock bulk struct that was previously successfully requested by clk_get_bulk().
Return
zero on success, or -ve error code.
Parameters
struct clk *clk
A clock struct that was previously successfully requested by clk_request/get_by_*().
Return
zero on success, or -ve error code.
Parameters
struct clk_bulk *bulk
A clock bulk struct that was previously successfully requested by clk_get_bulk().
Return
zero on success, or -ve error code.
-
boolclk_is_match(conststructclk *p, conststructclk *q)
check if two clk’s point to the same hardware clock
Parameters
const struct clk *p
clk compared against q
const struct clk *q
clk compared against p
Return
true
if the two struct clk pointers both point to the same hardware clock
node, and false
otherwise. Note that two NULL
clks are treated as matching.
Parameters
ulong id
The clock ID to search for
struct clk **clkp
A pointer to clock struct that has been found among added clocks to UCLASS_CLK
Return
zero on success, or -ENOENT on error
Parameters
struct clk *clk
A pointer to the clk
Return
true on binded, or false on no
Parameters
struct clk *clk
the clock to check
Return
true if valid, or false
Driver API
-
structclk_ops
The functions that a clock driver must implement.
Definition
struct clk_ops { int (*of_xlate)(struct clk *clock, struct ofnode_phandle_args *args); int (*request)(struct clk *clock); ulong (*round_rate)(struct clk *clk, ulong rate); ulong (*get_rate)(struct clk *clk); ulong (*set_rate)(struct clk *clk, ulong rate); int (*set_parent)(struct clk *clk, struct clk *parent); int (*enable)(struct clk *clk); int (*disable)(struct clk *clk); #if IS_ENABLED(CONFIG_CMD_CLK); void (*dump)(struct udevice *dev); #endif; };
Members
of_xlate
Translate a client’s device-tree (OF) clock specifier.
request
Request a translated clock.
round_rate
Adjust a rate to the exact rate a clock can provide.
get_rate
Get current clock rate.
set_rate
Set current clock rate.
set_parent
Set current clock parent
enable
Enable a clock.
disable
Disable a clock.
dump
Print clock information.
Description
The individual methods are described more fully below.
-
intof_xlate(structclk *clock, structofnode_phandle_args*args)
Translate a client’s device-tree (OF) clock specifier.
Parameters
struct clk *clock
The clock struct to hold the translation result.
struct ofnode_phandle_args *args
The clock specifier values from device tree.
Description
The clock core calls this function as the first step in implementing a client’s clk_get_by_*() call.
If this function pointer is set to NULL, the clock core will use a default implementation, which assumes #clock-cells = <1>, and that the DT cell contains a simple integer clock ID.
This function should be a simple translation of args into clock->id and (optionally) clock->data. All other processing, allocation, or error checking should take place in request().
At present, the clock API solely supports device-tree. If this changes, other xxx_xlate() functions may be added to support those other mechanisms.
Return
0 on success
-
EINVAL
if args does not have the correct format. For example, it could have too many/few arguments.-
ENOENT
if args has the correct format but cannot be translated. This can happen if translation involves a table lookup and args is not present.
Parameters
struct clk *clock
The clock struct to request; this has been filled in by a previoux xxx_xlate() function call, or by the caller of clk_request().
Description
The clock core calls this function as the second step in implementing a client’s clk_get_by_*() call, following a successful xxx_xlate() call, or as the only step in implementing a client’s clk_request() call.
This is the right place to do bounds checking (rejecting invalid or unimplemented clocks), allocate resources, or perform other setup not done during driver probe(). Most clock drivers should allocate resources in their probe() function, but it is possible to lazily initialize something here.
Return
0 on success
-
ENOENT
, if there is no clock corresponding to clock->id and clock->data.
Parameters
struct clk *clk
The clock to query.
ulong rate
Desired clock rate in Hz.
Description
This function returns a new rate which can be provided to set_rate(). This new rate should be the closest rate to rate which can be set without rounding. The following pseudo-code should hold:
for all rate in range(ULONG_MAX): rounded = round_rate(clk, rate) new_rate = set_rate(clk, rate) assert(IS_ERR_VALUE(new_rate) || new_rate == rounded)
Return
The rounded rate in Hz on success
A negative error value from another API (such as clk_get_rate()). This function must not return an error for any other reason.
Parameters
struct clk *clk
The clock to query.
Description
This returns the current rate of a clock. If the clock is disabled, it returns the rate at which the clock would run if it was enabled. The following pseudo-code should hold:
disable(clk) rate = get_rate(clk) enable(clk) assert(get_rate(clk) == rate)
Return
The rate of clk
-
ENOSYS
if this function is not implemented for clk-
ENOENT
if clk->id is invalid. Prefer using an assert instead, and doing this check in request().Another negative error value (such as
EIO
orECOMM
) if the rate could not be determined due to a bus error.
Parameters
struct clk *clk
The clock to manipulate.
ulong rate
New clock rate in Hz.
Description
Set the rate of clk to rate. The actual rate may be rounded. However, excessive rounding should be avoided. It is left to the driver author’s discretion when this function should attempt to round and when it should return an error. For example, a dividing clock might use the following pseudo-logic when implemening this function:
divisor = parent_rate / rate if divisor < min || divisor > max: return -EINVAL
If there is any concern about rounding, prefer to let consumers make the decision by calling round_rate().
Return
The new rate on success
-
ENOSYS
if this function is not implemented for clk-
ENOENT
if clk->id is invalid. Prefer using an assert instead, and doing this check in request().-
EINVAL
if rate is not valid for clk.Another negative error value (such as
EIO
orECOMM
) if the rate could not be set due to a bus error.
Parameters
struct clk *clk
The clock to manipulate.
struct clk *parent
New clock parent.
Description
Set the current parent of clk to parent. The rate of the clock may be modified by this call. If clk was enabled before this function, it should remain enabled after this function, although it may be temporarily disabled if necessary.
Return
0 on success
-
ENOSYS
if this function is not implemented for clk-
ENOENT
if clk->id or parent->id is invalid. Prefer using an assert instead, and doing this check in request().-
EINVAL
if parent is not a valid parent for clk.Another negative error value (such as
EIO
orECOMM
) if the parent could not be set due to a bus error.
Parameters
struct clk *clk
The clock to manipulate.
Description
Enable (un-gate) the clock. This function should not modify the rate of the clock (see get_rate() for details).
Return
0 on success
-
ENOSYS
if this function is not implemented for clk-
ENOENT
if clk->id is invalid. Prefer using an assert instead, and doing this check in request().Another negative error value (such as
EIO
orECOMM
) if the clock could not be enabled due to a bus error.
Parameters
struct clk *clk
The clock to manipulate.
Description
Disable (gate) the clock. This function should not modify the rate of the clock (see get_rate() for details).
0 on success
-
ENOSYS
if this function is not implemented for clk-
ENOENT
if clk->id is invalid. Prefer using an assert instead, and doing this check in request().Another negative error value (such as
EIO
orECOMM
) if the clock could not be disabled due to a bus error.
Parameters
struct udevice *dev
The clock device to dump.
Description
If present, this function is called by "clk dump" command for each bound device.