These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / wilc1000 / wilc_sdio.c
diff --git a/kernel/drivers/staging/wilc1000/wilc_sdio.c b/kernel/drivers/staging/wilc1000/wilc_sdio.c
new file mode 100644 (file)
index 0000000..300c571
--- /dev/null
@@ -0,0 +1,1014 @@
+/* ////////////////////////////////////////////////////////////////////////// */
+/*  */
+/* Copyright (c) Atmel Corporation.  All rights reserved. */
+/*  */
+/* Module Name:  wilc_sdio.c */
+/*  */
+/*  */
+/* //////////////////////////////////////////////////////////////////////////// */
+
+#include <linux/string.h>
+#include "wilc_wlan_if.h"
+#include "wilc_wlan.h"
+
+#define WILC_SDIO_BLOCK_SIZE 512
+
+typedef struct {
+       void *os_context;
+       u32 block_size;
+       int (*sdio_cmd52)(sdio_cmd52_t *);
+       int (*sdio_cmd53)(sdio_cmd53_t *);
+       int (*sdio_set_max_speed)(void);
+       int (*sdio_set_default_speed)(void);
+       wilc_debug_func dPrint;
+       int nint;
+#define MAX_NUN_INT_THRPT_ENH2 (5) /* Max num interrupts allowed in registers 0xf7, 0xf8 */
+       int has_thrpt_enh3;
+} wilc_sdio_t;
+
+static wilc_sdio_t g_sdio;
+
+#ifdef WILC_SDIO_IRQ_GPIO
+static int sdio_write_reg(u32 addr, u32 data);
+static int sdio_read_reg(u32 addr, u32 *data);
+#endif
+
+/********************************************
+ *
+ *      Function 0
+ *
+ ********************************************/
+
+static int sdio_set_func0_csa_address(u32 adr)
+{
+       sdio_cmd52_t cmd;
+
+       /**
+        *      Review: BIG ENDIAN
+        **/
+       cmd.read_write = 1;
+       cmd.function = 0;
+       cmd.raw = 0;
+       cmd.address = 0x10c;
+       cmd.data = (u8)adr;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n");
+               goto _fail_;
+       }
+
+       cmd.address = 0x10d;
+       cmd.data = (u8)(adr >> 8);
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10d data...\n");
+               goto _fail_;
+       }
+
+       cmd.address = 0x10e;
+       cmd.data = (u8)(adr >> 16);
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10e data...\n");
+               goto _fail_;
+       }
+
+       return 1;
+_fail_:
+       return 0;
+}
+
+static int sdio_set_func0_block_size(u32 block_size)
+{
+       sdio_cmd52_t cmd;
+
+       cmd.read_write = 1;
+       cmd.function = 0;
+       cmd.raw = 0;
+       cmd.address = 0x10;
+       cmd.data = (u8)block_size;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10 data...\n");
+               goto _fail_;
+       }
+
+       cmd.address = 0x11;
+       cmd.data = (u8)(block_size >> 8);
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x11 data...\n");
+               goto _fail_;
+       }
+
+       return 1;
+_fail_:
+       return 0;
+}
+
+/********************************************
+ *
+ *      Function 1
+ *
+ ********************************************/
+
+static int sdio_set_func1_block_size(u32 block_size)
+{
+       sdio_cmd52_t cmd;
+
+       cmd.read_write = 1;
+       cmd.function = 0;
+       cmd.raw = 0;
+       cmd.address = 0x110;
+       cmd.data = (u8)block_size;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x110 data...\n");
+               goto _fail_;
+       }
+       cmd.address = 0x111;
+       cmd.data = (u8)(block_size >> 8);
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x111 data...\n");
+               goto _fail_;
+       }
+
+       return 1;
+_fail_:
+       return 0;
+}
+
+static int sdio_clear_int(void)
+{
+#ifndef WILC_SDIO_IRQ_GPIO
+       /* u32 sts; */
+       sdio_cmd52_t cmd;
+
+       cmd.read_write = 0;
+       cmd.function = 1;
+       cmd.raw = 0;
+       cmd.address = 0x4;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+
+       return cmd.data;
+#else
+       u32 reg;
+
+       if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, &reg)) {
+               g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0);
+               return 0;
+       }
+       reg &= ~0x1;
+       sdio_write_reg(WILC_HOST_RX_CTRL_0, reg);
+       return 1;
+#endif
+
+}
+
+u32 sdio_xfer_cnt(void)
+{
+       u32 cnt = 0;
+       sdio_cmd52_t cmd;
+
+       cmd.read_write = 0;
+       cmd.function = 1;
+       cmd.raw = 0;
+       cmd.address = 0x1C;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+       cnt = cmd.data;
+
+       cmd.read_write = 0;
+       cmd.function = 1;
+       cmd.raw = 0;
+       cmd.address = 0x1D;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+       cnt |= (cmd.data << 8);
+
+       cmd.read_write = 0;
+       cmd.function = 1;
+       cmd.raw = 0;
+       cmd.address = 0x1E;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+       cnt |= (cmd.data << 16);
+
+       return cnt;
+}
+
+/********************************************
+ *
+ *      Sdio interfaces
+ *
+ ********************************************/
+int sdio_check_bs(void)
+{
+       sdio_cmd52_t cmd;
+
+       /**
+        *      poll until BS is 0
+        **/
+       cmd.read_write = 0;
+       cmd.function = 0;
+       cmd.raw = 0;
+       cmd.address = 0xc;
+       cmd.data = 0;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get BS register...\n");
+               goto _fail_;
+       }
+
+       return 1;
+
+_fail_:
+
+       return 0;
+}
+
+static int sdio_write_reg(u32 addr, u32 data)
+{
+#ifdef BIG_ENDIAN
+       data = BYTE_SWAP(data);
+#endif
+
+       if ((addr >= 0xf0) && (addr <= 0xff)) {
+               sdio_cmd52_t cmd;
+
+               cmd.read_write = 1;
+               cmd.function = 0;
+               cmd.raw = 0;
+               cmd.address = addr;
+               cmd.data = data;
+               if (!g_sdio.sdio_cmd52(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr);
+                       goto _fail_;
+               }
+       } else {
+               sdio_cmd53_t cmd;
+
+               /**
+                *      set the AHB address
+                **/
+               if (!sdio_set_func0_csa_address(addr))
+                       goto _fail_;
+
+               cmd.read_write = 1;
+               cmd.function = 0;
+               cmd.address = 0x10f;
+               cmd.block_mode = 0;
+               cmd.increment = 1;
+               cmd.count = 4;
+               cmd.buffer = (u8 *)&data;
+               cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
+
+               if (!g_sdio.sdio_cmd53(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, write reg (%08x)...\n", addr);
+                       goto _fail_;
+               }
+       }
+
+       return 1;
+
+_fail_:
+
+       return 0;
+}
+
+static int sdio_write(u32 addr, u8 *buf, u32 size)
+{
+       u32 block_size = g_sdio.block_size;
+       sdio_cmd53_t cmd;
+       int nblk, nleft;
+
+       cmd.read_write = 1;
+       if (addr > 0) {
+               /**
+                *      has to be word aligned...
+                **/
+               if (size & 0x3) {
+                       size += 4;
+                       size &= ~0x3;
+               }
+
+               /**
+                *      func 0 access
+                **/
+               cmd.function = 0;
+               cmd.address = 0x10f;
+       } else {
+               /**
+                *      has to be word aligned...
+                **/
+               if (size & 0x3) {
+                       size += 4;
+                       size &= ~0x3;
+               }
+
+               /**
+                *      func 1 access
+                **/
+               cmd.function = 1;
+               cmd.address = 0;
+       }
+
+       nblk = size / block_size;
+       nleft = size % block_size;
+
+       if (nblk > 0) {
+               cmd.block_mode = 1;
+               cmd.increment = 1;
+               cmd.count = nblk;
+               cmd.buffer = buf;
+               cmd.block_size = block_size;
+               if (addr > 0) {
+                       if (!sdio_set_func0_csa_address(addr))
+                               goto _fail_;
+               }
+               if (!g_sdio.sdio_cmd53(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr);
+                       goto _fail_;
+               }
+               if (addr > 0)
+                       addr += nblk * block_size;
+               buf += nblk * block_size;
+       }
+
+       if (nleft > 0) {
+               cmd.block_mode = 0;
+               cmd.increment = 1;
+               cmd.count = nleft;
+               cmd.buffer = buf;
+
+               cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
+
+               if (addr > 0) {
+                       if (!sdio_set_func0_csa_address(addr))
+                               goto _fail_;
+               }
+               if (!g_sdio.sdio_cmd53(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr);
+                       goto _fail_;
+               }
+       }
+
+       return 1;
+
+_fail_:
+
+       return 0;
+}
+
+static int sdio_read_reg(u32 addr, u32 *data)
+{
+       if ((addr >= 0xf0) && (addr <= 0xff)) {
+               sdio_cmd52_t cmd;
+
+               cmd.read_write = 0;
+               cmd.function = 0;
+               cmd.raw = 0;
+               cmd.address = addr;
+               if (!g_sdio.sdio_cmd52(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr);
+                       goto _fail_;
+               }
+               *data = cmd.data;
+       } else {
+               sdio_cmd53_t cmd;
+
+               if (!sdio_set_func0_csa_address(addr))
+                       goto _fail_;
+
+               cmd.read_write = 0;
+               cmd.function = 0;
+               cmd.address = 0x10f;
+               cmd.block_mode = 0;
+               cmd.increment = 1;
+               cmd.count = 4;
+               cmd.buffer = (u8 *)data;
+
+               cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
+
+               if (!g_sdio.sdio_cmd53(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, read reg (%08x)...\n", addr);
+                       goto _fail_;
+               }
+       }
+
+#ifdef BIG_ENDIAN
+       *data = BYTE_SWAP(*data);
+#endif
+
+       return 1;
+
+_fail_:
+
+       return 0;
+}
+
+static int sdio_read(u32 addr, u8 *buf, u32 size)
+{
+       u32 block_size = g_sdio.block_size;
+       sdio_cmd53_t cmd;
+       int nblk, nleft;
+
+       cmd.read_write = 0;
+       if (addr > 0) {
+               /**
+                *      has to be word aligned...
+                **/
+               if (size & 0x3) {
+                       size += 4;
+                       size &= ~0x3;
+               }
+
+               /**
+                *      func 0 access
+                **/
+               cmd.function = 0;
+               cmd.address = 0x10f;
+       } else {
+               /**
+                *      has to be word aligned...
+                **/
+               if (size & 0x3) {
+                       size += 4;
+                       size &= ~0x3;
+               }
+
+               /**
+                *      func 1 access
+                **/
+               cmd.function = 1;
+               cmd.address = 0;
+       }
+
+       nblk = size / block_size;
+       nleft = size % block_size;
+
+       if (nblk > 0) {
+               cmd.block_mode = 1;
+               cmd.increment = 1;
+               cmd.count = nblk;
+               cmd.buffer = buf;
+               cmd.block_size = block_size;
+               if (addr > 0) {
+                       if (!sdio_set_func0_csa_address(addr))
+                               goto _fail_;
+               }
+               if (!g_sdio.sdio_cmd53(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr);
+                       goto _fail_;
+               }
+               if (addr > 0)
+                       addr += nblk * block_size;
+               buf += nblk * block_size;
+       }       /* if (nblk > 0) */
+
+       if (nleft > 0) {
+               cmd.block_mode = 0;
+               cmd.increment = 1;
+               cmd.count = nleft;
+               cmd.buffer = buf;
+
+               cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
+
+               if (addr > 0) {
+                       if (!sdio_set_func0_csa_address(addr))
+                               goto _fail_;
+               }
+               if (!g_sdio.sdio_cmd53(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes read...\n", addr);
+                       goto _fail_;
+               }
+       }
+
+       return 1;
+
+_fail_:
+
+       return 0;
+}
+
+/********************************************
+ *
+ *      Bus interfaces
+ *
+ ********************************************/
+
+static int sdio_deinit(void *pv)
+{
+       return 1;
+}
+
+static int sdio_sync(void)
+{
+       u32 reg;
+
+       /**
+        *      Disable power sequencer
+        **/
+       if (!sdio_read_reg(WILC_MISC, &reg)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n");
+               return 0;
+       }
+
+       reg &= ~BIT(8);
+       if (!sdio_write_reg(WILC_MISC, reg)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n");
+               return 0;
+       }
+
+#ifdef WILC_SDIO_IRQ_GPIO
+       {
+               u32 reg;
+               int ret;
+
+               /**
+                *      interrupt pin mux select
+                **/
+               ret = sdio_read_reg(WILC_PIN_MUX_0, &reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
+                       return 0;
+               }
+               reg |= BIT(8);
+               ret = sdio_write_reg(WILC_PIN_MUX_0, reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
+                       return 0;
+               }
+
+               /**
+                *      interrupt enable
+                **/
+               ret = sdio_read_reg(WILC_INTR_ENABLE, &reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
+                       return 0;
+               }
+               reg |= BIT(16);
+               ret = sdio_write_reg(WILC_INTR_ENABLE, reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
+                       return 0;
+               }
+       }
+#endif
+
+       return 1;
+}
+
+static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func)
+{
+       sdio_cmd52_t cmd;
+       int loop;
+       u32 chipid;
+
+       memset(&g_sdio, 0, sizeof(wilc_sdio_t));
+
+       g_sdio.dPrint = func;
+       g_sdio.os_context = inp->os_context.os_private;
+
+       if (inp->io_func.io_init) {
+               if (!inp->io_func.io_init(g_sdio.os_context)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed io init bus...\n");
+                       return 0;
+               }
+       } else {
+               return 0;
+       }
+
+       g_sdio.sdio_cmd52       = inp->io_func.u.sdio.sdio_cmd52;
+       g_sdio.sdio_cmd53       = inp->io_func.u.sdio.sdio_cmd53;
+       g_sdio.sdio_set_max_speed       = inp->io_func.u.sdio.sdio_set_max_speed;
+       g_sdio.sdio_set_default_speed   = inp->io_func.u.sdio.sdio_set_default_speed;
+
+       /**
+        *      function 0 csa enable
+        **/
+       cmd.read_write = 1;
+       cmd.function = 0;
+       cmd.raw = 1;
+       cmd.address = 0x100;
+       cmd.data = 0x80;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, enable csa...\n");
+               goto _fail_;
+       }
+
+       /**
+        *      function 0 block size
+        **/
+       if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set func 0 block size...\n");
+               goto _fail_;
+       }
+       g_sdio.block_size = WILC_SDIO_BLOCK_SIZE;
+
+       /**
+        *      enable func1 IO
+        **/
+       cmd.read_write = 1;
+       cmd.function = 0;
+       cmd.raw = 1;
+       cmd.address = 0x2;
+       cmd.data = 0x2;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio] Fail cmd 52, set IOE register...\n");
+               goto _fail_;
+       }
+
+       /**
+        *      make sure func 1 is up
+        **/
+       cmd.read_write = 0;
+       cmd.function = 0;
+       cmd.raw = 0;
+       cmd.address = 0x3;
+       loop = 3;
+       do {
+               cmd.data = 0;
+               if (!g_sdio.sdio_cmd52(&cmd)) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get IOR register...\n");
+                       goto _fail_;
+               }
+               if (cmd.data == 0x2)
+                       break;
+       } while (loop--);
+
+       if (loop <= 0) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail func 1 is not ready...\n");
+               goto _fail_;
+       }
+
+       /**
+        *      func 1 is ready, set func 1 block size
+        **/
+       if (!sdio_set_func1_block_size(WILC_SDIO_BLOCK_SIZE)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail set func 1 block size...\n");
+               goto _fail_;
+       }
+
+       /**
+        *      func 1 interrupt enable
+        **/
+       cmd.read_write = 1;
+       cmd.function = 0;
+       cmd.raw = 1;
+       cmd.address = 0x4;
+       cmd.data = 0x3;
+       if (!g_sdio.sdio_cmd52(&cmd)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set IEN register...\n");
+               goto _fail_;
+       }
+
+       /**
+        *      make sure can read back chip id correctly
+        **/
+       if (!sdio_read_reg(0x1000, &chipid)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd read chip id...\n");
+               goto _fail_;
+       }
+       g_sdio.dPrint(N_ERR, "[wilc sdio]: chipid (%08x)\n", chipid);
+       if ((chipid & 0xfff) > 0x2a0)
+               g_sdio.has_thrpt_enh3 = 1;
+       else
+               g_sdio.has_thrpt_enh3 = 0;
+       g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3);
+
+       return 1;
+
+_fail_:
+
+       return 0;
+}
+
+static void sdio_set_max_speed(void)
+{
+       g_sdio.sdio_set_max_speed();
+}
+
+static void sdio_set_default_speed(void)
+{
+       g_sdio.sdio_set_default_speed();
+}
+
+static int sdio_read_size(u32 *size)
+{
+
+       u32 tmp;
+       sdio_cmd52_t cmd;
+
+       /**
+        *      Read DMA count in words
+        **/
+       cmd.read_write = 0;
+       cmd.function = 0;
+       cmd.raw = 0;
+       cmd.address = 0xf2;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+       tmp = cmd.data;
+
+       /* cmd.read_write = 0; */
+       /* cmd.function = 0; */
+       /* cmd.raw = 0; */
+       cmd.address = 0xf3;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+       tmp |= (cmd.data << 8);
+
+       *size = tmp;
+       return 1;
+}
+
+static int sdio_read_int(u32 *int_status)
+{
+
+       u32 tmp;
+       sdio_cmd52_t cmd;
+
+       sdio_read_size(&tmp);
+
+       /**
+        *      Read IRQ flags
+        **/
+#ifndef WILC_SDIO_IRQ_GPIO
+       cmd.function = 1;
+       cmd.address = 0x04;
+       cmd.data = 0;
+       g_sdio.sdio_cmd52(&cmd);
+
+       if (cmd.data & BIT(0))
+               tmp |= INT_0;
+       if (cmd.data & BIT(2))
+               tmp |= INT_1;
+       if (cmd.data & BIT(3))
+               tmp |= INT_2;
+       if (cmd.data & BIT(4))
+               tmp |= INT_3;
+       if (cmd.data & BIT(5))
+               tmp |= INT_4;
+       if (cmd.data & BIT(6))
+               tmp |= INT_5;
+       {
+               int i;
+
+               for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
+                       if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) {
+                               g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt (1) : tmp=%x, data=%x\n", tmp, cmd.data);
+                               break;
+                       }
+               }
+       }
+#else
+       {
+               u32 irq_flags;
+
+               cmd.read_write = 0;
+               cmd.function = 0;
+               cmd.raw = 0;
+               cmd.address = 0xf7;
+               cmd.data = 0;
+               g_sdio.sdio_cmd52(&cmd);
+               irq_flags = cmd.data & 0x1f;
+               tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET);
+       }
+
+#endif
+
+       *int_status = tmp;
+
+       return 1;
+}
+
+static int sdio_clear_int_ext(u32 val)
+{
+       int ret;
+
+       if (g_sdio.has_thrpt_enh3) {
+               u32 reg;
+
+#ifdef WILC_SDIO_IRQ_GPIO
+               {
+                       u32 flags;
+
+                       flags = val & (BIT(MAX_NUN_INT_THRPT_ENH2) - 1);
+                       reg = flags;
+               }
+#else
+               reg = 0;
+#endif
+               /* select VMM table 0 */
+               if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
+                       reg |= BIT(5);
+               /* select VMM table 1 */
+               if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
+                       reg |= BIT(6);
+               /* enable VMM */
+               if ((val & EN_VMM) == EN_VMM)
+                       reg |= BIT(7);
+               if (reg) {
+                       sdio_cmd52_t cmd;
+
+                       cmd.read_write = 1;
+                       cmd.function = 0;
+                       cmd.raw = 0;
+                       cmd.address = 0xf8;
+                       cmd.data = reg;
+
+                       ret = g_sdio.sdio_cmd52(&cmd);
+                       if (!ret) {
+                               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__);
+                               goto _fail_;
+                       }
+
+               }
+       } else {
+#ifdef WILC_SDIO_IRQ_GPIO
+               {
+                       /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
+                       /* Cannot clear multiple interrupts. Must clear each interrupt individually */
+                       u32 flags;
+
+                       flags = val & (BIT(MAX_NUM_INT) - 1);
+                       if (flags) {
+                               int i;
+
+                               ret = 1;
+                               for (i = 0; i < g_sdio.nint; i++) {
+                                       if (flags & 1) {
+                                               sdio_cmd52_t cmd;
+
+                                               cmd.read_write = 1;
+                                               cmd.function = 0;
+                                               cmd.raw = 0;
+                                               cmd.address = 0xf8;
+                                               cmd.data = BIT(i);
+
+                                               ret = g_sdio.sdio_cmd52(&cmd);
+                                               if (!ret) {
+                                                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__);
+                                                       goto _fail_;
+                                               }
+
+                                       }
+                                       if (!ret)
+                                               break;
+                                       flags >>= 1;
+                               }
+                               if (!ret)
+                                       goto _fail_;
+                               for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
+                                       if (flags & 1)
+                                               g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt cleared %d...\n", i);
+                                       flags >>= 1;
+                               }
+                       }
+               }
+#endif /* WILC_SDIO_IRQ_GPIO */
+
+               {
+                       u32 vmm_ctl;
+
+                       vmm_ctl = 0;
+                       /* select VMM table 0 */
+                       if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
+                               vmm_ctl |= BIT(0);
+                       /* select VMM table 1 */
+                       if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
+                               vmm_ctl |= BIT(1);
+                       /* enable VMM */
+                       if ((val & EN_VMM) == EN_VMM)
+                               vmm_ctl |= BIT(2);
+
+                       if (vmm_ctl) {
+                               sdio_cmd52_t cmd;
+
+                               cmd.read_write = 1;
+                               cmd.function = 0;
+                               cmd.raw = 0;
+                               cmd.address = 0xf6;
+                               cmd.data = vmm_ctl;
+                               ret = g_sdio.sdio_cmd52(&cmd);
+                               if (!ret) {
+                                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf6 data (%d) ...\n", __LINE__);
+                                       goto _fail_;
+                               }
+                       }
+               }
+       }
+
+       return 1;
+_fail_:
+       return 0;
+}
+
+static int sdio_sync_ext(int nint /*  how mant interrupts to enable. */)
+{
+       u32 reg;
+
+       if (nint > MAX_NUM_INT) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Too many interupts (%d)...\n", nint);
+               return 0;
+       }
+       if (nint > MAX_NUN_INT_THRPT_ENH2) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Error: Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n");
+               return 0;
+       }
+
+       g_sdio.nint = nint;
+
+       /**
+        *      Disable power sequencer
+        **/
+       if (!sdio_read_reg(WILC_MISC, &reg)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n");
+               return 0;
+       }
+
+       reg &= ~BIT(8);
+       if (!sdio_write_reg(WILC_MISC, reg)) {
+               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n");
+               return 0;
+       }
+
+#ifdef WILC_SDIO_IRQ_GPIO
+       {
+               u32 reg;
+               int ret, i;
+
+               /**
+                *      interrupt pin mux select
+                **/
+               ret = sdio_read_reg(WILC_PIN_MUX_0, &reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0);
+                       return 0;
+               }
+               reg |= BIT(8);
+               ret = sdio_write_reg(WILC_PIN_MUX_0, reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0);
+                       return 0;
+               }
+
+               /**
+                *      interrupt enable
+                **/
+               ret = sdio_read_reg(WILC_INTR_ENABLE, &reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE);
+                       return 0;
+               }
+
+               for (i = 0; (i < 5) && (nint > 0); i++, nint--)
+                       reg |= BIT((27 + i));
+               ret = sdio_write_reg(WILC_INTR_ENABLE, reg);
+               if (!ret) {
+                       g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE);
+                       return 0;
+               }
+               if (nint) {
+                       ret = sdio_read_reg(WILC_INTR2_ENABLE, &reg);
+                       if (!ret) {
+                               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE);
+                               return 0;
+                       }
+
+                       for (i = 0; (i < 3) && (nint > 0); i++, nint--)
+                               reg |= BIT(i);
+
+                       ret = sdio_read_reg(WILC_INTR2_ENABLE, &reg);
+                       if (!ret) {
+                               g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE);
+                               return 0;
+                       }
+               }
+       }
+#endif /* WILC_SDIO_IRQ_GPIO */
+       return 1;
+}
+
+/********************************************
+ *
+ *      Global sdio HIF function table
+ *
+ ********************************************/
+
+wilc_hif_func_t hif_sdio = {
+       sdio_init,
+       sdio_deinit,
+       sdio_read_reg,
+       sdio_write_reg,
+       sdio_read,
+       sdio_write,
+       sdio_sync,
+       sdio_clear_int,
+       sdio_read_int,
+       sdio_clear_int_ext,
+       sdio_read_size,
+       sdio_write,
+       sdio_read,
+       sdio_sync_ext,
+
+       sdio_set_max_speed,
+       sdio_set_default_speed,
+};
+