video: tegra: host: Remove version from dev name
[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-2012 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/slab.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/nvhost.h>
23
24 #include "bus.h"
25 #include "dev.h"
26
27 struct nvhost_bus *nvhost_bus_inst;
28 struct nvhost_master *nvhost;
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 struct nvhost_device_id *nvhost_bus_match_id(struct nvhost_device *dev,
79         struct nvhost_device_id *id_table)
80 {
81         while (id_table->name[0]) {
82                 if (strcmp(dev->name, id_table->name) == 0
83                                 && dev->version == id_table->version)
84                         return id_table;
85                 id_table++;
86         }
87         return NULL;
88 }
89
90 static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
91 {
92         struct nvhost_device *dev = to_nvhost_device(_dev);
93         struct nvhost_driver *ndrv = to_nvhost_driver(drv);
94
95         /* check if driver support multiple devices through id_table */
96         if (ndrv->id_table)
97                 return nvhost_bus_match_id(dev, ndrv->id_table) != NULL;
98         else /* driver does not support id_table */
99                 return !strncmp(dev->name, drv->name, strlen(drv->name));
100 }
101
102 static int nvhost_drv_probe(struct device *_dev)
103 {
104         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
105         struct nvhost_device *dev = to_nvhost_device(_dev);
106
107         if (drv && drv->probe) {
108                 if (drv->id_table)
109                         return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table));
110                 else
111                         return drv->probe(dev, NULL);
112         }
113         else
114                 return -ENODEV;
115 }
116
117 static int nvhost_drv_remove(struct device *_dev)
118 {
119         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
120         struct nvhost_device *dev = to_nvhost_device(_dev);
121
122         return drv->remove(dev);
123 }
124
125 static void nvhost_drv_shutdown(struct device *_dev)
126 {
127         struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
128         struct nvhost_device *dev = to_nvhost_device(_dev);
129
130         drv->shutdown(dev);
131 }
132
133 int nvhost_driver_register(struct nvhost_driver *drv)
134 {
135         drv->driver.bus = &nvhost_bus_inst->nvhost_bus_type;
136         if (drv->probe)
137                 drv->driver.probe = nvhost_drv_probe;
138         if (drv->remove)
139                 drv->driver.remove = nvhost_drv_remove;
140         if (drv->shutdown)
141                 drv->driver.shutdown = nvhost_drv_shutdown;
142
143         return driver_register(&drv->driver);
144 }
145 EXPORT_SYMBOL(nvhost_driver_register);
146
147 void nvhost_driver_unregister(struct nvhost_driver *drv)
148 {
149         driver_unregister(&drv->driver);
150 }
151 EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
152
153 int nvhost_add_devices(struct nvhost_device **devs, int num)
154 {
155         int i, ret = 0;
156
157         for (i = 0; i < num; i++) {
158                 ret = nvhost_device_register(devs[i]);
159                 if (ret) {
160                         while (--i >= 0)
161                                 nvhost_device_unregister(devs[i]);
162                         break;
163                 }
164         }
165
166         return ret;
167 }
168 EXPORT_SYMBOL_GPL(nvhost_add_devices);
169
170 int nvhost_device_register(struct nvhost_device *dev)
171 {
172         int i, ret = 0;
173
174         if (!dev)
175                 return -EINVAL;
176
177         device_initialize(&dev->dev);
178
179         /*  If the dev does not have a parent, assign host1x as parent */
180         if (!dev->dev.parent && nvhost && nvhost->dev != dev)
181                 dev->dev.parent = &nvhost->dev->dev;
182
183         dev->dev.bus = &nvhost_bus_inst->nvhost_bus_type;
184
185         if (dev->id != -1)
186                 dev_set_name(&dev->dev, "%s.%d", dev->name,  dev->id);
187         else
188                 dev_set_name(&dev->dev, "%s", dev->name);
189
190         for (i = 0; i < dev->num_resources; i++) {
191                 struct resource *p, *r = &dev->resource[i];
192
193                 if (r->name == NULL)
194                         r->name = dev_name(&dev->dev);
195
196                 p = r->parent;
197                 if (!p) {
198                         if (resource_type(r) == IORESOURCE_MEM)
199                                 p = &iomem_resource;
200                         else if (resource_type(r) == IORESOURCE_IO)
201                                 p = &ioport_resource;
202                 }
203
204                 if (p && insert_resource(p, r)) {
205                         pr_err("%s: failed to claim resource %d\n",
206                                dev_name(&dev->dev), i);
207                         ret = -EBUSY;
208                         goto failed;
209                 }
210         }
211
212         ret = device_add(&dev->dev);
213         if (ret == 0)
214                 return ret;
215
216 failed:
217         while (--i >= 0) {
218                 struct resource *r = &dev->resource[i];
219                 unsigned long type = resource_type(r);
220
221                 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
222                         release_resource(r);
223         }
224
225         return ret;
226 }
227 EXPORT_SYMBOL_GPL(nvhost_device_register);
228
229 void nvhost_device_unregister(struct nvhost_device *dev)
230 {
231         int i;
232         if (dev) {
233                 device_del(&dev->dev);
234
235                 for (i = 0; i < dev->num_resources; i++) {
236                         struct resource *r = &dev->resource[i];
237                         unsigned long type = resource_type(r);
238
239                         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
240                                 release_resource(r);
241                 }
242
243                 put_device(&dev->dev);
244         }
245 }
246 EXPORT_SYMBOL_GPL(nvhost_device_unregister);
247
248 #ifdef CONFIG_PM_SLEEP
249
250 static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
251 {
252         struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
253         struct nvhost_device *pdev = to_nvhost_device(dev);
254         int ret = 0;
255
256         if (dev->driver && pdrv->suspend)
257                 ret = pdrv->suspend(pdev, mesg);
258
259         return ret;
260 }
261
262 static int nvhost_legacy_resume(struct device *dev)
263 {
264         struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
265         struct nvhost_device *pdev = to_nvhost_device(dev);
266         int ret = 0;
267
268         if (dev->driver && pdrv->resume)
269                 ret = pdrv->resume(pdev);
270
271         return ret;
272 }
273
274 static int nvhost_pm_prepare(struct device *dev)
275 {
276         struct device_driver *drv = dev->driver;
277         int ret = 0;
278
279         if (drv && drv->pm && drv->pm->prepare)
280                 ret = drv->pm->prepare(dev);
281
282         return ret;
283 }
284
285 static void nvhost_pm_complete(struct device *dev)
286 {
287         struct device_driver *drv = dev->driver;
288
289         if (drv && drv->pm && drv->pm->complete)
290                 drv->pm->complete(dev);
291 }
292
293 #else /* !CONFIG_PM_SLEEP */
294
295 #define nvhost_pm_prepare               NULL
296 #define nvhost_pm_complete              NULL
297
298 #endif /* !CONFIG_PM_SLEEP */
299
300 #ifdef CONFIG_SUSPEND
301
302 int __weak nvhost_pm_suspend(struct device *dev)
303 {
304         struct device_driver *drv = dev->driver;
305         int ret = 0;
306
307         if (!drv)
308                 return 0;
309
310         if (drv->pm) {
311                 if (drv->pm->suspend)
312                         ret = drv->pm->suspend(dev);
313         } else {
314                 ret = nvhost_legacy_suspend(dev, PMSG_SUSPEND);
315         }
316
317         return ret;
318 }
319
320 int __weak nvhost_pm_suspend_noirq(struct device *dev)
321 {
322         struct device_driver *drv = dev->driver;
323         int ret = 0;
324
325         if (!drv)
326                 return 0;
327
328         if (drv->pm) {
329                 if (drv->pm->suspend_noirq)
330                         ret = drv->pm->suspend_noirq(dev);
331         }
332
333         return ret;
334 }
335
336 int __weak nvhost_pm_resume(struct device *dev)
337 {
338         struct device_driver *drv = dev->driver;
339         int ret = 0;
340
341         if (!drv)
342                 return 0;
343
344         if (drv->pm) {
345                 if (drv->pm->resume)
346                         ret = drv->pm->resume(dev);
347         } else {
348                 ret = nvhost_legacy_resume(dev);
349         }
350
351         return ret;
352 }
353
354 int __weak nvhost_pm_resume_noirq(struct device *dev)
355 {
356         struct device_driver *drv = dev->driver;
357         int ret = 0;
358
359         if (!drv)
360                 return 0;
361
362         if (drv->pm) {
363                 if (drv->pm->resume_noirq)
364                         ret = drv->pm->resume_noirq(dev);
365         }
366
367         return ret;
368 }
369
370 #else /* !CONFIG_SUSPEND */
371
372 #define nvhost_pm_suspend               NULL
373 #define nvhost_pm_resume                NULL
374 #define nvhost_pm_suspend_noirq NULL
375 #define nvhost_pm_resume_noirq  NULL
376
377 #endif /* !CONFIG_SUSPEND */
378
379 #ifdef CONFIG_HIBERNATION
380
381 static int nvhost_pm_freeze(struct device *dev)
382 {
383         struct device_driver *drv = dev->driver;
384         int ret = 0;
385
386         if (!drv)
387                 return 0;
388
389         if (drv->pm) {
390                 if (drv->pm->freeze)
391                         ret = drv->pm->freeze(dev);
392         } else {
393                 ret = nvhost_legacy_suspend(dev, PMSG_FREEZE);
394         }
395
396         return ret;
397 }
398
399 static int nvhost_pm_freeze_noirq(struct device *dev)
400 {
401         struct device_driver *drv = dev->driver;
402         int ret = 0;
403
404         if (!drv)
405                 return 0;
406
407         if (drv->pm) {
408                 if (drv->pm->freeze_noirq)
409                         ret = drv->pm->freeze_noirq(dev);
410         }
411
412         return ret;
413 }
414
415 static int nvhost_pm_thaw(struct device *dev)
416 {
417         struct device_driver *drv = dev->driver;
418         int ret = 0;
419
420         if (!drv)
421                 return 0;
422
423         if (drv->pm) {
424                 if (drv->pm->thaw)
425                         ret = drv->pm->thaw(dev);
426         } else {
427                 ret = nvhost_legacy_resume(dev);
428         }
429
430         return ret;
431 }
432
433 static int nvhost_pm_thaw_noirq(struct device *dev)
434 {
435         struct device_driver *drv = dev->driver;
436         int ret = 0;
437
438         if (!drv)
439                 return 0;
440
441         if (drv->pm) {
442                 if (drv->pm->thaw_noirq)
443                         ret = drv->pm->thaw_noirq(dev);
444         }
445
446         return ret;
447 }
448
449 static int nvhost_pm_poweroff(struct device *dev)
450 {
451         struct device_driver *drv = dev->driver;
452         int ret = 0;
453
454         if (!drv)
455                 return 0;
456
457         if (drv->pm) {
458                 if (drv->pm->poweroff)
459                         ret = drv->pm->poweroff(dev);
460         } else {
461                 ret = nvhost_legacy_suspend(dev, PMSG_HIBERNATE);
462         }
463
464         return ret;
465 }
466
467 static int nvhost_pm_poweroff_noirq(struct device *dev)
468 {
469         struct device_driver *drv = dev->driver;
470         int ret = 0;
471
472         if (!drv)
473                 return 0;
474
475         if (drv->pm) {
476                 if (drv->pm->poweroff_noirq)
477                         ret = drv->pm->poweroff_noirq(dev);
478         }
479
480         return ret;
481 }
482
483 static int nvhost_pm_restore(struct device *dev)
484 {
485         struct device_driver *drv = dev->driver;
486         int ret = 0;
487
488         if (!drv)
489                 return 0;
490
491         if (drv->pm) {
492                 if (drv->pm->restore)
493                         ret = drv->pm->restore(dev);
494         } else {
495                 ret = nvhost_legacy_resume(dev);
496         }
497
498         return ret;
499 }
500
501 static int nvhost_pm_restore_noirq(struct device *dev)
502 {
503         struct device_driver *drv = dev->driver;
504         int ret = 0;
505
506         if (!drv)
507                 return 0;
508
509         if (drv->pm) {
510                 if (drv->pm->restore_noirq)
511                         ret = drv->pm->restore_noirq(dev);
512         }
513
514         return ret;
515 }
516
517 #else /* !CONFIG_HIBERNATION */
518
519 #define nvhost_pm_freeze                NULL
520 #define nvhost_pm_thaw          NULL
521 #define nvhost_pm_poweroff              NULL
522 #define nvhost_pm_restore               NULL
523 #define nvhost_pm_freeze_noirq  NULL
524 #define nvhost_pm_thaw_noirq            NULL
525 #define nvhost_pm_poweroff_noirq        NULL
526 #define nvhost_pm_restore_noirq NULL
527
528 #endif /* !CONFIG_HIBERNATION */
529
530 #ifdef CONFIG_PM_RUNTIME
531
532 int __weak nvhost_pm_runtime_suspend(struct device *dev)
533 {
534         return pm_generic_runtime_suspend(dev);
535 };
536
537 int __weak nvhost_pm_runtime_resume(struct device *dev)
538 {
539         return pm_generic_runtime_resume(dev);
540 };
541
542 int __weak nvhost_pm_runtime_idle(struct device *dev)
543 {
544         return pm_generic_runtime_idle(dev);
545 };
546
547 #else /* !CONFIG_PM_RUNTIME */
548
549 #define nvhost_pm_runtime_suspend NULL
550 #define nvhost_pm_runtime_resume NULL
551 #define nvhost_pm_runtime_idle NULL
552
553 #endif /* !CONFIG_PM_RUNTIME */
554
555 static const struct dev_pm_ops nvhost_dev_pm_ops = {
556         .prepare = nvhost_pm_prepare,
557         .complete = nvhost_pm_complete,
558         .suspend = nvhost_pm_suspend,
559         .resume = nvhost_pm_resume,
560         .freeze = nvhost_pm_freeze,
561         .thaw = nvhost_pm_thaw,
562         .poweroff = nvhost_pm_poweroff,
563         .restore = nvhost_pm_restore,
564         .suspend_noirq = nvhost_pm_suspend_noirq,
565         .resume_noirq = nvhost_pm_resume_noirq,
566         .freeze_noirq = nvhost_pm_freeze_noirq,
567         .thaw_noirq = nvhost_pm_thaw_noirq,
568         .poweroff_noirq = nvhost_pm_poweroff_noirq,
569         .restore_noirq = nvhost_pm_restore_noirq,
570         .runtime_suspend = nvhost_pm_runtime_suspend,
571         .runtime_resume = nvhost_pm_runtime_resume,
572         .runtime_idle = nvhost_pm_runtime_idle,
573 };
574
575 static int set_parent(struct device *dev, void *data)
576 {
577         struct nvhost_device *ndev = to_nvhost_device(dev);
578         struct nvhost_master *host = data;
579         if (!dev->parent && ndev != host->dev)
580                 dev->parent = &host->dev->dev;
581         return 0;
582 }
583
584 int nvhost_bus_add_host(struct nvhost_master *host)
585 {
586         nvhost = host;
587
588         /*  Assign host1x as parent to all devices in nvhost bus */
589         bus_for_each_dev(&nvhost_bus_inst->nvhost_bus_type, NULL, host, set_parent);
590
591         return 0;
592 }
593
594 struct nvhost_bus *nvhost_bus_get(void)
595 {
596         return nvhost_bus_inst;
597 }
598
599 int nvhost_bus_init(void)
600 {
601         int err;
602         struct nvhost_chip_support *chip_ops;
603
604         pr_info("host1x bus init\n");
605
606         nvhost_bus_inst = kzalloc(sizeof(*nvhost_bus_inst), GFP_KERNEL);
607         if (nvhost_bus_inst == NULL) {
608                 pr_err("%s: Cannot allocate nvhost_bus\n", __func__);
609                 return -ENOMEM;
610         }
611
612         chip_ops = kzalloc(sizeof(*chip_ops), GFP_KERNEL);
613         if (chip_ops == NULL) {
614                 pr_err("%s: Cannot allocate nvhost_chip_support\n", __func__);
615                 kfree(nvhost_bus_inst);
616                 nvhost_bus_inst = NULL;
617                 return -ENOMEM;
618         }
619
620         nvhost_bus_inst->nvhost_bus_type.name = "nvhost";
621         nvhost_bus_inst->nvhost_bus_type.match = nvhost_bus_match;
622         nvhost_bus_inst->nvhost_bus_type.pm = &nvhost_dev_pm_ops;
623         nvhost_bus_inst->nvhost_chip_ops = chip_ops;
624
625         err = bus_register(&nvhost_bus_inst->nvhost_bus_type);
626
627         return err;
628 }
629 postcore_initcall(nvhost_bus_init);