|
@@ -50,9 +50,6 @@ static struct mwifiex_if_ops sdio_ops;
|
|
|
|
|
|
static struct semaphore add_remove_card_sem;
|
|
|
|
|
|
-static int mwifiex_sdio_resume(struct device *dev);
|
|
|
-static void mwifiex_sdio_interrupt(struct sdio_func *func);
|
|
|
-
|
|
|
/*
|
|
|
* SDIO probe.
|
|
|
*
|
|
@@ -112,6 +109,51 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * SDIO resume.
|
|
|
+ *
|
|
|
+ * Kernel needs to suspend all functions separately. Therefore all
|
|
|
+ * registered functions must have drivers with suspend and resume
|
|
|
+ * methods. Failing that the kernel simply removes the whole card.
|
|
|
+ *
|
|
|
+ * If already not resumed, this function turns on the traffic and
|
|
|
+ * sends a host sleep cancel request to the firmware.
|
|
|
+ */
|
|
|
+static int mwifiex_sdio_resume(struct device *dev)
|
|
|
+{
|
|
|
+ struct sdio_func *func = dev_to_sdio_func(dev);
|
|
|
+ struct sdio_mmc_card *card;
|
|
|
+ struct mwifiex_adapter *adapter;
|
|
|
+ mmc_pm_flag_t pm_flag = 0;
|
|
|
+
|
|
|
+ if (func) {
|
|
|
+ pm_flag = sdio_get_host_pm_caps(func);
|
|
|
+ card = sdio_get_drvdata(func);
|
|
|
+ if (!card || !card->adapter) {
|
|
|
+ pr_err("resume: invalid card or adapter\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ pr_err("resume: sdio_func is not specified\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ adapter = card->adapter;
|
|
|
+
|
|
|
+ if (!adapter->is_suspended) {
|
|
|
+ dev_warn(adapter->dev, "device already resumed\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ adapter->is_suspended = false;
|
|
|
+
|
|
|
+ /* Disable Host Sleep */
|
|
|
+ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
|
|
|
+ MWIFIEX_ASYNC_CMD);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* SDIO remove.
|
|
|
*
|
|
@@ -212,51 +254,6 @@ static int mwifiex_sdio_suspend(struct device *dev)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * SDIO resume.
|
|
|
- *
|
|
|
- * Kernel needs to suspend all functions separately. Therefore all
|
|
|
- * registered functions must have drivers with suspend and resume
|
|
|
- * methods. Failing that the kernel simply removes the whole card.
|
|
|
- *
|
|
|
- * If already not resumed, this function turns on the traffic and
|
|
|
- * sends a host sleep cancel request to the firmware.
|
|
|
- */
|
|
|
-static int mwifiex_sdio_resume(struct device *dev)
|
|
|
-{
|
|
|
- struct sdio_func *func = dev_to_sdio_func(dev);
|
|
|
- struct sdio_mmc_card *card;
|
|
|
- struct mwifiex_adapter *adapter;
|
|
|
- mmc_pm_flag_t pm_flag = 0;
|
|
|
-
|
|
|
- if (func) {
|
|
|
- pm_flag = sdio_get_host_pm_caps(func);
|
|
|
- card = sdio_get_drvdata(func);
|
|
|
- if (!card || !card->adapter) {
|
|
|
- pr_err("resume: invalid card or adapter\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- } else {
|
|
|
- pr_err("resume: sdio_func is not specified\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- adapter = card->adapter;
|
|
|
-
|
|
|
- if (!adapter->is_suspended) {
|
|
|
- dev_warn(adapter->dev, "device already resumed\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- adapter->is_suspended = false;
|
|
|
-
|
|
|
- /* Disable Host Sleep */
|
|
|
- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
|
|
|
- MWIFIEX_ASYNC_CMD);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/* Device ID for SD8786 */
|
|
|
#define SDIO_DEVICE_ID_MARVELL_8786 (0x9116)
|
|
|
/* Device ID for SD8787 */
|
|
@@ -706,6 +703,65 @@ static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
|
|
|
sdio_release_host(func);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This function reads the interrupt status from card.
|
|
|
+ */
|
|
|
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
|
|
|
+{
|
|
|
+ struct sdio_mmc_card *card = adapter->card;
|
|
|
+ u8 sdio_ireg;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (mwifiex_read_data_sync(adapter, card->mp_regs,
|
|
|
+ card->reg->max_mp_regs,
|
|
|
+ REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
|
|
|
+ dev_err(adapter->dev, "read mp_regs failed\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
|
|
|
+ if (sdio_ireg) {
|
|
|
+ /*
|
|
|
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
|
|
|
+ * For SDIO new mode CMD port interrupts
|
|
|
+ * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
|
|
|
+ * UP_LD_CMD_PORT_HOST_INT_STATUS
|
|
|
+ * Clear the interrupt status register
|
|
|
+ */
|
|
|
+ dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
|
|
|
+ spin_lock_irqsave(&adapter->int_lock, flags);
|
|
|
+ adapter->int_status |= sdio_ireg;
|
|
|
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * SDIO interrupt handler.
|
|
|
+ *
|
|
|
+ * This function reads the interrupt status from firmware and handles
|
|
|
+ * the interrupt in current thread (ksdioirqd) right away.
|
|
|
+ */
|
|
|
+static void
|
|
|
+mwifiex_sdio_interrupt(struct sdio_func *func)
|
|
|
+{
|
|
|
+ struct mwifiex_adapter *adapter;
|
|
|
+ struct sdio_mmc_card *card;
|
|
|
+
|
|
|
+ card = sdio_get_drvdata(func);
|
|
|
+ if (!card || !card->adapter) {
|
|
|
+ pr_debug("int: func=%p card=%p adapter=%p\n",
|
|
|
+ func, card, card ? card->adapter : NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ adapter = card->adapter;
|
|
|
+
|
|
|
+ if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
|
|
|
+ adapter->ps_state = PS_STATE_AWAKE;
|
|
|
+
|
|
|
+ mwifiex_interrupt_status(adapter);
|
|
|
+ mwifiex_main_process(adapter);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* This function enables the host interrupt.
|
|
|
*
|
|
@@ -962,65 +1018,6 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * This function reads the interrupt status from card.
|
|
|
- */
|
|
|
-static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
|
|
|
-{
|
|
|
- struct sdio_mmc_card *card = adapter->card;
|
|
|
- u8 sdio_ireg;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- if (mwifiex_read_data_sync(adapter, card->mp_regs,
|
|
|
- card->reg->max_mp_regs,
|
|
|
- REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
|
|
|
- dev_err(adapter->dev, "read mp_regs failed\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
|
|
|
- if (sdio_ireg) {
|
|
|
- /*
|
|
|
- * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
|
|
|
- * For SDIO new mode CMD port interrupts
|
|
|
- * DN_LD_CMD_PORT_HOST_INT_STATUS and/or
|
|
|
- * UP_LD_CMD_PORT_HOST_INT_STATUS
|
|
|
- * Clear the interrupt status register
|
|
|
- */
|
|
|
- dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
|
|
|
- spin_lock_irqsave(&adapter->int_lock, flags);
|
|
|
- adapter->int_status |= sdio_ireg;
|
|
|
- spin_unlock_irqrestore(&adapter->int_lock, flags);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * SDIO interrupt handler.
|
|
|
- *
|
|
|
- * This function reads the interrupt status from firmware and handles
|
|
|
- * the interrupt in current thread (ksdioirqd) right away.
|
|
|
- */
|
|
|
-static void
|
|
|
-mwifiex_sdio_interrupt(struct sdio_func *func)
|
|
|
-{
|
|
|
- struct mwifiex_adapter *adapter;
|
|
|
- struct sdio_mmc_card *card;
|
|
|
-
|
|
|
- card = sdio_get_drvdata(func);
|
|
|
- if (!card || !card->adapter) {
|
|
|
- pr_debug("int: func=%p card=%p adapter=%p\n",
|
|
|
- func, card, card ? card->adapter : NULL);
|
|
|
- return;
|
|
|
- }
|
|
|
- adapter = card->adapter;
|
|
|
-
|
|
|
- if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
|
|
|
- adapter->ps_state = PS_STATE_AWAKE;
|
|
|
-
|
|
|
- mwifiex_interrupt_status(adapter);
|
|
|
- mwifiex_main_process(adapter);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* This function decodes a received packet.
|
|
|
*
|