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