1*6f2a8791SKamlesh Gurudasani /* 2*6f2a8791SKamlesh Gurudasani * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com 3*6f2a8791SKamlesh Gurudasani * 4*6f2a8791SKamlesh Gurudasani * SPDX-License-Identifier: BSD-3-Clause 5*6f2a8791SKamlesh Gurudasani */ 6*6f2a8791SKamlesh Gurudasani 7*6f2a8791SKamlesh Gurudasani /* 8*6f2a8791SKamlesh Gurudasani * Device Clock Management API 9*6f2a8791SKamlesh Gurudasani * 10*6f2a8791SKamlesh Gurudasani * This header defines the device clock API for managing clocks attached to 11*6f2a8791SKamlesh Gurudasani * devices. It provides clock type definitions, device clock data structures, 12*6f2a8791SKamlesh Gurudasani * and functions for clock control including enable/disable, parent selection, 13*6f2a8791SKamlesh Gurudasani * frequency configuration, and state management. 14*6f2a8791SKamlesh Gurudasani */ 15*6f2a8791SKamlesh Gurudasani 16*6f2a8791SKamlesh Gurudasani #ifndef TI_DEVICE_CLK_H 17*6f2a8791SKamlesh Gurudasani #define TI_DEVICE_CLK_H 18*6f2a8791SKamlesh Gurudasani 19*6f2a8791SKamlesh Gurudasani #include <ti_build_assert.h> 20*6f2a8791SKamlesh Gurudasani #include <ti_pm_types.h> 21*6f2a8791SKamlesh Gurudasani 22*6f2a8791SKamlesh Gurudasani /* 23*6f2a8791SKamlesh Gurudasani * Sentinel value for invalid or non-existent device clock ID 24*6f2a8791SKamlesh Gurudasani * 25*6f2a8791SKamlesh Gurudasani * Used to indicate that a device clock index is invalid, uninitialized, or 26*6f2a8791SKamlesh Gurudasani * that no clock exists at the requested position. Functions returning 27*6f2a8791SKamlesh Gurudasani * ti_dev_clk_idx_t use this value to signal errors or missing clocks. 28*6f2a8791SKamlesh Gurudasani */ 29*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_ID_NONE ((ti_dev_clk_idx_t) (~0U)) 30*6f2a8791SKamlesh Gurudasani 31*6f2a8791SKamlesh Gurudasani /* 32*6f2a8791SKamlesh Gurudasani * Input clock type. 33*6f2a8791SKamlesh Gurudasani * 34*6f2a8791SKamlesh Gurudasani * This is a normal clock, it's an input to the IP from elsewhere. 35*6f2a8791SKamlesh Gurudasani */ 36*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_INPUT 0U 37*6f2a8791SKamlesh Gurudasani 38*6f2a8791SKamlesh Gurudasani /* 39*6f2a8791SKamlesh Gurudasani * Mux clock type. 40*6f2a8791SKamlesh Gurudasani * 41*6f2a8791SKamlesh Gurudasani * This is a clock mux that is meant to be controlled directly. The potential 42*6f2a8791SKamlesh Gurudasani * parents of the mux are listed after the mux as TYPE_PARENT. Set frequency 43*6f2a8791SKamlesh Gurudasani * calls to a mux are passed to the current parent. 44*6f2a8791SKamlesh Gurudasani */ 45*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_MUX 1U 46*6f2a8791SKamlesh Gurudasani 47*6f2a8791SKamlesh Gurudasani /* 48*6f2a8791SKamlesh Gurudasani * Mux parent clock type. 49*6f2a8791SKamlesh Gurudasani * 50*6f2a8791SKamlesh Gurudasani * This is a potential parent for a mux. Normal clocks are set to follow the 51*6f2a8791SKamlesh Gurudasani * device state (requested when device is enabled, unrequested otherwise) but 52*6f2a8791SKamlesh Gurudasani * mux parents are set to always unrequested by default. If they are selected 53*6f2a8791SKamlesh Gurudasani * they will get a ref count from the mux clock. 54*6f2a8791SKamlesh Gurudasani * 55*6f2a8791SKamlesh Gurudasani * Mux parents are present so they can be enabled and configured before being 56*6f2a8791SKamlesh Gurudasani * selected via the mux. 57*6f2a8791SKamlesh Gurudasani */ 58*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_PARENT 2U 59*6f2a8791SKamlesh Gurudasani 60*6f2a8791SKamlesh Gurudasani /* 61*6f2a8791SKamlesh Gurudasani * Output clock type. 62*6f2a8791SKamlesh Gurudasani * 63*6f2a8791SKamlesh Gurudasani * This is an output clock from the device. Setting the frequency informs 64*6f2a8791SKamlesh Gurudasani * potential consumers of the frequency but otherwise has no effect. 65*6f2a8791SKamlesh Gurudasani */ 66*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_TABLE_TYPE_OUTPUT 3U 67*6f2a8791SKamlesh Gurudasani 68*6f2a8791SKamlesh Gurudasani struct ti_device; 69*6f2a8791SKamlesh Gurudasani 70*6f2a8791SKamlesh Gurudasani /* 71*6f2a8791SKamlesh Gurudasani * Const clock device data 72*6f2a8791SKamlesh Gurudasani * 73*6f2a8791SKamlesh Gurudasani * This is the fixed data for tracking clocks attached to devices. 74*6f2a8791SKamlesh Gurudasani */ 75*6f2a8791SKamlesh Gurudasani struct ti_dev_clk_data { 76*6f2a8791SKamlesh Gurudasani /* Type of table entry */ 77*6f2a8791SKamlesh Gurudasani uint8_t type; 78*6f2a8791SKamlesh Gurudasani 79*6f2a8791SKamlesh Gurudasani /* 80*6f2a8791SKamlesh Gurudasani * Modifying the frequency of this clock will attempt to modify 81*6f2a8791SKamlesh Gurudasani * the parent freq. 82*6f2a8791SKamlesh Gurudasani */ 83*6f2a8791SKamlesh Gurudasani uint8_t modify_parent_freq; 84*6f2a8791SKamlesh Gurudasani 85*6f2a8791SKamlesh Gurudasani /* 86*6f2a8791SKamlesh Gurudasani * Clock divider, not valid for output, max 255 for parent otherwise 87*6f2a8791SKamlesh Gurudasani * up to USHORT_MAX/8. 88*6f2a8791SKamlesh Gurudasani */ 89*6f2a8791SKamlesh Gurudasani uint16_t div; 90*6f2a8791SKamlesh Gurudasani 91*6f2a8791SKamlesh Gurudasani /* For mux, the number of parents, for parents the index for the mux */ 92*6f2a8791SKamlesh Gurudasani uint8_t idx; 93*6f2a8791SKamlesh Gurudasani 94*6f2a8791SKamlesh Gurudasani /* For mux, the number of reserved parent slots */ 95*6f2a8791SKamlesh Gurudasani uint8_t n_reserved_parents; 96*6f2a8791SKamlesh Gurudasani 97*6f2a8791SKamlesh Gurudasani /* Which SoC clock this plugs into */ 98*6f2a8791SKamlesh Gurudasani uint16_t clk; 99*6f2a8791SKamlesh Gurudasani }; 100*6f2a8791SKamlesh Gurudasani 101*6f2a8791SKamlesh Gurudasani /* 102*6f2a8791SKamlesh Gurudasani * Dynamic clock device data 103*6f2a8791SKamlesh Gurudasani * 104*6f2a8791SKamlesh Gurudasani * This tracks the current state of a device attached clock via flags. 105*6f2a8791SKamlesh Gurudasani * This is just how the upstream clock is configured for the current 106*6f2a8791SKamlesh Gurudasani * device. The upstream clock still has its own data and state. 107*6f2a8791SKamlesh Gurudasani * 108*6f2a8791SKamlesh Gurudasani * A pointer to a bss that has been reserved for this data is pointed 109*6f2a8791SKamlesh Gurudasani * to by the device. If there is only one clock on the device, the field 110*6f2a8791SKamlesh Gurudasani * is shared with the device flags and a forced cast is made to return 111*6f2a8791SKamlesh Gurudasani * the field. 112*6f2a8791SKamlesh Gurudasani */ 113*6f2a8791SKamlesh Gurudasani struct ti_dev_clk { 114*6f2a8791SKamlesh Gurudasani uint8_t flags; 115*6f2a8791SKamlesh Gurudasani }; 116*6f2a8791SKamlesh Gurudasani 117*6f2a8791SKamlesh Gurudasani /* Declare a device clock of type input */ 118*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK(base, id, parent, _div)[(base) + (id)] = \ 119*6f2a8791SKamlesh Gurudasani { .clk = (parent), .div = (_div), \ 120*6f2a8791SKamlesh Gurudasani .type = TI_DEV_CLK_TABLE_TYPE_INPUT, \ 121*6f2a8791SKamlesh Gurudasani .modify_parent_freq = 1U } 122*6f2a8791SKamlesh Gurudasani 123*6f2a8791SKamlesh Gurudasani /* Declare a device clock of type mux */ 124*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_MUX(base, id, parent, _div, n_parents, n_reserved)[(base) + (id)] = \ 125*6f2a8791SKamlesh Gurudasani { .clk = (parent), .div = (_div), \ 126*6f2a8791SKamlesh Gurudasani .type = TI_DEV_CLK_TABLE_TYPE_MUX, \ 127*6f2a8791SKamlesh Gurudasani .idx = (n_parents), \ 128*6f2a8791SKamlesh Gurudasani .n_reserved_parents = (n_reserved), \ 129*6f2a8791SKamlesh Gurudasani .modify_parent_freq = 1U } 130*6f2a8791SKamlesh Gurudasani 131*6f2a8791SKamlesh Gurudasani /* 132*6f2a8791SKamlesh Gurudasani * Declare a device clock of type mux parent. To match clk_mux_parent, 133*6f2a8791SKamlesh Gurudasani * divider here can only be 8 bit 134*6f2a8791SKamlesh Gurudasani */ 135*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_PARENT(base, id, parent, _div, _idx)[(base) + (id)] = \ 136*6f2a8791SKamlesh Gurudasani { .clk = (parent), \ 137*6f2a8791SKamlesh Gurudasani .type = TI_DEV_CLK_TABLE_TYPE_PARENT, \ 138*6f2a8791SKamlesh Gurudasani .div = (_div) + (int) TI_BUILD_ASSERT_OR_ZERO(_div < 256), \ 139*6f2a8791SKamlesh Gurudasani .idx = (_idx), \ 140*6f2a8791SKamlesh Gurudasani .modify_parent_freq = 1U } 141*6f2a8791SKamlesh Gurudasani 142*6f2a8791SKamlesh Gurudasani /* Declare a device clock of type output. */ 143*6f2a8791SKamlesh Gurudasani #define TI_DEV_CLK_OUTPUT(base, id, child)[(base) + (id)] = \ 144*6f2a8791SKamlesh Gurudasani { .clk = (child), \ 145*6f2a8791SKamlesh Gurudasani .type = TI_DEV_CLK_TABLE_TYPE_OUTPUT, \ 146*6f2a8791SKamlesh Gurudasani .modify_parent_freq = 1U } 147*6f2a8791SKamlesh Gurudasani 148*6f2a8791SKamlesh Gurudasani /* 149*6f2a8791SKamlesh Gurudasani * Get the dynamic data associated with a device clock. 150*6f2a8791SKamlesh Gurudasani */ 151*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *ti_get_dev_clk(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 152*6f2a8791SKamlesh Gurudasani 153*6f2a8791SKamlesh Gurudasani /* 154*6f2a8791SKamlesh Gurudasani * Get the const data associated with a device clock. 155*6f2a8791SKamlesh Gurudasani */ 156*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *ti_get_dev_clk_data(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 157*6f2a8791SKamlesh Gurudasani 158*6f2a8791SKamlesh Gurudasani /* 159*6f2a8791SKamlesh Gurudasani * Lookup the clock API clock associated with a device clock index. 160*6f2a8791SKamlesh Gurudasani */ 161*6f2a8791SKamlesh Gurudasani struct ti_clk *ti_dev_get_clk(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 162*6f2a8791SKamlesh Gurudasani 163*6f2a8791SKamlesh Gurudasani /** 164*6f2a8791SKamlesh Gurudasani * ti_device_clk_set_gated() - Set the gate/ungate property for a device clock 165*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 166*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 167*6f2a8791SKamlesh Gurudasani * @gated: True to gate the clock, false to ungate. 168*6f2a8791SKamlesh Gurudasani * 169*6f2a8791SKamlesh Gurudasani * This sets/clears the gate/ungate property for a device clock. If a clock 170*6f2a8791SKamlesh Gurudasani * is gated, the internal clock API clock that it references is not ref 171*6f2a8791SKamlesh Gurudasani * counted. If it is ungated, then the refcount is incremented when the device 172*6f2a8791SKamlesh Gurudasani * is enabled and decremented when the device is disabled. 173*6f2a8791SKamlesh Gurudasani * 174*6f2a8791SKamlesh Gurudasani * Return: True if operation succeeded, false if it failed or clk_idx was invalid. 175*6f2a8791SKamlesh Gurudasani */ 176*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, bool gated); 177*6f2a8791SKamlesh Gurudasani 178*6f2a8791SKamlesh Gurudasani /** 179*6f2a8791SKamlesh Gurudasani * ti_device_clk_get_sw_gated() - Get the current state of the gated flag. 180*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 181*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 182*6f2a8791SKamlesh Gurudasani * 183*6f2a8791SKamlesh Gurudasani * Return: The current state of the gated flag as set by ti_device_clk_set_gated. 184*6f2a8791SKamlesh Gurudasani */ 185*6f2a8791SKamlesh Gurudasani bool ti_device_clk_get_sw_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 186*6f2a8791SKamlesh Gurudasani 187*6f2a8791SKamlesh Gurudasani /** 188*6f2a8791SKamlesh Gurudasani * ti_device_clk_set_parent() - Change a device mux clocks's parent. 189*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock mux and new parent is connected to. 190*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock mux on this device. 191*6f2a8791SKamlesh Gurudasani * @parent_idx: The index of the new clock parent on this device. 192*6f2a8791SKamlesh Gurudasani * 193*6f2a8791SKamlesh Gurudasani * Return: True if parent change was successful, false if it 194*6f2a8791SKamlesh Gurudasani * failed or one of the clock indexes was invalid. 195*6f2a8791SKamlesh Gurudasani */ 196*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, 197*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t parent_idx); 198*6f2a8791SKamlesh Gurudasani 199*6f2a8791SKamlesh Gurudasani /* 200*6f2a8791SKamlesh Gurudasani * Get the current parent of a device mux clock. 201*6f2a8791SKamlesh Gurudasani */ 202*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ti_device_clk_get_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 203*6f2a8791SKamlesh Gurudasani 204*6f2a8791SKamlesh Gurudasani /* 205*6f2a8791SKamlesh Gurudasani * Get the number of parents of a given device mux clock. 206*6f2a8791SKamlesh Gurudasani */ 207*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ti_device_clk_get_num_parents(struct ti_device *dev, 208*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t clk_idx); 209*6f2a8791SKamlesh Gurudasani 210*6f2a8791SKamlesh Gurudasani /** 211*6f2a8791SKamlesh Gurudasani * ti_device_clk_set_freq() - Set the frequency of a device's clock 212*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 213*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 214*6f2a8791SKamlesh Gurudasani * @min_freq_hz: The minimum acceptable frequency (Hz). 215*6f2a8791SKamlesh Gurudasani * @target_freq_hz: The target frequency in Hz. The clock API will 216*6f2a8791SKamlesh Gurudasani * attempt to set a frequency as close as possible. 217*6f2a8791SKamlesh Gurudasani * @max_freq_hz: The maximum acceptable frequency (Hz). 218*6f2a8791SKamlesh Gurudasani * 219*6f2a8791SKamlesh Gurudasani * This locates the correct clock and calls the internal clock API 220*6f2a8791SKamlesh Gurudasani * set function. If the clock is a mux type, we instead send the request to 221*6f2a8791SKamlesh Gurudasani * the parent. This is because calling set freq on the mux may switch the mux 222*6f2a8791SKamlesh Gurudasani * which is not what we want on muxes that are exposed on devices. 223*6f2a8791SKamlesh Gurudasani * 224*6f2a8791SKamlesh Gurudasani * Return: True if the new frequency was accepted, false otherwise. 225*6f2a8791SKamlesh Gurudasani */ 226*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, 227*6f2a8791SKamlesh Gurudasani uint32_t min_freq_hz, uint32_t target_freq_hz, 228*6f2a8791SKamlesh Gurudasani uint32_t max_freq_hz); 229*6f2a8791SKamlesh Gurudasani 230*6f2a8791SKamlesh Gurudasani /** 231*6f2a8791SKamlesh Gurudasani * ti_device_clk_get_freq() - Get the current frequency of a device clock. 232*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 233*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 234*6f2a8791SKamlesh Gurudasani * 235*6f2a8791SKamlesh Gurudasani * Return: Current clock frequency in Hz if enabled, or the 236*6f2a8791SKamlesh Gurudasani * frequency it would run at if enabled. Returns 0 if 237*6f2a8791SKamlesh Gurudasani * clk_idx is invalid or the clock cannot run. 238*6f2a8791SKamlesh Gurudasani */ 239*6f2a8791SKamlesh Gurudasani uint32_t ti_device_clk_get_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 240*6f2a8791SKamlesh Gurudasani 241*6f2a8791SKamlesh Gurudasani /** 242*6f2a8791SKamlesh Gurudasani * ti_device_clk_enable() - Enable a device clock 243*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 244*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 245*6f2a8791SKamlesh Gurudasani * 246*6f2a8791SKamlesh Gurudasani * This is called by the device pm code for each clock when the device is 247*6f2a8791SKamlesh Gurudasani * enabled. This allows the device clk code to take appropriate action. 248*6f2a8791SKamlesh Gurudasani */ 249*6f2a8791SKamlesh Gurudasani void ti_device_clk_enable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 250*6f2a8791SKamlesh Gurudasani 251*6f2a8791SKamlesh Gurudasani /** 252*6f2a8791SKamlesh Gurudasani * ti_device_clk_disable() - Disable a device clock 253*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 254*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 255*6f2a8791SKamlesh Gurudasani * 256*6f2a8791SKamlesh Gurudasani * This is called by the device pm code for each clock when the device is 257*6f2a8791SKamlesh Gurudasani * disabled. This allows the device clk code to take appropriate action. 258*6f2a8791SKamlesh Gurudasani */ 259*6f2a8791SKamlesh Gurudasani void ti_device_clk_disable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 260*6f2a8791SKamlesh Gurudasani 261*6f2a8791SKamlesh Gurudasani /** 262*6f2a8791SKamlesh Gurudasani * ti_device_clk_init() - Initialize a device clock 263*6f2a8791SKamlesh Gurudasani * @dev: The device ID that the clock is connected to. 264*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device. 265*6f2a8791SKamlesh Gurudasani * 266*6f2a8791SKamlesh Gurudasani * This is called by the device pm code for each clock when the device is 267*6f2a8791SKamlesh Gurudasani * disabled. This allows the device clk code to take appropriate action such 268*6f2a8791SKamlesh Gurudasani * setting default state. 269*6f2a8791SKamlesh Gurudasani */ 270*6f2a8791SKamlesh Gurudasani void ti_device_clk_init(struct ti_device *dev, ti_dev_clk_idx_t clk_idx); 271*6f2a8791SKamlesh Gurudasani 272*6f2a8791SKamlesh Gurudasani #endif /* TI_DEVICE_CLK_H */ 273