1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78#undef DEBUG
79
80#include <linux/kernel.h>
81#include <linux/platform_device.h>
82#include <linux/slab.h>
83#include <linux/err.h>
84#include <linux/io.h>
85#include <linux/clk.h>
86#include <linux/clkdev.h>
87
88#include <plat/omap_device.h>
89#include <plat/omap_hwmod.h>
90#include <plat/clock.h>
91
92
93#define USE_WAKEUP_LAT 0
94#define IGNORE_WAKEUP_LAT 1
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
113{
114 struct timespec a, b, c;
115
116 pr_debug("omap_device: %s: activating\n", od->pdev.name);
117
118 while (od->pm_lat_level > 0) {
119 struct omap_device_pm_latency *odpl;
120 unsigned long long act_lat = 0;
121
122 od->pm_lat_level--;
123
124 odpl = od->pm_lats + od->pm_lat_level;
125
126 if (!ignore_lat &&
127 (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit))
128 break;
129
130 read_persistent_clock(&a);
131
132
133 odpl->activate_func(od);
134
135 read_persistent_clock(&b);
136
137 c = timespec_sub(b, a);
138 act_lat = timespec_to_ns(&c);
139
140 pr_debug("omap_device: %s: pm_lat %d: activate: elapsed time "
141 "%llu nsec\n", od->pdev.name, od->pm_lat_level,
142 act_lat);
143
144 if (act_lat > odpl->activate_lat) {
145 odpl->activate_lat_worst = act_lat;
146 if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
147 odpl->activate_lat = act_lat;
148 pr_warning("omap_device: %s.%d: new worst case "
149 "activate latency %d: %llu\n",
150 od->pdev.name, od->pdev.id,
151 od->pm_lat_level, act_lat);
152 } else
153 pr_warning("omap_device: %s.%d: activate "
154 "latency %d higher than exptected. "
155 "(%llu > %d)\n",
156 od->pdev.name, od->pdev.id,
157 od->pm_lat_level, act_lat,
158 odpl->activate_lat);
159 }
160
161 od->dev_wakeup_lat -= odpl->activate_lat;
162 }
163
164 return 0;
165}
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
182{
183 struct timespec a, b, c;
184
185 pr_debug("omap_device: %s: deactivating\n", od->pdev.name);
186
187 while (od->pm_lat_level < od->pm_lats_cnt) {
188 struct omap_device_pm_latency *odpl;
189 unsigned long long deact_lat = 0;
190
191 odpl = od->pm_lats + od->pm_lat_level;
192
193 if (!ignore_lat &&
194 ((od->dev_wakeup_lat + odpl->activate_lat) >
195 od->_dev_wakeup_lat_limit))
196 break;
197
198 read_persistent_clock(&a);
199
200
201 odpl->deactivate_func(od);
202
203 read_persistent_clock(&b);
204
205 c = timespec_sub(b, a);
206 deact_lat = timespec_to_ns(&c);
207
208 pr_debug("omap_device: %s: pm_lat %d: deactivate: elapsed time "
209 "%llu nsec\n", od->pdev.name, od->pm_lat_level,
210 deact_lat);
211
212 if (deact_lat > odpl->deactivate_lat) {
213 odpl->deactivate_lat_worst = deact_lat;
214 if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
215 odpl->deactivate_lat = deact_lat;
216 pr_warning("omap_device: %s.%d: new worst case "
217 "deactivate latency %d: %llu\n",
218 od->pdev.name, od->pdev.id,
219 od->pm_lat_level, deact_lat);
220 } else
221 pr_warning("omap_device: %s.%d: deactivate "
222 "latency %d higher than exptected. "
223 "(%llu > %d)\n",
224 od->pdev.name, od->pdev.id,
225 od->pm_lat_level, deact_lat,
226 odpl->deactivate_lat);
227 }
228
229
230 od->dev_wakeup_lat += odpl->activate_lat;
231
232 od->pm_lat_level++;
233 }
234
235 return 0;
236}
237
238static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
239{
240 return container_of(pdev, struct omap_device, pdev);
241}
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259static void _add_optional_clock_clkdev(struct omap_device *od,
260 struct omap_hwmod *oh)
261{
262 int i;
263
264 for (i = 0; i < oh->opt_clks_cnt; i++) {
265 struct omap_hwmod_opt_clk *oc;
266 struct clk *r;
267 struct clk_lookup *l;
268
269 oc = &oh->opt_clks[i];
270
271 if (!oc->_clk)
272 continue;
273
274 r = clk_get_sys(dev_name(&od->pdev.dev), oc->role);
275 if (!IS_ERR(r))
276 continue;
277
278 r = omap_clk_get_by_name((char *)oc->clk);
279 if (IS_ERR(r)) {
280 pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n",
281 dev_name(&od->pdev.dev), oc->clk);
282 continue;
283 }
284
285 l = clkdev_alloc(r, oc->role, dev_name(&od->pdev.dev));
286 if (!l) {
287 pr_err("omap_device: %s: clkdev_alloc for %s failed\n",
288 dev_name(&od->pdev.dev), oc->role);
289 return;
290 }
291 clkdev_add(l);
292 }
293}
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313u32 omap_device_get_context_loss_count(struct platform_device *pdev)
314{
315 struct omap_device *od;
316 u32 ret = 0;
317
318 od = _find_by_pdev(pdev);
319
320 if (od->hwmods_cnt)
321 ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
322
323 return ret;
324}
325
326
327
328
329
330
331
332
333
334
335int omap_device_count_resources(struct omap_device *od)
336{
337 int c = 0;
338 int i;
339
340 for (i = 0; i < od->hwmods_cnt; i++)
341 c += omap_hwmod_count_resources(od->hwmods[i]);
342
343 pr_debug("omap_device: %s: counted %d total resources across %d "
344 "hwmods\n", od->pdev.name, c, od->hwmods_cnt);
345
346 return c;
347}
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366int omap_device_fill_resources(struct omap_device *od, struct resource *res)
367{
368 int c = 0;
369 int i, r;
370
371 for (i = 0; i < od->hwmods_cnt; i++) {
372 r = omap_hwmod_fill_resources(od->hwmods[i], res);
373 res += r;
374 c += r;
375 }
376
377 return 0;
378}
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397struct omap_device *omap_device_build(const char *pdev_name, int pdev_id,
398 struct omap_hwmod *oh, void *pdata,
399 int pdata_len,
400 struct omap_device_pm_latency *pm_lats,
401 int pm_lats_cnt, int is_early_device)
402{
403 struct omap_hwmod *ohs[] = { oh };
404
405 if (!oh)
406 return ERR_PTR(-EINVAL);
407
408 return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,
409 pdata_len, pm_lats, pm_lats_cnt,
410 is_early_device);
411}
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
431 struct omap_hwmod **ohs, int oh_cnt,
432 void *pdata, int pdata_len,
433 struct omap_device_pm_latency *pm_lats,
434 int pm_lats_cnt, int is_early_device)
435{
436 int ret = -ENOMEM;
437 struct omap_device *od;
438 char *pdev_name2;
439 struct resource *res = NULL;
440 int i, res_count;
441 struct omap_hwmod **hwmods;
442
443 if (!ohs || oh_cnt == 0 || !pdev_name)
444 return ERR_PTR(-EINVAL);
445
446 if (!pdata && pdata_len > 0)
447 return ERR_PTR(-EINVAL);
448
449 pr_debug("omap_device: %s: building with %d hwmods\n", pdev_name,
450 oh_cnt);
451
452 od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
453 if (!od)
454 return ERR_PTR(-ENOMEM);
455
456 od->hwmods_cnt = oh_cnt;
457
458 hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt,
459 GFP_KERNEL);
460 if (!hwmods)
461 goto odbs_exit1;
462
463 memcpy(hwmods, ohs, sizeof(struct omap_hwmod *) * oh_cnt);
464 od->hwmods = hwmods;
465
466 pdev_name2 = kzalloc(strlen(pdev_name) + 1, GFP_KERNEL);
467 if (!pdev_name2)
468 goto odbs_exit2;
469 strcpy(pdev_name2, pdev_name);
470
471 od->pdev.name = pdev_name2;
472 od->pdev.id = pdev_id;
473
474 res_count = omap_device_count_resources(od);
475 if (res_count > 0) {
476 res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
477 if (!res)
478 goto odbs_exit3;
479 }
480 omap_device_fill_resources(od, res);
481
482 od->pdev.num_resources = res_count;
483 od->pdev.resource = res;
484
485 ret = platform_device_add_data(&od->pdev, pdata, pdata_len);
486 if (ret)
487 goto odbs_exit4;
488
489 od->pm_lats = pm_lats;
490 od->pm_lats_cnt = pm_lats_cnt;
491
492 if (is_early_device)
493 ret = omap_early_device_register(od);
494 else
495 ret = omap_device_register(od);
496
497 for (i = 0; i < oh_cnt; i++) {
498 hwmods[i]->od = od;
499 _add_optional_clock_clkdev(od, hwmods[i]);
500 }
501
502 if (ret)
503 goto odbs_exit4;
504
505 return od;
506
507odbs_exit4:
508 kfree(res);
509odbs_exit3:
510 kfree(pdev_name2);
511odbs_exit2:
512 kfree(hwmods);
513odbs_exit1:
514 kfree(od);
515
516 pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
517
518 return ERR_PTR(ret);
519}
520
521
522
523
524
525
526
527
528
529
530int omap_early_device_register(struct omap_device *od)
531{
532 struct platform_device *devices[1];
533
534 devices[0] = &(od->pdev);
535 early_platform_add_devices(devices, 1);
536 return 0;
537}
538
539
540
541
542
543
544
545
546
547int omap_device_register(struct omap_device *od)
548{
549 pr_debug("omap_device: %s: registering\n", od->pdev.name);
550
551 od->pdev.dev.parent = &omap_device_parent;
552 return platform_device_register(&od->pdev);
553}
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571int omap_device_enable(struct platform_device *pdev)
572{
573 int ret;
574 struct omap_device *od;
575
576 od = _find_by_pdev(pdev);
577
578 if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
579 WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
580 od->pdev.name, od->pdev.id, __func__, od->_state);
581 return -EINVAL;
582 }
583
584
585 if (od->_state == OMAP_DEVICE_STATE_UNKNOWN)
586 od->pm_lat_level = od->pm_lats_cnt;
587
588 ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT);
589
590 od->dev_wakeup_lat = 0;
591 od->_dev_wakeup_lat_limit = UINT_MAX;
592 od->_state = OMAP_DEVICE_STATE_ENABLED;
593
594 return ret;
595}
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610int omap_device_idle(struct platform_device *pdev)
611{
612 int ret;
613 struct omap_device *od;
614
615 od = _find_by_pdev(pdev);
616
617 if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
618 WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
619 od->pdev.name, od->pdev.id, __func__, od->_state);
620 return -EINVAL;
621 }
622
623 ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
624
625 od->_state = OMAP_DEVICE_STATE_IDLE;
626
627 return ret;
628}
629
630
631
632
633
634
635
636
637
638
639
640
641int omap_device_shutdown(struct platform_device *pdev)
642{
643 int ret, i;
644 struct omap_device *od;
645
646 od = _find_by_pdev(pdev);
647
648 if (od->_state != OMAP_DEVICE_STATE_ENABLED &&
649 od->_state != OMAP_DEVICE_STATE_IDLE) {
650 WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
651 od->pdev.name, od->pdev.id, __func__, od->_state);
652 return -EINVAL;
653 }
654
655 ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
656
657 for (i = 0; i < od->hwmods_cnt; i++)
658 omap_hwmod_shutdown(od->hwmods[i]);
659
660 od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
661
662 return ret;
663}
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681int omap_device_align_pm_lat(struct platform_device *pdev,
682 u32 new_wakeup_lat_limit)
683{
684 int ret = -EINVAL;
685 struct omap_device *od;
686
687 od = _find_by_pdev(pdev);
688
689 if (new_wakeup_lat_limit == od->dev_wakeup_lat)
690 return 0;
691
692 od->_dev_wakeup_lat_limit = new_wakeup_lat_limit;
693
694 if (od->_state != OMAP_DEVICE_STATE_IDLE)
695 return 0;
696 else if (new_wakeup_lat_limit > od->dev_wakeup_lat)
697 ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
698 else if (new_wakeup_lat_limit < od->dev_wakeup_lat)
699 ret = _omap_device_activate(od, USE_WAKEUP_LAT);
700
701 return ret;
702}
703
704
705
706
707
708
709
710
711
712
713struct powerdomain *omap_device_get_pwrdm(struct omap_device *od)
714{
715
716
717
718
719
720 if (!od->hwmods_cnt)
721 return NULL;
722
723 return omap_hwmod_get_pwrdm(od->hwmods[0]);
724}
725
726
727
728
729
730
731
732
733
734
735
736
737void __iomem *omap_device_get_rt_va(struct omap_device *od)
738{
739 if (od->hwmods_cnt != 1)
740 return NULL;
741
742 return omap_hwmod_get_mpu_rt_va(od->hwmods[0]);
743}
744
745
746
747
748
749
750
751
752
753
754
755
756int omap_device_enable_hwmods(struct omap_device *od)
757{
758 int i;
759
760 for (i = 0; i < od->hwmods_cnt; i++)
761 omap_hwmod_enable(od->hwmods[i]);
762
763
764 return 0;
765}
766
767
768
769
770
771
772
773int omap_device_idle_hwmods(struct omap_device *od)
774{
775 int i;
776
777 for (i = 0; i < od->hwmods_cnt; i++)
778 omap_hwmod_idle(od->hwmods[i]);
779
780
781 return 0;
782}
783
784
785
786
787
788
789
790
791int omap_device_disable_clocks(struct omap_device *od)
792{
793 int i;
794
795 for (i = 0; i < od->hwmods_cnt; i++)
796 omap_hwmod_disable_clocks(od->hwmods[i]);
797
798
799 return 0;
800}
801
802
803
804
805
806
807
808
809int omap_device_enable_clocks(struct omap_device *od)
810{
811 int i;
812
813 for (i = 0; i < od->hwmods_cnt; i++)
814 omap_hwmod_enable_clocks(od->hwmods[i]);
815
816
817 return 0;
818}
819
820struct device omap_device_parent = {
821 .init_name = "omap",
822 .parent = &platform_bus,
823};
824
825static int __init omap_device_init(void)
826{
827 return device_register(&omap_device_parent);
828}
829core_initcall(omap_device_init);
830