diff options
Diffstat (limited to 'drivers/net/wireless/cw1200/cw1200_spi.c')
-rw-r--r-- | drivers/net/wireless/cw1200/cw1200_spi.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index d06376014bcd..f5e6b489ed32 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c | |||
@@ -40,7 +40,9 @@ struct hwbus_priv { | |||
40 | struct cw1200_common *core; | 40 | struct cw1200_common *core; |
41 | const struct cw1200_platform_data_spi *pdata; | 41 | const struct cw1200_platform_data_spi *pdata; |
42 | spinlock_t lock; /* Serialize all bus operations */ | 42 | spinlock_t lock; /* Serialize all bus operations */ |
43 | wait_queue_head_t wq; | ||
43 | int claimed; | 44 | int claimed; |
45 | int irq_disabled; | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) | 48 | #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) |
@@ -197,8 +199,11 @@ static void cw1200_spi_lock(struct hwbus_priv *self) | |||
197 | { | 199 | { |
198 | unsigned long flags; | 200 | unsigned long flags; |
199 | 201 | ||
202 | DECLARE_WAITQUEUE(wait, current); | ||
203 | |||
200 | might_sleep(); | 204 | might_sleep(); |
201 | 205 | ||
206 | add_wait_queue(&self->wq, &wait); | ||
202 | spin_lock_irqsave(&self->lock, flags); | 207 | spin_lock_irqsave(&self->lock, flags); |
203 | while (1) { | 208 | while (1) { |
204 | set_current_state(TASK_UNINTERRUPTIBLE); | 209 | set_current_state(TASK_UNINTERRUPTIBLE); |
@@ -211,6 +216,7 @@ static void cw1200_spi_lock(struct hwbus_priv *self) | |||
211 | set_current_state(TASK_RUNNING); | 216 | set_current_state(TASK_RUNNING); |
212 | self->claimed = 1; | 217 | self->claimed = 1; |
213 | spin_unlock_irqrestore(&self->lock, flags); | 218 | spin_unlock_irqrestore(&self->lock, flags); |
219 | remove_wait_queue(&self->wq, &wait); | ||
214 | 220 | ||
215 | return; | 221 | return; |
216 | } | 222 | } |
@@ -222,6 +228,8 @@ static void cw1200_spi_unlock(struct hwbus_priv *self) | |||
222 | spin_lock_irqsave(&self->lock, flags); | 228 | spin_lock_irqsave(&self->lock, flags); |
223 | self->claimed = 0; | 229 | self->claimed = 0; |
224 | spin_unlock_irqrestore(&self->lock, flags); | 230 | spin_unlock_irqrestore(&self->lock, flags); |
231 | wake_up(&self->wq); | ||
232 | |||
225 | return; | 233 | return; |
226 | } | 234 | } |
227 | 235 | ||
@@ -230,6 +238,8 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) | |||
230 | struct hwbus_priv *self = dev_id; | 238 | struct hwbus_priv *self = dev_id; |
231 | 239 | ||
232 | if (self->core) { | 240 | if (self->core) { |
241 | disable_irq_nosync(self->func->irq); | ||
242 | self->irq_disabled = 1; | ||
233 | cw1200_irq_handler(self->core); | 243 | cw1200_irq_handler(self->core); |
234 | return IRQ_HANDLED; | 244 | return IRQ_HANDLED; |
235 | } else { | 245 | } else { |
@@ -263,13 +273,22 @@ exit: | |||
263 | 273 | ||
264 | static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) | 274 | static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) |
265 | { | 275 | { |
266 | int ret = 0; | ||
267 | |||
268 | pr_debug("SW IRQ unsubscribe\n"); | 276 | pr_debug("SW IRQ unsubscribe\n"); |
269 | disable_irq_wake(self->func->irq); | 277 | disable_irq_wake(self->func->irq); |
270 | free_irq(self->func->irq, self); | 278 | free_irq(self->func->irq, self); |
271 | 279 | ||
272 | return ret; | 280 | return 0; |
281 | } | ||
282 | |||
283 | static int cw1200_spi_irq_enable(struct hwbus_priv *self, int enable) | ||
284 | { | ||
285 | /* Disables are handled by the interrupt handler */ | ||
286 | if (enable && self->irq_disabled) { | ||
287 | enable_irq(self->func->irq); | ||
288 | self->irq_disabled = 0; | ||
289 | } | ||
290 | |||
291 | return 0; | ||
273 | } | 292 | } |
274 | 293 | ||
275 | static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) | 294 | static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) |
@@ -349,6 +368,7 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = { | |||
349 | .unlock = cw1200_spi_unlock, | 368 | .unlock = cw1200_spi_unlock, |
350 | .align_size = cw1200_spi_align_size, | 369 | .align_size = cw1200_spi_align_size, |
351 | .power_mgmt = cw1200_spi_pm, | 370 | .power_mgmt = cw1200_spi_pm, |
371 | .irq_enable = cw1200_spi_irq_enable, | ||
352 | }; | 372 | }; |
353 | 373 | ||
354 | /* Probe Function to be called by SPI stack when device is discovered */ | 374 | /* Probe Function to be called by SPI stack when device is discovered */ |
@@ -400,6 +420,8 @@ static int cw1200_spi_probe(struct spi_device *func) | |||
400 | 420 | ||
401 | spi_set_drvdata(func, self); | 421 | spi_set_drvdata(func, self); |
402 | 422 | ||
423 | init_waitqueue_head(&self->wq); | ||
424 | |||
403 | status = cw1200_spi_irq_subscribe(self); | 425 | status = cw1200_spi_irq_subscribe(self); |
404 | 426 | ||
405 | status = cw1200_core_probe(&cw1200_spi_hwbus_ops, | 427 | status = cw1200_core_probe(&cw1200_spi_hwbus_ops, |