wl18xx: wlan_irq: support platform dependent interrupt types
authorEyal Reizer <eyalreizer@gmail.com>
Wed, 29 Apr 2015 14:50:03 +0000 (17:50 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Sat, 9 May 2015 13:42:27 +0000 (16:42 +0300)
* Interrupt request need to happen when the wilink chip is powered on and
  driving the wlan_irq line. This avoids spurious interrupt issues that
  are a result of different external pulls configuration on different
  platforms
* Allow working with wl18xx level-low and falling edge irqs by configuring
  wl18xx to invert the device interrupt

Signed-off-by: Eyal Reizer <eyalr@ti.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wl18xx/reg.h
drivers/net/wireless/ti/wlcore/main.c

index 717c4f5a02c2a28ce9d7f0cab1fb70bda6121ace..dc48448b76c01f68852f8f94d1af60c3b31ccfe6 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/ip.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
+#include <linux/irq.h>
 
 #include "../wlcore/wlcore.h"
 #include "../wlcore/debug.h"
@@ -578,7 +579,7 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
 
 static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
        [PART_TOP_PRCM_ELP_SOC] = {
-               .mem  = { .start = 0x00A02000, .size  = 0x00010000 },
+               .mem  = { .start = 0x00A00000, .size  = 0x00012000 },
                .reg  = { .start = 0x00807000, .size  = 0x00005000 },
                .mem2 = { .start = 0x00800000, .size  = 0x0000B000 },
                .mem3 = { .start = 0x00000000, .size  = 0x00000000 },
@@ -862,6 +863,7 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
 {
        u32 tmp;
        int ret;
+       u16 irq_invert;
 
        BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
                WL18XX_PHY_INIT_MEM_SIZE);
@@ -911,6 +913,28 @@ static int wl18xx_pre_upload(struct wl1271 *wl)
        /* re-enable FDSP clock */
        ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
                             MEM_FDSP_CLK_120_ENABLE);
+       if (ret < 0)
+               goto out;
+
+       ret = irq_get_trigger_type(wl->irq);
+       if ((ret == IRQ_TYPE_LEVEL_LOW) || (ret == IRQ_TYPE_EDGE_FALLING)) {
+               wl1271_info("using inverted interrupt logic: %d", ret);
+               ret = wlcore_set_partition(wl,
+                                          &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+               if (ret < 0)
+                       goto out;
+
+               ret = wl18xx_top_reg_read(wl, TOP_FN0_CCCR_REG_32, &irq_invert);
+               if (ret < 0)
+                       goto out;
+
+               irq_invert |= BIT(1);
+               ret = wl18xx_top_reg_write(wl, TOP_FN0_CCCR_REG_32, irq_invert);
+               if (ret < 0)
+                       goto out;
+
+               ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
+       }
 
 out:
        return ret;
index a433a75f3cd7c85d51f67cfb8d03830e35c041be..bac2364c8e72d58bdc0cebe0611f0f15da31fe40 100644 (file)
 
 #define WL18XX_WELP_ARM_COMMAND                (WL18XX_REGISTERS_BASE + 0x7100)
 #define WL18XX_ENABLE                  (WL18XX_REGISTERS_BASE + 0x01543C)
+#define TOP_FN0_CCCR_REG_32            (WL18XX_TOP_OCP_BASE + 0x64)
 
 /* PRCM registers */
 #define PLATFORM_DETECTION             0xA0E3E0
index 0be807951afe3bbcca6db42ea98855ff8536254a..c39a07b165917136b7e900fd50c2b6e4d288c6bb 100644 (file)
@@ -5966,10 +5966,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
 {
        int ret;
 
-       ret = wl12xx_set_power_on(wl);
-       if (ret < 0)
-               return ret;
-
        ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
        if (ret < 0)
                goto out;
@@ -5985,7 +5981,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
                ret = wl->ops->get_mac(wl);
 
 out:
-       wl1271_power_off(wl);
        return ret;
 }
 
@@ -6432,10 +6427,22 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
        else
                wl->irq_flags |= IRQF_ONESHOT;
 
+       ret = wl12xx_set_power_on(wl);
+       if (ret < 0)
+               goto out_free_nvs;
+
+       ret = wl12xx_get_hw_info(wl);
+       if (ret < 0) {
+               wl1271_error("couldn't get hw info");
+               wl1271_power_off(wl);
+               goto out_free_nvs;
+       }
+
        ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
                                   wl->irq_flags, pdev->name, wl);
        if (ret < 0) {
-               wl1271_error("request_irq() failed: %d", ret);
+               wl1271_error("interrupt configuration failed");
+               wl1271_power_off(wl);
                goto out_free_nvs;
        }
 
@@ -6449,12 +6456,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
        }
 #endif
        disable_irq(wl->irq);
-
-       ret = wl12xx_get_hw_info(wl);
-       if (ret < 0) {
-               wl1271_error("couldn't get hw info");
-               goto out_irq;
-       }
+       wl1271_power_off(wl);
 
        ret = wl->ops->identify_chip(wl);
        if (ret < 0)