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
9*6f2a8791SKamlesh Gurudasani *
10*6f2a8791SKamlesh Gurudasani * This module provides software support for managing clocks attached to
11*6f2a8791SKamlesh Gurudasani * devices, including enable/disable, frequency scaling, parent selection,
12*6f2a8791SKamlesh Gurudasani * and clock gating operations.
13*6f2a8791SKamlesh Gurudasani */
14*6f2a8791SKamlesh Gurudasani
15*6f2a8791SKamlesh Gurudasani #include <limits.h>
16*6f2a8791SKamlesh Gurudasani #include <stddef.h>
17*6f2a8791SKamlesh Gurudasani
18*6f2a8791SKamlesh Gurudasani #include <ti_clk_mux.h>
19*6f2a8791SKamlesh Gurudasani #include <ti_device.h>
20*6f2a8791SKamlesh Gurudasani #include <ti_device_clk.h>
21*6f2a8791SKamlesh Gurudasani
ti_get_dev_clk(struct ti_device * dev,ti_dev_clk_idx_t idx)22*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *ti_get_dev_clk(struct ti_device *dev, ti_dev_clk_idx_t idx)
23*6f2a8791SKamlesh Gurudasani {
24*6f2a8791SKamlesh Gurudasani const struct ti_dev_data *data = ti_get_dev_data(dev);
25*6f2a8791SKamlesh Gurudasani const struct ti_devgroup *devgrp = ti_dev_data_lookup_devgroup(data);
26*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *ret = NULL;
27*6f2a8791SKamlesh Gurudasani
28*6f2a8791SKamlesh Gurudasani if ((idx < data->n_clocks) && (devgrp != NULL)) {
29*6f2a8791SKamlesh Gurudasani uint32_t offset = data->dev_clk_idx;
30*6f2a8791SKamlesh Gurudasani
31*6f2a8791SKamlesh Gurudasani if (ti_clk_id_valid(devgrp->dev_clk_data[offset + idx].clk)) {
32*6f2a8791SKamlesh Gurudasani ret = &devgrp->dev_clk[offset + idx];
33*6f2a8791SKamlesh Gurudasani }
34*6f2a8791SKamlesh Gurudasani }
35*6f2a8791SKamlesh Gurudasani
36*6f2a8791SKamlesh Gurudasani return ret;
37*6f2a8791SKamlesh Gurudasani }
38*6f2a8791SKamlesh Gurudasani
ti_get_dev_clk_data(struct ti_device * dev,ti_dev_clk_idx_t idx)39*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *ti_get_dev_clk_data(struct ti_device *dev,
40*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t idx)
41*6f2a8791SKamlesh Gurudasani {
42*6f2a8791SKamlesh Gurudasani const struct ti_dev_data *data = ti_get_dev_data(dev);
43*6f2a8791SKamlesh Gurudasani const struct ti_devgroup *devgrp = ti_dev_data_lookup_devgroup(data);
44*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *ret = NULL;
45*6f2a8791SKamlesh Gurudasani
46*6f2a8791SKamlesh Gurudasani if ((idx < data->n_clocks) && (devgrp != NULL)) {
47*6f2a8791SKamlesh Gurudasani uint32_t offset = data->dev_clk_idx;
48*6f2a8791SKamlesh Gurudasani
49*6f2a8791SKamlesh Gurudasani ret = &devgrp->dev_clk_data[offset + idx];
50*6f2a8791SKamlesh Gurudasani }
51*6f2a8791SKamlesh Gurudasani
52*6f2a8791SKamlesh Gurudasani return ret;
53*6f2a8791SKamlesh Gurudasani }
54*6f2a8791SKamlesh Gurudasani
ti_dev_get_clk(struct ti_device * dev,ti_dev_clk_idx_t idx)55*6f2a8791SKamlesh Gurudasani struct ti_clk *ti_dev_get_clk(struct ti_device *dev, ti_dev_clk_idx_t idx)
56*6f2a8791SKamlesh Gurudasani {
57*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *entry = ti_get_dev_clk_data(dev, idx);
58*6f2a8791SKamlesh Gurudasani
59*6f2a8791SKamlesh Gurudasani return entry ? ti_clk_lookup((ti_clk_idx_t) entry->clk) : NULL;
60*6f2a8791SKamlesh Gurudasani }
61*6f2a8791SKamlesh Gurudasani
ti_device_clk_set_gated(struct ti_device * dev,ti_dev_clk_idx_t clk_idx,bool gated)62*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx, bool gated)
63*6f2a8791SKamlesh Gurudasani {
64*6f2a8791SKamlesh Gurudasani const struct ti_dev_data *data = ti_get_dev_data(dev);
65*6f2a8791SKamlesh Gurudasani const struct ti_devgroup *devgrp = ti_dev_data_lookup_devgroup(data);
66*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *dev_clkp = ti_get_dev_clk(dev, clk_idx);
67*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp = NULL;
68*6f2a8791SKamlesh Gurudasani bool is_enabled = false;
69*6f2a8791SKamlesh Gurudasani bool is_gated = false;
70*6f2a8791SKamlesh Gurudasani bool ret = true;
71*6f2a8791SKamlesh Gurudasani ti_clk_idx_t id;
72*6f2a8791SKamlesh Gurudasani
73*6f2a8791SKamlesh Gurudasani if ((dev_clkp == NULL) || (devgrp == NULL)) {
74*6f2a8791SKamlesh Gurudasani ret = false;
75*6f2a8791SKamlesh Gurudasani } else {
76*6f2a8791SKamlesh Gurudasani is_gated = ((((uint32_t) (dev_clkp->flags) & TI_DEV_CLK_FLAG_DISABLE) > 0U) ?
77*6f2a8791SKamlesh Gurudasani true : false);
78*6f2a8791SKamlesh Gurudasani if (is_gated != gated) {
79*6f2a8791SKamlesh Gurudasani is_enabled = (dev->flags & TI_DEV_FLAG_ENABLED_MASK) != 0UL;
80*6f2a8791SKamlesh Gurudasani id = (ti_clk_idx_t) devgrp->dev_clk_data[data->dev_clk_idx + clk_idx].clk;
81*6f2a8791SKamlesh Gurudasani clkp = ti_clk_lookup(id);
82*6f2a8791SKamlesh Gurudasani if (clkp == NULL) {
83*6f2a8791SKamlesh Gurudasani /* Clock lookup failed */
84*6f2a8791SKamlesh Gurudasani ret = false;
85*6f2a8791SKamlesh Gurudasani }
86*6f2a8791SKamlesh Gurudasani }
87*6f2a8791SKamlesh Gurudasani }
88*6f2a8791SKamlesh Gurudasani
89*6f2a8791SKamlesh Gurudasani if ((clkp != NULL) && ((clkp->flags & TI_CLK_FLAG_INITIALIZED) == 0U)) {
90*6f2a8791SKamlesh Gurudasani /* Clock not yet initialized (outside devgroup) */
91*6f2a8791SKamlesh Gurudasani ret = false;
92*6f2a8791SKamlesh Gurudasani } else if (clkp && gated) {
93*6f2a8791SKamlesh Gurudasani dev_clkp->flags |= TI_DEV_CLK_FLAG_DISABLE;
94*6f2a8791SKamlesh Gurudasani if (is_enabled) {
95*6f2a8791SKamlesh Gurudasani ti_clk_put(clkp);
96*6f2a8791SKamlesh Gurudasani }
97*6f2a8791SKamlesh Gurudasani } else if (clkp != NULL) {
98*6f2a8791SKamlesh Gurudasani dev_clkp->flags &= (uint8_t) ~TI_DEV_CLK_FLAG_DISABLE;
99*6f2a8791SKamlesh Gurudasani if (is_enabled) {
100*6f2a8791SKamlesh Gurudasani if (ti_clk_get(clkp)) {
101*6f2a8791SKamlesh Gurudasani ret = true;
102*6f2a8791SKamlesh Gurudasani } else {
103*6f2a8791SKamlesh Gurudasani ret = false;
104*6f2a8791SKamlesh Gurudasani }
105*6f2a8791SKamlesh Gurudasani }
106*6f2a8791SKamlesh Gurudasani } else {
107*6f2a8791SKamlesh Gurudasani /* Do Nothing */
108*6f2a8791SKamlesh Gurudasani }
109*6f2a8791SKamlesh Gurudasani
110*6f2a8791SKamlesh Gurudasani return ret;
111*6f2a8791SKamlesh Gurudasani }
112*6f2a8791SKamlesh Gurudasani
ti_device_clk_get_sw_gated(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)113*6f2a8791SKamlesh Gurudasani bool ti_device_clk_get_sw_gated(struct ti_device *dev, ti_dev_clk_idx_t clk_idx)
114*6f2a8791SKamlesh Gurudasani {
115*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *dev_clkp = ti_get_dev_clk(dev, clk_idx);
116*6f2a8791SKamlesh Gurudasani
117*6f2a8791SKamlesh Gurudasani return (dev_clkp != NULL) && ((dev_clkp->flags & TI_DEV_CLK_FLAG_DISABLE) != 0U);
118*6f2a8791SKamlesh Gurudasani }
119*6f2a8791SKamlesh Gurudasani
ti_device_clk_set_parent(struct ti_device * dev,ti_dev_clk_idx_t clk_idx,ti_dev_clk_idx_t parent_idx)120*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx,
121*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t parent_idx)
122*6f2a8791SKamlesh Gurudasani {
123*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp;
124*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *clock_data;
125*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *parent_data = NULL;
126*6f2a8791SKamlesh Gurudasani uint32_t depth;
127*6f2a8791SKamlesh Gurudasani bool ret = true;
128*6f2a8791SKamlesh Gurudasani
129*6f2a8791SKamlesh Gurudasani clkp = ti_dev_get_clk(dev, clk_idx);
130*6f2a8791SKamlesh Gurudasani clock_data = ti_get_dev_clk_data(dev, clk_idx);
131*6f2a8791SKamlesh Gurudasani if ((clkp == NULL) || (clock_data == NULL)) {
132*6f2a8791SKamlesh Gurudasani ret = false;
133*6f2a8791SKamlesh Gurudasani }
134*6f2a8791SKamlesh Gurudasani
135*6f2a8791SKamlesh Gurudasani if (ret && (clock_data->type != TI_DEV_CLK_TABLE_TYPE_MUX)) {
136*6f2a8791SKamlesh Gurudasani ret = false;
137*6f2a8791SKamlesh Gurudasani }
138*6f2a8791SKamlesh Gurudasani
139*6f2a8791SKamlesh Gurudasani if (ret) {
140*6f2a8791SKamlesh Gurudasani parent_data = ti_get_dev_clk_data(dev, parent_idx);
141*6f2a8791SKamlesh Gurudasani if (parent_data == NULL) {
142*6f2a8791SKamlesh Gurudasani ret = false;
143*6f2a8791SKamlesh Gurudasani }
144*6f2a8791SKamlesh Gurudasani }
145*6f2a8791SKamlesh Gurudasani
146*6f2a8791SKamlesh Gurudasani if (ret && (parent_data->type != TI_DEV_CLK_TABLE_TYPE_PARENT)) {
147*6f2a8791SKamlesh Gurudasani ret = false;
148*6f2a8791SKamlesh Gurudasani }
149*6f2a8791SKamlesh Gurudasani
150*6f2a8791SKamlesh Gurudasani /* Make sure it's within this clock muxes parents */
151*6f2a8791SKamlesh Gurudasani if (ret && ((parent_idx - clk_idx) > clock_data->idx)) {
152*6f2a8791SKamlesh Gurudasani ret = false;
153*6f2a8791SKamlesh Gurudasani }
154*6f2a8791SKamlesh Gurudasani
155*6f2a8791SKamlesh Gurudasani depth = soc_clock_count;
156*6f2a8791SKamlesh Gurudasani while (ret && (clkp != NULL) && (clkp->type != TI_CLK_TYPE_MUX) && (depth > 0U)) {
157*6f2a8791SKamlesh Gurudasani const struct ti_clk_parent *p;
158*6f2a8791SKamlesh Gurudasani
159*6f2a8791SKamlesh Gurudasani depth--;
160*6f2a8791SKamlesh Gurudasani p = ti_clk_mux_get_parent(clkp);
161*6f2a8791SKamlesh Gurudasani if (p != NULL) {
162*6f2a8791SKamlesh Gurudasani clkp = ti_clk_lookup((ti_clk_idx_t) p->clk);
163*6f2a8791SKamlesh Gurudasani } else {
164*6f2a8791SKamlesh Gurudasani clkp = NULL;
165*6f2a8791SKamlesh Gurudasani }
166*6f2a8791SKamlesh Gurudasani }
167*6f2a8791SKamlesh Gurudasani
168*6f2a8791SKamlesh Gurudasani if (depth == 0U) {
169*6f2a8791SKamlesh Gurudasani /* Clock tree cycle detected or depth exceeded */
170*6f2a8791SKamlesh Gurudasani ret = false;
171*6f2a8791SKamlesh Gurudasani }
172*6f2a8791SKamlesh Gurudasani
173*6f2a8791SKamlesh Gurudasani if (clkp == NULL) {
174*6f2a8791SKamlesh Gurudasani ret = false;
175*6f2a8791SKamlesh Gurudasani }
176*6f2a8791SKamlesh Gurudasani
177*6f2a8791SKamlesh Gurudasani if (ret) {
178*6f2a8791SKamlesh Gurudasani ret = ti_clk_mux_set_parent(clkp, parent_data->idx);
179*6f2a8791SKamlesh Gurudasani }
180*6f2a8791SKamlesh Gurudasani
181*6f2a8791SKamlesh Gurudasani return ret;
182*6f2a8791SKamlesh Gurudasani }
183*6f2a8791SKamlesh Gurudasani
ti_device_clk_get_parent(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)184*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ti_device_clk_get_parent(struct ti_device *dev, ti_dev_clk_idx_t clk_idx)
185*6f2a8791SKamlesh Gurudasani {
186*6f2a8791SKamlesh Gurudasani const struct ti_dev_data *data = ti_get_dev_data(dev);
187*6f2a8791SKamlesh Gurudasani const struct ti_devgroup *devgroup_ptr = ti_dev_data_lookup_devgroup(data);
188*6f2a8791SKamlesh Gurudasani const struct ti_clk_parent *p = NULL;
189*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp;
190*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *clock_data;
191*6f2a8791SKamlesh Gurudasani uint32_t depth;
192*6f2a8791SKamlesh Gurudasani uint32_t offset;
193*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t i;
194*6f2a8791SKamlesh Gurudasani
195*6f2a8791SKamlesh Gurudasani clkp = ti_dev_get_clk(dev, clk_idx);
196*6f2a8791SKamlesh Gurudasani clock_data = ti_get_dev_clk_data(dev, clk_idx);
197*6f2a8791SKamlesh Gurudasani if ((clkp == NULL) || (clock_data == NULL) || (devgroup_ptr == NULL)) {
198*6f2a8791SKamlesh Gurudasani return TI_DEV_CLK_ID_NONE;
199*6f2a8791SKamlesh Gurudasani }
200*6f2a8791SKamlesh Gurudasani
201*6f2a8791SKamlesh Gurudasani if (clock_data->type != TI_DEV_CLK_TABLE_TYPE_MUX) {
202*6f2a8791SKamlesh Gurudasani return TI_DEV_CLK_ID_NONE;
203*6f2a8791SKamlesh Gurudasani }
204*6f2a8791SKamlesh Gurudasani
205*6f2a8791SKamlesh Gurudasani depth = soc_clock_count;
206*6f2a8791SKamlesh Gurudasani while ((clkp != NULL) && (clkp->type != TI_CLK_TYPE_MUX) && (depth > 0U)) {
207*6f2a8791SKamlesh Gurudasani depth--;
208*6f2a8791SKamlesh Gurudasani p = ti_clk_mux_get_parent(clkp);
209*6f2a8791SKamlesh Gurudasani if (p != NULL) {
210*6f2a8791SKamlesh Gurudasani clkp = ti_clk_lookup((ti_clk_idx_t) p->clk);
211*6f2a8791SKamlesh Gurudasani } else {
212*6f2a8791SKamlesh Gurudasani clkp = NULL;
213*6f2a8791SKamlesh Gurudasani }
214*6f2a8791SKamlesh Gurudasani }
215*6f2a8791SKamlesh Gurudasani
216*6f2a8791SKamlesh Gurudasani if (depth == 0U) {
217*6f2a8791SKamlesh Gurudasani /* Clock tree cycle detected or depth exceeded */
218*6f2a8791SKamlesh Gurudasani return TI_DEV_CLK_ID_NONE;
219*6f2a8791SKamlesh Gurudasani }
220*6f2a8791SKamlesh Gurudasani
221*6f2a8791SKamlesh Gurudasani if (clkp == NULL) {
222*6f2a8791SKamlesh Gurudasani return TI_DEV_CLK_ID_NONE;
223*6f2a8791SKamlesh Gurudasani }
224*6f2a8791SKamlesh Gurudasani
225*6f2a8791SKamlesh Gurudasani p = ti_clk_mux_get_parent(clkp);
226*6f2a8791SKamlesh Gurudasani if (p == NULL) {
227*6f2a8791SKamlesh Gurudasani return TI_DEV_CLK_ID_NONE;
228*6f2a8791SKamlesh Gurudasani }
229*6f2a8791SKamlesh Gurudasani
230*6f2a8791SKamlesh Gurudasani offset = data->dev_clk_idx;
231*6f2a8791SKamlesh Gurudasani for (i = 0U; i < clock_data->idx; i++) {
232*6f2a8791SKamlesh Gurudasani if (devgroup_ptr->dev_clk_data[offset + i + clk_idx + 1U].clk == p->clk) {
233*6f2a8791SKamlesh Gurudasani return i + clk_idx + 1U;
234*6f2a8791SKamlesh Gurudasani }
235*6f2a8791SKamlesh Gurudasani }
236*6f2a8791SKamlesh Gurudasani
237*6f2a8791SKamlesh Gurudasani return TI_DEV_CLK_ID_NONE;
238*6f2a8791SKamlesh Gurudasani }
239*6f2a8791SKamlesh Gurudasani
ti_device_clk_get_num_parents(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)240*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ti_device_clk_get_num_parents(struct ti_device *dev,
241*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t clk_idx)
242*6f2a8791SKamlesh Gurudasani {
243*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp;
244*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *clock_data;
245*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t ret;
246*6f2a8791SKamlesh Gurudasani
247*6f2a8791SKamlesh Gurudasani clkp = ti_dev_get_clk(dev, clk_idx);
248*6f2a8791SKamlesh Gurudasani clock_data = ti_get_dev_clk_data(dev, clk_idx);
249*6f2a8791SKamlesh Gurudasani if ((clkp == NULL) || (clock_data == NULL)) {
250*6f2a8791SKamlesh Gurudasani ret = TI_DEV_CLK_ID_NONE;
251*6f2a8791SKamlesh Gurudasani } else if (clock_data->type != TI_DEV_CLK_TABLE_TYPE_MUX) {
252*6f2a8791SKamlesh Gurudasani if (ti_clk_mux_get_parent(clkp) != NULL) {
253*6f2a8791SKamlesh Gurudasani ret = 1U;
254*6f2a8791SKamlesh Gurudasani } else {
255*6f2a8791SKamlesh Gurudasani ret = 0U;
256*6f2a8791SKamlesh Gurudasani }
257*6f2a8791SKamlesh Gurudasani } else {
258*6f2a8791SKamlesh Gurudasani ret = (ti_dev_clk_idx_t) clock_data->idx;
259*6f2a8791SKamlesh Gurudasani /*
260*6f2a8791SKamlesh Gurudasani * Encode both total parents and reserved count:
261*6f2a8791SKamlesh Gurudasani * Bits 0-7: total parent count (including reserved)
262*6f2a8791SKamlesh Gurudasani * Bits 8-15: reserved parent count
263*6f2a8791SKamlesh Gurudasani */
264*6f2a8791SKamlesh Gurudasani ret = (ti_dev_clk_idx_t) ((clock_data->n_reserved_parents << 8) | clock_data->idx);
265*6f2a8791SKamlesh Gurudasani VERBOSE("%s total=%d reserved=%d encoded=0x%x\n", __func__,
266*6f2a8791SKamlesh Gurudasani clock_data->idx, clock_data->n_reserved_parents, ret);
267*6f2a8791SKamlesh Gurudasani }
268*6f2a8791SKamlesh Gurudasani
269*6f2a8791SKamlesh Gurudasani return ret;
270*6f2a8791SKamlesh Gurudasani }
271*6f2a8791SKamlesh Gurudasani
272*6f2a8791SKamlesh Gurudasani /**
273*6f2a8791SKamlesh Gurudasani * ti_dev_clk_set_freq() - Set the frequency of a device's clock.
274*6f2a8791SKamlesh Gurudasani * @dev: The device that the clock is connected to.
275*6f2a8791SKamlesh Gurudasani * @clk_idx: The index of the clock on this device.
276*6f2a8791SKamlesh Gurudasani * @min_freq_hz: The minimum acceptable frequency in Hz.
277*6f2a8791SKamlesh Gurudasani * @target_freq_hz: The target frequency in Hz.
278*6f2a8791SKamlesh Gurudasani * @max_freq_hz: The maximum acceptable frequency in Hz.
279*6f2a8791SKamlesh Gurudasani *
280*6f2a8791SKamlesh Gurudasani * Locates the correct clock and calls the internal clock API set frequency
281*6f2a8791SKamlesh Gurudasani * function. If the clock is a mux type, the request is sent to the parent
282*6f2a8791SKamlesh Gurudasani * to avoid switching the mux.
283*6f2a8791SKamlesh Gurudasani *
284*6f2a8791SKamlesh Gurudasani * Return: The actual frequency set, or 0 if no frequency could be found
285*6f2a8791SKamlesh Gurudasani * within the limits.
286*6f2a8791SKamlesh Gurudasani */
ti_dev_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)287*6f2a8791SKamlesh Gurudasani static uint32_t ti_dev_clk_set_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx,
288*6f2a8791SKamlesh Gurudasani uint32_t min_freq_hz, uint32_t target_freq_hz,
289*6f2a8791SKamlesh Gurudasani uint32_t max_freq_hz)
290*6f2a8791SKamlesh Gurudasani {
291*6f2a8791SKamlesh Gurudasani const struct ti_dev_data *data = ti_get_dev_data(dev);
292*6f2a8791SKamlesh Gurudasani const struct ti_devgroup *devgroup_ptr = ti_dev_data_lookup_devgroup(data);
293*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *clock_data;
294*6f2a8791SKamlesh Gurudasani struct ti_clk *parent = NULL;
295*6f2a8791SKamlesh Gurudasani uint32_t div_var = 1U;
296*6f2a8791SKamlesh Gurudasani uint32_t ret_freq = 0U;
297*6f2a8791SKamlesh Gurudasani ti_dev_clk_idx_t clk_idx_val = clk_idx;
298*6f2a8791SKamlesh Gurudasani bool changed;
299*6f2a8791SKamlesh Gurudasani
300*6f2a8791SKamlesh Gurudasani if (devgroup_ptr == NULL) {
301*6f2a8791SKamlesh Gurudasani return 0U;
302*6f2a8791SKamlesh Gurudasani }
303*6f2a8791SKamlesh Gurudasani
304*6f2a8791SKamlesh Gurudasani clock_data = ti_get_dev_clk_data(dev, clk_idx_val);
305*6f2a8791SKamlesh Gurudasani if (clock_data == NULL) {
306*6f2a8791SKamlesh Gurudasani /* Invalid clock idx */
307*6f2a8791SKamlesh Gurudasani return 0U;
308*6f2a8791SKamlesh Gurudasani }
309*6f2a8791SKamlesh Gurudasani
310*6f2a8791SKamlesh Gurudasani parent = ti_dev_get_clk(dev, clk_idx_val);
311*6f2a8791SKamlesh Gurudasani if (parent == NULL) {
312*6f2a8791SKamlesh Gurudasani /* Parent not present */
313*6f2a8791SKamlesh Gurudasani return 0U;
314*6f2a8791SKamlesh Gurudasani }
315*6f2a8791SKamlesh Gurudasani
316*6f2a8791SKamlesh Gurudasani /* Assign div based on selected clock */
317*6f2a8791SKamlesh Gurudasani div_var = clock_data->div;
318*6f2a8791SKamlesh Gurudasani
319*6f2a8791SKamlesh Gurudasani if ((parent->type == TI_CLK_TYPE_MUX) &&
320*6f2a8791SKamlesh Gurudasani (clock_data->type == TI_DEV_CLK_TABLE_TYPE_MUX)) {
321*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *parent_clk_data;
322*6f2a8791SKamlesh Gurudasani /* Send to parent */
323*6f2a8791SKamlesh Gurudasani clk_idx_val = ti_device_clk_get_parent(dev, clk_idx_val);
324*6f2a8791SKamlesh Gurudasani parent = ti_dev_get_clk(dev, clk_idx_val);
325*6f2a8791SKamlesh Gurudasani parent_clk_data = ti_get_dev_clk_data(dev, clk_idx_val);
326*6f2a8791SKamlesh Gurudasani if (parent_clk_data != NULL) {
327*6f2a8791SKamlesh Gurudasani /* We are sending to parent, so use that div instead */
328*6f2a8791SKamlesh Gurudasani div_var = parent_clk_data->div;
329*6f2a8791SKamlesh Gurudasani }
330*6f2a8791SKamlesh Gurudasani if (parent == NULL) {
331*6f2a8791SKamlesh Gurudasani /* Mux parent clock not present */
332*6f2a8791SKamlesh Gurudasani return 0U;
333*6f2a8791SKamlesh Gurudasani }
334*6f2a8791SKamlesh Gurudasani }
335*6f2a8791SKamlesh Gurudasani
336*6f2a8791SKamlesh Gurudasani if (clock_data->type == TI_DEV_CLK_TABLE_TYPE_OUTPUT) {
337*6f2a8791SKamlesh Gurudasani /* div is only for input clocks */
338*6f2a8791SKamlesh Gurudasani div_var = 1U;
339*6f2a8791SKamlesh Gurudasani }
340*6f2a8791SKamlesh Gurudasani
341*6f2a8791SKamlesh Gurudasani if (clock_data->modify_parent_freq == 0U) {
342*6f2a8791SKamlesh Gurudasani if (div_var != 0U) {
343*6f2a8791SKamlesh Gurudasani ret_freq = ti_clk_get_freq(parent) / div_var;
344*6f2a8791SKamlesh Gurudasani if ((ret_freq < min_freq_hz) || (ret_freq > max_freq_hz)) {
345*6f2a8791SKamlesh Gurudasani ret_freq = 0U;
346*6f2a8791SKamlesh Gurudasani }
347*6f2a8791SKamlesh Gurudasani }
348*6f2a8791SKamlesh Gurudasani return ret_freq;
349*6f2a8791SKamlesh Gurudasani }
350*6f2a8791SKamlesh Gurudasani
351*6f2a8791SKamlesh Gurudasani /* Try to modify the frequency */
352*6f2a8791SKamlesh Gurudasani changed = false;
353*6f2a8791SKamlesh Gurudasani if (clock_data->type == TI_DEV_CLK_TABLE_TYPE_OUTPUT) {
354*6f2a8791SKamlesh Gurudasani /*
355*6f2a8791SKamlesh Gurudasani * This is the only place device output clocks can have their
356*6f2a8791SKamlesh Gurudasani * frequency changed, from their own device.
357*6f2a8791SKamlesh Gurudasani */
358*6f2a8791SKamlesh Gurudasani ret_freq = ti_clk_value_set_freq(parent, target_freq_hz,
359*6f2a8791SKamlesh Gurudasani min_freq_hz, max_freq_hz,
360*6f2a8791SKamlesh Gurudasani &changed);
361*6f2a8791SKamlesh Gurudasani } else {
362*6f2a8791SKamlesh Gurudasani ret_freq = ti_clk_generic_set_freq_parent(NULL, parent,
363*6f2a8791SKamlesh Gurudasani target_freq_hz,
364*6f2a8791SKamlesh Gurudasani min_freq_hz,
365*6f2a8791SKamlesh Gurudasani max_freq_hz,
366*6f2a8791SKamlesh Gurudasani &changed,
367*6f2a8791SKamlesh Gurudasani div_var);
368*6f2a8791SKamlesh Gurudasani }
369*6f2a8791SKamlesh Gurudasani
370*6f2a8791SKamlesh Gurudasani return ret_freq;
371*6f2a8791SKamlesh Gurudasani }
372*6f2a8791SKamlesh Gurudasani
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)373*6f2a8791SKamlesh Gurudasani bool ti_device_clk_set_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx,
374*6f2a8791SKamlesh Gurudasani uint32_t min_freq_hz, uint32_t target_freq_hz,
375*6f2a8791SKamlesh Gurudasani uint32_t max_freq_hz)
376*6f2a8791SKamlesh Gurudasani {
377*6f2a8791SKamlesh Gurudasani return ti_dev_clk_set_freq(dev, clk_idx, min_freq_hz, target_freq_hz,
378*6f2a8791SKamlesh Gurudasani max_freq_hz) != 0U;
379*6f2a8791SKamlesh Gurudasani }
380*6f2a8791SKamlesh Gurudasani
ti_device_clk_get_freq(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)381*6f2a8791SKamlesh Gurudasani uint32_t ti_device_clk_get_freq(struct ti_device *dev, ti_dev_clk_idx_t clk_idx)
382*6f2a8791SKamlesh Gurudasani {
383*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp;
384*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *clock_data;
385*6f2a8791SKamlesh Gurudasani uint32_t freq_hz;
386*6f2a8791SKamlesh Gurudasani
387*6f2a8791SKamlesh Gurudasani clkp = ti_dev_get_clk(dev, clk_idx);
388*6f2a8791SKamlesh Gurudasani clock_data = ti_get_dev_clk_data(dev, clk_idx);
389*6f2a8791SKamlesh Gurudasani if ((clkp == NULL) || (clock_data == NULL)) {
390*6f2a8791SKamlesh Gurudasani freq_hz = 0U;
391*6f2a8791SKamlesh Gurudasani } else {
392*6f2a8791SKamlesh Gurudasani freq_hz = ti_clk_get_freq(clkp);
393*6f2a8791SKamlesh Gurudasani if (clock_data->type != TI_DEV_CLK_TABLE_TYPE_OUTPUT) {
394*6f2a8791SKamlesh Gurudasani if (clock_data->div != 0U) {
395*6f2a8791SKamlesh Gurudasani freq_hz /= clock_data->div;
396*6f2a8791SKamlesh Gurudasani } else {
397*6f2a8791SKamlesh Gurudasani freq_hz = 0U;
398*6f2a8791SKamlesh Gurudasani }
399*6f2a8791SKamlesh Gurudasani }
400*6f2a8791SKamlesh Gurudasani }
401*6f2a8791SKamlesh Gurudasani
402*6f2a8791SKamlesh Gurudasani return freq_hz;
403*6f2a8791SKamlesh Gurudasani }
404*6f2a8791SKamlesh Gurudasani
ti_device_clk_enable(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)405*6f2a8791SKamlesh Gurudasani void ti_device_clk_enable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx)
406*6f2a8791SKamlesh Gurudasani {
407*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *dev_clkp;
408*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp = NULL;
409*6f2a8791SKamlesh Gurudasani
410*6f2a8791SKamlesh Gurudasani dev_clkp = ti_get_dev_clk(dev, clk_idx);
411*6f2a8791SKamlesh Gurudasani if ((dev_clkp != NULL) && (0U == (dev_clkp->flags & TI_DEV_CLK_FLAG_DISABLE))) {
412*6f2a8791SKamlesh Gurudasani clkp = ti_dev_get_clk(dev, clk_idx);
413*6f2a8791SKamlesh Gurudasani }
414*6f2a8791SKamlesh Gurudasani
415*6f2a8791SKamlesh Gurudasani if (clkp != NULL) {
416*6f2a8791SKamlesh Gurudasani (void)ti_clk_get(clkp);
417*6f2a8791SKamlesh Gurudasani }
418*6f2a8791SKamlesh Gurudasani }
419*6f2a8791SKamlesh Gurudasani
ti_device_clk_disable(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)420*6f2a8791SKamlesh Gurudasani void ti_device_clk_disable(struct ti_device *dev, ti_dev_clk_idx_t clk_idx)
421*6f2a8791SKamlesh Gurudasani {
422*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *dev_clkp;
423*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp = NULL;
424*6f2a8791SKamlesh Gurudasani
425*6f2a8791SKamlesh Gurudasani dev_clkp = ti_get_dev_clk(dev, clk_idx);
426*6f2a8791SKamlesh Gurudasani if ((dev_clkp != NULL) && (0U == (dev_clkp->flags & TI_DEV_CLK_FLAG_DISABLE))) {
427*6f2a8791SKamlesh Gurudasani clkp = ti_dev_get_clk(dev, clk_idx);
428*6f2a8791SKamlesh Gurudasani }
429*6f2a8791SKamlesh Gurudasani
430*6f2a8791SKamlesh Gurudasani if (clkp != NULL) {
431*6f2a8791SKamlesh Gurudasani ti_clk_put(clkp);
432*6f2a8791SKamlesh Gurudasani }
433*6f2a8791SKamlesh Gurudasani }
434*6f2a8791SKamlesh Gurudasani
ti_device_clk_init(struct ti_device * dev,ti_dev_clk_idx_t clk_idx)435*6f2a8791SKamlesh Gurudasani void ti_device_clk_init(struct ti_device *dev, ti_dev_clk_idx_t clk_idx)
436*6f2a8791SKamlesh Gurudasani {
437*6f2a8791SKamlesh Gurudasani struct ti_clk *clkp = NULL;
438*6f2a8791SKamlesh Gurudasani struct ti_dev_clk *dev_clkp;
439*6f2a8791SKamlesh Gurudasani const struct ti_dev_clk_data *dev_clk_datap;
440*6f2a8791SKamlesh Gurudasani
441*6f2a8791SKamlesh Gurudasani dev_clkp = ti_get_dev_clk(dev, clk_idx);
442*6f2a8791SKamlesh Gurudasani dev_clk_datap = ti_get_dev_clk_data(dev, clk_idx);
443*6f2a8791SKamlesh Gurudasani
444*6f2a8791SKamlesh Gurudasani /* Don't configure parent clocks for anything until host does */
445*6f2a8791SKamlesh Gurudasani if ((dev_clk_datap != NULL) && (dev_clkp != NULL)) {
446*6f2a8791SKamlesh Gurudasani if (dev_clk_datap->type == TI_DEV_CLK_TABLE_TYPE_PARENT) {
447*6f2a8791SKamlesh Gurudasani dev_clkp->flags |= TI_DEV_CLK_FLAG_DISABLE;
448*6f2a8791SKamlesh Gurudasani }
449*6f2a8791SKamlesh Gurudasani }
450*6f2a8791SKamlesh Gurudasani
451*6f2a8791SKamlesh Gurudasani if ((dev_clk_datap != NULL) && (dev_clkp != NULL)) {
452*6f2a8791SKamlesh Gurudasani clkp = ti_clk_lookup((ti_clk_idx_t) dev_clk_datap->clk);
453*6f2a8791SKamlesh Gurudasani }
454*6f2a8791SKamlesh Gurudasani if (clkp != NULL) {
455*6f2a8791SKamlesh Gurudasani /* It's in another devgroup, don't attempt to bring it up */
456*6f2a8791SKamlesh Gurudasani if ((clkp->flags & TI_CLK_FLAG_INITIALIZED) == 0U) {
457*6f2a8791SKamlesh Gurudasani dev_clkp->flags |= TI_DEV_CLK_FLAG_DISABLE;
458*6f2a8791SKamlesh Gurudasani }
459*6f2a8791SKamlesh Gurudasani }
460*6f2a8791SKamlesh Gurudasani }
461