diff options
Diffstat (limited to 'arch/arm/mach-pxa/ssp.c')
-rw-r--r-- | arch/arm/mach-pxa/ssp.c | 128 |
1 files changed, 40 insertions, 88 deletions
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c index 4d826c021315..a68b30eff4d2 100644 --- a/arch/arm/mach-pxa/ssp.c +++ b/arch/arm/mach-pxa/ssp.c | |||
@@ -19,6 +19,8 @@ | |||
19 | * 22nd Aug 2003 Initial version. | 19 | * 22nd Aug 2003 Initial version. |
20 | * 20th Dec 2004 Added ssp_config for changing port config without | 20 | * 20th Dec 2004 Added ssp_config for changing port config without |
21 | * closing the port. | 21 | * closing the port. |
22 | * 4th Aug 2005 Added option to disable irq handler registration and | ||
23 | * cleaned up irq and clock detection. | ||
22 | */ | 24 | */ |
23 | 25 | ||
24 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -37,6 +39,26 @@ | |||
37 | 39 | ||
38 | #define PXA_SSP_PORTS 3 | 40 | #define PXA_SSP_PORTS 3 |
39 | 41 | ||
42 | struct ssp_info_ { | ||
43 | int irq; | ||
44 | u32 clock; | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * SSP port clock and IRQ settings | ||
49 | */ | ||
50 | static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = { | ||
51 | #if defined (CONFIG_PXA27x) | ||
52 | {IRQ_SSP, CKEN23_SSP1}, | ||
53 | {IRQ_SSP2, CKEN3_SSP2}, | ||
54 | {IRQ_SSP3, CKEN4_SSP3}, | ||
55 | #else | ||
56 | {IRQ_SSP, CKEN3_SSP}, | ||
57 | {IRQ_NSSP, CKEN9_NSSP}, | ||
58 | {IRQ_ASSP, CKEN10_ASSP}, | ||
59 | #endif | ||
60 | }; | ||
61 | |||
40 | static DECLARE_MUTEX(sem); | 62 | static DECLARE_MUTEX(sem); |
41 | static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; | 63 | static int use_count[PXA_SSP_PORTS] = {0, 0, 0}; |
42 | 64 | ||
@@ -210,9 +232,9 @@ int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 spee | |||
210 | * %-EBUSY if the resources are already in use | 232 | * %-EBUSY if the resources are already in use |
211 | * %0 on success | 233 | * %0 on success |
212 | */ | 234 | */ |
213 | int ssp_init(struct ssp_dev *dev, u32 port) | 235 | int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags) |
214 | { | 236 | { |
215 | int ret, irq; | 237 | int ret; |
216 | 238 | ||
217 | if (port > PXA_SSP_PORTS || port == 0) | 239 | if (port > PXA_SSP_PORTS || port == 0) |
218 | return -ENODEV; | 240 | return -ENODEV; |
@@ -229,61 +251,20 @@ int ssp_init(struct ssp_dev *dev, u32 port) | |||
229 | up(&sem); | 251 | up(&sem); |
230 | return -EBUSY; | 252 | return -EBUSY; |
231 | } | 253 | } |
232 | |||
233 | switch (port) { | ||
234 | case 1: | ||
235 | irq = IRQ_SSP; | ||
236 | break; | ||
237 | #if defined (CONFIG_PXA27x) | ||
238 | case 2: | ||
239 | irq = IRQ_SSP2; | ||
240 | break; | ||
241 | case 3: | ||
242 | irq = IRQ_SSP3; | ||
243 | break; | ||
244 | #else | ||
245 | case 2: | ||
246 | irq = IRQ_NSSP; | ||
247 | break; | ||
248 | case 3: | ||
249 | irq = IRQ_ASSP; | ||
250 | break; | ||
251 | #endif | ||
252 | default: | ||
253 | return -ENODEV; | ||
254 | } | ||
255 | |||
256 | dev->port = port; | 254 | dev->port = port; |
257 | 255 | ||
258 | ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev); | 256 | /* do we need to get irq */ |
259 | if (ret) | 257 | if (!(init_flags & SSP_NO_IRQ)) { |
260 | goto out_region; | 258 | ret = request_irq(ssp_info[port-1].irq, ssp_interrupt, |
259 | 0, "SSP", dev); | ||
260 | if (ret) | ||
261 | goto out_region; | ||
262 | dev->irq = ssp_info[port-1].irq; | ||
263 | } else | ||
264 | dev->irq = 0; | ||
261 | 265 | ||
262 | /* turn on SSP port clock */ | 266 | /* turn on SSP port clock */ |
263 | switch (dev->port) { | 267 | pxa_set_cken(ssp_info[port-1].clock, 1); |
264 | #if defined (CONFIG_PXA27x) | ||
265 | case 1: | ||
266 | pxa_set_cken(CKEN23_SSP1, 1); | ||
267 | break; | ||
268 | case 2: | ||
269 | pxa_set_cken(CKEN3_SSP2, 1); | ||
270 | break; | ||
271 | case 3: | ||
272 | pxa_set_cken(CKEN4_SSP3, 1); | ||
273 | break; | ||
274 | #else | ||
275 | case 1: | ||
276 | pxa_set_cken(CKEN3_SSP, 1); | ||
277 | break; | ||
278 | case 2: | ||
279 | pxa_set_cken(CKEN9_NSSP, 1); | ||
280 | break; | ||
281 | case 3: | ||
282 | pxa_set_cken(CKEN10_ASSP, 1); | ||
283 | break; | ||
284 | #endif | ||
285 | } | ||
286 | |||
287 | up(&sem); | 268 | up(&sem); |
288 | return 0; | 269 | return 0; |
289 | 270 | ||
@@ -301,46 +282,17 @@ out_region: | |||
301 | */ | 282 | */ |
302 | void ssp_exit(struct ssp_dev *dev) | 283 | void ssp_exit(struct ssp_dev *dev) |
303 | { | 284 | { |
304 | int irq; | ||
305 | |||
306 | down(&sem); | 285 | down(&sem); |
307 | SSCR0_P(dev->port) &= ~SSCR0_SSE; | 286 | SSCR0_P(dev->port) &= ~SSCR0_SSE; |
308 | 287 | ||
309 | /* find irq, save power and turn off SSP port clock */ | 288 | if (dev->port > PXA_SSP_PORTS || dev->port == 0) { |
310 | switch (dev->port) { | 289 | printk(KERN_WARNING "SSP: tried to close invalid port\n"); |
311 | #if defined (CONFIG_PXA27x) | 290 | return; |
312 | case 1: | ||
313 | irq = IRQ_SSP; | ||
314 | pxa_set_cken(CKEN23_SSP1, 0); | ||
315 | break; | ||
316 | case 2: | ||
317 | irq = IRQ_SSP2; | ||
318 | pxa_set_cken(CKEN3_SSP2, 0); | ||
319 | break; | ||
320 | case 3: | ||
321 | irq = IRQ_SSP3; | ||
322 | pxa_set_cken(CKEN4_SSP3, 0); | ||
323 | break; | ||
324 | #else | ||
325 | case 1: | ||
326 | irq = IRQ_SSP; | ||
327 | pxa_set_cken(CKEN3_SSP, 0); | ||
328 | break; | ||
329 | case 2: | ||
330 | irq = IRQ_NSSP; | ||
331 | pxa_set_cken(CKEN9_NSSP, 0); | ||
332 | break; | ||
333 | case 3: | ||
334 | irq = IRQ_ASSP; | ||
335 | pxa_set_cken(CKEN10_ASSP, 0); | ||
336 | break; | ||
337 | #endif | ||
338 | default: | ||
339 | printk(KERN_WARNING "SSP: tried to close invalid port\n"); | ||
340 | return; | ||
341 | } | 291 | } |
342 | 292 | ||
343 | free_irq(irq, dev); | 293 | pxa_set_cken(ssp_info[dev->port-1].clock, 0); |
294 | if (dev->irq) | ||
295 | free_irq(dev->irq, dev); | ||
344 | release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); | 296 | release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c); |
345 | use_count[dev->port - 1]--; | 297 | use_count[dev->port - 1]--; |
346 | up(&sem); | 298 | up(&sem); |