From 9a0d644f9eb62b9cbf9dbbc9f91a8cebdfa547ca Mon Sep 17 00:00:00 2001 From: Imre Kaloz Date: Wed, 27 Nov 2013 12:40:07 +0000 Subject: [PATCH] add device tree based initialization to wl12xx Signed-off-by: Imre Kaloz SVN-Revision: 38933 --- package/kernel/mac80211/Makefile | 2 +- ...latform-data-to-a-separate-structure.patch | 109 +++++++ ...ore-set-irq_flags-in-the-board-files.patch | 111 +++++++ ...ve-pwr_in_suspend-from-platform-data.patch | 48 +++ ...ead-of-enumerations-for-pdata-clocks.patch | 131 ++++++++ ...vice-tree-support-to-the-sdio-module.patch | 118 +++++++ ...core-sdio-add-wilink-clock-providers.patch | 50 +++ ...ore-sdio-get-clocks-from-device-tree.patch | 90 ++++++ ...if-we-got-correct-clock-data-from-DT.patch | 96 ++++++ ...latform-data-to-a-separate-structure.patch | 198 ++++++++++++ ...ore-set-irq_flags-in-the-board-files.patch | 237 ++++++++++++++ ...ve-pwr_in_suspend-from-platform-data.patch | 65 ++++ ...ead-of-enumerations-for-pdata-clocks.patch | 289 ++++++++++++++++++ ...vice-tree-support-to-the-sdio-module.patch | 122 ++++++++ ...core-sdio-add-wilink-clock-providers.patch | 54 ++++ ...ore-sdio-get-clocks-from-device-tree.patch | 94 ++++++ ...if-we-got-correct-clock-data-from-DT.patch | 101 ++++++ ...tation-dt-bindings-TI-WiLink-modules.patch | 102 +++++++ 18 files changed, 2016 insertions(+), 1 deletion(-) create mode 100644 package/kernel/mac80211/patches/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch create mode 100644 package/kernel/mac80211/patches/901-wlcore-set-irq_flags-in-the-board-files.patch create mode 100644 package/kernel/mac80211/patches/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch create mode 100644 package/kernel/mac80211/patches/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch create mode 100644 package/kernel/mac80211/patches/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch create mode 100644 package/kernel/mac80211/patches/905-wlcore-sdio-add-wilink-clock-providers.patch create mode 100644 package/kernel/mac80211/patches/906-wlcore-sdio-get-clocks-from-device-tree.patch create mode 100644 package/kernel/mac80211/patches/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch create mode 100644 target/linux/omap/patches-3.12/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch create mode 100644 target/linux/omap/patches-3.12/901-wlcore-set-irq_flags-in-the-board-files.patch create mode 100644 target/linux/omap/patches-3.12/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch create mode 100644 target/linux/omap/patches-3.12/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch create mode 100644 target/linux/omap/patches-3.12/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch create mode 100644 target/linux/omap/patches-3.12/905-wlcore-sdio-add-wilink-clock-providers.patch create mode 100644 target/linux/omap/patches-3.12/906-wlcore-sdio-get-clocks-from-device-tree.patch create mode 100644 target/linux/omap/patches-3.12/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch create mode 100644 target/linux/omap/patches-3.12/908-Documentation-dt-bindings-TI-WiLink-modules.patch diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index 399bcf4ec3d6..aafa28bd1e76 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 PKG_VERSION:=2013-11-05 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources PKG_BACKPORT_VERSION:= PKG_MD5SUM:=5ef839d02d19c341629555a529beebee diff --git a/package/kernel/mac80211/patches/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch b/package/kernel/mac80211/patches/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch new file mode 100644 index 000000000000..a8af257c3472 --- /dev/null +++ b/package/kernel/mac80211/patches/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch @@ -0,0 +1,109 @@ +Move the wl1251 part of the wl12xx platform data structure into a new +structure specifically for wl1251. Change the platform data built-in +block and board files accordingly. + +Cc: Tony Lindgren +Signed-off-by: Luciano Coelho +Acked-by: Tony Lindgren +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wilink_platform_data.c ++++ b/drivers/net/wireless/ti/wilink_platform_data.c +@@ -23,17 +23,17 @@ + #include + #include + +-static struct wl12xx_platform_data *platform_data; ++static struct wl12xx_platform_data *wl12xx_platform_data; + + int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) + { +- if (platform_data) ++ if (wl12xx_platform_data) + return -EBUSY; + if (!data) + return -EINVAL; + +- platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); +- if (!platform_data) ++ wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); ++ if (!wl12xx_platform_data) + return -ENOMEM; + + return 0; +@@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(cons + + struct wl12xx_platform_data *wl12xx_get_platform_data(void) + { +- if (!platform_data) ++ if (!wl12xx_platform_data) + return ERR_PTR(-ENODEV); + +- return platform_data; ++ return wl12xx_platform_data; + } + EXPORT_SYMBOL(wl12xx_get_platform_data); ++ ++static struct wl1251_platform_data *wl1251_platform_data; ++ ++int __init wl1251_set_platform_data(const struct wl1251_platform_data *data) ++{ ++ if (wl1251_platform_data) ++ return -EBUSY; ++ if (!data) ++ return -EINVAL; ++ ++ wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); ++ if (!wl1251_platform_data) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++struct wl1251_platform_data *wl1251_get_platform_data(void) ++{ ++ if (!wl1251_platform_data) ++ return ERR_PTR(-ENODEV); ++ ++ return wl1251_platform_data; ++} ++EXPORT_SYMBOL(wl1251_get_platform_data); +--- a/drivers/net/wireless/ti/wl1251/sdio.c ++++ b/drivers/net/wireless/ti/wl1251/sdio.c +@@ -227,7 +227,7 @@ static int wl1251_sdio_probe(struct sdio + struct wl1251 *wl; + struct ieee80211_hw *hw; + struct wl1251_sdio *wl_sdio; +- const struct wl12xx_platform_data *wl12xx_board_data; ++ const struct wl1251_platform_data *wl1251_board_data; + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) +@@ -254,11 +254,11 @@ static int wl1251_sdio_probe(struct sdio + wl->if_priv = wl_sdio; + wl->if_ops = &wl1251_sdio_ops; + +- wl12xx_board_data = wl12xx_get_platform_data(); +- if (!IS_ERR(wl12xx_board_data)) { +- wl->set_power = wl12xx_board_data->set_power; +- wl->irq = wl12xx_board_data->irq; +- wl->use_eeprom = wl12xx_board_data->use_eeprom; ++ wl1251_board_data = wl1251_get_platform_data(); ++ if (!IS_ERR(wl1251_board_data)) { ++ wl->set_power = wl1251_board_data->set_power; ++ wl->irq = wl1251_board_data->irq; ++ wl->use_eeprom = wl1251_board_data->use_eeprom; + } + + if (wl->irq) { +--- a/drivers/net/wireless/ti/wl1251/spi.c ++++ b/drivers/net/wireless/ti/wl1251/spi.c +@@ -241,7 +241,7 @@ static const struct wl1251_if_operations + + static int wl1251_spi_probe(struct spi_device *spi) + { +- struct wl12xx_platform_data *pdata; ++ struct wl1251_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1251 *wl; + int ret; diff --git a/package/kernel/mac80211/patches/901-wlcore-set-irq_flags-in-the-board-files.patch b/package/kernel/mac80211/patches/901-wlcore-set-irq_flags-in-the-board-files.patch new file mode 100644 index 000000000000..1730beab9594 --- /dev/null +++ b/package/kernel/mac80211/patches/901-wlcore-set-irq_flags-in-the-board-files.patch @@ -0,0 +1,111 @@ +The platform_quirk element in the platform data was used to change the +way the IRQ is triggered. When set, the EDGE_IRQ quirk would change +the irqflags used and treat edge trigger differently from the rest. + +Instead of hiding this irq flag setting behind the quirk, have the +board files set the flags during initialization. This will be more +meaningful than driver-specific quirks when we switch to DT. + +Additionally, fix missing gpio_request() calls in the boarding files +(so that setting the flags actually works). + +Cc: Tony Lindgren +Cc: Sekhar Nori +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi +Acked-by: Sekhar Nori + +--- a/drivers/net/wireless/ti/wlcore/debugfs.c ++++ b/drivers/net/wireless/ti/wlcore/debugfs.c +@@ -502,7 +502,7 @@ static ssize_t driver_state_read(struct + DRIVER_STATE_PRINT_HEX(irq); + /* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */ + DRIVER_STATE_PRINT_HEX(hw_pg_ver); +- DRIVER_STATE_PRINT_HEX(platform_quirks); ++ DRIVER_STATE_PRINT_HEX(irq_flags); + DRIVER_STATE_PRINT_HEX(chip.id); + DRIVER_STATE_PRINT_STR(chip.fw_ver_str); + DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); +--- a/drivers/net/wireless/ti/wlcore/main.c ++++ b/drivers/net/wireless/ti/wlcore/main.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "wlcore.h" + #include "debug.h" +@@ -528,7 +529,7 @@ static int wlcore_irq_locked(struct wl12 + * In case edge triggered interrupt must be used, we cannot iterate + * more than once without introducing race conditions with the hardirq. + */ +- if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) ++ if (wl->irq_flags & IRQF_TRIGGER_RISING) + loopcount = 1; + + wl1271_debug(DEBUG_IRQ, "IRQ work"); +@@ -5925,7 +5926,6 @@ struct ieee80211_hw *wlcore_alloc_hw(siz + wl->ap_ps_map = 0; + wl->ap_fw_ps_map = 0; + wl->quirks = 0; +- wl->platform_quirks = 0; + wl->system_hlid = WL12XX_SYSTEM_HLID; + wl->active_sta_count = 0; + wl->active_link_count = 0; +@@ -6066,7 +6066,7 @@ static void wlcore_nvs_cb(const struct f + 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; + +@@ -6094,18 +6094,17 @@ static void wlcore_nvs_cb(const struct f + 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 (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) { +- irqflags = IRQF_TRIGGER_RISING; +- hardirq_fn = wlcore_hardirq; +- } else { +- irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; +- } ++ wl->irq_flags = irq_get_trigger_type(wl->irq); ++ ++ hardirq_fn = wlcore_hardirq; ++ ++ /* Since we don't use the primary handler, we must set ONESHOT */ ++ wl->irq_flags |= IRQF_ONESHOT; + + ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq, +- irqflags, pdev->name, wl); ++ wl->irq_flags, pdev->name, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free_nvs; +--- a/drivers/net/wireless/ti/wlcore/wlcore.h ++++ b/drivers/net/wireless/ti/wlcore/wlcore.h +@@ -186,6 +186,8 @@ struct wl1271 { + + int irq; + ++ int irq_flags; ++ + spinlock_t wl_lock; + + enum wlcore_state state; +@@ -393,9 +395,6 @@ struct wl1271 { + /* Quirks of specific hardware revisions */ + unsigned int quirks; + +- /* Platform limitations */ +- unsigned int platform_quirks; +- + /* number of currently active RX BA sessions */ + int ba_rx_session_count; + diff --git a/package/kernel/mac80211/patches/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch b/package/kernel/mac80211/patches/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch new file mode 100644 index 000000000000..757f59871675 --- /dev/null +++ b/package/kernel/mac80211/patches/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch @@ -0,0 +1,48 @@ +The pwr_in_suspend flag depends on the MMC settings which can be +retrieved from the SDIO subsystem, so it doesn't need to be part of +the platform data structure. Move it to the platform device data that +is passed from SDIO to wlcore. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wlcore/main.c ++++ b/drivers/net/wireless/ti/wlcore/main.c +@@ -6065,7 +6065,6 @@ static void wlcore_nvs_cb(const struct f + 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; + + int ret; + irq_handler_t hardirq_fn = NULL; +@@ -6115,7 +6114,7 @@ static void wlcore_nvs_cb(const struct f + if (!ret) { + wl->irq_wake_enabled = true; + device_init_wakeup(wl->dev, 1); +- if (pdata->pwr_in_suspend) ++ if (pdev_data->pwr_in_suspend) + wl->hw->wiphy->wowlan = &wlcore_wowlan_support; + } + #endif +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -260,7 +260,7 @@ static int wl1271_probe(struct sdio_func + dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); + + if (mmcflags & MMC_PM_KEEP_POWER) +- pdev_data->pdata->pwr_in_suspend = true; ++ pdev_data->pwr_in_suspend = true; + + sdio_set_drvdata(func, glue); + +--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h ++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h +@@ -209,6 +209,7 @@ struct wl1271_if_operations { + struct wlcore_platdev_data { + struct wl12xx_platform_data *pdata; + struct wl1271_if_operations *if_ops; ++ bool pwr_in_suspend; + }; + + #define MAX_NUM_KEYS 14 diff --git a/package/kernel/mac80211/patches/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch b/package/kernel/mac80211/patches/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch new file mode 100644 index 000000000000..4b20932f5387 --- /dev/null +++ b/package/kernel/mac80211/patches/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch @@ -0,0 +1,131 @@ +Instead of defining an enumeration with the FW specific values for the +different clock rates, use the actual frequency instead. Also add a +boolean to specify whether the clock is XTAL or not. + +Change all board files to reflect this. + +Additionally, this reverts commit 26f45c (ARM: OMAP2+: Legacy support +for wl12xx when booted with devicetree), since this is not be needed +anymore, now that DT support for WiLink is implemented. + +Cc: Tony Lindgren +Cc: Sekhar Nori +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wl12xx/main.c ++++ b/drivers/net/wireless/ti/wl12xx/main.c +@@ -1711,6 +1711,43 @@ static struct ieee80211_sta_ht_cap wl12x + }, + }; + ++static const struct wl12xx_clock wl12xx_refclock_table[] = { ++ { 19200000, false, WL12XX_REFCLOCK_19 }, ++ { 26000000, false, WL12XX_REFCLOCK_26 }, ++ { 26000000, true, WL12XX_REFCLOCK_26_XTAL }, ++ { 38400000, false, WL12XX_REFCLOCK_38 }, ++ { 38400000, true, WL12XX_REFCLOCK_38_XTAL }, ++ { 52000000, false, WL12XX_REFCLOCK_52 }, ++ { 0, false, 0 } ++}; ++ ++static const struct wl12xx_clock wl12xx_tcxoclock_table[] = { ++ { 16368000, true, WL12XX_TCXOCLOCK_16_368 }, ++ { 16800000, true, WL12XX_TCXOCLOCK_16_8 }, ++ { 19200000, true, WL12XX_TCXOCLOCK_19_2 }, ++ { 26000000, true, WL12XX_TCXOCLOCK_26 }, ++ { 32736000, true, WL12XX_TCXOCLOCK_32_736 }, ++ { 33600000, true, WL12XX_TCXOCLOCK_33_6 }, ++ { 38400000, true, WL12XX_TCXOCLOCK_38_4 }, ++ { 52000000, true, WL12XX_TCXOCLOCK_52 }, ++ { 0, false, 0 } ++}; ++ ++static int wl12xx_get_clock_idx(const struct wl12xx_clock *table, ++ u32 freq, bool xtal) ++{ ++ int i = 0; ++ ++ while(table[i].freq != 0) { ++ if ((table[i].freq == freq) && ++ (table[i].xtal == xtal)) ++ return table[i].hw_idx; ++ i++; ++ }; ++ ++ return -EINVAL; ++} ++ + static int wl12xx_setup(struct wl1271 *wl) + { + struct wl12xx_priv *priv = wl->priv; +@@ -1732,7 +1769,16 @@ static int wl12xx_setup(struct wl1271 *w + wl12xx_conf_init(wl); + + if (!fref_param) { +- priv->ref_clock = pdata->board_ref_clock; ++ priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, ++ pdata->ref_clock_freq, ++ pdata->ref_clock_xtal); ++ if (priv->ref_clock < 0) { ++ wl1271_error("Invalid ref_clock frequency (%d Hz, %s)", ++ pdata->ref_clock_freq, ++ pdata->ref_clock_xtal ? "XTAL" : "not XTAL"); ++ ++ return priv->ref_clock; ++ } + } else { + if (!strcmp(fref_param, "19.2")) + priv->ref_clock = WL12XX_REFCLOCK_19; +@@ -1751,7 +1797,15 @@ static int wl12xx_setup(struct wl1271 *w + } + + if (!tcxo_param) { +- priv->tcxo_clock = pdata->board_tcxo_clock; ++ priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, ++ pdata->tcxo_clock_freq, ++ true); ++ if (priv->tcxo_clock < 0) { ++ wl1271_error("Invalid tcxo_clock frequency (%d Hz)", ++ pdata->tcxo_clock_freq); ++ ++ return priv->tcxo_clock; ++ } + } else { + if (!strcmp(tcxo_param, "19.2")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; +--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h ++++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h +@@ -79,4 +79,32 @@ struct wl12xx_priv { + struct wl127x_rx_mem_pool_addr *rx_mem_addr; + }; + ++/* Reference clock values */ ++enum { ++ WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ ++ WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ ++ WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ ++ WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ ++ WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ ++ WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ ++}; ++ ++/* TCXO clock values */ ++enum { ++ WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ ++ WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ ++ WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ ++ WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ ++ WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ ++ WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ ++ WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ ++ WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ ++}; ++ ++struct wl12xx_clock { ++ u32 freq; ++ bool xtal; ++ u8 hw_idx; ++}; ++ + #endif /* __WL12XX_PRIV_H__ */ diff --git a/package/kernel/mac80211/patches/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch b/package/kernel/mac80211/patches/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch new file mode 100644 index 000000000000..9e1d19070fdc --- /dev/null +++ b/package/kernel/mac80211/patches/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch @@ -0,0 +1,118 @@ +If platform data is not available, try to get the required information +from the device tree. Register an OF match table and parse the +appropriate device tree nodes. + +Parse interrupt property only, for now. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -30,7 +30,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -214,6 +214,43 @@ static struct wl1271_if_operations sdio_ + .set_block_size = wl1271_sdio_set_block_size, + }; + ++static struct wl12xx_platform_data *wlcore_get_pdata_from_of(struct device *dev) ++{ ++ struct wl12xx_platform_data *pdata; ++ struct device_node *np = dev->of_node; ++ ++ if (!np) { ++ np = of_find_matching_node(NULL, dev->driver->of_match_table); ++ if (!np) { ++ dev_notice(dev, "device tree node not available\n"); ++ pdata = ERR_PTR(-ENODEV); ++ goto out; ++ } ++ } ++ ++ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ dev_err(dev, "can't allocate platform data\n"); ++ pdata = ERR_PTR(-ENODEV); ++ goto out; ++ } ++ ++ pdata->irq = irq_of_parse_and_map(np, 0); ++ if (pdata->irq < 0) { ++ dev_err(dev, "can't get interrupt gpio from the device tree\n"); ++ goto out_free; ++ } ++ ++ goto out; ++ ++out_free: ++ kfree(pdata); ++ pdata = ERR_PTR(-ENODEV); ++ ++out: ++ return pdata; ++} ++ + static int wl1271_probe(struct sdio_func *func, + const struct sdio_device_id *id) + { +@@ -248,11 +285,22 @@ static int wl1271_probe(struct sdio_func + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + ++ /* The pdata allocated here is freed when the device is freed, ++ * so we don't need an additional out label to free it in case ++ * of error further on. ++ */ ++ ++ /* Try to get legacy platform data from the board file */ + pdev_data->pdata = wl12xx_get_platform_data(); + if (IS_ERR(pdev_data->pdata)) { +- ret = PTR_ERR(pdev_data->pdata); +- dev_err(glue->dev, "missing wlan platform data: %d\n", ret); +- goto out_free_glue; ++ dev_info(&func->dev, ++ "legacy platform data not found, trying device tree\n"); ++ ++ pdev_data->pdata = wlcore_get_pdata_from_of(&func->dev); ++ if (IS_ERR(pdev_data->pdata)) { ++ dev_err(&func->dev, "can't get platform data\n"); ++ goto out_free_glue; ++ } + } + + /* if sdio can keep power while host is suspended, enable wow */ +@@ -386,16 +434,25 @@ static const struct dev_pm_ops wl1271_sd + }; + #endif + ++static const struct of_device_id wlcore_sdio_of_match_table[] = { ++ { .compatible = "ti,wilink6" }, ++ { .compatible = "ti,wilink7" }, ++ { .compatible = "ti,wilink8" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, wlcore_sdio_of_match_table); ++ + static struct sdio_driver wl1271_sdio_driver = { + .name = "wl1271_sdio", + .id_table = wl1271_devices, + .probe = wl1271_probe, + .remove = wl1271_remove, +-#ifdef CONFIG_PM + .drv = { ++#ifdef CONFIG_PM + .pm = &wl1271_sdio_pm_ops, +- }, + #endif ++ .of_match_table = of_match_ptr(wlcore_sdio_of_match_table), ++ }, + }; + + static int __init wl1271_init(void) diff --git a/package/kernel/mac80211/patches/905-wlcore-sdio-add-wilink-clock-providers.patch b/package/kernel/mac80211/patches/905-wlcore-sdio-add-wilink-clock-providers.patch new file mode 100644 index 000000000000..be1f9ada43c4 --- /dev/null +++ b/package/kernel/mac80211/patches/905-wlcore-sdio-add-wilink-clock-providers.patch @@ -0,0 +1,50 @@ +Add refclock and tcxoclock as clock providers in WiLink. These clocks +are not accesible outside the WiLink module, but they are registered +in the clock framework anyway. Only the WiLink chip consumes these +clocks. + +In theory, the WiLink chip could be connected to external clocks +instead of using these internal clocks, so make the clock consumer +code generic enough. If external clocks are used, then the internal +clock device tree nodes are not necessary, but the external ones must +be specified. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "wlcore.h" + #include "wl12xx_80211.h" +@@ -214,10 +215,15 @@ static struct wl1271_if_operations sdio_ + .set_block_size = wl1271_sdio_set_block_size, + }; + ++static const struct of_device_id wlcore_sdio_of_clk_match_table[] = { ++ { .compatible = "ti,wilink-clock" }, ++}; ++ + static struct wl12xx_platform_data *wlcore_get_pdata_from_of(struct device *dev) + { + struct wl12xx_platform_data *pdata; + struct device_node *np = dev->of_node; ++ struct device_node *clock_node; + + if (!np) { + np = of_find_matching_node(NULL, dev->driver->of_match_table); +@@ -241,6 +247,9 @@ static struct wl12xx_platform_data *wlco + goto out_free; + } + ++ for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table) ++ of_fixed_clk_setup(clock_node); ++ + goto out; + + out_free: diff --git a/package/kernel/mac80211/patches/906-wlcore-sdio-get-clocks-from-device-tree.patch b/package/kernel/mac80211/patches/906-wlcore-sdio-get-clocks-from-device-tree.patch new file mode 100644 index 000000000000..09ff4aff9698 --- /dev/null +++ b/package/kernel/mac80211/patches/906-wlcore-sdio-get-clocks-from-device-tree.patch @@ -0,0 +1,90 @@ +Read the clock nodes from the device tree and use them to set the +frequency for the refclock and the tcxo clock. + +Also, call sdio_set_drvdata() earlier, so the glue is already set in +the driver data when we call wlcore_get_pdata_from_of() and we don't +need to pass it as a parameter. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -53,6 +53,7 @@ static bool dump = false; + struct wl12xx_sdio_glue { + struct device *dev; + struct platform_device *core; ++ struct clk *refclock, *tcxoclock; + }; + + static const struct sdio_device_id wl1271_devices[] = { +@@ -224,6 +225,7 @@ static struct wl12xx_platform_data *wlco + struct wl12xx_platform_data *pdata; + struct device_node *np = dev->of_node; + struct device_node *clock_node; ++ struct wl12xx_sdio_glue *glue = sdio_get_drvdata(dev_to_sdio_func(dev)); + + if (!np) { + np = of_find_matching_node(NULL, dev->driver->of_match_table); +@@ -250,6 +252,26 @@ static struct wl12xx_platform_data *wlco + for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table) + of_fixed_clk_setup(clock_node); + ++ /* TODO: make sure we have this when needed (ie. for WL6 and WL7) */ ++ glue->refclock = of_clk_get_by_name(np, "refclock"); ++ if (IS_ERR(glue->refclock)) { ++ dev_err(dev, "couldn't find refclock on the device tree\n"); ++ glue->refclock = NULL; ++ } else { ++ clk_prepare_enable(glue->refclock); ++ pdata->ref_clock_freq = clk_get_rate(glue->refclock); ++ } ++ ++ /* TODO: make sure we have this when needed (ie. for WL7) */ ++ glue->tcxoclock = of_clk_get_by_name(np, "tcxoclock"); ++ if (IS_ERR(glue->tcxoclock)) { ++ dev_err(dev, "couldn't find tcxoclock on the device tree\n"); ++ glue->tcxoclock = NULL; ++ } else { ++ clk_prepare_enable(glue->tcxoclock); ++ pdata->ref_clock_freq = clk_get_rate(glue->tcxoclock); ++ } ++ + goto out; + + out_free: +@@ -294,6 +316,8 @@ static int wl1271_probe(struct sdio_func + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + ++ sdio_set_drvdata(func, glue); ++ + /* The pdata allocated here is freed when the device is freed, + * so we don't need an additional out label to free it in case + * of error further on. +@@ -319,8 +343,6 @@ static int wl1271_probe(struct sdio_func + if (mmcflags & MMC_PM_KEEP_POWER) + pdev_data->pwr_in_suspend = true; + +- sdio_set_drvdata(func, glue); +- + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + +@@ -387,6 +409,16 @@ static void wl1271_remove(struct sdio_fu + { + struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); + ++ if (glue->refclock) { ++ clk_disable_unprepare(glue->refclock); ++ clk_put(glue->refclock); ++ } ++ ++ if (glue->tcxoclock) { ++ clk_disable_unprepare(glue->tcxoclock); ++ clk_put(glue->tcxoclock); ++ } ++ + /* Undo decrement done above in wl1271_probe */ + pm_runtime_get_noresume(&func->dev); + diff --git a/package/kernel/mac80211/patches/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch b/package/kernel/mac80211/patches/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch new file mode 100644 index 000000000000..6b09177ded3b --- /dev/null +++ b/package/kernel/mac80211/patches/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch @@ -0,0 +1,96 @@ +The fref and the tcxo clocks settings are optional in some platforms. +WiLink8 doesn't need either, so we don't check the values. WiLink 6 +only needs the fref clock, so we check that it is valid or return with +an error. WiLink7 needs both clocks, if either is not available we +return with an error. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- a/drivers/net/wireless/ti/wl12xx/main.c ++++ b/drivers/net/wireless/ti/wl12xx/main.c +@@ -930,6 +930,11 @@ static int wl128x_boot_clk(struct wl1271 + u16 sys_clk_cfg; + int ret; + ++ if ((priv->ref_clock < 0) || (priv->tcxo_clock < 0)) { ++ wl1271_error("Missing fref and/or tcxo clock settings\n"); ++ return -EINVAL; ++ } ++ + /* For XTAL-only modes, FREF will be used after switching from TCXO */ + if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL || + priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) { +@@ -979,6 +984,11 @@ static int wl127x_boot_clk(struct wl1271 + u32 clk; + int ret; + ++ if (priv->ref_clock < 0) { ++ wl1271_error("Missing fref clock settings\n"); ++ return -EINVAL; ++ } ++ + if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) + wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; + +@@ -1768,7 +1778,7 @@ static int wl12xx_setup(struct wl1271 *w + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap); + wl12xx_conf_init(wl); + +- if (!fref_param) { ++ if (!fref_param && (pdata->ref_clock_freq > 0)) { + priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, + pdata->ref_clock_freq, + pdata->ref_clock_xtal); +@@ -1779,6 +1789,8 @@ static int wl12xx_setup(struct wl1271 *w + + return priv->ref_clock; + } ++ } else if (!fref_param) { ++ priv->ref_clock = -EINVAL; + } else { + if (!strcmp(fref_param, "19.2")) + priv->ref_clock = WL12XX_REFCLOCK_19; +@@ -1796,7 +1808,7 @@ static int wl12xx_setup(struct wl1271 *w + wl1271_error("Invalid fref parameter %s", fref_param); + } + +- if (!tcxo_param) { ++ if (!fref_param && (pdata->tcxo_clock_freq > 0)) { + priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, + pdata->tcxo_clock_freq, + true); +@@ -1806,7 +1818,9 @@ static int wl12xx_setup(struct wl1271 *w + + return priv->tcxo_clock; + } +- } else { ++ } else if (!fref_param) { ++ priv->tcxo_clock = -EINVAL; ++ }else { + if (!strcmp(tcxo_param, "19.2")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; + else if (!strcmp(tcxo_param, "26")) +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -252,20 +252,16 @@ static struct wl12xx_platform_data *wlco + for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table) + of_fixed_clk_setup(clock_node); + +- /* TODO: make sure we have this when needed (ie. for WL6 and WL7) */ + glue->refclock = of_clk_get_by_name(np, "refclock"); + if (IS_ERR(glue->refclock)) { +- dev_err(dev, "couldn't find refclock on the device tree\n"); + glue->refclock = NULL; + } else { + clk_prepare_enable(glue->refclock); + pdata->ref_clock_freq = clk_get_rate(glue->refclock); + } + +- /* TODO: make sure we have this when needed (ie. for WL7) */ + glue->tcxoclock = of_clk_get_by_name(np, "tcxoclock"); + if (IS_ERR(glue->tcxoclock)) { +- dev_err(dev, "couldn't find tcxoclock on the device tree\n"); + glue->tcxoclock = NULL; + } else { + clk_prepare_enable(glue->tcxoclock); diff --git a/target/linux/omap/patches-3.12/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch b/target/linux/omap/patches-3.12/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch new file mode 100644 index 000000000000..fa6059ac3516 --- /dev/null +++ b/target/linux/omap/patches-3.12/900-wl1251-split-wl251-platform-data-to-a-separate-structure.patch @@ -0,0 +1,198 @@ +Move the wl1251 part of the wl12xx platform data structure into a new +structure specifically for wl1251. Change the platform data built-in +block and board files accordingly. + +Cc: Tony Lindgren +Signed-off-by: Luciano Coelho +Acked-by: Tony Lindgren +Reviewed-by: Felipe Balbi + +--- + arch/arm/mach-omap2/board-omap3pandora.c | 4 +-- + arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +- + drivers/net/wireless/ti/wilink_platform_data.c | 37 +++++++++++++++++++++----- + drivers/net/wireless/ti/wl1251/sdio.c | 12 ++++----- + drivers/net/wireless/ti/wl1251/spi.c | 2 +- + include/linux/wl12xx.h | 22 ++++++++++++++- + 6 files changed, 62 insertions(+), 17 deletions(-) + +--- a/arch/arm/mach-omap2/board-omap3pandora.c ++++ b/arch/arm/mach-omap2/board-omap3pandora.c +@@ -536,7 +536,7 @@ static struct spi_board_info omap3pandor + + static void __init pandora_wl1251_init(void) + { +- struct wl12xx_platform_data pandora_wl1251_pdata; ++ struct wl1251_platform_data pandora_wl1251_pdata; + int ret; + + memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata)); +@@ -550,7 +550,7 @@ static void __init pandora_wl1251_init(v + goto fail_irq; + + pandora_wl1251_pdata.use_eeprom = true; +- ret = wl12xx_set_platform_data(&pandora_wl1251_pdata); ++ ret = wl1251_set_platform_data(&pandora_wl1251_pdata); + if (ret < 0) + goto fail_irq; + +--- a/arch/arm/mach-omap2/board-rx51-peripherals.c ++++ b/arch/arm/mach-omap2/board-rx51-peripherals.c +@@ -82,7 +82,7 @@ enum { + RX51_SPI_MIPID, /* LCD panel */ + }; + +-static struct wl12xx_platform_data wl1251_pdata; ++static struct wl1251_platform_data wl1251_pdata; + static struct tsc2005_platform_data tsc2005_pdata; + + #if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE) +--- a/drivers/net/wireless/ti/wilink_platform_data.c ++++ b/drivers/net/wireless/ti/wilink_platform_data.c +@@ -23,17 +23,17 @@ + #include + #include + +-static struct wl12xx_platform_data *platform_data; ++static struct wl12xx_platform_data *wl12xx_platform_data; + + int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) + { +- if (platform_data) ++ if (wl12xx_platform_data) + return -EBUSY; + if (!data) + return -EINVAL; + +- platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); +- if (!platform_data) ++ wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); ++ if (!wl12xx_platform_data) + return -ENOMEM; + + return 0; +@@ -41,9 +41,34 @@ int __init wl12xx_set_platform_data(cons + + struct wl12xx_platform_data *wl12xx_get_platform_data(void) + { +- if (!platform_data) ++ if (!wl12xx_platform_data) + return ERR_PTR(-ENODEV); + +- return platform_data; ++ return wl12xx_platform_data; + } + EXPORT_SYMBOL(wl12xx_get_platform_data); ++ ++static struct wl1251_platform_data *wl1251_platform_data; ++ ++int __init wl1251_set_platform_data(const struct wl1251_platform_data *data) ++{ ++ if (wl1251_platform_data) ++ return -EBUSY; ++ if (!data) ++ return -EINVAL; ++ ++ wl1251_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); ++ if (!wl1251_platform_data) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++struct wl1251_platform_data *wl1251_get_platform_data(void) ++{ ++ if (!wl1251_platform_data) ++ return ERR_PTR(-ENODEV); ++ ++ return wl1251_platform_data; ++} ++EXPORT_SYMBOL(wl1251_get_platform_data); +--- a/drivers/net/wireless/ti/wl1251/sdio.c ++++ b/drivers/net/wireless/ti/wl1251/sdio.c +@@ -227,7 +227,7 @@ static int wl1251_sdio_probe(struct sdio + struct wl1251 *wl; + struct ieee80211_hw *hw; + struct wl1251_sdio *wl_sdio; +- const struct wl12xx_platform_data *wl12xx_board_data; ++ const struct wl1251_platform_data *wl1251_board_data; + + hw = wl1251_alloc_hw(); + if (IS_ERR(hw)) +@@ -254,11 +254,11 @@ static int wl1251_sdio_probe(struct sdio + wl->if_priv = wl_sdio; + wl->if_ops = &wl1251_sdio_ops; + +- wl12xx_board_data = wl12xx_get_platform_data(); +- if (!IS_ERR(wl12xx_board_data)) { +- wl->set_power = wl12xx_board_data->set_power; +- wl->irq = wl12xx_board_data->irq; +- wl->use_eeprom = wl12xx_board_data->use_eeprom; ++ wl1251_board_data = wl1251_get_platform_data(); ++ if (!IS_ERR(wl1251_board_data)) { ++ wl->set_power = wl1251_board_data->set_power; ++ wl->irq = wl1251_board_data->irq; ++ wl->use_eeprom = wl1251_board_data->use_eeprom; + } + + if (wl->irq) { +--- a/drivers/net/wireless/ti/wl1251/spi.c ++++ b/drivers/net/wireless/ti/wl1251/spi.c +@@ -238,7 +238,7 @@ static const struct wl1251_if_operations + + static int wl1251_spi_probe(struct spi_device *spi) + { +- struct wl12xx_platform_data *pdata; ++ struct wl1251_platform_data *pdata; + struct ieee80211_hw *hw; + struct wl1251 *wl; + int ret; +--- a/include/linux/wl12xx.h ++++ b/include/linux/wl12xx.h +@@ -48,11 +48,15 @@ enum { + WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ + }; + +-struct wl12xx_platform_data { ++struct wl1251_platform_data { + void (*set_power)(bool enable); + /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ + int irq; + bool use_eeprom; ++}; ++ ++struct wl12xx_platform_data { ++ int irq; + int board_ref_clock; + int board_tcxo_clock; + unsigned long platform_quirks; +@@ -68,6 +72,10 @@ int wl12xx_set_platform_data(const struc + + struct wl12xx_platform_data *wl12xx_get_platform_data(void); + ++int wl1251_set_platform_data(const struct wl1251_platform_data *data); ++ ++struct wl1251_platform_data *wl1251_get_platform_data(void); ++ + #else + + static inline +@@ -81,6 +89,18 @@ struct wl12xx_platform_data *wl12xx_get_ + { + return ERR_PTR(-ENODATA); + } ++ ++static inline ++int wl1251_set_platform_data(const struct wl1251_platform_data *data) ++{ ++ return -ENOSYS; ++} ++ ++static inline ++struct wl1251_platform_data *wl1251_get_platform_data(void) ++{ ++ return ERR_PTR(-ENODATA); ++} + + #endif + diff --git a/target/linux/omap/patches-3.12/901-wlcore-set-irq_flags-in-the-board-files.patch b/target/linux/omap/patches-3.12/901-wlcore-set-irq_flags-in-the-board-files.patch new file mode 100644 index 000000000000..f090735c65ba --- /dev/null +++ b/target/linux/omap/patches-3.12/901-wlcore-set-irq_flags-in-the-board-files.patch @@ -0,0 +1,237 @@ +The platform_quirk element in the platform data was used to change the +way the IRQ is triggered. When set, the EDGE_IRQ quirk would change +the irqflags used and treat edge trigger differently from the rest. + +Instead of hiding this irq flag setting behind the quirk, have the +board files set the flags during initialization. This will be more +meaningful than driver-specific quirks when we switch to DT. + +Additionally, fix missing gpio_request() calls in the boarding files +(so that setting the flags actually works). + +Cc: Tony Lindgren +Cc: Sekhar Nori +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi +Acked-by: Sekhar Nori + +--- + arch/arm/mach-davinci/board-da850-evm.c | 8 +++++++- + arch/arm/mach-omap2/board-omap3evm.c | 19 ++++++++++++++++++ + arch/arm/mach-omap2/board-zoom-peripherals.c | 30 +++++++++++++++++++++++++--- + drivers/net/wireless/ti/wlcore/debugfs.c | 2 +- + drivers/net/wireless/ti/wlcore/main.c | 17 ++++++++-------- + drivers/net/wireless/ti/wlcore/wlcore.h | 5 ++--- + include/linux/wl12xx.h | 4 ---- + 7 files changed, 64 insertions(+), 21 deletions(-) + +--- a/arch/arm/mach-davinci/board-da850-evm.c ++++ b/arch/arm/mach-davinci/board-da850-evm.c +@@ -1371,7 +1371,6 @@ static const short da850_wl12xx_pins[] _ + static struct wl12xx_platform_data da850_wl12xx_wlan_data __initdata = { + .irq = -1, + .board_ref_clock = WL12XX_REFCLOCK_38, +- .platform_quirks = WL12XX_PLATFORM_QUIRK_EDGE_IRQ, + }; + + static __init int da850_wl12xx_init(void) +@@ -1402,6 +1401,13 @@ static __init int da850_wl12xx_init(void + goto free_wlan_en; + } + ++ ret = irq_set_irq_type(gpio_to_irq(DA850_WLAN_IRQ), ++ IRQ_TYPE_EDGE_RISING); ++ if (ret) { ++ pr_err("Could not set wl12xx irq type: %d\n", ret); ++ goto free; ++ } ++ + da850_wl12xx_wlan_data.irq = gpio_to_irq(DA850_WLAN_IRQ); + + ret = wl12xx_set_platform_data(&da850_wl12xx_wlan_data); +--- a/arch/arm/mach-omap2/board-omap3evm.c ++++ b/arch/arm/mach-omap2/board-omap3evm.c +@@ -627,12 +627,31 @@ static void __init omap3_evm_wl12xx_init + + /* WL12xx WLAN Init */ + omap3evm_wlan_data.irq = gpio_to_irq(OMAP3EVM_WLAN_IRQ_GPIO); ++ ++ ret = gpio_request_one(OMAP3EVM_WLAN_IRQ_GPIO, GPIOF_IN, ++ "OMAP3EVM_WLAN_IRQ_GPIO"); ++ if (ret) { ++ pr_err("error requesting wl12xx gpio: %d\n", ret); ++ goto out; ++ } ++ ++ ret = irq_set_irq_type(gpio_to_irq(OMAP3EVM_WLAN_IRQ_GPIO), ++ IRQ_TYPE_LEVEL_HIGH); ++ if (ret) { ++ pr_err("error setting wl12xx irq type: %d\n", ret); ++ goto free; ++ } ++ + ret = wl12xx_set_platform_data(&omap3evm_wlan_data); + if (ret) + pr_err("error setting wl12xx data: %d\n", ret); + ret = platform_device_register(&omap3evm_wlan_regulator); + if (ret) + pr_err("error registering wl12xx device: %d\n", ret); ++out: ++ return; ++free: ++ gpio_free(OMAP3EVM_WLAN_IRQ_GPIO); + #endif + } + +--- a/arch/arm/mach-omap2/board-zoom-peripherals.c ++++ b/arch/arm/mach-omap2/board-zoom-peripherals.c +@@ -339,16 +339,40 @@ static void enable_board_wakeup_source(v + OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); + } + +-void __init zoom_peripherals_init(void) ++static void __init zoom_wilink_init(void) + { + int ret; + + omap_zoom_wlan_data.irq = gpio_to_irq(OMAP_ZOOM_WLAN_IRQ_GPIO); +- ret = wl12xx_set_platform_data(&omap_zoom_wlan_data); + +- if (ret) ++ ret = gpio_request_one(OMAP_ZOOM_WLAN_IRQ_GPIO, GPIOF_IN, ++ "OMAP_ZOOM_WLAN_IRQ_GPIO"); ++ if (ret) { ++ pr_err("error requesting wl12xx gpio: %d\n", ret); ++ goto out; ++ } ++ ++ ret = irq_set_irq_type(gpio_to_irq(OMAP_ZOOM_WLAN_IRQ_GPIO), ++ IRQ_TYPE_LEVEL_HIGH); ++ if (ret) { ++ pr_err("error setting wl12xx irq type: %d\n", ret); ++ goto free; ++ } ++ ++ ret = wl12xx_set_platform_data(&omap_zoom_wlan_data); ++ if (ret) { + pr_err("error setting wl12xx data: %d\n", ret); ++ goto free; ++ } ++out: ++ return; ++free: ++ gpio_free(OMAP_ZOOM_WLAN_IRQ_GPIO); ++} + ++void __init zoom_peripherals_init(void) ++{ ++ zoom_wilink_init(); + omap_hsmmc_init(mmc); + omap_i2c_init(); + pwm_add_table(zoom_pwm_lookup, ARRAY_SIZE(zoom_pwm_lookup)); +--- a/drivers/net/wireless/ti/wlcore/debugfs.c ++++ b/drivers/net/wireless/ti/wlcore/debugfs.c +@@ -486,7 +486,7 @@ static ssize_t driver_state_read(struct + DRIVER_STATE_PRINT_HEX(irq); + /* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */ + DRIVER_STATE_PRINT_HEX(hw_pg_ver); +- DRIVER_STATE_PRINT_HEX(platform_quirks); ++ DRIVER_STATE_PRINT_HEX(irq_flags); + DRIVER_STATE_PRINT_HEX(chip.id); + DRIVER_STATE_PRINT_STR(chip.fw_ver_str); + DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); +--- a/drivers/net/wireless/ti/wlcore/main.c ++++ b/drivers/net/wireless/ti/wlcore/main.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "wlcore.h" + #include "debug.h" +@@ -516,7 +517,7 @@ static int wlcore_irq_locked(struct wl12 + * In case edge triggered interrupt must be used, we cannot iterate + * more than once without introducing race conditions with the hardirq. + */ +- if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) ++ if (wl->irq_flags & IRQF_TRIGGER_RISING) + loopcount = 1; + + wl1271_debug(DEBUG_IRQ, "IRQ work"); +@@ -5766,7 +5767,6 @@ struct ieee80211_hw *wlcore_alloc_hw(siz + wl->ap_ps_map = 0; + wl->ap_fw_ps_map = 0; + wl->quirks = 0; +- wl->platform_quirks = 0; + wl->system_hlid = WL12XX_SYSTEM_HLID; + wl->active_sta_count = 0; + wl->active_link_count = 0; +@@ -5902,7 +5902,7 @@ static void wlcore_nvs_cb(const struct f + struct platform_device *pdev = wl->pdev; + struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data; + struct wl12xx_platform_data *pdata = pdev_data->pdata; +- unsigned long irqflags; ++ + int ret; + + if (fw) { +@@ -5929,16 +5929,15 @@ static void wlcore_nvs_cb(const struct f + 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 (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) +- irqflags = IRQF_TRIGGER_RISING; +- else +- irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; ++ wl->irq_flags = irq_get_trigger_type(wl->irq); ++ ++ /* Since we don't use the primary handler, we must set ONESHOT */ ++ wl->irq_flags |= IRQF_ONESHOT; + + ret = request_threaded_irq(wl->irq, NULL, wlcore_irq, +- irqflags, pdev->name, wl); ++ wl->irq_flags, pdev->name, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free_nvs; +--- a/drivers/net/wireless/ti/wlcore/wlcore.h ++++ b/drivers/net/wireless/ti/wlcore/wlcore.h +@@ -185,6 +185,8 @@ struct wl1271 { + + int irq; + ++ int irq_flags; ++ + spinlock_t wl_lock; + + enum wlcore_state state; +@@ -384,9 +386,6 @@ struct wl1271 { + /* Quirks of specific hardware revisions */ + unsigned int quirks; + +- /* Platform limitations */ +- unsigned int platform_quirks; +- + /* number of currently active RX BA sessions */ + int ba_rx_session_count; + +--- a/include/linux/wl12xx.h ++++ b/include/linux/wl12xx.h +@@ -59,13 +59,9 @@ struct wl12xx_platform_data { + int irq; + int board_ref_clock; + int board_tcxo_clock; +- unsigned long platform_quirks; + bool pwr_in_suspend; + }; + +-/* Platform does not support level trigger interrupts */ +-#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) +- + #ifdef CONFIG_WILINK_PLATFORM_DATA + + int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); diff --git a/target/linux/omap/patches-3.12/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch b/target/linux/omap/patches-3.12/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch new file mode 100644 index 000000000000..662d713e2f7f --- /dev/null +++ b/target/linux/omap/patches-3.12/902-wlcore-remove-pwr_in_suspend-from-platform-data.patch @@ -0,0 +1,65 @@ +The pwr_in_suspend flag depends on the MMC settings which can be +retrieved from the SDIO subsystem, so it doesn't need to be part of +the platform data structure. Move it to the platform device data that +is passed from SDIO to wlcore. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- + drivers/net/wireless/ti/wlcore/main.c | 3 +-- + drivers/net/wireless/ti/wlcore/sdio.c | 2 +- + drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 + + include/linux/wl12xx.h | 1 - + 4 files changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ti/wlcore/main.c ++++ b/drivers/net/wireless/ti/wlcore/main.c +@@ -5901,7 +5901,6 @@ static void wlcore_nvs_cb(const struct f + struct wl1271 *wl = context; + struct platform_device *pdev = wl->pdev; + struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data; +- struct wl12xx_platform_data *pdata = pdev_data->pdata; + + int ret; + +@@ -5948,7 +5947,7 @@ static void wlcore_nvs_cb(const struct f + if (!ret) { + wl->irq_wake_enabled = true; + device_init_wakeup(wl->dev, 1); +- if (pdata->pwr_in_suspend) ++ if (pdev_data->pwr_in_suspend) + wl->hw->wiphy->wowlan = &wlcore_wowlan_support; + } + #endif +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -260,7 +260,7 @@ static int wl1271_probe(struct sdio_func + dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); + + if (mmcflags & MMC_PM_KEEP_POWER) +- pdev_data->pdata->pwr_in_suspend = true; ++ pdev_data->pwr_in_suspend = true; + + sdio_set_drvdata(func, glue); + +--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h ++++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h +@@ -209,6 +209,7 @@ struct wl1271_if_operations { + struct wlcore_platdev_data { + struct wl12xx_platform_data *pdata; + struct wl1271_if_operations *if_ops; ++ bool pwr_in_suspend; + }; + + #define MAX_NUM_KEYS 14 +--- a/include/linux/wl12xx.h ++++ b/include/linux/wl12xx.h +@@ -59,7 +59,6 @@ struct wl12xx_platform_data { + int irq; + int board_ref_clock; + int board_tcxo_clock; +- bool pwr_in_suspend; + }; + + #ifdef CONFIG_WILINK_PLATFORM_DATA diff --git a/target/linux/omap/patches-3.12/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch b/target/linux/omap/patches-3.12/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch new file mode 100644 index 000000000000..4b5149cec756 --- /dev/null +++ b/target/linux/omap/patches-3.12/903-wl12xx-use-frequency-instead-of-enumerations-for-pdata-clocks.patch @@ -0,0 +1,289 @@ +Instead of defining an enumeration with the FW specific values for the +different clock rates, use the actual frequency instead. Also add a +boolean to specify whether the clock is XTAL or not. + +Change all board files to reflect this. + +Additionally, this reverts commit 26f45c (ARM: OMAP2+: Legacy support +for wl12xx when booted with devicetree), since this is not be needed +anymore, now that DT support for WiLink is implemented. + +Cc: Tony Lindgren +Cc: Sekhar Nori +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- + arch/arm/mach-davinci/board-da850-evm.c | 3 +- + arch/arm/mach-omap2/board-omap3evm.c | 3 +- + arch/arm/mach-omap2/board-zoom-peripherals.c | 3 +- + arch/arm/mach-omap2/devices.c | 39 ------------------- + drivers/net/wireless/ti/wl12xx/main.c | 58 +++++++++++++++++++++++++++- + drivers/net/wireless/ti/wl12xx/wl12xx.h | 28 ++++++++++++++ + include/linux/wl12xx.h | 27 ++----------- + 7 files changed, 93 insertions(+), 68 deletions(-) + +--- a/arch/arm/mach-davinci/board-da850-evm.c ++++ b/arch/arm/mach-davinci/board-da850-evm.c +@@ -1370,7 +1370,8 @@ static const short da850_wl12xx_pins[] _ + + static struct wl12xx_platform_data da850_wl12xx_wlan_data __initdata = { + .irq = -1, +- .board_ref_clock = WL12XX_REFCLOCK_38, ++ .ref_clock_freq = 38400000, ++ .ref_clock_xtal = false, + }; + + static __init int da850_wl12xx_init(void) +--- a/arch/arm/mach-omap2/board-omap3evm.c ++++ b/arch/arm/mach-omap2/board-omap3evm.c +@@ -473,7 +473,8 @@ static struct platform_device omap3evm_w + }; + + struct wl12xx_platform_data omap3evm_wlan_data __initdata = { +- .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */ ++ .ref_clock_freq = 38400000, ++ .ref_clock_xtal = false, + }; + #endif + +--- a/arch/arm/mach-omap2/board-zoom-peripherals.c ++++ b/arch/arm/mach-omap2/board-zoom-peripherals.c +@@ -244,7 +244,8 @@ static struct platform_device *zoom_devi + }; + + static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = { +- .board_ref_clock = WL12XX_REFCLOCK_26, /* 26 MHz */ ++ .ref_clock_freq = 26000000, ++ .ref_clock_xtal = false, + }; + + static struct omap2_hsmmc_info mmc[] = { +--- a/arch/arm/mach-omap2/devices.c ++++ b/arch/arm/mach-omap2/devices.c +@@ -8,7 +8,6 @@ + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +-#include + #include + #include + #include +@@ -19,7 +18,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -475,40 +473,6 @@ static void omap_init_vout(void) + static inline void omap_init_vout(void) {} + #endif + +-#if IS_ENABLED(CONFIG_WL12XX) +- +-static struct wl12xx_platform_data wl12xx __initdata; +- +-void __init omap_init_wl12xx_of(void) +-{ +- int ret; +- +- if (!of_have_populated_dt()) +- return; +- +- if (of_machine_is_compatible("ti,omap4-sdp")) { +- wl12xx.board_ref_clock = WL12XX_REFCLOCK_26; +- wl12xx.board_tcxo_clock = WL12XX_TCXOCLOCK_26; +- wl12xx.irq = gpio_to_irq(53); +- } else if (of_machine_is_compatible("ti,omap4-panda")) { +- wl12xx.board_ref_clock = WL12XX_REFCLOCK_38; +- wl12xx.irq = gpio_to_irq(53); +- } else { +- return; +- } +- +- ret = wl12xx_set_platform_data(&wl12xx); +- if (ret) { +- pr_err("error setting wl12xx data: %d\n", ret); +- return; +- } +-} +-#else +-static inline void omap_init_wl12xx_of(void) +-{ +-} +-#endif +- + /*-------------------------------------------------------------------------*/ + + static int __init omap2_init_devices(void) +@@ -531,9 +495,6 @@ static int __init omap2_init_devices(voi + omap_init_sham(); + omap_init_aes(); + omap_init_rng(); +- } else { +- /* These can be removed when bindings are done */ +- omap_init_wl12xx_of(); + } + omap_init_sti(); + omap_init_vout(); +--- a/drivers/net/wireless/ti/wl12xx/main.c ++++ b/drivers/net/wireless/ti/wl12xx/main.c +@@ -1701,6 +1701,43 @@ static struct ieee80211_sta_ht_cap wl12x + }, + }; + ++static const struct wl12xx_clock wl12xx_refclock_table[] = { ++ { 19200000, false, WL12XX_REFCLOCK_19 }, ++ { 26000000, false, WL12XX_REFCLOCK_26 }, ++ { 26000000, true, WL12XX_REFCLOCK_26_XTAL }, ++ { 38400000, false, WL12XX_REFCLOCK_38 }, ++ { 38400000, true, WL12XX_REFCLOCK_38_XTAL }, ++ { 52000000, false, WL12XX_REFCLOCK_52 }, ++ { 0, false, 0 } ++}; ++ ++static const struct wl12xx_clock wl12xx_tcxoclock_table[] = { ++ { 16368000, true, WL12XX_TCXOCLOCK_16_368 }, ++ { 16800000, true, WL12XX_TCXOCLOCK_16_8 }, ++ { 19200000, true, WL12XX_TCXOCLOCK_19_2 }, ++ { 26000000, true, WL12XX_TCXOCLOCK_26 }, ++ { 32736000, true, WL12XX_TCXOCLOCK_32_736 }, ++ { 33600000, true, WL12XX_TCXOCLOCK_33_6 }, ++ { 38400000, true, WL12XX_TCXOCLOCK_38_4 }, ++ { 52000000, true, WL12XX_TCXOCLOCK_52 }, ++ { 0, false, 0 } ++}; ++ ++static int wl12xx_get_clock_idx(const struct wl12xx_clock *table, ++ u32 freq, bool xtal) ++{ ++ int i = 0; ++ ++ while(table[i].freq != 0) { ++ if ((table[i].freq == freq) && ++ (table[i].xtal == xtal)) ++ return table[i].hw_idx; ++ i++; ++ }; ++ ++ return -EINVAL; ++} ++ + static int wl12xx_setup(struct wl1271 *wl) + { + struct wl12xx_priv *priv = wl->priv; +@@ -1722,7 +1759,16 @@ static int wl12xx_setup(struct wl1271 *w + wl12xx_conf_init(wl); + + if (!fref_param) { +- priv->ref_clock = pdata->board_ref_clock; ++ priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, ++ pdata->ref_clock_freq, ++ pdata->ref_clock_xtal); ++ if (priv->ref_clock < 0) { ++ wl1271_error("Invalid ref_clock frequency (%d Hz, %s)", ++ pdata->ref_clock_freq, ++ pdata->ref_clock_xtal ? "XTAL" : "not XTAL"); ++ ++ return priv->ref_clock; ++ } + } else { + if (!strcmp(fref_param, "19.2")) + priv->ref_clock = WL12XX_REFCLOCK_19; +@@ -1741,7 +1787,15 @@ static int wl12xx_setup(struct wl1271 *w + } + + if (!tcxo_param) { +- priv->tcxo_clock = pdata->board_tcxo_clock; ++ priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, ++ pdata->tcxo_clock_freq, ++ true); ++ if (priv->tcxo_clock < 0) { ++ wl1271_error("Invalid tcxo_clock frequency (%d Hz)", ++ pdata->tcxo_clock_freq); ++ ++ return priv->tcxo_clock; ++ } + } else { + if (!strcmp(tcxo_param, "19.2")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; +--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h ++++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h +@@ -79,4 +79,32 @@ struct wl12xx_priv { + struct wl127x_rx_mem_pool_addr *rx_mem_addr; + }; + ++/* Reference clock values */ ++enum { ++ WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ ++ WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ ++ WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ ++ WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ ++ WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ ++ WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ ++}; ++ ++/* TCXO clock values */ ++enum { ++ WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ ++ WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ ++ WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ ++ WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ ++ WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ ++ WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ ++ WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ ++ WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ ++}; ++ ++struct wl12xx_clock { ++ u32 freq; ++ bool xtal; ++ u8 hw_idx; ++}; ++ + #endif /* __WL12XX_PRIV_H__ */ +--- a/include/linux/wl12xx.h ++++ b/include/linux/wl12xx.h +@@ -26,28 +26,6 @@ + + #include + +-/* Reference clock values */ +-enum { +- WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ +- WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ +- WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ +- WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ +- WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ +- WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ +-}; +- +-/* TCXO clock values */ +-enum { +- WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ +- WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ +- WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ +- WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ +- WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ +- WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ +- WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ +- WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ +-}; +- + struct wl1251_platform_data { + void (*set_power)(bool enable); + /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ +@@ -57,8 +35,9 @@ struct wl1251_platform_data { + + struct wl12xx_platform_data { + int irq; +- int board_ref_clock; +- int board_tcxo_clock; ++ int ref_clock_freq; /* in Hertz */ ++ bool ref_clock_xtal; /* specify whether the clock is XTAL or not */ ++ int tcxo_clock_freq; /* in Hertz, tcxo is always XTAL */ + }; + + #ifdef CONFIG_WILINK_PLATFORM_DATA diff --git a/target/linux/omap/patches-3.12/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch b/target/linux/omap/patches-3.12/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch new file mode 100644 index 000000000000..b95295625e0f --- /dev/null +++ b/target/linux/omap/patches-3.12/904-wlcore-add-initial-device-tree-support-to-the-sdio-module.patch @@ -0,0 +1,122 @@ +If platform data is not available, try to get the required information +from the device tree. Register an OF match table and parse the +appropriate device tree nodes. + +Parse interrupt property only, for now. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- + drivers/net/wireless/ti/wlcore/sdio.c | 69 ++++++++++++++++++++++++++++++++--- + 1 file changed, 63 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -30,7 +30,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -214,6 +214,43 @@ static struct wl1271_if_operations sdio_ + .set_block_size = wl1271_sdio_set_block_size, + }; + ++static struct wl12xx_platform_data *wlcore_get_pdata_from_of(struct device *dev) ++{ ++ struct wl12xx_platform_data *pdata; ++ struct device_node *np = dev->of_node; ++ ++ if (!np) { ++ np = of_find_matching_node(NULL, dev->driver->of_match_table); ++ if (!np) { ++ dev_notice(dev, "device tree node not available\n"); ++ pdata = ERR_PTR(-ENODEV); ++ goto out; ++ } ++ } ++ ++ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ dev_err(dev, "can't allocate platform data\n"); ++ pdata = ERR_PTR(-ENODEV); ++ goto out; ++ } ++ ++ pdata->irq = irq_of_parse_and_map(np, 0); ++ if (pdata->irq < 0) { ++ dev_err(dev, "can't get interrupt gpio from the device tree\n"); ++ goto out_free; ++ } ++ ++ goto out; ++ ++out_free: ++ kfree(pdata); ++ pdata = ERR_PTR(-ENODEV); ++ ++out: ++ return pdata; ++} ++ + static int wl1271_probe(struct sdio_func *func, + const struct sdio_device_id *id) + { +@@ -248,11 +285,22 @@ static int wl1271_probe(struct sdio_func + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + ++ /* The pdata allocated here is freed when the device is freed, ++ * so we don't need an additional out label to free it in case ++ * of error further on. ++ */ ++ ++ /* Try to get legacy platform data from the board file */ + pdev_data->pdata = wl12xx_get_platform_data(); + if (IS_ERR(pdev_data->pdata)) { +- ret = PTR_ERR(pdev_data->pdata); +- dev_err(glue->dev, "missing wlan platform data: %d\n", ret); +- goto out_free_glue; ++ dev_info(&func->dev, ++ "legacy platform data not found, trying device tree\n"); ++ ++ pdev_data->pdata = wlcore_get_pdata_from_of(&func->dev); ++ if (IS_ERR(pdev_data->pdata)) { ++ dev_err(&func->dev, "can't get platform data\n"); ++ goto out_free_glue; ++ } + } + + /* if sdio can keep power while host is suspended, enable wow */ +@@ -386,16 +434,25 @@ static const struct dev_pm_ops wl1271_sd + }; + #endif + ++static const struct of_device_id wlcore_sdio_of_match_table[] = { ++ { .compatible = "ti,wilink6" }, ++ { .compatible = "ti,wilink7" }, ++ { .compatible = "ti,wilink8" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, wlcore_sdio_of_match_table); ++ + static struct sdio_driver wl1271_sdio_driver = { + .name = "wl1271_sdio", + .id_table = wl1271_devices, + .probe = wl1271_probe, + .remove = wl1271_remove, +-#ifdef CONFIG_PM + .drv = { ++#ifdef CONFIG_PM + .pm = &wl1271_sdio_pm_ops, +- }, + #endif ++ .of_match_table = of_match_ptr(wlcore_sdio_of_match_table), ++ }, + }; + + static int __init wl1271_init(void) diff --git a/target/linux/omap/patches-3.12/905-wlcore-sdio-add-wilink-clock-providers.patch b/target/linux/omap/patches-3.12/905-wlcore-sdio-add-wilink-clock-providers.patch new file mode 100644 index 000000000000..c800ec700c34 --- /dev/null +++ b/target/linux/omap/patches-3.12/905-wlcore-sdio-add-wilink-clock-providers.patch @@ -0,0 +1,54 @@ +Add refclock and tcxoclock as clock providers in WiLink. These clocks +are not accesible outside the WiLink module, but they are registered +in the clock framework anyway. Only the WiLink chip consumes these +clocks. + +In theory, the WiLink chip could be connected to external clocks +instead of using these internal clocks, so make the clock consumer +code generic enough. If external clocks are used, then the internal +clock device tree nodes are not necessary, but the external ones must +be specified. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- +drivers/net/wireless/ti/wlcore/sdio.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "wlcore.h" + #include "wl12xx_80211.h" +@@ -214,10 +215,15 @@ static struct wl1271_if_operations sdio_ + .set_block_size = wl1271_sdio_set_block_size, + }; + ++static const struct of_device_id wlcore_sdio_of_clk_match_table[] = { ++ { .compatible = "ti,wilink-clock" }, ++}; ++ + static struct wl12xx_platform_data *wlcore_get_pdata_from_of(struct device *dev) + { + struct wl12xx_platform_data *pdata; + struct device_node *np = dev->of_node; ++ struct device_node *clock_node; + + if (!np) { + np = of_find_matching_node(NULL, dev->driver->of_match_table); +@@ -241,6 +247,9 @@ static struct wl12xx_platform_data *wlco + goto out_free; + } + ++ for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table) ++ of_fixed_clk_setup(clock_node); ++ + goto out; + + out_free: diff --git a/target/linux/omap/patches-3.12/906-wlcore-sdio-get-clocks-from-device-tree.patch b/target/linux/omap/patches-3.12/906-wlcore-sdio-get-clocks-from-device-tree.patch new file mode 100644 index 000000000000..63d4f9b16424 --- /dev/null +++ b/target/linux/omap/patches-3.12/906-wlcore-sdio-get-clocks-from-device-tree.patch @@ -0,0 +1,94 @@ +Read the clock nodes from the device tree and use them to set the +frequency for the refclock and the tcxo clock. + +Also, call sdio_set_drvdata() earlier, so the glue is already set in +the driver data when we call wlcore_get_pdata_from_of() and we don't +need to pass it as a parameter. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- +drivers/net/wireless/ti/wlcore/sdio.c | 36 +++++++++++++++++++++++++++++++++-- + 1 file changed, 34 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -53,6 +53,7 @@ static bool dump = false; + struct wl12xx_sdio_glue { + struct device *dev; + struct platform_device *core; ++ struct clk *refclock, *tcxoclock; + }; + + static const struct sdio_device_id wl1271_devices[] = { +@@ -224,6 +225,7 @@ static struct wl12xx_platform_data *wlco + struct wl12xx_platform_data *pdata; + struct device_node *np = dev->of_node; + struct device_node *clock_node; ++ struct wl12xx_sdio_glue *glue = sdio_get_drvdata(dev_to_sdio_func(dev)); + + if (!np) { + np = of_find_matching_node(NULL, dev->driver->of_match_table); +@@ -250,6 +252,26 @@ static struct wl12xx_platform_data *wlco + for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table) + of_fixed_clk_setup(clock_node); + ++ /* TODO: make sure we have this when needed (ie. for WL6 and WL7) */ ++ glue->refclock = of_clk_get_by_name(np, "refclock"); ++ if (IS_ERR(glue->refclock)) { ++ dev_err(dev, "couldn't find refclock on the device tree\n"); ++ glue->refclock = NULL; ++ } else { ++ clk_prepare_enable(glue->refclock); ++ pdata->ref_clock_freq = clk_get_rate(glue->refclock); ++ } ++ ++ /* TODO: make sure we have this when needed (ie. for WL7) */ ++ glue->tcxoclock = of_clk_get_by_name(np, "tcxoclock"); ++ if (IS_ERR(glue->tcxoclock)) { ++ dev_err(dev, "couldn't find tcxoclock on the device tree\n"); ++ glue->tcxoclock = NULL; ++ } else { ++ clk_prepare_enable(glue->tcxoclock); ++ pdata->ref_clock_freq = clk_get_rate(glue->tcxoclock); ++ } ++ + goto out; + + out_free: +@@ -294,6 +316,8 @@ static int wl1271_probe(struct sdio_func + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + ++ sdio_set_drvdata(func, glue); ++ + /* The pdata allocated here is freed when the device is freed, + * so we don't need an additional out label to free it in case + * of error further on. +@@ -319,8 +343,6 @@ static int wl1271_probe(struct sdio_func + if (mmcflags & MMC_PM_KEEP_POWER) + pdev_data->pwr_in_suspend = true; + +- sdio_set_drvdata(func, glue); +- + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + +@@ -387,6 +409,16 @@ static void wl1271_remove(struct sdio_fu + { + struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); + ++ if (glue->refclock) { ++ clk_disable_unprepare(glue->refclock); ++ clk_put(glue->refclock); ++ } ++ ++ if (glue->tcxoclock) { ++ clk_disable_unprepare(glue->tcxoclock); ++ clk_put(glue->tcxoclock); ++ } ++ + /* Undo decrement done above in wl1271_probe */ + pm_runtime_get_noresume(&func->dev); + diff --git a/target/linux/omap/patches-3.12/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch b/target/linux/omap/patches-3.12/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch new file mode 100644 index 000000000000..6b98c5225576 --- /dev/null +++ b/target/linux/omap/patches-3.12/907-wlcore-wl12xx-check-if-we-got-correct-clock-data-from-DT.patch @@ -0,0 +1,101 @@ +The fref and the tcxo clocks settings are optional in some platforms. +WiLink8 doesn't need either, so we don't check the values. WiLink 6 +only needs the fref clock, so we check that it is valid or return with +an error. WiLink7 needs both clocks, if either is not available we +return with an error. + +Signed-off-by: Luciano Coelho +Reviewed-by: Felipe Balbi + +--- +drivers/net/wireless/ti/wl12xx/main.c | 20 +++++++++++++++++--- + drivers/net/wireless/ti/wlcore/sdio.c | 4 ---- + 2 files changed, 17 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ti/wl12xx/main.c ++++ b/drivers/net/wireless/ti/wl12xx/main.c +@@ -927,6 +927,11 @@ static int wl128x_boot_clk(struct wl1271 + u16 sys_clk_cfg; + int ret; + ++ if ((priv->ref_clock < 0) || (priv->tcxo_clock < 0)) { ++ wl1271_error("Missing fref and/or tcxo clock settings\n"); ++ return -EINVAL; ++ } ++ + /* For XTAL-only modes, FREF will be used after switching from TCXO */ + if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL || + priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) { +@@ -976,6 +981,11 @@ static int wl127x_boot_clk(struct wl1271 + u32 clk; + int ret; + ++ if (priv->ref_clock < 0) { ++ wl1271_error("Missing fref clock settings\n"); ++ return -EINVAL; ++ } ++ + if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) + wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; + +@@ -1758,7 +1768,7 @@ static int wl12xx_setup(struct wl1271 *w + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap); + wl12xx_conf_init(wl); + +- if (!fref_param) { ++ if (!fref_param && (pdata->ref_clock_freq > 0)) { + priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, + pdata->ref_clock_freq, + pdata->ref_clock_xtal); +@@ -1769,6 +1779,8 @@ static int wl12xx_setup(struct wl1271 *w + + return priv->ref_clock; + } ++ } else if (!fref_param) { ++ priv->ref_clock = -EINVAL; + } else { + if (!strcmp(fref_param, "19.2")) + priv->ref_clock = WL12XX_REFCLOCK_19; +@@ -1786,7 +1798,7 @@ static int wl12xx_setup(struct wl1271 *w + wl1271_error("Invalid fref parameter %s", fref_param); + } + +- if (!tcxo_param) { ++ if (!fref_param && (pdata->tcxo_clock_freq > 0)) { + priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, + pdata->tcxo_clock_freq, + true); +@@ -1796,7 +1808,9 @@ static int wl12xx_setup(struct wl1271 *w + + return priv->tcxo_clock; + } +- } else { ++ } else if (!fref_param) { ++ priv->tcxo_clock = -EINVAL; ++ }else { + if (!strcmp(tcxo_param, "19.2")) + priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; + else if (!strcmp(tcxo_param, "26")) +--- a/drivers/net/wireless/ti/wlcore/sdio.c ++++ b/drivers/net/wireless/ti/wlcore/sdio.c +@@ -252,20 +252,16 @@ static struct wl12xx_platform_data *wlco + for_each_matching_node(clock_node, wlcore_sdio_of_clk_match_table) + of_fixed_clk_setup(clock_node); + +- /* TODO: make sure we have this when needed (ie. for WL6 and WL7) */ + glue->refclock = of_clk_get_by_name(np, "refclock"); + if (IS_ERR(glue->refclock)) { +- dev_err(dev, "couldn't find refclock on the device tree\n"); + glue->refclock = NULL; + } else { + clk_prepare_enable(glue->refclock); + pdata->ref_clock_freq = clk_get_rate(glue->refclock); + } + +- /* TODO: make sure we have this when needed (ie. for WL7) */ + glue->tcxoclock = of_clk_get_by_name(np, "tcxoclock"); + if (IS_ERR(glue->tcxoclock)) { +- dev_err(dev, "couldn't find tcxoclock on the device tree\n"); + glue->tcxoclock = NULL; + } else { + clk_prepare_enable(glue->tcxoclock); diff --git a/target/linux/omap/patches-3.12/908-Documentation-dt-bindings-TI-WiLink-modules.patch b/target/linux/omap/patches-3.12/908-Documentation-dt-bindings-TI-WiLink-modules.patch new file mode 100644 index 000000000000..beee4c8c0c83 --- /dev/null +++ b/target/linux/omap/patches-3.12/908-Documentation-dt-bindings-TI-WiLink-modules.patch @@ -0,0 +1,102 @@ +From patchwork Tue Jul 30 20:21:08 2013 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v3] Documentation: dt: bindings: TI WiLink modules +From: Luciano Coelho +X-Patchwork-Id: 2835914 +Message-Id: <1375215668-29171-1-git-send-email-coelho@ti.com> +To: , +Cc: , , , + , , + , , + , + , , + , +Date: Tue, 30 Jul 2013 23:21:08 +0300 + +Add device tree bindings documentation for the TI WiLink modules. +Currently only the WLAN part of the WiLink6, WiLink7 and WiLink8 +modules is supported. + +Signed-off-by: Luciano Coelho +Reviewed-by: Laurent Pinchart + +--- +In v3, use IRQ_TYPE_LEVEL_HIGH in the example, as suggested by Laurent. + + .../devicetree/bindings/net/wireless/ti-wilink.txt | 68 ++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/wireless/ti-wilink.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/wireless/ti-wilink.txt +@@ -0,0 +1,68 @@ ++TI WiLink Wireless Modules Device Tree Bindings ++=============================================== ++ ++The WiLink modules provide wireless connectivity, such as WLAN, ++Bluetooth, FM and NFC. ++ ++There are several different modules available, which can be grouped by ++their generation: WiLink6, WiLink7 and WiLink8. WiLink4 is not ++currently supported with device tree. ++ ++Currently, only the WLAN portion of the modules is supported with ++device tree. ++ ++Required properties: ++-------------------- ++ ++- compatible: should be "ti,wilink6", "ti,wilink7" or "ti,wilink8" ++- interrupt-parent: the interrupt controller ++- interrupts: out-of-band WLAN interrupt ++ See the interrupt controller's bindings documentation for ++ detailed definition. ++ ++Optional properties: ++-------------------- ++ ++- clocks: list of clocks needed by the chip as follows: ++ ++ refclock: the internal WLAN reference clock frequency (required for ++ WiLink6 and WiLink7; not used for WiLink8). ++ ++ tcxoclock: the internal WLAN TCXO clock frequency (required for ++ WiLink7 not used for WiLink6 and WiLink8). ++ ++ The clocks must be defined and named accordingly. For example: ++ ++ clocks = <&refclock> ++ clock-names = "refclock"; ++ ++ refclock: refclock { ++ compatible = "ti,wilink-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <38400000>; ++ }; ++ ++ Some modules that contain the WiLink chip provide clocks in the ++ module itself. In this case, we define a "ti,wilink-clock" as shown ++ above. But any other clock could in theory be used, so the proper ++ clock definition should be used. ++ ++ ++Example: ++-------- ++ ++Example definition that can be used in OMAP4 Panda: ++ ++wlan { ++ compatible = "ti,wilink6"; ++ interrupt-parent = <&gpio2>; ++ interrupts = <21 IRQ_TYPE_LEVEL_HIGH>; /* gpio line 53 */ ++ clocks = <&refclock>; ++ clock-names = "refclock"; ++ ++ refclock: refclock { ++ compatible = "ti,wilink-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <38400000>; ++ }; ++}; -- 2.30.2