1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/clk-provider.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/module.h>
20#include <linux/of_address.h>
21#include <linux/of_device.h>
22#include <linux/platform_device.h>
23#include <linux/slab.h>
24#include <linux/soc/ti/ti_sci_protocol.h>
25#include <linux/bsearch.h>
26
27#define SCI_CLK_SSC_ENABLE BIT(0)
28#define SCI_CLK_ALLOW_FREQ_CHANGE BIT(1)
29#define SCI_CLK_INPUT_TERMINATION BIT(2)
30
31
32
33
34
35
36
37
38
39struct sci_clk_provider {
40 const struct ti_sci_handle *sci;
41 const struct ti_sci_clk_ops *ops;
42 struct device *dev;
43 struct sci_clk **clocks;
44 int num_clocks;
45};
46
47
48
49
50
51
52
53
54
55
56struct sci_clk {
57 struct clk_hw hw;
58 u16 dev_id;
59 u8 clk_id;
60 u8 num_parents;
61 struct sci_clk_provider *provider;
62 u8 flags;
63};
64
65#define to_sci_clk(_hw) container_of(_hw, struct sci_clk, hw)
66
67
68
69
70
71
72
73static int sci_clk_prepare(struct clk_hw *hw)
74{
75 struct sci_clk *clk = to_sci_clk(hw);
76 bool enable_ssc = clk->flags & SCI_CLK_SSC_ENABLE;
77 bool allow_freq_change = clk->flags & SCI_CLK_ALLOW_FREQ_CHANGE;
78 bool input_termination = clk->flags & SCI_CLK_INPUT_TERMINATION;
79
80 return clk->provider->ops->get_clock(clk->provider->sci, clk->dev_id,
81 clk->clk_id, enable_ssc,
82 allow_freq_change,
83 input_termination);
84}
85
86
87
88
89
90
91
92static void sci_clk_unprepare(struct clk_hw *hw)
93{
94 struct sci_clk *clk = to_sci_clk(hw);
95 int ret;
96
97 ret = clk->provider->ops->put_clock(clk->provider->sci, clk->dev_id,
98 clk->clk_id);
99 if (ret)
100 dev_err(clk->provider->dev,
101 "unprepare failed for dev=%d, clk=%d, ret=%d\n",
102 clk->dev_id, clk->clk_id, ret);
103}
104
105
106
107
108
109
110
111
112static int sci_clk_is_prepared(struct clk_hw *hw)
113{
114 struct sci_clk *clk = to_sci_clk(hw);
115 bool req_state, current_state;
116 int ret;
117
118 ret = clk->provider->ops->is_on(clk->provider->sci, clk->dev_id,
119 clk->clk_id, &req_state,
120 ¤t_state);
121 if (ret) {
122 dev_err(clk->provider->dev,
123 "is_prepared failed for dev=%d, clk=%d, ret=%d\n",
124 clk->dev_id, clk->clk_id, ret);
125 return 0;
126 }
127
128 return req_state;
129}
130
131
132
133
134
135
136
137
138
139static unsigned long sci_clk_recalc_rate(struct clk_hw *hw,
140 unsigned long parent_rate)
141{
142 struct sci_clk *clk = to_sci_clk(hw);
143 u64 freq;
144 int ret;
145
146 ret = clk->provider->ops->get_freq(clk->provider->sci, clk->dev_id,
147 clk->clk_id, &freq);
148 if (ret) {
149 dev_err(clk->provider->dev,
150 "recalc-rate failed for dev=%d, clk=%d, ret=%d\n",
151 clk->dev_id, clk->clk_id, ret);
152 return 0;
153 }
154
155 return freq;
156}
157
158
159
160
161
162
163
164
165
166
167
168static int sci_clk_determine_rate(struct clk_hw *hw,
169 struct clk_rate_request *req)
170{
171 struct sci_clk *clk = to_sci_clk(hw);
172 int ret;
173 u64 new_rate;
174
175 ret = clk->provider->ops->get_best_match_freq(clk->provider->sci,
176 clk->dev_id,
177 clk->clk_id,
178 req->min_rate,
179 req->rate,
180 req->max_rate,
181 &new_rate);
182 if (ret) {
183 dev_err(clk->provider->dev,
184 "determine-rate failed for dev=%d, clk=%d, ret=%d\n",
185 clk->dev_id, clk->clk_id, ret);
186 return ret;
187 }
188
189 req->rate = new_rate;
190
191 return 0;
192}
193
194
195
196
197
198
199
200
201
202
203static int sci_clk_set_rate(struct clk_hw *hw, unsigned long rate,
204 unsigned long parent_rate)
205{
206 struct sci_clk *clk = to_sci_clk(hw);
207
208 return clk->provider->ops->set_freq(clk->provider->sci, clk->dev_id,
209 clk->clk_id, rate, rate, rate);
210}
211
212
213
214
215
216
217
218static u8 sci_clk_get_parent(struct clk_hw *hw)
219{
220 struct sci_clk *clk = to_sci_clk(hw);
221 u8 parent_id;
222 int ret;
223
224 ret = clk->provider->ops->get_parent(clk->provider->sci, clk->dev_id,
225 clk->clk_id, &parent_id);
226 if (ret) {
227 dev_err(clk->provider->dev,
228 "get-parent failed for dev=%d, clk=%d, ret=%d\n",
229 clk->dev_id, clk->clk_id, ret);
230 return 0;
231 }
232
233 return parent_id - clk->clk_id - 1;
234}
235
236
237
238
239
240
241
242
243static int sci_clk_set_parent(struct clk_hw *hw, u8 index)
244{
245 struct sci_clk *clk = to_sci_clk(hw);
246
247 return clk->provider->ops->set_parent(clk->provider->sci, clk->dev_id,
248 clk->clk_id,
249 index + 1 + clk->clk_id);
250}
251
252static const struct clk_ops sci_clk_ops = {
253 .prepare = sci_clk_prepare,
254 .unprepare = sci_clk_unprepare,
255 .is_prepared = sci_clk_is_prepared,
256 .recalc_rate = sci_clk_recalc_rate,
257 .determine_rate = sci_clk_determine_rate,
258 .set_rate = sci_clk_set_rate,
259 .get_parent = sci_clk_get_parent,
260 .set_parent = sci_clk_set_parent,
261};
262
263
264
265
266
267
268
269
270
271
272
273
274static int _sci_clk_build(struct sci_clk_provider *provider,
275 struct sci_clk *sci_clk)
276{
277 struct clk_init_data init = { NULL };
278 char *name = NULL;
279 char **parent_names = NULL;
280 int i;
281 int ret = 0;
282
283 name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev),
284 sci_clk->dev_id, sci_clk->clk_id);
285
286 init.name = name;
287
288
289
290
291
292
293
294 if (sci_clk->num_parents < 2)
295 sci_clk->num_parents = 0;
296
297 if (sci_clk->num_parents) {
298 parent_names = kcalloc(sci_clk->num_parents, sizeof(char *),
299 GFP_KERNEL);
300
301 if (!parent_names) {
302 ret = -ENOMEM;
303 goto err;
304 }
305
306 for (i = 0; i < sci_clk->num_parents; i++) {
307 char *parent_name;
308
309 parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d",
310 dev_name(provider->dev),
311 sci_clk->dev_id,
312 sci_clk->clk_id + 1 + i);
313 if (!parent_name) {
314 ret = -ENOMEM;
315 goto err;
316 }
317 parent_names[i] = parent_name;
318 }
319 init.parent_names = (void *)parent_names;
320 }
321
322 init.ops = &sci_clk_ops;
323 init.num_parents = sci_clk->num_parents;
324 sci_clk->hw.init = &init;
325
326 ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
327 if (ret)
328 dev_err(provider->dev, "failed clk register with %d\n", ret);
329
330err:
331 if (parent_names) {
332 for (i = 0; i < sci_clk->num_parents; i++)
333 kfree(parent_names[i]);
334
335 kfree(parent_names);
336 }
337
338 kfree(name);
339
340 return ret;
341}
342
343static int _cmp_sci_clk(const void *a, const void *b)
344{
345 const struct sci_clk *ca = a;
346 const struct sci_clk *cb = *(struct sci_clk **)b;
347
348 if (ca->dev_id == cb->dev_id && ca->clk_id == cb->clk_id)
349 return 0;
350 if (ca->dev_id > cb->dev_id ||
351 (ca->dev_id == cb->dev_id && ca->clk_id > cb->clk_id))
352 return 1;
353 return -1;
354}
355
356
357
358
359
360
361
362
363
364
365
366static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data)
367{
368 struct sci_clk_provider *provider = data;
369 struct sci_clk **clk;
370 struct sci_clk key;
371
372 if (clkspec->args_count != 2)
373 return ERR_PTR(-EINVAL);
374
375 key.dev_id = clkspec->args[0];
376 key.clk_id = clkspec->args[1];
377
378 clk = bsearch(&key, provider->clocks, provider->num_clocks,
379 sizeof(clk), _cmp_sci_clk);
380
381 if (!clk)
382 return ERR_PTR(-ENODEV);
383
384 return &(*clk)->hw;
385}
386
387static int ti_sci_init_clocks(struct sci_clk_provider *p)
388{
389 int i;
390 int ret;
391
392 for (i = 0; i < p->num_clocks; i++) {
393 ret = _sci_clk_build(p, p->clocks[i]);
394 if (ret)
395 return ret;
396 }
397
398 return 0;
399}
400
401static const struct of_device_id ti_sci_clk_of_match[] = {
402 { .compatible = "ti,k2g-sci-clk" },
403 { },
404};
405MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match);
406
407
408
409
410
411
412
413
414
415
416
417static int ti_sci_clk_probe(struct platform_device *pdev)
418{
419 struct device *dev = &pdev->dev;
420 struct device_node *np = dev->of_node;
421 struct sci_clk_provider *provider;
422 const struct ti_sci_handle *handle;
423 int ret;
424 int num_clks = 0;
425 struct sci_clk **clks = NULL;
426 struct sci_clk **tmp_clks;
427 struct sci_clk *sci_clk;
428 int max_clks = 0;
429 int clk_id = 0;
430 int dev_id = 0;
431 u8 num_parents;
432 int gap_size = 0;
433
434 handle = devm_ti_sci_get_handle(dev);
435 if (IS_ERR(handle))
436 return PTR_ERR(handle);
437
438 provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
439 if (!provider)
440 return -ENOMEM;
441
442 provider->sci = handle;
443 provider->ops = &handle->ops.clk_ops;
444 provider->dev = dev;
445
446 while (1) {
447 ret = provider->ops->get_num_parents(provider->sci, dev_id,
448 clk_id, &num_parents);
449 if (ret) {
450 gap_size++;
451 if (!clk_id) {
452 if (gap_size >= 5)
453 break;
454 dev_id++;
455 } else {
456 if (gap_size >= 2) {
457 dev_id++;
458 clk_id = 0;
459 gap_size = 0;
460 } else {
461 clk_id++;
462 }
463 }
464 continue;
465 }
466
467 gap_size = 0;
468
469 if (num_clks == max_clks) {
470 tmp_clks = devm_kmalloc_array(dev, max_clks + 64,
471 sizeof(sci_clk),
472 GFP_KERNEL);
473 memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk));
474 if (max_clks)
475 devm_kfree(dev, clks);
476 max_clks += 64;
477 clks = tmp_clks;
478 }
479
480 sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL);
481 if (!sci_clk)
482 return -ENOMEM;
483 sci_clk->dev_id = dev_id;
484 sci_clk->clk_id = clk_id;
485 sci_clk->provider = provider;
486 sci_clk->num_parents = num_parents;
487
488 clks[num_clks] = sci_clk;
489
490 clk_id++;
491 num_clks++;
492 }
493
494 provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk),
495 GFP_KERNEL);
496 if (!provider->clocks)
497 return -ENOMEM;
498
499 memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk));
500
501 provider->num_clocks = num_clks;
502
503 devm_kfree(dev, clks);
504
505 ret = ti_sci_init_clocks(provider);
506 if (ret) {
507 pr_err("ti-sci-init-clocks failed.\n");
508 return ret;
509 }
510
511 return of_clk_add_hw_provider(np, sci_clk_get, provider);
512}
513
514
515
516
517
518
519
520
521
522static int ti_sci_clk_remove(struct platform_device *pdev)
523{
524 of_clk_del_provider(pdev->dev.of_node);
525
526 return 0;
527}
528
529static struct platform_driver ti_sci_clk_driver = {
530 .probe = ti_sci_clk_probe,
531 .remove = ti_sci_clk_remove,
532 .driver = {
533 .name = "ti-sci-clk",
534 .of_match_table = of_match_ptr(ti_sci_clk_of_match),
535 },
536};
537module_platform_driver(ti_sci_clk_driver);
538
539MODULE_LICENSE("GPL v2");
540MODULE_DESCRIPTION("TI System Control Interface(SCI) Clock driver");
541MODULE_AUTHOR("Tero Kristo");
542MODULE_ALIAS("platform:ti-sci-clk");
543