|
@@ -47,6 +47,7 @@
|
|
* module_exit function is called.
|
|
* module_exit function is called.
|
|
*/
|
|
*/
|
|
static u8 user_rmmod;
|
|
static u8 user_rmmod;
|
|
|
|
+static u8 sdio_ireg;
|
|
|
|
|
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
|
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
|
|
.helper = "sd8688_helper.bin",
|
|
.helper = "sd8688_helper.bin",
|
|
@@ -555,78 +556,79 @@ exit:
|
|
return ret;
|
|
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;
|
|
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)
|
|
if (priv->btmrvl_dev.tx_dnld_rdy)
|
|
BT_DBG("tx_done already received: "
|
|
BT_DBG("tx_done already received: "
|
|
- " int_status=0x%x", sdio_ireg);
|
|
|
|
|
|
+ " int_status=0x%x", ireg);
|
|
else
|
|
else
|
|
priv->btmrvl_dev.tx_dnld_rdy = true;
|
|
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);
|
|
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)
|
|
static void btmrvl_sdio_interrupt(struct sdio_func *func)
|
|
{
|
|
{
|
|
struct btmrvl_private *priv;
|
|
struct btmrvl_private *priv;
|
|
- struct hci_dev *hcidev;
|
|
|
|
struct btmrvl_sdio_card *card;
|
|
struct btmrvl_sdio_card *card;
|
|
|
|
+ ulong flags;
|
|
u8 ireg = 0;
|
|
u8 ireg = 0;
|
|
|
|
+ int ret;
|
|
|
|
|
|
card = sdio_get_drvdata(func);
|
|
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)
|
|
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 */
|
|
/* Initialize the interface specific function pointers */
|
|
priv->hw_host_to_card = btmrvl_sdio_host_to_card;
|
|
priv->hw_host_to_card = btmrvl_sdio_host_to_card;
|
|
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
|
|
priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
|
|
|
|
+ priv->hw_process_int_status = btmrvl_sdio_process_int_status;
|
|
|
|
|
|
if (btmrvl_register_hdev(priv)) {
|
|
if (btmrvl_register_hdev(priv)) {
|
|
BT_ERR("Register hdev failed!");
|
|
BT_ERR("Register hdev failed!");
|