aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/bus.c')
-rw-r--r--arch/sh/kernel/cpu/bus.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/bus.c b/arch/sh/kernel/cpu/bus.c
new file mode 100644
index 000000000000..ace82f4b4a59
--- /dev/null
+++ b/arch/sh/kernel/cpu/bus.c
@@ -0,0 +1,195 @@
1/*
2 * arch/sh/kernel/cpu/bus.c
3 *
4 * Virtual bus for SuperH.
5 *
6 * Copyright (C) 2004 Paul Mundt
7 *
8 * Shamelessly cloned from arch/arm/mach-omap/bus.c, which was written
9 * by:
10 *
11 * Copyright (C) 2003 - 2004 Nokia Corporation
12 * Written by Tony Lindgren <tony@atomide.com>
13 * Portions of code based on sa1111.c.
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 2 of the License, or (at your
18 * option) any later version.
19 */
20#include <linux/kernel.h>
21#include <linux/device.h>
22#include <linux/init.h>
23#include <linux/module.h>
24#include <asm/bus-sh.h>
25
26static int sh_bus_match(struct device *dev, struct device_driver *drv)
27{
28 struct sh_driver *shdrv = to_sh_driver(drv);
29 struct sh_dev *shdev = to_sh_dev(dev);
30
31 return shdev->dev_id == shdrv->dev_id;
32}
33
34static int sh_bus_suspend(struct device *dev, u32 state)
35{
36 struct sh_dev *shdev = to_sh_dev(dev);
37 struct sh_driver *shdrv = to_sh_driver(dev->driver);
38
39 if (shdrv && shdrv->suspend)
40 return shdrv->suspend(shdev, state);
41
42 return 0;
43}
44
45static int sh_bus_resume(struct device *dev)
46{
47 struct sh_dev *shdev = to_sh_dev(dev);
48 struct sh_driver *shdrv = to_sh_driver(dev->driver);
49
50 if (shdrv && shdrv->resume)
51 return shdrv->resume(shdev);
52
53 return 0;
54}
55
56static struct device sh_bus_devices[SH_NR_BUSES] = {
57 {
58 .bus_id = SH_BUS_NAME_VIRT,
59 },
60};
61
62struct bus_type sh_bus_types[SH_NR_BUSES] = {
63 {
64 .name = SH_BUS_NAME_VIRT,
65 .match = sh_bus_match,
66 .suspend = sh_bus_suspend,
67 .resume = sh_bus_resume,
68 },
69};
70
71static int sh_device_probe(struct device *dev)
72{
73 struct sh_dev *shdev = to_sh_dev(dev);
74 struct sh_driver *shdrv = to_sh_driver(dev->driver);
75
76 if (shdrv && shdrv->probe)
77 return shdrv->probe(shdev);
78
79 return -ENODEV;
80}
81
82static int sh_device_remove(struct device *dev)
83{
84 struct sh_dev *shdev = to_sh_dev(dev);
85 struct sh_driver *shdrv = to_sh_driver(dev->driver);
86
87 if (shdrv && shdrv->remove)
88 return shdrv->remove(shdev);
89
90 return 0;
91}
92
93int sh_device_register(struct sh_dev *dev)
94{
95 if (!dev)
96 return -EINVAL;
97
98 if (dev->bus_id < 0 || dev->bus_id >= SH_NR_BUSES) {
99 printk(KERN_ERR "%s: bus_id invalid: %s bus: %d\n",
100 __FUNCTION__, dev->name, dev->bus_id);
101 return -EINVAL;
102 }
103
104 dev->dev.parent = &sh_bus_devices[dev->bus_id];
105 dev->dev.bus = &sh_bus_types[dev->bus_id];
106
107 /* This is needed for USB OHCI to work */
108 if (dev->dma_mask)
109 dev->dev.dma_mask = dev->dma_mask;
110
111 snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%s%u",
112 dev->name, dev->dev_id);
113
114 printk(KERN_INFO "Registering SH device '%s'. Parent at %s\n",
115 dev->dev.bus_id, dev->dev.parent->bus_id);
116
117 return device_register(&dev->dev);
118}
119
120void sh_device_unregister(struct sh_dev *dev)
121{
122 device_unregister(&dev->dev);
123}
124
125int sh_driver_register(struct sh_driver *drv)
126{
127 if (!drv)
128 return -EINVAL;
129
130 if (drv->bus_id < 0 || drv->bus_id >= SH_NR_BUSES) {
131 printk(KERN_ERR "%s: bus_id invalid: bus: %d device %d\n",
132 __FUNCTION__, drv->bus_id, drv->dev_id);
133 return -EINVAL;
134 }
135
136 drv->drv.probe = sh_device_probe;
137 drv->drv.remove = sh_device_remove;
138 drv->drv.bus = &sh_bus_types[drv->bus_id];
139
140 return driver_register(&drv->drv);
141}
142
143void sh_driver_unregister(struct sh_driver *drv)
144{
145 driver_unregister(&drv->drv);
146}
147
148static int __init sh_bus_init(void)
149{
150 int i, ret = 0;
151
152 for (i = 0; i < SH_NR_BUSES; i++) {
153 ret = device_register(&sh_bus_devices[i]);
154 if (ret != 0) {
155 printk(KERN_ERR "Unable to register bus device %s\n",
156 sh_bus_devices[i].bus_id);
157 continue;
158 }
159
160 ret = bus_register(&sh_bus_types[i]);
161 if (ret != 0) {
162 printk(KERN_ERR "Unable to register bus %s\n",
163 sh_bus_types[i].name);
164 device_unregister(&sh_bus_devices[i]);
165 }
166 }
167
168 printk(KERN_INFO "SH Virtual Bus initialized\n");
169
170 return ret;
171}
172
173static void __exit sh_bus_exit(void)
174{
175 int i;
176
177 for (i = 0; i < SH_NR_BUSES; i++) {
178 bus_unregister(&sh_bus_types[i]);
179 device_unregister(&sh_bus_devices[i]);
180 }
181}
182
183module_init(sh_bus_init);
184module_exit(sh_bus_exit);
185
186MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
187MODULE_DESCRIPTION("SH Virtual Bus");
188MODULE_LICENSE("GPL");
189
190EXPORT_SYMBOL(sh_bus_types);
191EXPORT_SYMBOL(sh_device_register);
192EXPORT_SYMBOL(sh_device_unregister);
193EXPORT_SYMBOL(sh_driver_register);
194EXPORT_SYMBOL(sh_driver_unregister);
195