diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-02-19 10:22:50 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-20 20:11:49 -0500 |
commit | 53521d8c90d366191b6c134f88a8ebe83de60614 (patch) | |
tree | 2d4b8bed0db743927586389ab035aab816d22f36 | |
parent | c2bcbe65fc88d61f9a806367ff6eab76c9eabb3a (diff) |
ssb: Make the GPIO API reentrancy safe
This fixes the GPIO API to be reentrancy safe.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/ssb/driver_chipcommon.c | 6 | ||||
-rw-r--r-- | drivers/ssb/driver_extif.c | 5 | ||||
-rw-r--r-- | drivers/ssb/embedded.c | 106 | ||||
-rw-r--r-- | drivers/ssb/main.c | 3 | ||||
-rw-r--r-- | include/linux/ssb/ssb.h | 5 | ||||
-rw-r--r-- | include/linux/ssb/ssb_embedded.h | 8 |
6 files changed, 122 insertions, 11 deletions
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7ea0c0faa9ab..e586321a473a 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c | |||
@@ -357,37 +357,31 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) | |||
357 | { | 357 | { |
358 | return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; | 358 | return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; |
359 | } | 359 | } |
360 | EXPORT_SYMBOL(ssb_chipco_gpio_in); | ||
361 | 360 | ||
362 | u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) | 361 | u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) |
363 | { | 362 | { |
364 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); | 363 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); |
365 | } | 364 | } |
366 | EXPORT_SYMBOL(ssb_chipco_gpio_out); | ||
367 | 365 | ||
368 | u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) | 366 | u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) |
369 | { | 367 | { |
370 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); | 368 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); |
371 | } | 369 | } |
372 | EXPORT_SYMBOL(ssb_chipco_gpio_outen); | ||
373 | 370 | ||
374 | u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) | 371 | u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) |
375 | { | 372 | { |
376 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); | 373 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); |
377 | } | 374 | } |
378 | EXPORT_SYMBOL(ssb_chipco_gpio_control); | ||
379 | 375 | ||
380 | u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) | 376 | u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) |
381 | { | 377 | { |
382 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); | 378 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); |
383 | } | 379 | } |
384 | EXPORT_SYMBOL(ssb_chipco_gpio_intmask); | ||
385 | 380 | ||
386 | u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) | 381 | u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) |
387 | { | 382 | { |
388 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); | 383 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); |
389 | } | 384 | } |
390 | EXPORT_SYMBOL(ssb_chipco_gpio_polarity); | ||
391 | 385 | ||
392 | #ifdef CONFIG_SSB_SERIAL | 386 | #ifdef CONFIG_SSB_SERIAL |
393 | int ssb_chipco_serial_init(struct ssb_chipcommon *cc, | 387 | int ssb_chipco_serial_init(struct ssb_chipcommon *cc, |
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c index 10c6b287f8bb..c3e1d3e6d610 100644 --- a/drivers/ssb/driver_extif.c +++ b/drivers/ssb/driver_extif.c | |||
@@ -122,30 +122,25 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) | |||
122 | { | 122 | { |
123 | return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; | 123 | return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; |
124 | } | 124 | } |
125 | EXPORT_SYMBOL(ssb_extif_gpio_in); | ||
126 | 125 | ||
127 | u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) | 126 | u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) |
128 | { | 127 | { |
129 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), | 128 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), |
130 | mask, value); | 129 | mask, value); |
131 | } | 130 | } |
132 | EXPORT_SYMBOL(ssb_extif_gpio_out); | ||
133 | 131 | ||
134 | u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) | 132 | u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) |
135 | { | 133 | { |
136 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), | 134 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), |
137 | mask, value); | 135 | mask, value); |
138 | } | 136 | } |
139 | EXPORT_SYMBOL(ssb_extif_gpio_outen); | ||
140 | 137 | ||
141 | u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) | 138 | u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) |
142 | { | 139 | { |
143 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); | 140 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); |
144 | } | 141 | } |
145 | EXPORT_SYMBOL(ssb_extif_gpio_polarity); | ||
146 | 142 | ||
147 | u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) | 143 | u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) |
148 | { | 144 | { |
149 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); | 145 | return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); |
150 | } | 146 | } |
151 | EXPORT_SYMBOL(ssb_extif_gpio_intmask); | ||
diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index 751f58ac612c..d3ade821555c 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <linux/ssb/ssb.h> | 11 | #include <linux/ssb/ssb.h> |
12 | #include <linux/ssb/ssb_embedded.h> | 12 | #include <linux/ssb/ssb_embedded.h> |
13 | 13 | ||
14 | #include "ssb_private.h" | ||
15 | |||
14 | 16 | ||
15 | int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) | 17 | int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) |
16 | { | 18 | { |
@@ -24,3 +26,107 @@ int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks) | |||
24 | } | 26 | } |
25 | return -ENODEV; | 27 | return -ENODEV; |
26 | } | 28 | } |
29 | |||
30 | u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask) | ||
31 | { | ||
32 | unsigned long flags; | ||
33 | u32 res = 0; | ||
34 | |||
35 | spin_lock_irqsave(&bus->gpio_lock, flags); | ||
36 | if (ssb_chipco_available(&bus->chipco)) | ||
37 | res = ssb_chipco_gpio_in(&bus->chipco, mask); | ||
38 | else if (ssb_extif_available(&bus->extif)) | ||
39 | res = ssb_extif_gpio_in(&bus->extif, mask); | ||
40 | else | ||
41 | SSB_WARN_ON(1); | ||
42 | spin_unlock_irqrestore(&bus->gpio_lock, flags); | ||
43 | |||
44 | return res; | ||
45 | } | ||
46 | EXPORT_SYMBOL(ssb_gpio_in); | ||
47 | |||
48 | u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | u32 res = 0; | ||
52 | |||
53 | spin_lock_irqsave(&bus->gpio_lock, flags); | ||
54 | if (ssb_chipco_available(&bus->chipco)) | ||
55 | res = ssb_chipco_gpio_out(&bus->chipco, mask, value); | ||
56 | else if (ssb_extif_available(&bus->extif)) | ||
57 | res = ssb_extif_gpio_out(&bus->extif, mask, value); | ||
58 | else | ||
59 | SSB_WARN_ON(1); | ||
60 | spin_unlock_irqrestore(&bus->gpio_lock, flags); | ||
61 | |||
62 | return res; | ||
63 | } | ||
64 | EXPORT_SYMBOL(ssb_gpio_out); | ||
65 | |||
66 | u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value) | ||
67 | { | ||
68 | unsigned long flags; | ||
69 | u32 res = 0; | ||
70 | |||
71 | spin_lock_irqsave(&bus->gpio_lock, flags); | ||
72 | if (ssb_chipco_available(&bus->chipco)) | ||
73 | res = ssb_chipco_gpio_outen(&bus->chipco, mask, value); | ||
74 | else if (ssb_extif_available(&bus->extif)) | ||
75 | res = ssb_extif_gpio_outen(&bus->extif, mask, value); | ||
76 | else | ||
77 | SSB_WARN_ON(1); | ||
78 | spin_unlock_irqrestore(&bus->gpio_lock, flags); | ||
79 | |||
80 | return res; | ||
81 | } | ||
82 | EXPORT_SYMBOL(ssb_gpio_outen); | ||
83 | |||
84 | u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value) | ||
85 | { | ||
86 | unsigned long flags; | ||
87 | u32 res = 0; | ||
88 | |||
89 | spin_lock_irqsave(&bus->gpio_lock, flags); | ||
90 | if (ssb_chipco_available(&bus->chipco)) | ||
91 | res = ssb_chipco_gpio_control(&bus->chipco, mask, value); | ||
92 | spin_unlock_irqrestore(&bus->gpio_lock, flags); | ||
93 | |||
94 | return res; | ||
95 | } | ||
96 | EXPORT_SYMBOL(ssb_gpio_control); | ||
97 | |||
98 | u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value) | ||
99 | { | ||
100 | unsigned long flags; | ||
101 | u32 res = 0; | ||
102 | |||
103 | spin_lock_irqsave(&bus->gpio_lock, flags); | ||
104 | if (ssb_chipco_available(&bus->chipco)) | ||
105 | res = ssb_chipco_gpio_intmask(&bus->chipco, mask, value); | ||
106 | else if (ssb_extif_available(&bus->extif)) | ||
107 | res = ssb_extif_gpio_intmask(&bus->extif, mask, value); | ||
108 | else | ||
109 | SSB_WARN_ON(1); | ||
110 | spin_unlock_irqrestore(&bus->gpio_lock, flags); | ||
111 | |||
112 | return res; | ||
113 | } | ||
114 | EXPORT_SYMBOL(ssb_gpio_intmask); | ||
115 | |||
116 | u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value) | ||
117 | { | ||
118 | unsigned long flags; | ||
119 | u32 res = 0; | ||
120 | |||
121 | spin_lock_irqsave(&bus->gpio_lock, flags); | ||
122 | if (ssb_chipco_available(&bus->chipco)) | ||
123 | res = ssb_chipco_gpio_polarity(&bus->chipco, mask, value); | ||
124 | else if (ssb_extif_available(&bus->extif)) | ||
125 | res = ssb_extif_gpio_polarity(&bus->extif, mask, value); | ||
126 | else | ||
127 | SSB_WARN_ON(1); | ||
128 | spin_unlock_irqrestore(&bus->gpio_lock, flags); | ||
129 | |||
130 | return res; | ||
131 | } | ||
132 | EXPORT_SYMBOL(ssb_gpio_polarity); | ||
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 9028ed5715a1..af07ab22708f 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -569,6 +569,9 @@ static int ssb_bus_register(struct ssb_bus *bus, | |||
569 | 569 | ||
570 | spin_lock_init(&bus->bar_lock); | 570 | spin_lock_init(&bus->bar_lock); |
571 | INIT_LIST_HEAD(&bus->list); | 571 | INIT_LIST_HEAD(&bus->list); |
572 | #ifdef CONFIG_SSB_EMBEDDED | ||
573 | spin_lock_init(&bus->gpio_lock); | ||
574 | #endif | ||
572 | 575 | ||
573 | /* Powerup the bus */ | 576 | /* Powerup the bus */ |
574 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | 577 | err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); |
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 9d5da8b2ccf9..d14c03685717 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h | |||
@@ -283,6 +283,11 @@ struct ssb_bus { | |||
283 | /* Contents of the SPROM. */ | 283 | /* Contents of the SPROM. */ |
284 | struct ssb_sprom sprom; | 284 | struct ssb_sprom sprom; |
285 | 285 | ||
286 | #ifdef CONFIG_SSB_EMBEDDED | ||
287 | /* Lock for GPIO register access. */ | ||
288 | spinlock_t gpio_lock; | ||
289 | #endif /* EMBEDDED */ | ||
290 | |||
286 | /* Internal-only stuff follows. Do not touch. */ | 291 | /* Internal-only stuff follows. Do not touch. */ |
287 | struct list_head list; | 292 | struct list_head list; |
288 | #ifdef CONFIG_SSB_DEBUG | 293 | #ifdef CONFIG_SSB_DEBUG |
diff --git a/include/linux/ssb/ssb_embedded.h b/include/linux/ssb/ssb_embedded.h index 80bd58496450..8d8dedff059d 100644 --- a/include/linux/ssb/ssb_embedded.h +++ b/include/linux/ssb/ssb_embedded.h | |||
@@ -7,4 +7,12 @@ | |||
7 | 7 | ||
8 | extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); | 8 | extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks); |
9 | 9 | ||
10 | /* Generic GPIO API */ | ||
11 | u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask); | ||
12 | u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value); | ||
13 | u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value); | ||
14 | u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value); | ||
15 | u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value); | ||
16 | u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value); | ||
17 | |||
10 | #endif /* LINUX_SSB_EMBEDDED_H_ */ | 18 | #endif /* LINUX_SSB_EMBEDDED_H_ */ |