diff options
-rw-r--r-- | drivers/net/wireless/cw1200/cw1200_spi.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/cw1200/fwio.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/cw1200/hwbus.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/cw1200/hwio.c | 15 |
4 files changed, 33 insertions, 4 deletions
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index d06376014bcd..c31580ba883b 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c | |||
@@ -41,6 +41,7 @@ struct hwbus_priv { | |||
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 | int claimed; | 43 | int claimed; |
44 | int irq_disabled; | ||
44 | }; | 45 | }; |
45 | 46 | ||
46 | #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) | 47 | #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) |
@@ -230,6 +231,8 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) | |||
230 | struct hwbus_priv *self = dev_id; | 231 | struct hwbus_priv *self = dev_id; |
231 | 232 | ||
232 | if (self->core) { | 233 | if (self->core) { |
234 | disable_irq_nosync(self->func->irq); | ||
235 | self->irq_disabled = 1; | ||
233 | cw1200_irq_handler(self->core); | 236 | cw1200_irq_handler(self->core); |
234 | return IRQ_HANDLED; | 237 | return IRQ_HANDLED; |
235 | } else { | 238 | } else { |
@@ -263,13 +266,22 @@ exit: | |||
263 | 266 | ||
264 | static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) | 267 | static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) |
265 | { | 268 | { |
266 | int ret = 0; | ||
267 | |||
268 | pr_debug("SW IRQ unsubscribe\n"); | 269 | pr_debug("SW IRQ unsubscribe\n"); |
269 | disable_irq_wake(self->func->irq); | 270 | disable_irq_wake(self->func->irq); |
270 | free_irq(self->func->irq, self); | 271 | free_irq(self->func->irq, self); |
271 | 272 | ||
272 | return ret; | 273 | return 0; |
274 | } | ||
275 | |||
276 | static int cw1200_spi_irq_enable(struct hwbus_priv *self, int enable) | ||
277 | { | ||
278 | /* Disables are handled by the interrupt handler */ | ||
279 | if (enable && self->irq_disabled) { | ||
280 | enable_irq(self->func->irq); | ||
281 | self->irq_disabled = 0; | ||
282 | } | ||
283 | |||
284 | return 0; | ||
273 | } | 285 | } |
274 | 286 | ||
275 | static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) | 287 | static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) |
@@ -349,6 +361,7 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = { | |||
349 | .unlock = cw1200_spi_unlock, | 361 | .unlock = cw1200_spi_unlock, |
350 | .align_size = cw1200_spi_align_size, | 362 | .align_size = cw1200_spi_align_size, |
351 | .power_mgmt = cw1200_spi_pm, | 363 | .power_mgmt = cw1200_spi_pm, |
364 | .irq_enable = cw1200_spi_irq_enable, | ||
352 | }; | 365 | }; |
353 | 366 | ||
354 | /* Probe Function to be called by SPI stack when device is discovered */ | 367 | /* Probe Function to be called by SPI stack when device is discovered */ |
diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index acdff0f7f952..0b2061bbc68b 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c | |||
@@ -485,7 +485,7 @@ int cw1200_load_firmware(struct cw1200_common *priv) | |||
485 | 485 | ||
486 | /* Enable interrupt signalling */ | 486 | /* Enable interrupt signalling */ |
487 | priv->hwbus_ops->lock(priv->hwbus_priv); | 487 | priv->hwbus_ops->lock(priv->hwbus_priv); |
488 | ret = __cw1200_irq_enable(priv, 1); | 488 | ret = __cw1200_irq_enable(priv, 2); |
489 | priv->hwbus_ops->unlock(priv->hwbus_priv); | 489 | priv->hwbus_ops->unlock(priv->hwbus_priv); |
490 | if (ret < 0) | 490 | if (ret < 0) |
491 | goto unsubscribe; | 491 | goto unsubscribe; |
diff --git a/drivers/net/wireless/cw1200/hwbus.h b/drivers/net/wireless/cw1200/hwbus.h index 8b2fc831c3de..51dfb3a90735 100644 --- a/drivers/net/wireless/cw1200/hwbus.h +++ b/drivers/net/wireless/cw1200/hwbus.h | |||
@@ -28,6 +28,7 @@ struct hwbus_ops { | |||
28 | void (*unlock)(struct hwbus_priv *self); | 28 | void (*unlock)(struct hwbus_priv *self); |
29 | size_t (*align_size)(struct hwbus_priv *self, size_t size); | 29 | size_t (*align_size)(struct hwbus_priv *self, size_t size); |
30 | int (*power_mgmt)(struct hwbus_priv *self, bool suspend); | 30 | int (*power_mgmt)(struct hwbus_priv *self, bool suspend); |
31 | int (*irq_enable)(struct hwbus_priv *self, int enable); | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | #endif /* CW1200_HWBUS_H */ | 34 | #endif /* CW1200_HWBUS_H */ |
diff --git a/drivers/net/wireless/cw1200/hwio.c b/drivers/net/wireless/cw1200/hwio.c index ff230b7aeedd..41bd7615ccaa 100644 --- a/drivers/net/wireless/cw1200/hwio.c +++ b/drivers/net/wireless/cw1200/hwio.c | |||
@@ -273,6 +273,21 @@ int __cw1200_irq_enable(struct cw1200_common *priv, int enable) | |||
273 | u16 val16; | 273 | u16 val16; |
274 | int ret; | 274 | int ret; |
275 | 275 | ||
276 | /* We need to do this hack because the SPI layer can sleep on I/O | ||
277 | and the general path involves I/O to the device in interrupt | ||
278 | context. | ||
279 | |||
280 | However, the initial enable call needs to go to the hardware. | ||
281 | |||
282 | We don't worry about shutdown because we do a full reset which | ||
283 | clears the interrupt enabled bits. | ||
284 | */ | ||
285 | if (priv->hwbus_ops->irq_enable) { | ||
286 | ret = priv->hwbus_ops->irq_enable(priv->hwbus_priv, enable); | ||
287 | if (ret || enable < 2) | ||
288 | return ret; | ||
289 | } | ||
290 | |||
276 | if (HIF_8601_SILICON == priv->hw_type) { | 291 | if (HIF_8601_SILICON == priv->hw_type) { |
277 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | 292 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); |
278 | if (ret < 0) { | 293 | if (ret < 0) { |