video: tegra: host: use runtime pm for clock management
[linux-2.6.git] / drivers / video / tegra / host / bus.c
1 /*
2  * drivers/video/tegra/host/bus.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Author: Erik Gilling <konkers@google.com>
6  *
7  * Copyright (C) 2010-2011 NVIDIA Corporation
8  *
9  * This software is licensed under the terms of the GNU General Public
10  * License version 2, as published by the Free Software Foundation, and
11  * may be copied, distributed, and modified under those terms.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  */
19
20 #include <linux/pm_runtime.h>
21 #include <linux/nvhost.h>
22 #include <mach/clk.h>
23 #include "dev.h"
24
25 struct nvhost_master *nvhost;
26
27 struct resource *nvhost_get_resource(struct nvhost_device *dev,
28                                        unsigned int type, unsigned int num)
29 {
30         int i;
31
32         for (i = 0; i < dev->num_resources; i++) {
33                 struct resource *r = &dev->resource[i];
34
35                 if (type == resource_type(r) && num-- == 0)
36                         return r;
37         }
38         return NULL;
39 }
40 EXPORT_SYMBOL_GPL(nvhost_get_resource);
41
42 int nvhost_get_irq(struct nvhost_device *dev, unsigned int num)
43 {
44         struct resource *r = nvhost_get_resource(dev, IORESOURCE_IRQ, num);
45
46         return r ? r->start : -ENXIO;
47 }
48 EXPORT_SYMBOL_GPL(nvhost_get_irq);
49
50 struct resource *nvhost_get_resource_byname(struct nvhost_device *dev,
51                                               unsigned int type,
52                                               const char *name)
53 {
54         int i;
55
56         for (i = 0; i < dev->num_resources; i++) {
57                 struct resource *r = &dev->resource[i];
58
59                 if (type == resource_type(r) && !strcmp(r->name, name))
60                         return r;
61         }
62         return NULL;
63 }
64 EXPORT_SYMBOL_GPL(nvhost_get_resource_byname);
65
66 int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
67 {
68         struct resource *r = nvhost_get_resource_byname(dev, IORESOURCE_IRQ,
69                                                           name);
70
71         return r ? r->start : -ENXIO;
72 }
73 EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
74
75 static int nvhost_drv_probe(struct device *_dev)
76 {
77         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
78         struct nvhost_device *dev = to_nvhost_device(_dev);
79
80         return drv->probe(dev);
81 }
82
83 static int nvhost_drv_remove(struct device *_dev)
84 {
85         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
86         struct nvhost_device *dev = to_nvhost_device(_dev);
87
88         return drv->remove(dev);
89 }
90
91 static void nvhost_drv_shutdown(struct device *_dev)
92 {
93         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
94         struct nvhost_device *dev = to_nvhost_device(_dev);
95
96         drv->shutdown(dev);
97 }
98
99 int nvhost_driver_register(struct nvhost_driver *drv)
100 {
101         drv->driver.bus = &nvhost_bus_type;
102         if (drv->probe)
103                 drv->driver.probe = nvhost_drv_probe;
104         if (drv->remove)
105                 drv->driver.remove = nvhost_drv_remove;
106         if (drv->shutdown)
107                 drv->driver.shutdown = nvhost_drv_shutdown;
108
109         return driver_register(&drv->driver);
110 }
111 EXPORT_SYMBOL(nvhost_driver_register);
112
113 void nvhost_driver_unregister(struct nvhost_driver *drv)
114 {
115         driver_unregister(&drv->driver);
116 }
117 EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
118
119 int nvhost_device_register(struct nvhost_device *dev)
120 {
121         int i, ret = 0;
122
123         if (!dev)
124                 return -EINVAL;
125
126         device_initialize(&dev->dev);
127
128         /*  If the dev does not have a parent, assign host1x as parent */
129         if (!dev->dev.parent && nvhost && nvhost->dev != dev)
130                 dev->dev.parent = &nvhost->dev->dev;
131
132         dev->dev.bus = &nvhost_bus_type;
133
134         if (dev->id != -1)
135                 dev_set_name(&dev->dev, "%s.%d", dev->name,  dev->id);
136         else
137                 dev_set_name(&dev->dev, "%s", dev->name);
138
139         for (i = 0; i < dev->num_resources; i++) {
140                 struct resource *p, *r = &dev->resource[i];
141
142                 if (r->name == NULL)
143                         r->name = dev_name(&dev->dev);
144
145                 p = r->parent;
146                 if (!p) {
147                         if (resource_type(r) == IORESOURCE_MEM)
148                                 p = &iomem_resource;
149                         else if (resource_type(r) == IORESOURCE_IO)
150                                 p = &ioport_resource;
151                 }
152
153                 if (p && insert_resource(p, r)) {
154                         pr_err("%s: failed to claim resource %d\n",
155                                dev_name(&dev->dev), i);
156                         ret = -EBUSY;
157                         goto failed;
158                 }
159         }
160
161         ret = device_add(&dev->dev);
162         if (ret == 0)
163                 return ret;
164
165 failed:
166         while (--i >= 0) {
167                 struct resource *r = &dev->resource[i];
168                 unsigned long type = resource_type(r);
169
170                 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
171                         release_resource(r);
172         }
173
174         return ret;
175 }
176 EXPORT_SYMBOL_GPL(nvhost_device_register);
177
178 void nvhost_device_unregister(struct nvhost_device *dev)
179 {
180         int i;
181         if (dev) {
182                 device_del(&dev->dev);
183
184                 for (i = 0; i < dev->num_resources; i++) {
185                         struct resource *r = &dev->resource[i];
186                         unsigned long type = resource_type(r);
187
188                         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
189                                 release_resource(r);
190                 }
191
192                 put_device(&dev->dev);
193         }
194 }
195 EXPORT_SYMBOL_GPL(nvhost_device_unregister);
196
197 static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
198 {
199         struct nvhost_device *dev = to_nvhost_device(_dev);
200
201         return !strncmp(dev->name, drv->name, strlen(drv->name));
202 }
203
204 #ifdef CONFIG_PM_SLEEP
205
206 static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
207 {
208         struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
209         struct nvhost_device *pdev = to_nvhost_device(dev);
210         int ret = 0;
211
212         if (dev->driver && pdrv->suspend)
213                 ret = pdrv->suspend(pdev, mesg);
214
215         return ret;
216 }
217
218 static int nvhost_legacy_resume(struct device *dev)
219 {
220         struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
221         struct nvhost_device *pdev = to_nvhost_device(dev);
222         int ret = 0;
223
224         if (dev->driver && pdrv->resume)
225                 ret = pdrv->resume(pdev);
226
227         return ret;
228 }
229
230 static int nvhost_pm_prepare(struct device *dev)
231 {
232         struct device_driver *drv = dev->driver;
233         int ret = 0;
234
235         if (drv && drv->pm && drv->pm->prepare)
236                 ret = drv->pm->prepare(dev);
237
238         return ret;
239 }
240
241 static void nvhost_pm_complete(struct device *dev)
242 {
243         struct device_driver *drv = dev->driver;
244
245         if (drv && drv->pm && drv->pm->complete)
246                 drv->pm->complete(dev);
247 }
248
249 #else /* !CONFIG_PM_SLEEP */
250
251 #define nvhost_pm_prepare               NULL
252 #define nvhost_pm_complete              NULL
253
254 #endif /* !CONFIG_PM_SLEEP */
255
256 #ifdef CONFIG_SUSPEND
257
258 int __weak nvhost_pm_suspend(struct device *dev)
259 {
260         struct device_driver *drv = dev->driver;
261         int ret = 0;
262
263         if (!drv)
264                 return 0;
265
266         if (drv->pm) {
267                 if (drv->pm->suspend)
268                         ret = drv->pm->suspend(dev);
269         } else {
270                 ret = nvhost_legacy_suspend(dev, PMSG_SUSPEND);
271         }
272
273         return ret;
274 }
275
276 int __weak nvhost_pm_suspend_noirq(struct device *dev)
277 {
278         struct device_driver *drv = dev->driver;
279         int ret = 0;
280
281         if (!drv)
282                 return 0;
283
284         if (drv->pm) {
285                 if (drv->pm->suspend_noirq)
286                         ret = drv->pm->suspend_noirq(dev);
287         }
288
289         return ret;
290 }
291
292 int __weak nvhost_pm_resume(struct device *dev)
293 {
294         struct device_driver *drv = dev->driver;
295         int ret = 0;
296
297         if (!drv)
298                 return 0;
299
300         if (drv->pm) {
301                 if (drv->pm->resume)
302                         ret = drv->pm->resume(dev);
303         } else {
304                 ret = nvhost_legacy_resume(dev);
305         }
306
307         return ret;
308 }
309
310 int __weak nvhost_pm_resume_noirq(struct device *dev)
311 {
312         struct device_driver *drv = dev->driver;
313         int ret = 0;
314
315         if (!drv)
316                 return 0;
317
318         if (drv->pm) {
319                 if (drv->pm->resume_noirq)
320                         ret = drv->pm->resume_noirq(dev);
321         }
322
323         return ret;
324 }
325
326 #else /* !CONFIG_SUSPEND */
327
328 #define nvhost_pm_suspend               NULL
329 #define nvhost_pm_resume                NULL
330 #define nvhost_pm_suspend_noirq NULL
331 #define nvhost_pm_resume_noirq  NULL
332
333 #endif /* !CONFIG_SUSPEND */
334
335 #ifdef CONFIG_HIBERNATION
336
337 static int nvhost_pm_freeze(struct device *dev)
338 {
339         struct device_driver *drv = dev->driver;
340         int ret = 0;
341
342         if (!drv)
343                 return 0;
344
345         if (drv->pm) {
346                 if (drv->pm->freeze)
347                         ret = drv->pm->freeze(dev);
348         } else {
349                 ret = nvhost_legacy_suspend(dev, PMSG_FREEZE);
350         }
351
352         return ret;
353 }
354
355 static int nvhost_pm_freeze_noirq(struct device *dev)
356 {
357         struct device_driver *drv = dev->driver;
358         int ret = 0;
359
360         if (!drv)
361                 return 0;
362
363         if (drv->pm) {
364                 if (drv->pm->freeze_noirq)
365                         ret = drv->pm->freeze_noirq(dev);
366         }
367
368         return ret;
369 }
370
371 static int nvhost_pm_thaw(struct device *dev)
372 {
373         struct device_driver *drv = dev->driver;
374         int ret = 0;
375
376         if (!drv)
377                 return 0;
378
379         if (drv->pm) {
380                 if (drv->pm->thaw)
381                         ret = drv->pm->thaw(dev);
382         } else {
383                 ret = nvhost_legacy_resume(dev);
384         }
385
386         return ret;
387 }
388
389 static int nvhost_pm_thaw_noirq(struct device *dev)
390 {
391         struct device_driver *drv = dev->driver;
392         int ret = 0;
393
394         if (!drv)
395                 return 0;
396
397         if (drv->pm) {
398                 if (drv->pm->thaw_noirq)
399                         ret = drv->pm->thaw_noirq(dev);
400         }
401
402         return ret;
403 }
404
405 static int nvhost_pm_poweroff(struct device *dev)
406 {
407         struct device_driver *drv = dev->driver;
408         int ret = 0;
409
410         if (!drv)
411                 return 0;
412
413         if (drv->pm) {
414                 if (drv->pm->poweroff)
415                         ret = drv->pm->poweroff(dev);
416         } else {
417                 ret = nvhost_legacy_suspend(dev, PMSG_HIBERNATE);
418         }
419
420         return ret;
421 }
422
423 static int nvhost_pm_poweroff_noirq(struct device *dev)
424 {
425         struct device_driver *drv = dev->driver;
426         int ret = 0;
427
428         if (!drv)
429                 return 0;
430
431         if (drv->pm) {
432                 if (drv->pm->poweroff_noirq)
433                         ret = drv->pm->poweroff_noirq(dev);
434         }
435
436         return ret;
437 }
438
439 static int nvhost_pm_restore(struct device *dev)
440 {
441         struct device_driver *drv = dev->driver;
442         int ret = 0;
443
444         if (!drv)
445                 return 0;
446
447         if (drv->pm) {
448                 if (drv->pm->restore)
449                         ret = drv->pm->restore(dev);
450         } else {
451                 ret = nvhost_legacy_resume(dev);
452         }
453
454         return ret;
455 }
456
457 static int nvhost_pm_restore_noirq(struct device *dev)
458 {
459         struct device_driver *drv = dev->driver;
460         int ret = 0;
461
462         if (!drv)
463                 return 0;
464
465         if (drv->pm) {
466                 if (drv->pm->restore_noirq)
467                         ret = drv->pm->restore_noirq(dev);
468         }
469
470         return ret;
471 }
472
473 #else /* !CONFIG_HIBERNATION */
474
475 #define nvhost_pm_freeze                NULL
476 #define nvhost_pm_thaw          NULL
477 #define nvhost_pm_poweroff              NULL
478 #define nvhost_pm_restore               NULL
479 #define nvhost_pm_freeze_noirq  NULL
480 #define nvhost_pm_thaw_noirq            NULL
481 #define nvhost_pm_poweroff_noirq        NULL
482 #define nvhost_pm_restore_noirq NULL
483
484 #endif /* !CONFIG_HIBERNATION */
485
486 #ifdef CONFIG_PM_RUNTIME
487
488 int __weak nvhost_pm_runtime_suspend(struct device *dev)
489 {
490         int i;
491         struct nvhost_device *device = to_nvhost_device(dev);
492
493         for (i = 0; i < device->num_clks; i++)
494                 clk_disable(device->clk[i]);
495
496         if (device->can_powergate)
497                 schedule_delayed_work(&device->powerstate_down,
498                         msecs_to_jiffies(device->powergate_delay));
499
500         return 0;
501 };
502
503 int __weak nvhost_pm_runtime_resume(struct device *dev)
504 {
505         int i;
506         struct nvhost_device *device = to_nvhost_device(dev);
507
508         for (i = 0; i < device->num_clks; i++)
509                 clk_enable(device->clk[i]);
510
511         return 0;
512 };
513
514 int __weak nvhost_pm_runtime_idle(struct device *dev)
515 {
516         pm_runtime_autosuspend(dev);
517         return 0;
518 };
519
520 #else /* !CONFIG_PM_RUNTIME */
521
522 #define nvhost_pm_runtime_suspend NULL
523 #define nvhost_pm_runtime_resume NULL
524 #define nvhost_pm_runtime_idle NULL
525
526 #endif /* !CONFIG_PM_RUNTIME */
527
528 static const struct dev_pm_ops nvhost_dev_pm_ops = {
529         .prepare = nvhost_pm_prepare,
530         .complete = nvhost_pm_complete,
531         .suspend = nvhost_pm_suspend,
532         .resume = nvhost_pm_resume,
533         .freeze = nvhost_pm_freeze,
534         .thaw = nvhost_pm_thaw,
535         .poweroff = nvhost_pm_poweroff,
536         .restore = nvhost_pm_restore,
537         .suspend_noirq = nvhost_pm_suspend_noirq,
538         .resume_noirq = nvhost_pm_resume_noirq,
539         .freeze_noirq = nvhost_pm_freeze_noirq,
540         .thaw_noirq = nvhost_pm_thaw_noirq,
541         .poweroff_noirq = nvhost_pm_poweroff_noirq,
542         .restore_noirq = nvhost_pm_restore_noirq,
543         .runtime_suspend = nvhost_pm_runtime_suspend,
544         .runtime_resume = nvhost_pm_runtime_resume,
545         .runtime_idle = nvhost_pm_runtime_idle,
546 };
547
548 struct bus_type nvhost_bus_type = {
549         .name           = "nvhost",
550         .match          = nvhost_bus_match,
551         .pm             = &nvhost_dev_pm_ops,
552 };
553 EXPORT_SYMBOL(nvhost_bus_type);
554
555 static int set_parent(struct device *dev, void *data)
556 {
557         struct nvhost_device *ndev = to_nvhost_device(dev);
558         struct nvhost_master *host = data;
559         if (!dev->parent && ndev != host->dev)
560                 dev->parent = &host->dev->dev;
561         return 0;
562 }
563
564 int nvhost_bus_add_host(struct nvhost_master *host)
565 {
566         nvhost = host;
567
568         /*  Assign host1x as parent to all devices in nvhost bus */
569         bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
570
571         return 0;
572 }
573
574
575 int nvhost_bus_init(void)
576 {
577         int err;
578
579         pr_info("host1x bus init\n");
580
581         err = bus_register(&nvhost_bus_type);
582
583         return err;
584 }
585 postcore_initcall(nvhost_bus_init);
586