/* * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com * * SPDX-License-Identifier: BSD-3-Clause */ /* * Device Clock Management API * * This header defines the device clock API for managing clocks attached to * devices. It provides clock type definitions, device clock data structures, * and functions for clock control including enable/disable, parent selection, * frequency configuration, and state management. */ #ifndef TI_DEVICE_CLK_H #define TI_DEVICE_CLK_H #include #include /* * Sentinel value for invalid or non-existent device clock ID * * Used to indicate that a device clock index is invalid, uninitialized, or * that no clock exists at the requested position. Functions returning * ti_dev_clk_idx_t use this value to signal errors or missing clocks. */ #define TI_DEV_CLK_ID_NONE ((ti_dev_clk_idx_t) (~0U)) /* * Input clock type. * * This is a normal clock, it's an input to the IP from elsewhere. */ #define TI_DEV_CLK_TABLE_TYPE_INPUT 0U /* * Mux clock type. * * This is a clock mux that is meant to be controlled directly. The potential * parents of the mux are listed after the mux as TYPE_PARENT. Set frequency * calls to a mux are passed to the current parent. */ #define TI_DEV_CLK_TABLE_TYPE_MUX 1U /* * Mux parent clock type. * * This is a potential parent for a mux. Normal clocks are set to follow the * device state (requested when device is enabled, unrequested otherwise) but * mux parents are set to always unrequested by default. If they are selected * they will get a ref count from the mux clock. * * Mux parents are present so they can be enabled and configured before being * selected via the mux. */ #define TI_DEV_CLK_TABLE_TYPE_PARENT 2U /* * Output clock type. * * This is an output clock from the device. Setting the frequency informs * potential consumers of the frequency but otherwise has no effect. */ #define TI_DEV_CLK_TABLE_TYPE_OUTPUT 3U struct ti_device; /* * Const clock device data * * This is the fixed data for tracking clocks attached to devices. */ struct ti_dev_clk_data { /* Type of table entry */ uint8_t type; /* * Modifying the frequency of this clock will attempt to modify * the parent freq. */ uint8_t modify_parent_freq; /* * Clock divider, not valid for output, max 255 for parent otherwise * up to USHORT_MAX/8. */ uint16_t div; /* For mux, the number of parents, for parents the index for the mux */ uint8_t idx; /* For mux, the number of reserved parent slots */ uint8_t n_reserved_parents; /* Which SoC clock this plugs into */ uint16_t clk; }; /* * Dynamic clock device data * * This tracks the current state of a device attached clock via flags. * This is just how the upstream clock is configured for the current * device. The upstream clock still has its own data and state. * * A pointer to a bss that has been reserved for this data is pointed * to by the device. If there is only one clock on the device, the field * is shared with the device flags and a forced cast is made to return * the field. */ struct ti_dev_clk { uint8_t flags; }; /* Declare a device clock of type input */ #define TI_DEV_CLK(base, id, parent, _div)[(base) + (id)] = \ { .clk = (parent), .div = (_div), \ .type = TI_DEV_CLK_TABLE_TYPE_INPUT, \ .modify_parent_freq = 1U } /* Declare a device clock of type mux */ #define TI_DEV_CLK_MUX(base, id, parent, _div, n_parents, n_reserved)[(base) + (id)] = \ { .clk = (parent), .div = (_div), \ .type = TI_DEV_CLK_TABLE_TYPE_MUX, \ .idx = (n_parents), \ .n_reserved_parents = (n_reserved), \ .modify_parent_freq = 1U } /* * Declare a device clock of type mux parent. To match clk_mux_parent, * divider here can only be 8 bit */ #define TI_DEV_CLK_PARENT(base, id, parent, _div, _idx)[(base) + (id)] = \ { .clk = (parent), \ .type = TI_DEV_CLK_TABLE_TYPE_PARENT, \ .div = (_div) + (int) TI_BUILD_ASSERT_OR_ZERO(_div < 256), \ .idx = (_idx), \ .modify_parent_freq = 1U } /* Declare a device clock of type output. */ #define TI_DEV_CLK_OUTPUT(base, id, child)[(base) + (id)] = \ { .clk = (child), \ .type = TI_DEV_CLK_TABLE_TYPE_OUTPUT, \ .modify_parent_freq = 1U } /* * Get the dynamic data associated with a device clock. */ struct ti_dev_clk *ti_get_dev_clk(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /* * Get the const data associated with a device clock. */ const struct ti_dev_clk_data *ti_get_dev_clk_data(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /* * Lookup the clock API clock associated with a device clock index. */ struct ti_clk *ti_dev_get_clk(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /** * ti_device_clk_set_gated() - Set the gate/ungate property for a device clock * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * @gated: True to gate the clock, false to ungate. * * This sets/clears the gate/ungate property for a device clock. If a clock * is gated, the internal clock API clock that it references is not ref * counted. If it is ungated, then the refcount is incremented when the device * is enabled and decremented when the device is disabled. * * Return: True if operation succeeded, false if it failed or clk_idx was invalid. */ bool ti_device_clk_set_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, bool gated); /** * ti_device_clk_get_sw_gated() - Get the current state of the gated flag. * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * * Return: The current state of the gated flag as set by ti_device_clk_set_gated. */ bool ti_device_clk_get_sw_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /** * ti_device_clk_set_parent() - Change a device mux clocks's parent. * @dev: The device ID that the clock mux and new parent is connected to. * @clk_idx: The index of the clock mux on this device. * @parent_idx: The index of the new clock parent on this device. * * Return: True if parent change was successful, false if it * failed or one of the clock indexes was invalid. */ bool ti_device_clk_set_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, ti_dev_clk_idx_t parent_idx); /* * Get the current parent of a device mux clock. */ ti_dev_clk_idx_t ti_device_clk_get_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /* * Get the number of parents of a given device mux clock. */ ti_dev_clk_idx_t ti_device_clk_get_num_parents(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /** * ti_device_clk_set_freq() - Set the frequency of a device's clock * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * @min_freq_hz: The minimum acceptable frequency (Hz). * @target_freq_hz: The target frequency in Hz. The clock API will * attempt to set a frequency as close as possible. * @max_freq_hz: The maximum acceptable frequency (Hz). * * This locates the correct clock and calls the internal clock API * set function. If the clock is a mux type, we instead send the request to * the parent. This is because calling set freq on the mux may switch the mux * which is not what we want on muxes that are exposed on devices. * * Return: True if the new frequency was accepted, false otherwise. */ bool ti_device_clk_set_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, uint32_t min_freq_hz, uint32_t target_freq_hz, uint32_t max_freq_hz); /** * ti_device_clk_get_freq() - Get the current frequency of a device clock. * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * * Return: Current clock frequency in Hz if enabled, or the * frequency it would run at if enabled. Returns 0 if * clk_idx is invalid or the clock cannot run. */ uint32_t ti_device_clk_get_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /** * ti_device_clk_enable() - Enable a device clock * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * * This is called by the device pm code for each clock when the device is * enabled. This allows the device clk code to take appropriate action. */ void ti_device_clk_enable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /** * ti_device_clk_disable() - Disable a device clock * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * * This is called by the device pm code for each clock when the device is * disabled. This allows the device clk code to take appropriate action. */ void ti_device_clk_disable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); /** * ti_device_clk_init() - Initialize a device clock * @dev: The device ID that the clock is connected to. * @clk_idx: The index of the clock on this device. * * This is called by the device pm code for each clock when the device is * disabled. This allows the device clk code to take appropriate action such * setting default state. */ void ti_device_clk_init(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); #endif /* TI_DEVICE_CLK_H */