GNU Linux-libre 4.19.245-gnu1
[releases.git] / arch / arm / mach-omap2 / omap_device.c
1 /*
2  * omap_device implementation
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation
5  * Paul Walmsley, Kevin Hilman
6  *
7  * Developed in collaboration with (alphabetical order): Benoit
8  * Cousson, Thara Gopinath, Tony Lindgren, Rajendra Nayak, Vikram
9  * Pandita, Sakari Poussa, Anand Sawant, Santosh Shilimkar, Richard
10  * Woodruff
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  *
16  * This code provides a consistent interface for OMAP device drivers
17  * to control power management and interconnect properties of their
18  * devices.
19  *
20  * In the medium- to long-term, this code should be implemented as a
21  * proper omap_bus/omap_device in Linux, no more platform_data func
22  * pointers
23  *
24  *
25  */
26 #undef DEBUG
27
28 #include <linux/kernel.h>
29 #include <linux/platform_device.h>
30 #include <linux/slab.h>
31 #include <linux/err.h>
32 #include <linux/io.h>
33 #include <linux/clk.h>
34 #include <linux/clkdev.h>
35 #include <linux/pm_domain.h>
36 #include <linux/pm_runtime.h>
37 #include <linux/of.h>
38 #include <linux/of_address.h>
39 #include <linux/of_irq.h>
40 #include <linux/notifier.h>
41
42 #include "common.h"
43 #include "soc.h"
44 #include "omap_device.h"
45 #include "omap_hwmod.h"
46
47 /* Private functions */
48
49 static void _add_clkdev(struct omap_device *od, const char *clk_alias,
50                        const char *clk_name)
51 {
52         struct clk *r;
53         int rc;
54
55         if (!clk_alias || !clk_name)
56                 return;
57
58         dev_dbg(&od->pdev->dev, "Creating %s -> %s\n", clk_alias, clk_name);
59
60         r = clk_get_sys(dev_name(&od->pdev->dev), clk_alias);
61         if (!IS_ERR(r)) {
62                 dev_dbg(&od->pdev->dev,
63                          "alias %s already exists\n", clk_alias);
64                 clk_put(r);
65                 return;
66         }
67
68         r = clk_get_sys(NULL, clk_name);
69
70         if (IS_ERR(r)) {
71                 struct of_phandle_args clkspec;
72
73                 clkspec.np = of_find_node_by_name(NULL, clk_name);
74
75                 r = of_clk_get_from_provider(&clkspec);
76
77                 rc = clk_register_clkdev(r, clk_alias,
78                                          dev_name(&od->pdev->dev));
79         } else {
80                 rc = clk_add_alias(clk_alias, dev_name(&od->pdev->dev),
81                                    clk_name, NULL);
82         }
83
84         if (rc) {
85                 if (rc == -ENODEV || rc == -ENOMEM)
86                         dev_err(&od->pdev->dev,
87                                 "clkdev_alloc for %s failed\n", clk_alias);
88                 else
89                         dev_err(&od->pdev->dev,
90                                 "clk_get for %s failed\n", clk_name);
91         }
92 }
93
94 /**
95  * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks
96  * and main clock
97  * @od: struct omap_device *od
98  * @oh: struct omap_hwmod *oh
99  *
100  * For the main clock and every optional clock present per hwmod per
101  * omap_device, this function adds an entry in the clkdev table of the
102  * form <dev-id=dev_name, con-id=role> if it does not exist already.
103  *
104  * The function is called from inside omap_device_build_ss(), after
105  * omap_device_register.
106  *
107  * This allows drivers to get a pointer to its optional clocks based on its role
108  * by calling clk_get(<dev*>, <role>).
109  * In the case of the main clock, a "fck" alias is used.
110  *
111  * No return value.
112  */
113 static void _add_hwmod_clocks_clkdev(struct omap_device *od,
114                                      struct omap_hwmod *oh)
115 {
116         int i;
117
118         _add_clkdev(od, "fck", oh->main_clk);
119
120         for (i = 0; i < oh->opt_clks_cnt; i++)
121                 _add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk);
122 }
123
124
125 /**
126  * omap_device_build_from_dt - build an omap_device with multiple hwmods
127  * @pdev_name: name of the platform_device driver to use
128  * @pdev_id: this platform_device's connection ID
129  * @oh: ptr to the single omap_hwmod that backs this omap_device
130  * @pdata: platform_data ptr to associate with the platform_device
131  * @pdata_len: amount of memory pointed to by @pdata
132  *
133  * Function for building an omap_device already registered from device-tree
134  *
135  * Returns 0 or PTR_ERR() on error.
136  */
137 static int omap_device_build_from_dt(struct platform_device *pdev)
138 {
139         struct omap_hwmod **hwmods;
140         struct omap_device *od;
141         struct omap_hwmod *oh;
142         struct device_node *node = pdev->dev.of_node;
143         struct resource res;
144         const char *oh_name;
145         int oh_cnt, i, ret = 0;
146         bool device_active = false, skip_pm_domain = false;
147
148         oh_cnt = of_property_count_strings(node, "ti,hwmods");
149         if (oh_cnt <= 0) {
150                 dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
151                 return -ENODEV;
152         }
153
154         /* SDMA still needs special handling for omap_device_build() */
155         ret = of_property_read_string_index(node, "ti,hwmods", 0, &oh_name);
156         if (!ret && (!strncmp("dma_system", oh_name, 10) ||
157                      !strncmp("dma", oh_name, 3)))
158                 skip_pm_domain = true;
159
160         /* Use ti-sysc driver instead of omap_device? */
161         if (!skip_pm_domain &&
162             !omap_hwmod_parse_module_range(NULL, node, &res))
163                 return -ENODEV;
164
165         hwmods = kcalloc(oh_cnt, sizeof(struct omap_hwmod *), GFP_KERNEL);
166         if (!hwmods) {
167                 ret = -ENOMEM;
168                 goto odbfd_exit;
169         }
170
171         for (i = 0; i < oh_cnt; i++) {
172                 of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
173                 oh = omap_hwmod_lookup(oh_name);
174                 if (!oh) {
175                         dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
176                                 oh_name);
177                         ret = -EINVAL;
178                         goto odbfd_exit1;
179                 }
180                 hwmods[i] = oh;
181                 if (oh->flags & HWMOD_INIT_NO_IDLE)
182                         device_active = true;
183         }
184
185         od = omap_device_alloc(pdev, hwmods, oh_cnt);
186         if (IS_ERR(od)) {
187                 dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
188                         oh_name);
189                 ret = PTR_ERR(od);
190                 goto odbfd_exit1;
191         }
192
193         /* Fix up missing resource names */
194         for (i = 0; i < pdev->num_resources; i++) {
195                 struct resource *r = &pdev->resource[i];
196
197                 if (r->name == NULL)
198                         r->name = dev_name(&pdev->dev);
199         }
200
201         if (!skip_pm_domain) {
202                 dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
203                 if (device_active) {
204                         omap_device_enable(pdev);
205                         pm_runtime_set_active(&pdev->dev);
206                 }
207         }
208
209 odbfd_exit1:
210         kfree(hwmods);
211 odbfd_exit:
212         /* if data/we are at fault.. load up a fail handler */
213         if (ret)
214                 dev_pm_domain_set(&pdev->dev, &omap_device_fail_pm_domain);
215
216         return ret;
217 }
218
219 static int _omap_device_notifier_call(struct notifier_block *nb,
220                                       unsigned long event, void *dev)
221 {
222         struct platform_device *pdev = to_platform_device(dev);
223         struct omap_device *od;
224         int err;
225
226         switch (event) {
227         case BUS_NOTIFY_REMOVED_DEVICE:
228                 if (pdev->archdata.od)
229                         omap_device_delete(pdev->archdata.od);
230                 break;
231         case BUS_NOTIFY_UNBOUND_DRIVER:
232                 od = to_omap_device(pdev);
233                 if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
234                         dev_info(dev, "enabled after unload, idling\n");
235                         err = omap_device_idle(pdev);
236                         if (err)
237                                 dev_err(dev, "failed to idle\n");
238                 }
239                 break;
240         case BUS_NOTIFY_BIND_DRIVER:
241                 od = to_omap_device(pdev);
242                 if (od) {
243                         od->_driver_status = BUS_NOTIFY_BIND_DRIVER;
244                         if (od->_state == OMAP_DEVICE_STATE_ENABLED &&
245                             pm_runtime_status_suspended(dev)) {
246                                 pm_runtime_set_active(dev);
247                         }
248                 }
249                 break;
250         case BUS_NOTIFY_ADD_DEVICE:
251                 if (pdev->dev.of_node)
252                         omap_device_build_from_dt(pdev);
253                 omap_auxdata_legacy_init(dev);
254                 /* fall through */
255         default:
256                 od = to_omap_device(pdev);
257                 if (od)
258                         od->_driver_status = event;
259         }
260
261         return NOTIFY_DONE;
262 }
263
264 /**
265  * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
266  * @od: struct omap_device *od
267  *
268  * Enable all underlying hwmods.  Returns 0.
269  */
270 static int _omap_device_enable_hwmods(struct omap_device *od)
271 {
272         int ret = 0;
273         int i;
274
275         for (i = 0; i < od->hwmods_cnt; i++)
276                 ret |= omap_hwmod_enable(od->hwmods[i]);
277
278         return ret;
279 }
280
281 /**
282  * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
283  * @od: struct omap_device *od
284  *
285  * Idle all underlying hwmods.  Returns 0.
286  */
287 static int _omap_device_idle_hwmods(struct omap_device *od)
288 {
289         int ret = 0;
290         int i;
291
292         for (i = 0; i < od->hwmods_cnt; i++)
293                 ret |= omap_hwmod_idle(od->hwmods[i]);
294
295         return ret;
296 }
297
298 /* Public functions for use by core code */
299
300 /**
301  * omap_device_get_context_loss_count - get lost context count
302  * @od: struct omap_device *
303  *
304  * Using the primary hwmod, query the context loss count for this
305  * device.
306  *
307  * Callers should consider context for this device lost any time this
308  * function returns a value different than the value the caller got
309  * the last time it called this function.
310  *
311  * If any hwmods exist for the omap_device associated with @pdev,
312  * return the context loss counter for that hwmod, otherwise return
313  * zero.
314  */
315 int omap_device_get_context_loss_count(struct platform_device *pdev)
316 {
317         struct omap_device *od;
318         u32 ret = 0;
319
320         od = to_omap_device(pdev);
321
322         if (od->hwmods_cnt)
323                 ret = omap_hwmod_get_context_loss_count(od->hwmods[0]);
324
325         return ret;
326 }
327
328 /**
329  * omap_device_alloc - allocate an omap_device
330  * @pdev: platform_device that will be included in this omap_device
331  * @oh: ptr to the single omap_hwmod that backs this omap_device
332  * @pdata: platform_data ptr to associate with the platform_device
333  * @pdata_len: amount of memory pointed to by @pdata
334  *
335  * Convenience function for allocating an omap_device structure and filling
336  * hwmods, and resources.
337  *
338  * Returns an struct omap_device pointer or ERR_PTR() on error;
339  */
340 struct omap_device *omap_device_alloc(struct platform_device *pdev,
341                                         struct omap_hwmod **ohs, int oh_cnt)
342 {
343         int ret = -ENOMEM;
344         struct omap_device *od;
345         int i;
346         struct omap_hwmod **hwmods;
347
348         od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
349         if (!od) {
350                 ret = -ENOMEM;
351                 goto oda_exit1;
352         }
353         od->hwmods_cnt = oh_cnt;
354
355         hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
356         if (!hwmods)
357                 goto oda_exit2;
358
359         od->hwmods = hwmods;
360         od->pdev = pdev;
361         pdev->archdata.od = od;
362
363         for (i = 0; i < oh_cnt; i++) {
364                 hwmods[i]->od = od;
365                 _add_hwmod_clocks_clkdev(od, hwmods[i]);
366         }
367
368         return od;
369
370 oda_exit2:
371         kfree(od);
372 oda_exit1:
373         dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret);
374
375         return ERR_PTR(ret);
376 }
377
378 void omap_device_delete(struct omap_device *od)
379 {
380         if (!od)
381                 return;
382
383         od->pdev->archdata.od = NULL;
384         kfree(od->hwmods);
385         kfree(od);
386 }
387
388 /**
389  * omap_device_copy_resources - Add legacy IO and IRQ resources
390  * @oh: interconnect target module
391  * @pdev: platform device to copy resources to
392  *
393  * We still have legacy DMA and smartreflex needing resources.
394  * Let's populate what they need until we can eventually just
395  * remove this function. Note that there should be no need to
396  * call this from omap_device_build_from_dt(), nor should there
397  * be any need to call it for other devices.
398  */
399 static int
400 omap_device_copy_resources(struct omap_hwmod *oh,
401                            struct platform_device *pdev)
402 {
403         struct device_node *np, *child;
404         struct property *prop;
405         struct resource *res;
406         const char *name;
407         int error, irq = 0;
408
409         if (!oh || !oh->od || !oh->od->pdev)
410                 return -EINVAL;
411
412         np = oh->od->pdev->dev.of_node;
413         if (!np) {
414                 error = -ENODEV;
415                 goto error;
416         }
417
418         res = kcalloc(2, sizeof(*res), GFP_KERNEL);
419         if (!res)
420                 return -ENOMEM;
421
422         /* Do we have a dts range for the interconnect target module? */
423         error = omap_hwmod_parse_module_range(oh, np, res);
424
425         /* No ranges, rely on device reg entry */
426         if (error)
427                 error = of_address_to_resource(np, 0, res);
428         if (error)
429                 goto free;
430
431         /* SmartReflex needs first IO resource name to be "mpu" */
432         res[0].name = "mpu";
433
434         /*
435          * We may have a configured "ti,sysc" interconnect target with a
436          * dts child with the interrupt. If so use the first child's
437          * first interrupt for "ti-hwmods" legacy support.
438          */
439         of_property_for_each_string(np, "compatible", prop, name)
440                 if (!strncmp("ti,sysc-", name, 8))
441                         break;
442
443         child = of_get_next_available_child(np, NULL);
444
445         if (name)
446                 irq = irq_of_parse_and_map(child, 0);
447         if (!irq)
448                 irq = irq_of_parse_and_map(np, 0);
449         if (!irq) {
450                 error = -EINVAL;
451                 goto free;
452         }
453
454         /* Legacy DMA code needs interrupt name to be "0" */
455         res[1].start = irq;
456         res[1].end = irq;
457         res[1].flags = IORESOURCE_IRQ;
458         res[1].name = "0";
459
460         error = platform_device_add_resources(pdev, res, 2);
461
462 free:
463         kfree(res);
464
465 error:
466         WARN(error, "%s: %s device %s failed: %i\n",
467              __func__, oh->name, dev_name(&pdev->dev),
468              error);
469
470         return error;
471 }
472
473 /**
474  * omap_device_build - build and register an omap_device with one omap_hwmod
475  * @pdev_name: name of the platform_device driver to use
476  * @pdev_id: this platform_device's connection ID
477  * @oh: ptr to the single omap_hwmod that backs this omap_device
478  * @pdata: platform_data ptr to associate with the platform_device
479  * @pdata_len: amount of memory pointed to by @pdata
480  *
481  * Convenience function for building and registering a single
482  * omap_device record, which in turn builds and registers a
483  * platform_device record.  See omap_device_build_ss() for more
484  * information.  Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
485  * passes along the return value of omap_device_build_ss().
486  */
487 struct platform_device __init *omap_device_build(const char *pdev_name,
488                                                  int pdev_id,
489                                                  struct omap_hwmod *oh,
490                                                  void *pdata, int pdata_len)
491 {
492         int ret = -ENOMEM;
493         struct platform_device *pdev;
494         struct omap_device *od;
495
496         if (!oh || !pdev_name)
497                 return ERR_PTR(-EINVAL);
498
499         if (!pdata && pdata_len > 0)
500                 return ERR_PTR(-EINVAL);
501
502         if (strncmp(oh->name, "smartreflex", 11) &&
503             strncmp(oh->name, "dma", 3)) {
504                 pr_warn("%s need to update %s to probe with dt\na",
505                         __func__, pdev_name);
506                 ret = -ENODEV;
507                 goto odbs_exit;
508         }
509
510         pdev = platform_device_alloc(pdev_name, pdev_id);
511         if (!pdev) {
512                 ret = -ENOMEM;
513                 goto odbs_exit;
514         }
515
516         /* Set the dev_name early to allow dev_xxx in omap_device_alloc */
517         if (pdev->id != -1)
518                 dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
519         else
520                 dev_set_name(&pdev->dev, "%s", pdev->name);
521
522         /*
523          * Must be called before omap_device_alloc() as oh->od
524          * only contains the currently registered omap_device
525          * and will get overwritten by omap_device_alloc().
526          */
527         ret = omap_device_copy_resources(oh, pdev);
528         if (ret)
529                 goto odbs_exit1;
530
531         od = omap_device_alloc(pdev, &oh, 1);
532         if (IS_ERR(od)) {
533                 ret = PTR_ERR(od);
534                 goto odbs_exit1;
535         }
536
537         ret = platform_device_add_data(pdev, pdata, pdata_len);
538         if (ret)
539                 goto odbs_exit2;
540
541         ret = omap_device_register(pdev);
542         if (ret)
543                 goto odbs_exit2;
544
545         return pdev;
546
547 odbs_exit2:
548         omap_device_delete(od);
549 odbs_exit1:
550         platform_device_put(pdev);
551 odbs_exit:
552
553         pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
554
555         return ERR_PTR(ret);
556 }
557
558 #ifdef CONFIG_PM
559 static int _od_runtime_suspend(struct device *dev)
560 {
561         struct platform_device *pdev = to_platform_device(dev);
562         int ret;
563
564         ret = pm_generic_runtime_suspend(dev);
565         if (ret)
566                 return ret;
567
568         return omap_device_idle(pdev);
569 }
570
571 static int _od_runtime_resume(struct device *dev)
572 {
573         struct platform_device *pdev = to_platform_device(dev);
574         int ret;
575
576         ret = omap_device_enable(pdev);
577         if (ret) {
578                 dev_err(dev, "use pm_runtime_put_sync_suspend() in driver?\n");
579                 return ret;
580         }
581
582         return pm_generic_runtime_resume(dev);
583 }
584
585 static int _od_fail_runtime_suspend(struct device *dev)
586 {
587         dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
588         return -ENODEV;
589 }
590
591 static int _od_fail_runtime_resume(struct device *dev)
592 {
593         dev_warn(dev, "%s: FIXME: missing hwmod/omap_dev info\n", __func__);
594         return -ENODEV;
595 }
596
597 #endif
598
599 #ifdef CONFIG_SUSPEND
600 static int _od_suspend_noirq(struct device *dev)
601 {
602         struct platform_device *pdev = to_platform_device(dev);
603         struct omap_device *od = to_omap_device(pdev);
604         int ret;
605
606         /* Don't attempt late suspend on a driver that is not bound */
607         if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
608                 return 0;
609
610         ret = pm_generic_suspend_noirq(dev);
611
612         if (!ret && !pm_runtime_status_suspended(dev)) {
613                 if (pm_generic_runtime_suspend(dev) == 0) {
614                         omap_device_idle(pdev);
615                         od->flags |= OMAP_DEVICE_SUSPENDED;
616                 }
617         }
618
619         return ret;
620 }
621
622 static int _od_resume_noirq(struct device *dev)
623 {
624         struct platform_device *pdev = to_platform_device(dev);
625         struct omap_device *od = to_omap_device(pdev);
626
627         if (od->flags & OMAP_DEVICE_SUSPENDED) {
628                 od->flags &= ~OMAP_DEVICE_SUSPENDED;
629                 omap_device_enable(pdev);
630                 pm_generic_runtime_resume(dev);
631         }
632
633         return pm_generic_resume_noirq(dev);
634 }
635 #else
636 #define _od_suspend_noirq NULL
637 #define _od_resume_noirq NULL
638 #endif
639
640 struct dev_pm_domain omap_device_fail_pm_domain = {
641         .ops = {
642                 SET_RUNTIME_PM_OPS(_od_fail_runtime_suspend,
643                                    _od_fail_runtime_resume, NULL)
644         }
645 };
646
647 struct dev_pm_domain omap_device_pm_domain = {
648         .ops = {
649                 SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
650                                    NULL)
651                 USE_PLATFORM_PM_SLEEP_OPS
652                 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq,
653                                               _od_resume_noirq)
654         }
655 };
656
657 /**
658  * omap_device_register - register an omap_device with one omap_hwmod
659  * @od: struct omap_device * to register
660  *
661  * Register the omap_device structure.  This currently just calls
662  * platform_device_register() on the underlying platform_device.
663  * Returns the return value of platform_device_register().
664  */
665 int omap_device_register(struct platform_device *pdev)
666 {
667         pr_debug("omap_device: %s: registering\n", pdev->name);
668
669         dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain);
670         return platform_device_add(pdev);
671 }
672
673
674 /* Public functions for use by device drivers through struct platform_data */
675
676 /**
677  * omap_device_enable - fully activate an omap_device
678  * @od: struct omap_device * to activate
679  *
680  * Do whatever is necessary for the hwmods underlying omap_device @od
681  * to be accessible and ready to operate.  This generally involves
682  * enabling clocks, setting SYSCONFIG registers; and in the future may
683  * involve remuxing pins.  Device drivers should call this function
684  * indirectly via pm_runtime_get*().  Returns -EINVAL if called when
685  * the omap_device is already enabled, or passes along the return
686  * value of _omap_device_enable_hwmods().
687  */
688 int omap_device_enable(struct platform_device *pdev)
689 {
690         int ret;
691         struct omap_device *od;
692
693         od = to_omap_device(pdev);
694
695         if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
696                 dev_warn(&pdev->dev,
697                          "omap_device: %s() called from invalid state %d\n",
698                          __func__, od->_state);
699                 return -EINVAL;
700         }
701
702         ret = _omap_device_enable_hwmods(od);
703
704         if (ret == 0)
705                 od->_state = OMAP_DEVICE_STATE_ENABLED;
706
707         return ret;
708 }
709
710 /**
711  * omap_device_idle - idle an omap_device
712  * @od: struct omap_device * to idle
713  *
714  * Idle omap_device @od.  Device drivers call this function indirectly
715  * via pm_runtime_put*().  Returns -EINVAL if the omap_device is not
716  * currently enabled, or passes along the return value of
717  * _omap_device_idle_hwmods().
718  */
719 int omap_device_idle(struct platform_device *pdev)
720 {
721         int ret;
722         struct omap_device *od;
723
724         od = to_omap_device(pdev);
725
726         if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
727                 dev_warn(&pdev->dev,
728                          "omap_device: %s() called from invalid state %d\n",
729                          __func__, od->_state);
730                 return -EINVAL;
731         }
732
733         ret = _omap_device_idle_hwmods(od);
734
735         if (ret == 0)
736                 od->_state = OMAP_DEVICE_STATE_IDLE;
737
738         return ret;
739 }
740
741 /**
742  * omap_device_assert_hardreset - set a device's hardreset line
743  * @pdev: struct platform_device * to reset
744  * @name: const char * name of the reset line
745  *
746  * Set the hardreset line identified by @name on the IP blocks
747  * associated with the hwmods backing the platform_device @pdev.  All
748  * of the hwmods associated with @pdev must have the same hardreset
749  * line linked to them for this to work.  Passes along the return value
750  * of omap_hwmod_assert_hardreset() in the event of any failure, or
751  * returns 0 upon success.
752  */
753 int omap_device_assert_hardreset(struct platform_device *pdev, const char *name)
754 {
755         struct omap_device *od = to_omap_device(pdev);
756         int ret = 0;
757         int i;
758
759         for (i = 0; i < od->hwmods_cnt; i++) {
760                 ret = omap_hwmod_assert_hardreset(od->hwmods[i], name);
761                 if (ret)
762                         break;
763         }
764
765         return ret;
766 }
767
768 /**
769  * omap_device_deassert_hardreset - release a device's hardreset line
770  * @pdev: struct platform_device * to reset
771  * @name: const char * name of the reset line
772  *
773  * Release the hardreset line identified by @name on the IP blocks
774  * associated with the hwmods backing the platform_device @pdev.  All
775  * of the hwmods associated with @pdev must have the same hardreset
776  * line linked to them for this to work.  Passes along the return
777  * value of omap_hwmod_deassert_hardreset() in the event of any
778  * failure, or returns 0 upon success.
779  */
780 int omap_device_deassert_hardreset(struct platform_device *pdev,
781                                    const char *name)
782 {
783         struct omap_device *od = to_omap_device(pdev);
784         int ret = 0;
785         int i;
786
787         for (i = 0; i < od->hwmods_cnt; i++) {
788                 ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name);
789                 if (ret)
790                         break;
791         }
792
793         return ret;
794 }
795
796 /**
797  * omap_device_get_by_hwmod_name() - convert a hwmod name to
798  * device pointer.
799  * @oh_name: name of the hwmod device
800  *
801  * Returns back a struct device * pointer associated with a hwmod
802  * device represented by a hwmod_name
803  */
804 struct device *omap_device_get_by_hwmod_name(const char *oh_name)
805 {
806         struct omap_hwmod *oh;
807
808         if (!oh_name) {
809                 WARN(1, "%s: no hwmod name!\n", __func__);
810                 return ERR_PTR(-EINVAL);
811         }
812
813         oh = omap_hwmod_lookup(oh_name);
814         if (!oh) {
815                 WARN(1, "%s: no hwmod for %s\n", __func__,
816                         oh_name);
817                 return ERR_PTR(-ENODEV);
818         }
819         if (!oh->od) {
820                 WARN(1, "%s: no omap_device for %s\n", __func__,
821                         oh_name);
822                 return ERR_PTR(-ENODEV);
823         }
824
825         return &oh->od->pdev->dev;
826 }
827
828 static struct notifier_block platform_nb = {
829         .notifier_call = _omap_device_notifier_call,
830 };
831
832 static int __init omap_device_init(void)
833 {
834         bus_register_notifier(&platform_bus_type, &platform_nb);
835         return 0;
836 }
837 omap_postcore_initcall(omap_device_init);
838
839 /**
840  * omap_device_late_idle - idle devices without drivers
841  * @dev: struct device * associated with omap_device
842  * @data: unused
843  *
844  * Check the driver bound status of this device, and idle it
845  * if there is no driver attached.
846  */
847 static int __init omap_device_late_idle(struct device *dev, void *data)
848 {
849         struct platform_device *pdev = to_platform_device(dev);
850         struct omap_device *od = to_omap_device(pdev);
851         int i;
852
853         if (!od)
854                 return 0;
855
856         /*
857          * If omap_device state is enabled, but has no driver bound,
858          * idle it.
859          */
860
861         /*
862          * Some devices (like memory controllers) are always kept
863          * enabled, and should not be idled even with no drivers.
864          */
865         for (i = 0; i < od->hwmods_cnt; i++)
866                 if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
867                         return 0;
868
869         if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER &&
870             od->_driver_status != BUS_NOTIFY_BIND_DRIVER) {
871                 if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
872                         dev_warn(dev, "%s: enabled but no driver.  Idling\n",
873                                  __func__);
874                         omap_device_idle(pdev);
875                 }
876         }
877
878         return 0;
879 }
880
881 static int __init omap_device_late_init(void)
882 {
883         bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
884
885         return 0;
886 }
887 omap_late_initcall_sync(omap_device_late_init);