diff options
author | Paul Mundt <lethal@linux-sh.org> | 2005-11-07 03:58:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:53:28 -0500 |
commit | 055a2512144cd7e60dcaae7a13e460df43b98787 (patch) | |
tree | bf304d17352f1b3b59edb35a6f67672c6490caa1 /drivers/sh/superhyway/superhyway.c | |
parent | 72777373b3a09c9132a787d5e1e03eaf64f30a64 (diff) |
[PATCH] superhyway: multiple block support and VCR rework
This extends the API somewhat to allow for platform-specific VCR reading and
writing. Some platforms (like SH4-202) implement the VCR in a split VCRL and
VCRH, but end up being in reverse order or have other quirks that need to be
dealt with, so we add a set of superhyway_ops per-bus to accomodate this.
We also have to extend the per-device resources somewhat, as some devices now
conveniently split control and data blocks. So we allow a platform to
register its set of SuperHyway devices via superhyway_add_devices() with the
control block always ordered as the first resource (as this is the one that
userspace cares about).
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/sh/superhyway/superhyway.c')
-rw-r--r-- | drivers/sh/superhyway/superhyway.c | 75 |
1 files changed, 55 insertions, 20 deletions
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c index 28757cb9d246..7bdab2a7f59c 100644 --- a/drivers/sh/superhyway/superhyway.c +++ b/drivers/sh/superhyway/superhyway.c | |||
@@ -27,19 +27,20 @@ static struct device superhyway_bus_device = { | |||
27 | 27 | ||
28 | static void superhyway_device_release(struct device *dev) | 28 | static void superhyway_device_release(struct device *dev) |
29 | { | 29 | { |
30 | kfree(to_superhyway_device(dev)); | 30 | struct superhyway_device *sdev = to_superhyway_device(dev); |
31 | |||
32 | kfree(sdev->resource); | ||
33 | kfree(sdev); | ||
31 | } | 34 | } |
32 | 35 | ||
33 | /** | 36 | /** |
34 | * superhyway_add_device - Add a SuperHyway module | 37 | * superhyway_add_device - Add a SuperHyway module |
35 | * @mod_id: Module ID (taken from MODULE.VCR.MOD_ID). | ||
36 | * @base: Physical address where module is mapped. | 38 | * @base: Physical address where module is mapped. |
37 | * @vcr: VCR value. | 39 | * @sdev: SuperHyway device to add, or NULL to allocate a new one. |
40 | * @bus: Bus where SuperHyway module resides. | ||
38 | * | 41 | * |
39 | * This is responsible for adding a new SuperHyway module. This sets up a new | 42 | * This is responsible for adding a new SuperHyway module. This sets up a new |
40 | * struct superhyway_device for the module being added. Each one of @mod_id, | 43 | * struct superhyway_device for the module being added if @sdev == NULL. |
41 | * @base, and @vcr are registered with the new device for further use | ||
42 | * elsewhere. | ||
43 | * | 44 | * |
44 | * Devices are initially added in the order that they are scanned (from the | 45 | * Devices are initially added in the order that they are scanned (from the |
45 | * top-down of the memory map), and are assigned an ID based on the order that | 46 | * top-down of the memory map), and are assigned an ID based on the order that |
@@ -49,28 +50,40 @@ static void superhyway_device_release(struct device *dev) | |||
49 | * Further work can and should be done in superhyway_scan_bus(), to be sure | 50 | * Further work can and should be done in superhyway_scan_bus(), to be sure |
50 | * that any new modules are properly discovered and subsequently registered. | 51 | * that any new modules are properly discovered and subsequently registered. |
51 | */ | 52 | */ |
52 | int superhyway_add_device(unsigned int mod_id, unsigned long base, | 53 | int superhyway_add_device(unsigned long base, struct superhyway_device *sdev, |
53 | unsigned long long vcr) | 54 | struct superhyway_bus *bus) |
54 | { | 55 | { |
55 | struct superhyway_device *dev; | 56 | struct superhyway_device *dev = sdev; |
57 | |||
58 | if (!dev) { | ||
59 | dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL); | ||
60 | if (!dev) | ||
61 | return -ENOMEM; | ||
56 | 62 | ||
57 | dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL); | 63 | memset(dev, 0, sizeof(struct superhyway_device)); |
58 | if (!dev) | 64 | } |
59 | return -ENOMEM; | ||
60 | 65 | ||
61 | memset(dev, 0, sizeof(struct superhyway_device)); | 66 | dev->bus = bus; |
67 | superhyway_read_vcr(dev, base, &dev->vcr); | ||
62 | 68 | ||
63 | dev->id.id = mod_id; | 69 | if (!dev->resource) { |
64 | sprintf(dev->name, "SuperHyway device %04x", dev->id.id); | 70 | dev->resource = kmalloc(sizeof(struct resource), GFP_KERNEL); |
71 | if (!dev->resource) { | ||
72 | kfree(dev); | ||
73 | return -ENOMEM; | ||
74 | } | ||
75 | |||
76 | dev->resource->name = dev->name; | ||
77 | dev->resource->start = base; | ||
78 | dev->resource->end = dev->resource->start + 0x01000000; | ||
79 | } | ||
65 | 80 | ||
66 | dev->vcr = *((struct vcr_info *)(&vcr)); | ||
67 | dev->resource.name = dev->name; | ||
68 | dev->resource.start = base; | ||
69 | dev->resource.end = dev->resource.start + 0x01000000; | ||
70 | dev->dev.parent = &superhyway_bus_device; | 81 | dev->dev.parent = &superhyway_bus_device; |
71 | dev->dev.bus = &superhyway_bus_type; | 82 | dev->dev.bus = &superhyway_bus_type; |
72 | dev->dev.release = superhyway_device_release; | 83 | dev->dev.release = superhyway_device_release; |
84 | dev->id.id = dev->vcr.mod_id; | ||
73 | 85 | ||
86 | sprintf(dev->name, "SuperHyway device %04x", dev->id.id); | ||
74 | sprintf(dev->dev.bus_id, "%02x", superhyway_devices); | 87 | sprintf(dev->dev.bus_id, "%02x", superhyway_devices); |
75 | 88 | ||
76 | superhyway_devices++; | 89 | superhyway_devices++; |
@@ -78,10 +91,31 @@ int superhyway_add_device(unsigned int mod_id, unsigned long base, | |||
78 | return device_register(&dev->dev); | 91 | return device_register(&dev->dev); |
79 | } | 92 | } |
80 | 93 | ||
94 | int superhyway_add_devices(struct superhyway_bus *bus, | ||
95 | struct superhyway_device **devices, | ||
96 | int nr_devices) | ||
97 | { | ||
98 | int i, ret = 0; | ||
99 | |||
100 | for (i = 0; i < nr_devices; i++) { | ||
101 | struct superhyway_device *dev = devices[i]; | ||
102 | ret |= superhyway_add_device(dev->resource[0].start, dev, bus); | ||
103 | } | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
81 | static int __init superhyway_init(void) | 108 | static int __init superhyway_init(void) |
82 | { | 109 | { |
110 | struct superhyway_bus *bus; | ||
111 | int ret = 0; | ||
112 | |||
83 | device_register(&superhyway_bus_device); | 113 | device_register(&superhyway_bus_device); |
84 | return superhyway_scan_bus(); | 114 | |
115 | for (bus = superhyway_channels; bus->ops; bus++) | ||
116 | ret |= superhyway_scan_bus(bus); | ||
117 | |||
118 | return ret; | ||
85 | } | 119 | } |
86 | 120 | ||
87 | postcore_initcall(superhyway_init); | 121 | postcore_initcall(superhyway_init); |
@@ -197,6 +231,7 @@ module_exit(superhyway_bus_exit); | |||
197 | 231 | ||
198 | EXPORT_SYMBOL(superhyway_bus_type); | 232 | EXPORT_SYMBOL(superhyway_bus_type); |
199 | EXPORT_SYMBOL(superhyway_add_device); | 233 | EXPORT_SYMBOL(superhyway_add_device); |
234 | EXPORT_SYMBOL(superhyway_add_devices); | ||
200 | EXPORT_SYMBOL(superhyway_register_driver); | 235 | EXPORT_SYMBOL(superhyway_register_driver); |
201 | EXPORT_SYMBOL(superhyway_unregister_driver); | 236 | EXPORT_SYMBOL(superhyway_unregister_driver); |
202 | 237 | ||