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