diff options
author | Eyal Reizer <eyalr@ti.com> | 2015-04-21 09:56:58 +0300 |
---|---|---|
committer | Vishal Mahaveer <vishalm@ti.com> | 2015-04-23 16:36:56 -0500 |
commit | 0e08f3bddc5ab71d33502cb3feb99ab56d04e4c0 (patch) | |
tree | d09c687f8bb3524f27c31fee909600f63498c508 | |
parent | 635f605e19bb559e23632827c631d5c2ab57b771 (diff) | |
download | wlan-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>
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; |