diff options
Diffstat (limited to 'arch/sh/drivers')
-rw-r--r-- | arch/sh/drivers/Kconfig | 9 | ||||
-rw-r--r-- | arch/sh/drivers/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/drivers/dma/Makefile | 4 | ||||
-rw-r--r-- | arch/sh/drivers/dma/dma-api.c | 274 | ||||
-rw-r--r-- | arch/sh/drivers/dma/dma-sh.c | 9 | ||||
-rw-r--r-- | arch/sh/drivers/dma/dma-sysfs.c | 23 | ||||
-rw-r--r-- | arch/sh/drivers/pci/ops-titan.c | 24 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.c | 14 | ||||
-rw-r--r-- | arch/sh/drivers/push-switch.c | 138 |
9 files changed, 379 insertions, 118 deletions
diff --git a/arch/sh/drivers/Kconfig b/arch/sh/drivers/Kconfig new file mode 100644 index 000000000000..c54c758e6243 --- /dev/null +++ b/arch/sh/drivers/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | menu "Additional SuperH Device Drivers" | ||
2 | |||
3 | config PUSH_SWITCH | ||
4 | tristate "Push switch support" | ||
5 | help | ||
6 | This enables support for the push switch framework, a simple | ||
7 | framework that allows for sysfs driven switch status reporting. | ||
8 | |||
9 | endmenu | ||
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile index 338c3729d270..bf18dbfb6787 100644 --- a/arch/sh/drivers/Makefile +++ b/arch/sh/drivers/Makefile | |||
@@ -5,4 +5,4 @@ | |||
5 | obj-$(CONFIG_PCI) += pci/ | 5 | obj-$(CONFIG_PCI) += pci/ |
6 | obj-$(CONFIG_SH_DMA) += dma/ | 6 | obj-$(CONFIG_SH_DMA) += dma/ |
7 | obj-$(CONFIG_SUPERHYWAY) += superhyway/ | 7 | obj-$(CONFIG_SUPERHYWAY) += superhyway/ |
8 | 8 | obj-$(CONFIG_PUSH_SWITCH) += push-switch.o | |
diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile index 065d4c90970e..db1295d32268 100644 --- a/arch/sh/drivers/dma/Makefile +++ b/arch/sh/drivers/dma/Makefile | |||
@@ -2,8 +2,8 @@ | |||
2 | # Makefile for the SuperH DMA specific kernel interface routines under Linux. | 2 | # Makefile for the SuperH DMA specific kernel interface routines under Linux. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += dma-api.o dma-isa.o | 5 | obj-y += dma-api.o |
6 | obj-$(CONFIG_ISA_DMA_API) += dma-isa.o | ||
6 | obj-$(CONFIG_SYSFS) += dma-sysfs.o | 7 | obj-$(CONFIG_SYSFS) += dma-sysfs.o |
7 | obj-$(CONFIG_SH_DMA) += dma-sh.o | 8 | obj-$(CONFIG_SH_DMA) += dma-sh.o |
8 | obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o | 9 | obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o |
9 | |||
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index 47c3e837599b..e062067edd24 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c | |||
@@ -11,61 +11,27 @@ | |||
11 | */ | 11 | */ |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
16 | #include <linux/proc_fs.h> | 15 | #include <linux/proc_fs.h> |
17 | #include <linux/list.h> | 16 | #include <linux/list.h> |
18 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/mm.h> | ||
19 | #include <asm/dma.h> | 19 | #include <asm/dma.h> |
20 | 20 | ||
21 | DEFINE_SPINLOCK(dma_spin_lock); | 21 | DEFINE_SPINLOCK(dma_spin_lock); |
22 | static LIST_HEAD(registered_dmac_list); | 22 | static LIST_HEAD(registered_dmac_list); |
23 | 23 | ||
24 | /* | ||
25 | * A brief note about the reasons for this API as it stands. | ||
26 | * | ||
27 | * For starters, the old ISA DMA API didn't work for us for a number of | ||
28 | * reasons, for one, the vast majority of channels on the SH DMAC are | ||
29 | * dual-address mode only, and both the new and the old DMA APIs are after the | ||
30 | * concept of managing a DMA buffer, which doesn't overly fit this model very | ||
31 | * well. In addition to which, the new API is largely geared at IOMMUs and | ||
32 | * GARTs, and doesn't even support the channel notion very well. | ||
33 | * | ||
34 | * The other thing that's a marginal issue, is the sheer number of random DMA | ||
35 | * engines that are present (ie, in boards like the Dreamcast), some of which | ||
36 | * cascade off of the SH DMAC, and others do not. As such, there was a real | ||
37 | * need for a scalable subsystem that could deal with both single and | ||
38 | * dual-address mode usage, in addition to interoperating with cascaded DMACs. | ||
39 | * | ||
40 | * There really isn't any reason why this needs to be SH specific, though I'm | ||
41 | * not aware of too many other processors (with the exception of some MIPS) | ||
42 | * that have the same concept of a dual address mode, or any real desire to | ||
43 | * actually make use of the DMAC even if such a subsystem were exposed | ||
44 | * elsewhere. | ||
45 | * | ||
46 | * The idea for this was derived from the ARM port, which acted as an excellent | ||
47 | * reference when trying to address these issues. | ||
48 | * | ||
49 | * It should also be noted that the decision to add Yet Another DMA API(tm) to | ||
50 | * the kernel wasn't made easily, and was only decided upon after conferring | ||
51 | * with jejb with regards to the state of the old and new APIs as they applied | ||
52 | * to these circumstances. Philip Blundell was also a great help in figuring | ||
53 | * out some single-address mode DMA semantics that were otherwise rather | ||
54 | * confusing. | ||
55 | */ | ||
56 | |||
57 | struct dma_info *get_dma_info(unsigned int chan) | 24 | struct dma_info *get_dma_info(unsigned int chan) |
58 | { | 25 | { |
59 | struct dma_info *info; | 26 | struct dma_info *info; |
60 | unsigned int total = 0; | ||
61 | 27 | ||
62 | /* | 28 | /* |
63 | * Look for each DMAC's range to determine who the owner of | 29 | * Look for each DMAC's range to determine who the owner of |
64 | * the channel is. | 30 | * the channel is. |
65 | */ | 31 | */ |
66 | list_for_each_entry(info, ®istered_dmac_list, list) { | 32 | list_for_each_entry(info, ®istered_dmac_list, list) { |
67 | total += info->nr_channels; | 33 | if ((chan < info->first_channel_nr) || |
68 | if (chan > total) | 34 | (chan >= info->first_channel_nr + info->nr_channels)) |
69 | continue; | 35 | continue; |
70 | 36 | ||
71 | return info; | 37 | return info; |
@@ -73,6 +39,22 @@ struct dma_info *get_dma_info(unsigned int chan) | |||
73 | 39 | ||
74 | return NULL; | 40 | return NULL; |
75 | } | 41 | } |
42 | EXPORT_SYMBOL(get_dma_info); | ||
43 | |||
44 | struct dma_info *get_dma_info_by_name(const char *dmac_name) | ||
45 | { | ||
46 | struct dma_info *info; | ||
47 | |||
48 | list_for_each_entry(info, ®istered_dmac_list, list) { | ||
49 | if (dmac_name && (strcmp(dmac_name, info->name) != 0)) | ||
50 | continue; | ||
51 | else | ||
52 | return info; | ||
53 | } | ||
54 | |||
55 | return NULL; | ||
56 | } | ||
57 | EXPORT_SYMBOL(get_dma_info_by_name); | ||
76 | 58 | ||
77 | static unsigned int get_nr_channels(void) | 59 | static unsigned int get_nr_channels(void) |
78 | { | 60 | { |
@@ -91,63 +73,161 @@ static unsigned int get_nr_channels(void) | |||
91 | struct dma_channel *get_dma_channel(unsigned int chan) | 73 | struct dma_channel *get_dma_channel(unsigned int chan) |
92 | { | 74 | { |
93 | struct dma_info *info = get_dma_info(chan); | 75 | struct dma_info *info = get_dma_info(chan); |
76 | struct dma_channel *channel; | ||
77 | int i; | ||
94 | 78 | ||
95 | if (!info) | 79 | if (unlikely(!info)) |
96 | return ERR_PTR(-EINVAL); | 80 | return ERR_PTR(-EINVAL); |
97 | 81 | ||
98 | return info->channels + chan; | 82 | for (i = 0; i < info->nr_channels; i++) { |
83 | channel = &info->channels[i]; | ||
84 | if (channel->chan == chan) | ||
85 | return channel; | ||
86 | } | ||
87 | |||
88 | return NULL; | ||
99 | } | 89 | } |
90 | EXPORT_SYMBOL(get_dma_channel); | ||
100 | 91 | ||
101 | int get_dma_residue(unsigned int chan) | 92 | int get_dma_residue(unsigned int chan) |
102 | { | 93 | { |
103 | struct dma_info *info = get_dma_info(chan); | 94 | struct dma_info *info = get_dma_info(chan); |
104 | struct dma_channel *channel = &info->channels[chan]; | 95 | struct dma_channel *channel = get_dma_channel(chan); |
105 | 96 | ||
106 | if (info->ops->get_residue) | 97 | if (info->ops->get_residue) |
107 | return info->ops->get_residue(channel); | 98 | return info->ops->get_residue(channel); |
108 | 99 | ||
109 | return 0; | 100 | return 0; |
110 | } | 101 | } |
102 | EXPORT_SYMBOL(get_dma_residue); | ||
111 | 103 | ||
112 | int request_dma(unsigned int chan, const char *dev_id) | 104 | static int search_cap(const char **haystack, const char *needle) |
113 | { | 105 | { |
114 | struct dma_info *info = get_dma_info(chan); | 106 | const char **p; |
115 | struct dma_channel *channel = &info->channels[chan]; | 107 | |
108 | for (p = haystack; *p; p++) | ||
109 | if (strcmp(*p, needle) == 0) | ||
110 | return 1; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * request_dma_bycap - Allocate a DMA channel based on its capabilities | ||
117 | * @dmac: List of DMA controllers to search | ||
118 | * @caps: List of capabilites | ||
119 | * | ||
120 | * Search all channels of all DMA controllers to find a channel which | ||
121 | * matches the requested capabilities. The result is the channel | ||
122 | * number if a match is found, or %-ENODEV if no match is found. | ||
123 | * | ||
124 | * Note that not all DMA controllers export capabilities, in which | ||
125 | * case they can never be allocated using this API, and so | ||
126 | * request_dma() must be used specifying the channel number. | ||
127 | */ | ||
128 | int request_dma_bycap(const char **dmac, const char **caps, const char *dev_id) | ||
129 | { | ||
130 | unsigned int found = 0; | ||
131 | struct dma_info *info; | ||
132 | const char **p; | ||
133 | int i; | ||
134 | |||
135 | BUG_ON(!dmac || !caps); | ||
136 | |||
137 | list_for_each_entry(info, ®istered_dmac_list, list) | ||
138 | if (strcmp(*dmac, info->name) == 0) { | ||
139 | found = 1; | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | if (!found) | ||
144 | return -ENODEV; | ||
145 | |||
146 | for (i = 0; i < info->nr_channels; i++) { | ||
147 | struct dma_channel *channel = &info->channels[i]; | ||
148 | |||
149 | if (unlikely(!channel->caps)) | ||
150 | continue; | ||
151 | |||
152 | for (p = caps; *p; p++) { | ||
153 | if (!search_cap(channel->caps, *p)) | ||
154 | break; | ||
155 | if (request_dma(channel->chan, dev_id) == 0) | ||
156 | return channel->chan; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | return -EINVAL; | ||
161 | } | ||
162 | EXPORT_SYMBOL(request_dma_bycap); | ||
163 | |||
164 | int dmac_search_free_channel(const char *dev_id) | ||
165 | { | ||
166 | struct dma_channel *channel = { 0 }; | ||
167 | struct dma_info *info = get_dma_info(0); | ||
168 | int i; | ||
169 | |||
170 | for (i = 0; i < info->nr_channels; i++) { | ||
171 | channel = &info->channels[i]; | ||
172 | if (unlikely(!channel)) | ||
173 | return -ENODEV; | ||
174 | |||
175 | if (atomic_read(&channel->busy) == 0) | ||
176 | break; | ||
177 | } | ||
116 | 178 | ||
117 | down(&channel->sem); | 179 | if (info->ops->request) { |
180 | int result = info->ops->request(channel); | ||
181 | if (result) | ||
182 | return result; | ||
118 | 183 | ||
119 | if (!info->ops || chan >= MAX_DMA_CHANNELS) { | 184 | atomic_set(&channel->busy, 1); |
120 | up(&channel->sem); | 185 | return channel->chan; |
121 | return -EINVAL; | ||
122 | } | 186 | } |
123 | 187 | ||
124 | atomic_set(&channel->busy, 1); | 188 | return -ENOSYS; |
189 | } | ||
190 | |||
191 | int request_dma(unsigned int chan, const char *dev_id) | ||
192 | { | ||
193 | struct dma_channel *channel = { 0 }; | ||
194 | struct dma_info *info = get_dma_info(chan); | ||
195 | int result; | ||
196 | |||
197 | channel = get_dma_channel(chan); | ||
198 | if (atomic_xchg(&channel->busy, 1)) | ||
199 | return -EBUSY; | ||
125 | 200 | ||
126 | strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); | 201 | strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); |
127 | 202 | ||
128 | up(&channel->sem); | 203 | if (info->ops->request) { |
204 | result = info->ops->request(channel); | ||
205 | if (result) | ||
206 | atomic_set(&channel->busy, 0); | ||
129 | 207 | ||
130 | if (info->ops->request) | 208 | return result; |
131 | return info->ops->request(channel); | 209 | } |
132 | 210 | ||
133 | return 0; | 211 | return 0; |
134 | } | 212 | } |
213 | EXPORT_SYMBOL(request_dma); | ||
135 | 214 | ||
136 | void free_dma(unsigned int chan) | 215 | void free_dma(unsigned int chan) |
137 | { | 216 | { |
138 | struct dma_info *info = get_dma_info(chan); | 217 | struct dma_info *info = get_dma_info(chan); |
139 | struct dma_channel *channel = &info->channels[chan]; | 218 | struct dma_channel *channel = get_dma_channel(chan); |
140 | 219 | ||
141 | if (info->ops->free) | 220 | if (info->ops->free) |
142 | info->ops->free(channel); | 221 | info->ops->free(channel); |
143 | 222 | ||
144 | atomic_set(&channel->busy, 0); | 223 | atomic_set(&channel->busy, 0); |
145 | } | 224 | } |
225 | EXPORT_SYMBOL(free_dma); | ||
146 | 226 | ||
147 | void dma_wait_for_completion(unsigned int chan) | 227 | void dma_wait_for_completion(unsigned int chan) |
148 | { | 228 | { |
149 | struct dma_info *info = get_dma_info(chan); | 229 | struct dma_info *info = get_dma_info(chan); |
150 | struct dma_channel *channel = &info->channels[chan]; | 230 | struct dma_channel *channel = get_dma_channel(chan); |
151 | 231 | ||
152 | if (channel->flags & DMA_TEI_CAPABLE) { | 232 | if (channel->flags & DMA_TEI_CAPABLE) { |
153 | wait_event(channel->wait_queue, | 233 | wait_event(channel->wait_queue, |
@@ -158,21 +238,52 @@ void dma_wait_for_completion(unsigned int chan) | |||
158 | while (info->ops->get_residue(channel)) | 238 | while (info->ops->get_residue(channel)) |
159 | cpu_relax(); | 239 | cpu_relax(); |
160 | } | 240 | } |
241 | EXPORT_SYMBOL(dma_wait_for_completion); | ||
242 | |||
243 | int register_chan_caps(const char *dmac, struct dma_chan_caps *caps) | ||
244 | { | ||
245 | struct dma_info *info; | ||
246 | unsigned int found = 0; | ||
247 | int i; | ||
248 | |||
249 | list_for_each_entry(info, ®istered_dmac_list, list) | ||
250 | if (strcmp(dmac, info->name) == 0) { | ||
251 | found = 1; | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | if (unlikely(!found)) | ||
256 | return -ENODEV; | ||
257 | |||
258 | for (i = 0; i < info->nr_channels; i++, caps++) { | ||
259 | struct dma_channel *channel; | ||
260 | |||
261 | if ((info->first_channel_nr + i) != caps->ch_num) | ||
262 | return -EINVAL; | ||
263 | |||
264 | channel = &info->channels[i]; | ||
265 | channel->caps = caps->caplist; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | EXPORT_SYMBOL(register_chan_caps); | ||
161 | 271 | ||
162 | void dma_configure_channel(unsigned int chan, unsigned long flags) | 272 | void dma_configure_channel(unsigned int chan, unsigned long flags) |
163 | { | 273 | { |
164 | struct dma_info *info = get_dma_info(chan); | 274 | struct dma_info *info = get_dma_info(chan); |
165 | struct dma_channel *channel = &info->channels[chan]; | 275 | struct dma_channel *channel = get_dma_channel(chan); |
166 | 276 | ||
167 | if (info->ops->configure) | 277 | if (info->ops->configure) |
168 | info->ops->configure(channel, flags); | 278 | info->ops->configure(channel, flags); |
169 | } | 279 | } |
280 | EXPORT_SYMBOL(dma_configure_channel); | ||
170 | 281 | ||
171 | int dma_xfer(unsigned int chan, unsigned long from, | 282 | int dma_xfer(unsigned int chan, unsigned long from, |
172 | unsigned long to, size_t size, unsigned int mode) | 283 | unsigned long to, size_t size, unsigned int mode) |
173 | { | 284 | { |
174 | struct dma_info *info = get_dma_info(chan); | 285 | struct dma_info *info = get_dma_info(chan); |
175 | struct dma_channel *channel = &info->channels[chan]; | 286 | struct dma_channel *channel = get_dma_channel(chan); |
176 | 287 | ||
177 | channel->sar = from; | 288 | channel->sar = from; |
178 | channel->dar = to; | 289 | channel->dar = to; |
@@ -181,8 +292,20 @@ int dma_xfer(unsigned int chan, unsigned long from, | |||
181 | 292 | ||
182 | return info->ops->xfer(channel); | 293 | return info->ops->xfer(channel); |
183 | } | 294 | } |
295 | EXPORT_SYMBOL(dma_xfer); | ||
296 | |||
297 | int dma_extend(unsigned int chan, unsigned long op, void *param) | ||
298 | { | ||
299 | struct dma_info *info = get_dma_info(chan); | ||
300 | struct dma_channel *channel = get_dma_channel(chan); | ||
301 | |||
302 | if (info->ops->extend) | ||
303 | return info->ops->extend(channel, op, param); | ||
304 | |||
305 | return -ENOSYS; | ||
306 | } | ||
307 | EXPORT_SYMBOL(dma_extend); | ||
184 | 308 | ||
185 | #ifdef CONFIG_PROC_FS | ||
186 | static int dma_read_proc(char *buf, char **start, off_t off, | 309 | static int dma_read_proc(char *buf, char **start, off_t off, |
187 | int len, int *eof, void *data) | 310 | int len, int *eof, void *data) |
188 | { | 311 | { |
@@ -214,8 +337,6 @@ static int dma_read_proc(char *buf, char **start, off_t off, | |||
214 | 337 | ||
215 | return p - buf; | 338 | return p - buf; |
216 | } | 339 | } |
217 | #endif | ||
218 | |||
219 | 340 | ||
220 | int register_dmac(struct dma_info *info) | 341 | int register_dmac(struct dma_info *info) |
221 | { | 342 | { |
@@ -224,8 +345,7 @@ int register_dmac(struct dma_info *info) | |||
224 | INIT_LIST_HEAD(&info->list); | 345 | INIT_LIST_HEAD(&info->list); |
225 | 346 | ||
226 | printk(KERN_INFO "DMA: Registering %s handler (%d channel%s).\n", | 347 | printk(KERN_INFO "DMA: Registering %s handler (%d channel%s).\n", |
227 | info->name, info->nr_channels, | 348 | info->name, info->nr_channels, info->nr_channels > 1 ? "s" : ""); |
228 | info->nr_channels > 1 ? "s" : ""); | ||
229 | 349 | ||
230 | BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); | 350 | BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); |
231 | 351 | ||
@@ -242,28 +362,26 @@ int register_dmac(struct dma_info *info) | |||
242 | 362 | ||
243 | size = sizeof(struct dma_channel) * info->nr_channels; | 363 | size = sizeof(struct dma_channel) * info->nr_channels; |
244 | 364 | ||
245 | info->channels = kmalloc(size, GFP_KERNEL); | 365 | info->channels = kzalloc(size, GFP_KERNEL); |
246 | if (!info->channels) | 366 | if (!info->channels) |
247 | return -ENOMEM; | 367 | return -ENOMEM; |
248 | |||
249 | memset(info->channels, 0, size); | ||
250 | } | 368 | } |
251 | 369 | ||
252 | total_channels = get_nr_channels(); | 370 | total_channels = get_nr_channels(); |
253 | for (i = 0; i < info->nr_channels; i++) { | 371 | for (i = 0; i < info->nr_channels; i++) { |
254 | struct dma_channel *chan = info->channels + i; | 372 | struct dma_channel *chan = &info->channels[i]; |
373 | |||
374 | atomic_set(&chan->busy, 0); | ||
255 | 375 | ||
256 | chan->chan = i; | 376 | chan->chan = info->first_channel_nr + i; |
257 | chan->vchan = i + total_channels; | 377 | chan->vchan = info->first_channel_nr + i + total_channels; |
258 | 378 | ||
259 | memcpy(chan->dev_id, "Unused", 7); | 379 | memcpy(chan->dev_id, "Unused", 7); |
260 | 380 | ||
261 | if (info->flags & DMAC_CHANNELS_TEI_CAPABLE) | 381 | if (info->flags & DMAC_CHANNELS_TEI_CAPABLE) |
262 | chan->flags |= DMA_TEI_CAPABLE; | 382 | chan->flags |= DMA_TEI_CAPABLE; |
263 | 383 | ||
264 | init_MUTEX(&chan->sem); | ||
265 | init_waitqueue_head(&chan->wait_queue); | 384 | init_waitqueue_head(&chan->wait_queue); |
266 | |||
267 | dma_create_sysfs_files(chan, info); | 385 | dma_create_sysfs_files(chan, info); |
268 | } | 386 | } |
269 | 387 | ||
@@ -271,6 +389,7 @@ int register_dmac(struct dma_info *info) | |||
271 | 389 | ||
272 | return 0; | 390 | return 0; |
273 | } | 391 | } |
392 | EXPORT_SYMBOL(register_dmac); | ||
274 | 393 | ||
275 | void unregister_dmac(struct dma_info *info) | 394 | void unregister_dmac(struct dma_info *info) |
276 | { | 395 | { |
@@ -285,31 +404,16 @@ void unregister_dmac(struct dma_info *info) | |||
285 | list_del(&info->list); | 404 | list_del(&info->list); |
286 | platform_device_unregister(info->pdev); | 405 | platform_device_unregister(info->pdev); |
287 | } | 406 | } |
407 | EXPORT_SYMBOL(unregister_dmac); | ||
288 | 408 | ||
289 | static int __init dma_api_init(void) | 409 | static int __init dma_api_init(void) |
290 | { | 410 | { |
291 | printk("DMA: Registering DMA API.\n"); | 411 | printk(KERN_NOTICE "DMA: Registering DMA API.\n"); |
292 | |||
293 | #ifdef CONFIG_PROC_FS | ||
294 | create_proc_read_entry("dma", 0, 0, dma_read_proc, 0); | 412 | create_proc_read_entry("dma", 0, 0, dma_read_proc, 0); |
295 | #endif | ||
296 | |||
297 | return 0; | 413 | return 0; |
298 | } | 414 | } |
299 | |||
300 | subsys_initcall(dma_api_init); | 415 | subsys_initcall(dma_api_init); |
301 | 416 | ||
302 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | 417 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); |
303 | MODULE_DESCRIPTION("DMA API for SuperH"); | 418 | MODULE_DESCRIPTION("DMA API for SuperH"); |
304 | MODULE_LICENSE("GPL"); | 419 | MODULE_LICENSE("GPL"); |
305 | |||
306 | EXPORT_SYMBOL(request_dma); | ||
307 | EXPORT_SYMBOL(free_dma); | ||
308 | EXPORT_SYMBOL(register_dmac); | ||
309 | EXPORT_SYMBOL(get_dma_residue); | ||
310 | EXPORT_SYMBOL(get_dma_info); | ||
311 | EXPORT_SYMBOL(get_dma_channel); | ||
312 | EXPORT_SYMBOL(dma_xfer); | ||
313 | EXPORT_SYMBOL(dma_wait_for_completion); | ||
314 | EXPORT_SYMBOL(dma_configure_channel); | ||
315 | |||
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index 660786013350..f63721ed86c2 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c | |||
@@ -94,20 +94,13 @@ static int sh_dmac_request_dma(struct dma_channel *chan) | |||
94 | if (unlikely(!chan->flags & DMA_TEI_CAPABLE)) | 94 | if (unlikely(!chan->flags & DMA_TEI_CAPABLE)) |
95 | return 0; | 95 | return 0; |
96 | 96 | ||
97 | chan->name = kzalloc(32, GFP_KERNEL); | ||
98 | if (unlikely(chan->name == NULL)) | ||
99 | return -ENOMEM; | ||
100 | snprintf(chan->name, 32, "DMAC Transfer End (Channel %d)", | ||
101 | chan->chan); | ||
102 | |||
103 | return request_irq(get_dmte_irq(chan->chan), dma_tei, | 97 | return request_irq(get_dmte_irq(chan->chan), dma_tei, |
104 | IRQF_DISABLED, chan->name, chan); | 98 | IRQF_DISABLED, chan->dev_id, chan); |
105 | } | 99 | } |
106 | 100 | ||
107 | static void sh_dmac_free_dma(struct dma_channel *chan) | 101 | static void sh_dmac_free_dma(struct dma_channel *chan) |
108 | { | 102 | { |
109 | free_irq(get_dmte_irq(chan->chan), chan); | 103 | free_irq(get_dmte_irq(chan->chan), chan); |
110 | kfree(chan->name); | ||
111 | } | 104 | } |
112 | 105 | ||
113 | static void | 106 | static void |
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c index 29b8ef9873d1..eebcd4768bbf 100644 --- a/arch/sh/drivers/dma/dma-sysfs.c +++ b/arch/sh/drivers/dma/dma-sysfs.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * sysfs interface for SH DMA API | 4 | * sysfs interface for SH DMA API |
5 | * | 5 | * |
6 | * Copyright (C) 2004, 2005 Paul Mundt | 6 | * Copyright (C) 2004 - 2006 Paul Mundt |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -21,7 +21,6 @@ | |||
21 | static struct sysdev_class dma_sysclass = { | 21 | static struct sysdev_class dma_sysclass = { |
22 | set_kset_name("dma"), | 22 | set_kset_name("dma"), |
23 | }; | 23 | }; |
24 | |||
25 | EXPORT_SYMBOL(dma_sysclass); | 24 | EXPORT_SYMBOL(dma_sysclass); |
26 | 25 | ||
27 | static ssize_t dma_show_devices(struct sys_device *dev, char *buf) | 26 | static ssize_t dma_show_devices(struct sys_device *dev, char *buf) |
@@ -31,7 +30,10 @@ static ssize_t dma_show_devices(struct sys_device *dev, char *buf) | |||
31 | 30 | ||
32 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | 31 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { |
33 | struct dma_info *info = get_dma_info(i); | 32 | struct dma_info *info = get_dma_info(i); |
34 | struct dma_channel *channel = &info->channels[i]; | 33 | struct dma_channel *channel = get_dma_channel(i); |
34 | |||
35 | if (unlikely(!info) || !channel) | ||
36 | continue; | ||
35 | 37 | ||
36 | len += sprintf(buf + len, "%2d: %14s %s\n", | 38 | len += sprintf(buf + len, "%2d: %14s %s\n", |
37 | channel->chan, info->name, | 39 | channel->chan, info->name, |
@@ -125,11 +127,16 @@ int dma_create_sysfs_files(struct dma_channel *chan, struct dma_info *info) | |||
125 | if (ret) | 127 | if (ret) |
126 | return ret; | 128 | return ret; |
127 | 129 | ||
128 | sysdev_create_file(dev, &attr_dev_id); | 130 | ret |= sysdev_create_file(dev, &attr_dev_id); |
129 | sysdev_create_file(dev, &attr_count); | 131 | ret |= sysdev_create_file(dev, &attr_count); |
130 | sysdev_create_file(dev, &attr_mode); | 132 | ret |= sysdev_create_file(dev, &attr_mode); |
131 | sysdev_create_file(dev, &attr_flags); | 133 | ret |= sysdev_create_file(dev, &attr_flags); |
132 | sysdev_create_file(dev, &attr_config); | 134 | ret |= sysdev_create_file(dev, &attr_config); |
135 | |||
136 | if (unlikely(ret)) { | ||
137 | dev_err(&info->pdev->dev, "Failed creating attrs\n"); | ||
138 | return ret; | ||
139 | } | ||
133 | 140 | ||
134 | snprintf(name, sizeof(name), "dma%d", chan->chan); | 141 | snprintf(name, sizeof(name), "dma%d", chan->chan); |
135 | return sysfs_create_link(&info->pdev->dev.kobj, &dev->kobj, name); | 142 | return sysfs_create_link(&info->pdev->dev.kobj, &dev->kobj, name); |
diff --git a/arch/sh/drivers/pci/ops-titan.c b/arch/sh/drivers/pci/ops-titan.c index cd56d53375e7..ac8ee2312cd8 100644 --- a/arch/sh/drivers/pci/ops-titan.c +++ b/arch/sh/drivers/pci/ops-titan.c | |||
@@ -15,25 +15,21 @@ | |||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
18 | #include <asm/io.h> | 18 | #include <linux/io.h> |
19 | #include <asm/titan.h> | 19 | #include <asm/titan.h> |
20 | #include "pci-sh4.h" | 20 | #include "pci-sh4.h" |
21 | 21 | ||
22 | static char titan_irq_tab[] __initdata = { | ||
23 | TITAN_IRQ_WAN, | ||
24 | TITAN_IRQ_LAN, | ||
25 | TITAN_IRQ_MPCIA, | ||
26 | TITAN_IRQ_MPCIB, | ||
27 | TITAN_IRQ_USB, | ||
28 | }; | ||
29 | |||
22 | int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) | 30 | int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) |
23 | { | 31 | { |
24 | int irq = -1; | 32 | int irq = titan_irq_tab[slot]; |
25 | |||
26 | switch (slot) { | ||
27 | case 0: irq = TITAN_IRQ_WAN; break; /* eth0 (WAN) */ | ||
28 | case 1: irq = TITAN_IRQ_LAN; break; /* eth1 (LAN) */ | ||
29 | case 2: irq = TITAN_IRQ_MPCIA; break; /* mPCI A */ | ||
30 | case 3: irq = TITAN_IRQ_MPCIB; break; /* mPCI B */ | ||
31 | case 4: irq = TITAN_IRQ_USB; break; /* USB */ | ||
32 | default: | ||
33 | printk(KERN_INFO "PCI: Bad IRQ mapping " | ||
34 | "request for slot %d\n", slot); | ||
35 | return -1; | ||
36 | } | ||
37 | 33 | ||
38 | printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n", | 34 | printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n", |
39 | slot, pin - 1 + 'A', irq); | 35 | slot, pin - 1 + 'A', irq); |
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index d6e635296534..602b644c35ad 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c | |||
@@ -22,6 +22,20 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include "pci-sh4.h" | 23 | #include "pci-sh4.h" |
24 | 24 | ||
25 | #define INTC_BASE 0xffd00000 | ||
26 | #define INTC_ICR0 (INTC_BASE+0x0) | ||
27 | #define INTC_ICR1 (INTC_BASE+0x1c) | ||
28 | #define INTC_INTPRI (INTC_BASE+0x10) | ||
29 | #define INTC_INTREQ (INTC_BASE+0x24) | ||
30 | #define INTC_INTMSK0 (INTC_BASE+0x44) | ||
31 | #define INTC_INTMSK1 (INTC_BASE+0x48) | ||
32 | #define INTC_INTMSK2 (INTC_BASE+0x40080) | ||
33 | #define INTC_INTMSKCLR0 (INTC_BASE+0x64) | ||
34 | #define INTC_INTMSKCLR1 (INTC_BASE+0x68) | ||
35 | #define INTC_INTMSKCLR2 (INTC_BASE+0x40084) | ||
36 | #define INTC_INT2MSKR (INTC_BASE+0x40038) | ||
37 | #define INTC_INT2MSKCR (INTC_BASE+0x4003c) | ||
38 | |||
25 | /* | 39 | /* |
26 | * Initialization. Try all known PCI access methods. Note that we support | 40 | * Initialization. Try all known PCI access methods. Note that we support |
27 | * using both PCI BIOS and direct access: in such cases, we use I/O ports | 41 | * using both PCI BIOS and direct access: in such cases, we use I/O ports |
diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c new file mode 100644 index 000000000000..f2b9157c314f --- /dev/null +++ b/arch/sh/drivers/push-switch.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * Generic push-switch framework | ||
3 | * | ||
4 | * Copyright (C) 2006 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <asm/push-switch.h> | ||
15 | |||
16 | #define DRV_NAME "push-switch" | ||
17 | #define DRV_VERSION "0.1.0" | ||
18 | |||
19 | static ssize_t switch_show(struct device *dev, | ||
20 | struct device_attribute *attr, | ||
21 | char *buf) | ||
22 | { | ||
23 | struct push_switch_platform_info *psw_info = dev->platform_data; | ||
24 | return sprintf(buf, "%s\n", psw_info->name); | ||
25 | } | ||
26 | static DEVICE_ATTR(switch, S_IRUGO, switch_show, NULL); | ||
27 | |||
28 | static void switch_timer(unsigned long data) | ||
29 | { | ||
30 | struct push_switch *psw = (struct push_switch *)data; | ||
31 | |||
32 | schedule_work(&psw->work); | ||
33 | } | ||
34 | |||
35 | static void switch_work_handler(void *data) | ||
36 | { | ||
37 | struct platform_device *pdev = data; | ||
38 | struct push_switch *psw = platform_get_drvdata(pdev); | ||
39 | |||
40 | psw->state = 0; | ||
41 | |||
42 | kobject_uevent(&pdev->dev.kobj, KOBJ_CHANGE); | ||
43 | } | ||
44 | |||
45 | static int switch_drv_probe(struct platform_device *pdev) | ||
46 | { | ||
47 | struct push_switch_platform_info *psw_info; | ||
48 | struct push_switch *psw; | ||
49 | int ret, irq; | ||
50 | |||
51 | psw = kzalloc(sizeof(struct push_switch), GFP_KERNEL); | ||
52 | if (unlikely(!psw)) | ||
53 | return -ENOMEM; | ||
54 | |||
55 | irq = platform_get_irq(pdev, 0); | ||
56 | if (unlikely(irq < 0)) { | ||
57 | ret = -ENODEV; | ||
58 | goto err; | ||
59 | } | ||
60 | |||
61 | psw_info = pdev->dev.platform_data; | ||
62 | BUG_ON(!psw_info); | ||
63 | |||
64 | ret = request_irq(irq, psw_info->irq_handler, | ||
65 | IRQF_DISABLED | psw_info->irq_flags, | ||
66 | psw_info->name ? psw_info->name : DRV_NAME, pdev); | ||
67 | if (unlikely(ret < 0)) | ||
68 | goto err; | ||
69 | |||
70 | if (psw_info->name) { | ||
71 | ret = device_create_file(&pdev->dev, &dev_attr_switch); | ||
72 | if (unlikely(ret)) { | ||
73 | dev_err(&pdev->dev, "Failed creating device attrs\n"); | ||
74 | ret = -EINVAL; | ||
75 | goto err_irq; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | INIT_WORK(&psw->work, switch_work_handler, pdev); | ||
80 | init_timer(&psw->debounce); | ||
81 | |||
82 | psw->debounce.function = switch_timer; | ||
83 | psw->debounce.data = (unsigned long)psw; | ||
84 | |||
85 | platform_set_drvdata(pdev, psw); | ||
86 | |||
87 | return 0; | ||
88 | |||
89 | err_irq: | ||
90 | free_irq(irq, pdev); | ||
91 | err: | ||
92 | kfree(psw); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static int switch_drv_remove(struct platform_device *pdev) | ||
97 | { | ||
98 | struct push_switch *psw = platform_get_drvdata(pdev); | ||
99 | struct push_switch_platform_info *psw_info = pdev->dev.platform_data; | ||
100 | int irq = platform_get_irq(pdev, 0); | ||
101 | |||
102 | if (psw_info->name) | ||
103 | device_remove_file(&pdev->dev, &dev_attr_switch); | ||
104 | |||
105 | platform_set_drvdata(pdev, NULL); | ||
106 | flush_scheduled_work(); | ||
107 | del_timer_sync(&psw->debounce); | ||
108 | free_irq(irq, pdev); | ||
109 | |||
110 | kfree(psw); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static struct platform_driver switch_driver = { | ||
116 | .probe = switch_drv_probe, | ||
117 | .remove = switch_drv_remove, | ||
118 | .driver = { | ||
119 | .name = DRV_NAME, | ||
120 | }, | ||
121 | }; | ||
122 | |||
123 | static int __init switch_init(void) | ||
124 | { | ||
125 | printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); | ||
126 | return platform_driver_register(&switch_driver); | ||
127 | } | ||
128 | |||
129 | static void __exit switch_exit(void) | ||
130 | { | ||
131 | platform_driver_unregister(&switch_driver); | ||
132 | } | ||
133 | module_init(switch_init); | ||
134 | module_exit(switch_exit); | ||
135 | |||
136 | MODULE_VERSION(DRV_VERSION); | ||
137 | MODULE_AUTHOR("Paul Mundt"); | ||
138 | MODULE_LICENSE("GPLv2"); | ||