aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/btmrvl_sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btmrvl_sdio.c')
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c97
1 files changed, 50 insertions, 47 deletions
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 47f0f91..182e553 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -47,6 +47,7 @@
* module_exit function is called.
*/
static u8 user_rmmod;
+static u8 sdio_ireg;
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
.helper = "sd8688_helper.bin",
@@ -555,78 +556,79 @@ exit:
return ret;
}
-static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg)
+static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)
{
- int ret;
- u8 sdio_ireg = 0;
+ ulong flags;
+ u8 ireg;
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
- *ireg = 0;
-
- sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
- if (ret) {
- BT_ERR("sdio_readb: read int status register failed");
- ret = -EIO;
- goto done;
- }
-
- if (sdio_ireg != 0) {
- /*
- * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
- * Clear the interrupt status register and re-enable the
- * interrupt.
- */
- BT_DBG("sdio_ireg = 0x%x", sdio_ireg);
-
- sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
- UP_LD_HOST_INT_STATUS),
- HOST_INTSTATUS_REG, &ret);
- if (ret) {
- BT_ERR("sdio_writeb: clear int status register "
- "failed");
- ret = -EIO;
- goto done;
- }
- }
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ ireg = sdio_ireg;
+ sdio_ireg = 0;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
- if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ sdio_claim_host(card->func);
+ if (ireg & DN_LD_HOST_INT_STATUS) {
if (priv->btmrvl_dev.tx_dnld_rdy)
BT_DBG("tx_done already received: "
- " int_status=0x%x", sdio_ireg);
+ " int_status=0x%x", ireg);
else
priv->btmrvl_dev.tx_dnld_rdy = true;
}
- if (sdio_ireg & UP_LD_HOST_INT_STATUS)
+ if (ireg & UP_LD_HOST_INT_STATUS)
btmrvl_sdio_card_to_host(priv);
- *ireg = sdio_ireg;
-
- ret = 0;
+ sdio_release_host(card->func);
-done:
- return ret;
+ return 0;
}
static void btmrvl_sdio_interrupt(struct sdio_func *func)
{
struct btmrvl_private *priv;
- struct hci_dev *hcidev;
struct btmrvl_sdio_card *card;
+ ulong flags;
u8 ireg = 0;
+ int ret;
card = sdio_get_drvdata(func);
- if (card && card->priv) {
- priv = card->priv;
- hcidev = priv->btmrvl_dev.hcidev;
+ if (!card || !card->priv) {
+ BT_ERR("sbi_interrupt(%p) card or priv is "
+ "NULL, card=%p\n", func, card);
+ return;
+ }
- if (btmrvl_sdio_get_int_status(priv, &ireg))
- BT_ERR("reading HOST_INT_STATUS_REG failed");
- else
- BT_DBG("HOST_INT_STATUS_REG %#x", ireg);
+ priv = card->priv;
- btmrvl_interrupt(priv);
+ ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_readb: read int status register failed");
+ return;
}
+
+ if (ireg != 0) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register and re-enable the
+ * interrupt.
+ */
+ BT_DBG("ireg = 0x%x", ireg);
+
+ sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
+ UP_LD_HOST_INT_STATUS),
+ HOST_INTSTATUS_REG, &ret);
+ if (ret) {
+ BT_ERR("sdio_writeb: clear int status register failed");
+ return;
+ }
+ }
+
+ spin_lock_irqsave(&priv->driver_lock, flags);
+ sdio_ireg |= ireg;
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+ btmrvl_interrupt(priv);
}
static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
@@ -930,6 +932,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
/* Initialize the interface specific function pointers */
priv->hw_host_to_card = btmrvl_sdio_host_to_card;
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
+ priv->hw_process_int_status = btmrvl_sdio_process_int_status;
if (btmrvl_register_hdev(priv)) {
BT_ERR("Register hdev failed!");