xref: /rk3399_ARM-atf/drivers/ti/clk/include/ti_clk_div.h (revision a28114d66a6d43db4accef5fd5d6dab6c059e584)
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