summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEyal Reizer <eyalr@ti.com>2015-04-21 09:56:58 +0300
committerVishal Mahaveer <vishalm@ti.com>2015-04-23 16:36:56 -0500
commit0e08f3bddc5ab71d33502cb3feb99ab56d04e4c0 (patch)
treed09c687f8bb3524f27c31fee909600f63498c508
parent635f605e19bb559e23632827c631d5c2ab57b771 (diff)
downloadwlan-0e08f3bddc5ab71d33502cb3feb99ab56d04e4c0.tar.gz
wl18xx: wlan_irq platfform dependent interrupt configuration
* Move interrupt request and type configuration into a seperate function that handles all wlan_irq interrupt related setup. * 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 configuration of interrupt type (level, edge, polarity) based on the irq trigger type that is read from device tree * Allow working with wl18xx level-low and falling edge irqs by configuring wl18xx to invert the device interrupt Change-Id: I14ff9a1009967822adc75abaec6cec5ef9655a23 Signed-off-by: Eyal Reizer <eyalr@ti.com>
-rw-r--r--mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/main.c26
-rw-r--r--mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/reg.h1
-rw-r--r--mac80211/compat_wl18xx/drivers/net/wireless/ti/wlcore/main.c114
3 files changed, 95 insertions, 46 deletions
diff --git a/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/main.c b/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/main.c
index b8fbc070..b02d36a1 100644
--- a/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/main.c
+++ b/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/main.c
@@ -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"
@@ -580,7 +581,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 },
@@ -864,6 +865,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);
@@ -913,6 +915,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;
diff --git a/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/reg.h b/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/reg.h
index a433a75f..bac2364c 100644
--- a/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/reg.h
+++ b/mac80211/compat_wl18xx/drivers/net/wireless/ti/wl18xx/reg.h
@@ -109,6 +109,7 @@
#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
diff --git a/mac80211/compat_wl18xx/drivers/net/wireless/ti/wlcore/main.c b/mac80211/compat_wl18xx/drivers/net/wireless/ti/wlcore/main.c
index 2992aaab..0f9d5b95 100644
--- a/mac80211/compat_wl18xx/drivers/net/wireless/ti/wlcore/main.c
+++ b/mac80211/compat_wl18xx/drivers/net/wireless/ti/wlcore/main.c
@@ -27,6 +27,7 @@
#include <linux/vmalloc.h>
#include <linux/wl12xx.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include "wlcore.h"
#include "debug.h"
@@ -6032,10 +6033,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;
@@ -6051,7 +6048,6 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
ret = wl->ops->get_mac(wl);
out:
- wl1271_power_off(wl);
return ret;
}
@@ -6477,15 +6473,68 @@ static irqreturn_t wlcore_hardirq(int irq, void *cookie)
return IRQ_WAKE_THREAD;
}
-static void wlcore_nvs_cb(const struct firmware *fw, void *context)
+static int wl12xx_interrupt_config(struct wl1271 *wl)
{
- struct wl1271 *wl = context;
struct platform_device *pdev = wl->pdev;
struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
struct wl12xx_platform_data *pdata = pdev_data->pdata;
unsigned long irqflags;
- int ret;
irq_handler_t hardirq_fn = NULL;
+ int ret;
+
+ wl->irq = platform_get_irq(pdev, 0);
+ wl->platform_quirks = pdata->platform_quirks;
+
+ switch (irq_get_trigger_type(wl->irq)) {
+ case IRQ_TYPE_LEVEL_LOW:
+ irqflags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ irqflags = IRQF_TRIGGER_RISING;
+ hardirq_fn = wlcore_hardirq;
+ wl->platform_quirks |= WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ irqflags = IRQF_TRIGGER_FALLING;
+ hardirq_fn = wlcore_hardirq;
+ wl->platform_quirks |= WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
+ break;
+ default:
+ wl1271_error("invalid interrupt trigger type");
+ return -EOPNOTSUPP;
+ }
+
+ ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
+ irqflags, pdev->name, wl);
+ if (ret < 0) {
+ wl1271_error("request_irq() failed: %d", ret);
+ goto out;
+ }
+
+#ifdef CONFIG_PM
+ ret = enable_irq_wake(wl->irq);
+ if (!ret) {
+ wl->irq_wake_enabled = true;
+ device_init_wakeup(wl->dev, 1);
+ if (pdata->pwr_in_suspend)
+ wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
+ }
+#endif
+ disable_irq(wl->irq);
+
+out:
+ return ret;
+}
+
+static void wlcore_nvs_cb(const struct firmware *fw, void *context)
+{
+ struct wl1271 *wl = context;
+ struct platform_device *pdev = wl->pdev;
+ struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
+ int ret;
if (fw) {
wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
@@ -6510,53 +6559,28 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
/* adjust some runtime configuration parameters */
wlcore_adjust_conf(wl);
- wl->irq = platform_get_irq(pdev, 0);
- wl->platform_quirks = pdata->platform_quirks;
wl->if_ops = pdev_data->if_ops;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
- irqflags = IRQF_TRIGGER_RISING;
- hardirq_fn = wlcore_hardirq;
-#else
- if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) {
- irqflags = IRQF_TRIGGER_RISING;
- hardirq_fn = wlcore_hardirq;
- } else {
- irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
- }
-#endif
+ ret = wl12xx_set_power_on(wl);
+ if (ret < 0)
+ goto out_free_nvs;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
- ret = compat_request_threaded_irq(&wl->irq_compat, wl->irq,
- hardirq_fn, wlcore_irq,
- irqflags,
- pdev->name, wl);
-#else
- ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
- irqflags, pdev->name, wl);
-#endif
+ ret = wl12xx_get_hw_info(wl);
if (ret < 0) {
- wl1271_error("request_irq() failed: %d", ret);
+ wl1271_error("couldn't get hw info");
+ wl1271_power_off(wl);
goto out_free_nvs;
}
-#ifdef CONFIG_PM
- ret = enable_irq_wake(wl->irq);
- if (!ret) {
- wl->irq_wake_enabled = true;
- device_init_wakeup(wl->dev, 1);
- if (pdata->pwr_in_suspend)
- wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
- }
-#endif
- disable_irq(wl->irq);
-
- ret = wl12xx_get_hw_info(wl);
+ ret = wl12xx_interrupt_config(wl);
if (ret < 0) {
- wl1271_error("couldn't get hw info");
- goto out_irq;
+ wl1271_error("interrupt configuration failed");
+ wl1271_power_off(wl);
+ goto out_free_nvs;
}
+ wl1271_power_off(wl);
+
ret = wl->ops->identify_chip(wl);
if (ret < 0)
goto out_irq;