1 // SPDX-License-Identifier: GPL-2.0-only
3 * Microchip Image Sensor Controller (ISC) common clock driver setup
5 * Copyright (C) 2016 Microchip Technology, Inc.
8 * Author: Eugen Hristev <eugen.hristev@microchip.com>
11 #include <linux/clk.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk-provider.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
17 #include "microchip-isc-regs.h"
18 #include "microchip-isc.h"
20 static int isc_wait_clk_stable(struct clk_hw
*hw
)
22 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
23 struct regmap
*regmap
= isc_clk
->regmap
;
24 unsigned long timeout
= jiffies
+ usecs_to_jiffies(1000);
27 while (time_before(jiffies
, timeout
)) {
28 regmap_read(regmap
, ISC_CLKSR
, &status
);
29 if (!(status
& ISC_CLKSR_SIP
))
32 usleep_range(10, 250);
38 static int isc_clk_prepare(struct clk_hw
*hw
)
40 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
43 ret
= pm_runtime_resume_and_get(isc_clk
->dev
);
47 return isc_wait_clk_stable(hw
);
50 static void isc_clk_unprepare(struct clk_hw
*hw
)
52 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
54 isc_wait_clk_stable(hw
);
56 pm_runtime_put_sync(isc_clk
->dev
);
59 static int isc_clk_enable(struct clk_hw
*hw
)
61 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
63 struct regmap
*regmap
= isc_clk
->regmap
;
67 dev_dbg(isc_clk
->dev
, "ISC CLK: %s, id = %d, div = %d, parent id = %d\n",
68 __func__
, id
, isc_clk
->div
, isc_clk
->parent_id
);
70 spin_lock_irqsave(&isc_clk
->lock
, flags
);
71 regmap_update_bits(regmap
, ISC_CLKCFG
,
72 ISC_CLKCFG_DIV_MASK(id
) | ISC_CLKCFG_SEL_MASK(id
),
73 (isc_clk
->div
<< ISC_CLKCFG_DIV_SHIFT(id
)) |
74 (isc_clk
->parent_id
<< ISC_CLKCFG_SEL_SHIFT(id
)));
76 regmap_write(regmap
, ISC_CLKEN
, ISC_CLK(id
));
77 spin_unlock_irqrestore(&isc_clk
->lock
, flags
);
79 regmap_read(regmap
, ISC_CLKSR
, &status
);
80 if (status
& ISC_CLK(id
))
86 static void isc_clk_disable(struct clk_hw
*hw
)
88 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
92 spin_lock_irqsave(&isc_clk
->lock
, flags
);
93 regmap_write(isc_clk
->regmap
, ISC_CLKDIS
, ISC_CLK(id
));
94 spin_unlock_irqrestore(&isc_clk
->lock
, flags
);
97 static int isc_clk_is_enabled(struct clk_hw
*hw
)
99 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
103 ret
= pm_runtime_resume_and_get(isc_clk
->dev
);
107 regmap_read(isc_clk
->regmap
, ISC_CLKSR
, &status
);
109 pm_runtime_put_sync(isc_clk
->dev
);
111 return status
& ISC_CLK(isc_clk
->id
) ? 1 : 0;
115 isc_clk_recalc_rate(struct clk_hw
*hw
, unsigned long parent_rate
)
117 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
119 return DIV_ROUND_CLOSEST(parent_rate
, isc_clk
->div
+ 1);
122 static int isc_clk_determine_rate(struct clk_hw
*hw
,
123 struct clk_rate_request
*req
)
125 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
126 long best_rate
= -EINVAL
;
130 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
131 struct clk_hw
*parent
;
132 unsigned long parent_rate
;
134 parent
= clk_hw_get_parent_by_index(hw
, i
);
138 parent_rate
= clk_hw_get_rate(parent
);
142 for (div
= 1; div
< ISC_CLK_MAX_DIV
+ 2; div
++) {
146 rate
= DIV_ROUND_CLOSEST(parent_rate
, div
);
147 diff
= abs(req
->rate
- rate
);
149 if (best_diff
< 0 || best_diff
> diff
) {
152 req
->best_parent_rate
= parent_rate
;
153 req
->best_parent_hw
= parent
;
156 if (!best_diff
|| rate
< req
->rate
)
164 dev_dbg(isc_clk
->dev
,
165 "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
167 __clk_get_name((req
->best_parent_hw
)->clk
),
168 req
->best_parent_rate
);
173 req
->rate
= best_rate
;
178 static int isc_clk_set_parent(struct clk_hw
*hw
, u8 index
)
180 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
182 if (index
>= clk_hw_get_num_parents(hw
))
185 isc_clk
->parent_id
= index
;
190 static u8
isc_clk_get_parent(struct clk_hw
*hw
)
192 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
194 return isc_clk
->parent_id
;
197 static int isc_clk_set_rate(struct clk_hw
*hw
,
199 unsigned long parent_rate
)
201 struct isc_clk
*isc_clk
= to_isc_clk(hw
);
207 div
= DIV_ROUND_CLOSEST(parent_rate
, rate
);
208 if (div
> (ISC_CLK_MAX_DIV
+ 1) || !div
)
211 isc_clk
->div
= div
- 1;
216 static const struct clk_ops isc_clk_ops
= {
217 .prepare
= isc_clk_prepare
,
218 .unprepare
= isc_clk_unprepare
,
219 .enable
= isc_clk_enable
,
220 .disable
= isc_clk_disable
,
221 .is_enabled
= isc_clk_is_enabled
,
222 .recalc_rate
= isc_clk_recalc_rate
,
223 .determine_rate
= isc_clk_determine_rate
,
224 .set_parent
= isc_clk_set_parent
,
225 .get_parent
= isc_clk_get_parent
,
226 .set_rate
= isc_clk_set_rate
,
229 static int isc_clk_register(struct isc_device
*isc
, unsigned int id
)
231 struct regmap
*regmap
= isc
->regmap
;
232 struct device_node
*np
= isc
->dev
->of_node
;
233 struct isc_clk
*isc_clk
;
234 struct clk_init_data init
;
235 const char *clk_name
= np
->name
;
236 const char *parent_names
[3];
239 if (id
== ISC_ISPCK
&& !isc
->ispck_required
)
242 num_parents
= of_clk_get_parent_count(np
);
243 if (num_parents
< 1 || num_parents
> 3)
246 if (num_parents
> 2 && id
== ISC_ISPCK
)
249 of_clk_parent_fill(np
, parent_names
, num_parents
);
252 of_property_read_string(np
, "clock-output-names", &clk_name
);
254 clk_name
= "isc-ispck";
256 init
.parent_names
= parent_names
;
257 init
.num_parents
= num_parents
;
258 init
.name
= clk_name
;
259 init
.ops
= &isc_clk_ops
;
260 init
.flags
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
;
262 isc_clk
= &isc
->isc_clks
[id
];
263 isc_clk
->hw
.init
= &init
;
264 isc_clk
->regmap
= regmap
;
266 isc_clk
->dev
= isc
->dev
;
267 spin_lock_init(&isc_clk
->lock
);
269 isc_clk
->clk
= clk_register(isc
->dev
, &isc_clk
->hw
);
270 if (IS_ERR(isc_clk
->clk
)) {
271 dev_err(isc
->dev
, "%s: clock register fail\n", clk_name
);
272 return PTR_ERR(isc_clk
->clk
);
273 } else if (id
== ISC_MCK
) {
274 of_clk_add_provider(np
, of_clk_src_simple_get
, isc_clk
->clk
);
280 int microchip_isc_clk_init(struct isc_device
*isc
)
285 for (i
= 0; i
< ARRAY_SIZE(isc
->isc_clks
); i
++)
286 isc
->isc_clks
[i
].clk
= ERR_PTR(-EINVAL
);
288 for (i
= 0; i
< ARRAY_SIZE(isc
->isc_clks
); i
++) {
289 ret
= isc_clk_register(isc
, i
);
296 EXPORT_SYMBOL_GPL(microchip_isc_clk_init
);
298 void microchip_isc_clk_cleanup(struct isc_device
*isc
)
302 of_clk_del_provider(isc
->dev
->of_node
);
304 for (i
= 0; i
< ARRAY_SIZE(isc
->isc_clks
); i
++) {
305 struct isc_clk
*isc_clk
= &isc
->isc_clks
[i
];
307 if (!IS_ERR(isc_clk
->clk
))
308 clk_unregister(isc_clk
->clk
);
311 EXPORT_SYMBOL_GPL(microchip_isc_clk_cleanup
);