1*243873aaSKamlesh Gurudasani /* 2*243873aaSKamlesh Gurudasani * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com 3*243873aaSKamlesh Gurudasani * 4*243873aaSKamlesh Gurudasani * SPDX-License-Identifier: BSD-3-Clause 5*243873aaSKamlesh Gurudasani */ 6*243873aaSKamlesh Gurudasani 7*243873aaSKamlesh Gurudasani /* 8*243873aaSKamlesh Gurudasani * TI Clock Divider API Header 9*243873aaSKamlesh Gurudasani * 10*243873aaSKamlesh Gurudasani * This header defines the data structures and interfaces for programmable 11*243873aaSKamlesh Gurudasani * clock dividers. It provides divider data structures, driver interfaces, 12*243873aaSKamlesh Gurudasani * and APIs for divider value get/set operations supporting both power-of-2 13*243873aaSKamlesh Gurudasani * and arbitrary integer division ratios. 14*243873aaSKamlesh Gurudasani */ 15*243873aaSKamlesh Gurudasani 16*243873aaSKamlesh Gurudasani #ifndef TI_CLK_DIV_H 17*243873aaSKamlesh Gurudasani #define TI_CLK_DIV_H 18*243873aaSKamlesh Gurudasani 19*243873aaSKamlesh Gurudasani #include <ti_clk.h> 20*243873aaSKamlesh Gurudasani 21*243873aaSKamlesh Gurudasani /* 22*243873aaSKamlesh Gurudasani * Base divider clock data structure 23*243873aaSKamlesh Gurudasani * 24*243873aaSKamlesh Gurudasani * This structure contains the fundamental divider configuration including 25*243873aaSKamlesh Gurudasani * the maximum divider value and default divider ratio. 26*243873aaSKamlesh Gurudasani */ 27*243873aaSKamlesh Gurudasani struct ti_clk_data_div { 28*243873aaSKamlesh Gurudasani /* Base driver data structure */ 29*243873aaSKamlesh Gurudasani struct ti_clk_drv_data data; 30*243873aaSKamlesh Gurudasani /* Maximum divider value (divider range is 1 to max_div) */ 31*243873aaSKamlesh Gurudasani uint16_t max_div; 32*243873aaSKamlesh Gurudasani /* Default divider value at initialization */ 33*243873aaSKamlesh Gurudasani uint16_t default_div; 34*243873aaSKamlesh Gurudasani }; 35*243873aaSKamlesh Gurudasani 36*243873aaSKamlesh Gurudasani /* 37*243873aaSKamlesh Gurudasani * Register-based divider clock data structure 38*243873aaSKamlesh Gurudasani * 39*243873aaSKamlesh Gurudasani * This structure defines a divider implemented via a hardware register field. 40*243873aaSKamlesh Gurudasani * The divider value is stored in a bit field within the specified register. 41*243873aaSKamlesh Gurudasani */ 42*243873aaSKamlesh Gurudasani struct ti_clk_data_div_reg { 43*243873aaSKamlesh Gurudasani /* Register address containing divider field */ 44*243873aaSKamlesh Gurudasani uint32_t reg; 45*243873aaSKamlesh Gurudasani /* Base divider data */ 46*243873aaSKamlesh Gurudasani struct ti_clk_data_div data_div; 47*243873aaSKamlesh Gurudasani /* Starting bit position of divider field */ 48*243873aaSKamlesh Gurudasani uint8_t bit; 49*243873aaSKamlesh Gurudasani /* If true, divider values start at 1 (not 0) */ 50*243873aaSKamlesh Gurudasani uint8_t start_at_1; 51*243873aaSKamlesh Gurudasani }; 52*243873aaSKamlesh Gurudasani 53*243873aaSKamlesh Gurudasani /* 54*243873aaSKamlesh Gurudasani * Register-based divider with GO bit for change propagation 55*243873aaSKamlesh Gurudasani * 56*243873aaSKamlesh Gurudasani * This structure extends the basic register divider with a GO bit mechanism. 57*243873aaSKamlesh Gurudasani * After modifying the divider value, the GO bit must be set to propagate 58*243873aaSKamlesh Gurudasani * the change through the clock tree. 59*243873aaSKamlesh Gurudasani */ 60*243873aaSKamlesh Gurudasani struct ti_clk_data_div_reg_go { 61*243873aaSKamlesh Gurudasani /* Register address containing divider field */ 62*243873aaSKamlesh Gurudasani uint32_t reg; 63*243873aaSKamlesh Gurudasani /* Base divider data */ 64*243873aaSKamlesh Gurudasani struct ti_clk_data_div data_div; 65*243873aaSKamlesh Gurudasani /* Starting bit position of divider field */ 66*243873aaSKamlesh Gurudasani uint8_t bit; 67*243873aaSKamlesh Gurudasani /* If true, divider values start at 1 (not 0) */ 68*243873aaSKamlesh Gurudasani uint8_t start_at_1; 69*243873aaSKamlesh Gurudasani /* GO bit number to trigger divider change */ 70*243873aaSKamlesh Gurudasani uint8_t go; 71*243873aaSKamlesh Gurudasani }; 72*243873aaSKamlesh Gurudasani 73*243873aaSKamlesh Gurudasani /* 74*243873aaSKamlesh Gurudasani * Divider clock driver operations structure 75*243873aaSKamlesh Gurudasani * 76*243873aaSKamlesh Gurudasani * This structure extends the base clock driver with divider-specific operations 77*243873aaSKamlesh Gurudasani * for getting, setting, and validating divider values. 78*243873aaSKamlesh Gurudasani */ 79*243873aaSKamlesh Gurudasani struct ti_clk_drv_div { 80*243873aaSKamlesh Gurudasani /* Base clock driver operations */ 81*243873aaSKamlesh Gurudasani struct ti_clk_drv drv; 82*243873aaSKamlesh Gurudasani 83*243873aaSKamlesh Gurudasani /* 84*243873aaSKamlesh Gurudasani * Set the divider value for a clock 85*243873aaSKamlesh Gurudasani */ 86*243873aaSKamlesh Gurudasani bool (*set_div)(struct ti_clk *clkp, uint32_t div); 87*243873aaSKamlesh Gurudasani 88*243873aaSKamlesh Gurudasani /* 89*243873aaSKamlesh Gurudasani * Get the current divider value for a clock 90*243873aaSKamlesh Gurudasani */ 91*243873aaSKamlesh Gurudasani uint32_t (*get_div)(struct ti_clk *clkp); 92*243873aaSKamlesh Gurudasani 93*243873aaSKamlesh Gurudasani /* 94*243873aaSKamlesh Gurudasani * Validate if a divider value is supported 95*243873aaSKamlesh Gurudasani */ 96*243873aaSKamlesh Gurudasani bool (*valid_div)(struct ti_clk *clkp, uint32_t div); 97*243873aaSKamlesh Gurudasani }; 98*243873aaSKamlesh Gurudasani 99*243873aaSKamlesh Gurudasani /* Divider driver for read-write register-based dividers */ 100*243873aaSKamlesh Gurudasani extern const struct ti_clk_drv_div ti_clk_drv_div_reg; 101*243873aaSKamlesh Gurudasani 102*243873aaSKamlesh Gurudasani /* Divider driver for read-only register-based dividers */ 103*243873aaSKamlesh Gurudasani extern const struct ti_clk_drv_div ti_clk_drv_div_reg_ro; 104*243873aaSKamlesh Gurudasani 105*243873aaSKamlesh Gurudasani /* Divider driver for register-based dividers with GO bit propagation */ 106*243873aaSKamlesh Gurudasani extern const struct ti_clk_drv_div ti_clk_drv_div_reg_go; 107*243873aaSKamlesh Gurudasani 108*243873aaSKamlesh Gurudasani /* Divider driver for fixed (non-programmable) dividers */ 109*243873aaSKamlesh Gurudasani extern const struct ti_clk_drv_div ti_clk_drv_div_fixed; 110*243873aaSKamlesh Gurudasani 111*243873aaSKamlesh Gurudasani /** 112*243873aaSKamlesh Gurudasani * ti_clk_div_set_freq() - Sets the frequency of a divider clock 113*243873aaSKamlesh Gurudasani * @clkp: The divider clock to configure 114*243873aaSKamlesh Gurudasani * @target_hz: Target frequency in Hz 115*243873aaSKamlesh Gurudasani * @min_hz: Minimum acceptable frequency in Hz 116*243873aaSKamlesh Gurudasani * @max_hz: Maximum acceptable frequency in Hz 117*243873aaSKamlesh Gurudasani * @changed: Output parameter set to true if frequency changed 118*243873aaSKamlesh Gurudasani * 119*243873aaSKamlesh Gurudasani * This function adjusts the divider value to achieve the target frequency. 120*243873aaSKamlesh Gurudasani * It can also propagate frequency changes to the parent if allowed. 121*243873aaSKamlesh Gurudasani * 122*243873aaSKamlesh Gurudasani * Return: Best achievable frequency in Hz, 0 on failure 123*243873aaSKamlesh Gurudasani */ 124*243873aaSKamlesh Gurudasani uint32_t ti_clk_div_set_freq(struct ti_clk *clkp, uint32_t target_hz, 125*243873aaSKamlesh Gurudasani uint32_t min_hz, uint32_t max_hz, 126*243873aaSKamlesh Gurudasani bool *changed); 127*243873aaSKamlesh Gurudasani 128*243873aaSKamlesh Gurudasani /** 129*243873aaSKamlesh Gurudasani * ti_clk_div_get_freq() - Gets the current frequency of a divider clock 130*243873aaSKamlesh Gurudasani * @clkp: The divider clock to query 131*243873aaSKamlesh Gurudasani * 132*243873aaSKamlesh Gurudasani * Return: Current frequency in Hz 133*243873aaSKamlesh Gurudasani */ 134*243873aaSKamlesh Gurudasani uint32_t ti_clk_div_get_freq(struct ti_clk *clkp); 135*243873aaSKamlesh Gurudasani 136*243873aaSKamlesh Gurudasani /** 137*243873aaSKamlesh Gurudasani * ti_clk_div_set_freq_static_parent() - Sets frequency for dividers with fixed parent frequency 138*243873aaSKamlesh Gurudasani * @clkp: The divider clock to configure 139*243873aaSKamlesh Gurudasani * @target_hz: Target frequency in Hz 140*243873aaSKamlesh Gurudasani * @min_hz: Minimum acceptable frequency in Hz 141*243873aaSKamlesh Gurudasani * @max_hz: Maximum acceptable frequency in Hz 142*243873aaSKamlesh Gurudasani * @changed: Output parameter set to true if frequency changed 143*243873aaSKamlesh Gurudasani * 144*243873aaSKamlesh Gurudasani * This variant is optimized for dividers whose parent frequency cannot 145*243873aaSKamlesh Gurudasani * be changed. It only adjusts the divider value itself. 146*243873aaSKamlesh Gurudasani * 147*243873aaSKamlesh Gurudasani * Return: Best achievable frequency in Hz, 0 on failure 148*243873aaSKamlesh Gurudasani */ 149*243873aaSKamlesh Gurudasani uint32_t ti_clk_div_set_freq_static_parent(struct ti_clk *clkp, uint32_t target_hz, 150*243873aaSKamlesh Gurudasani uint32_t min_hz, uint32_t max_hz, 151*243873aaSKamlesh Gurudasani bool *changed); 152*243873aaSKamlesh Gurudasani 153*243873aaSKamlesh Gurudasani /** 154*243873aaSKamlesh Gurudasani * ti_clk_div_reg_go_get_div() - Gets divider value for GO-bit register divider 155*243873aaSKamlesh Gurudasani * @clkp: The divider clock to query 156*243873aaSKamlesh Gurudasani * 157*243873aaSKamlesh Gurudasani * Return: Current divider value 158*243873aaSKamlesh Gurudasani */ 159*243873aaSKamlesh Gurudasani uint32_t ti_clk_div_reg_go_get_div(struct ti_clk *clkp); 160*243873aaSKamlesh Gurudasani 161*243873aaSKamlesh Gurudasani /** 162*243873aaSKamlesh Gurudasani * ti_clk_div_reg_go_set_div() - Sets divider value for GO-bit register divider 163*243873aaSKamlesh Gurudasani * @clkp: The divider clock to modify 164*243873aaSKamlesh Gurudasani * @div: The divider value to set 165*243873aaSKamlesh Gurudasani * 166*243873aaSKamlesh Gurudasani * Sets the divider value and triggers the GO bit to propagate the change. 167*243873aaSKamlesh Gurudasani * 168*243873aaSKamlesh Gurudasani * Return: True if successful 169*243873aaSKamlesh Gurudasani */ 170*243873aaSKamlesh Gurudasani bool ti_clk_div_reg_go_set_div(struct ti_clk *clkp, uint32_t div); 171*243873aaSKamlesh Gurudasani 172*243873aaSKamlesh Gurudasani /** 173*243873aaSKamlesh Gurudasani * ti_clk_div_reg_get_div() - Gets divider value from register-based divider 174*243873aaSKamlesh Gurudasani * @clkp: The divider clock to query 175*243873aaSKamlesh Gurudasani * 176*243873aaSKamlesh Gurudasani * Return: Current divider value 177*243873aaSKamlesh Gurudasani */ 178*243873aaSKamlesh Gurudasani uint32_t ti_clk_div_reg_get_div(struct ti_clk *clkp); 179*243873aaSKamlesh Gurudasani 180*243873aaSKamlesh Gurudasani /** 181*243873aaSKamlesh Gurudasani * ti_clk_div_reg_set_div() - Sets divider value for register-based divider 182*243873aaSKamlesh Gurudasani * @clkp: The divider clock to modify 183*243873aaSKamlesh Gurudasani * @div: The divider value to set 184*243873aaSKamlesh Gurudasani * 185*243873aaSKamlesh Gurudasani * Return: True if successful 186*243873aaSKamlesh Gurudasani */ 187*243873aaSKamlesh Gurudasani bool ti_clk_div_reg_set_div(struct ti_clk *clkp, uint32_t div); 188*243873aaSKamlesh Gurudasani 189*243873aaSKamlesh Gurudasani /** 190*243873aaSKamlesh Gurudasani * ti_clk_get_div() - Generic divider value getter 191*243873aaSKamlesh Gurudasani * @clkp: The divider clock to query 192*243873aaSKamlesh Gurudasani * 193*243873aaSKamlesh Gurudasani * Dispatches to the appropriate driver-specific get_div function. 194*243873aaSKamlesh Gurudasani * 195*243873aaSKamlesh Gurudasani * Return: Current divider value 196*243873aaSKamlesh Gurudasani */ 197*243873aaSKamlesh Gurudasani uint32_t ti_clk_get_div(struct ti_clk *clkp); 198*243873aaSKamlesh Gurudasani 199*243873aaSKamlesh Gurudasani /** 200*243873aaSKamlesh Gurudasani * ti_clk_div_init() - Initializes a divider clock 201*243873aaSKamlesh Gurudasani * @clkp: The divider clock to initialize 202*243873aaSKamlesh Gurudasani * 203*243873aaSKamlesh Gurudasani * Performs initialization including setting default divider value and 204*243873aaSKamlesh Gurudasani * configuring hardware registers. 205*243873aaSKamlesh Gurudasani * 206*243873aaSKamlesh Gurudasani * Return: 0 on success, error code otherwise 207*243873aaSKamlesh Gurudasani */ 208*243873aaSKamlesh Gurudasani int32_t ti_clk_div_init(struct ti_clk *clkp); 209*243873aaSKamlesh Gurudasani 210*243873aaSKamlesh Gurudasani #endif /* TI_CLK_DIV_H */ 211