AA: mac80211: sync with trunk r41113
[12.09/openwrt.git] / package / mac80211 / patches / 900-wlcore-Add-support-for-DT-platform-data.patch
diff --git a/package/mac80211/patches/900-wlcore-Add-support-for-DT-platform-data.patch b/package/mac80211/patches/900-wlcore-Add-support-for-DT-platform-data.patch
new file mode 100644 (file)
index 0000000..856dea8
--- /dev/null
@@ -0,0 +1,139 @@
+When running with DT, we no longer have a board file that can set up the
+platform data for wlcore. Allow this data to be passed from DT.
+
+Since some platforms use a gpio-irq, add support for passing either the
+irq number or the gpio number. For the latter case, the driver will
+request the gpio and convert it to the irq number. If an irq is
+specified, it'll be used as is.
+
+[Arik - the pdev_data pointer does not belong to us and is freed when
+the device is released. Dereference to our private data first.]
+
+Signed-off-by: Ido Yariv <ido@wizery.com>
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+---
+ drivers/net/wireless/ti/wlcore/sdio.c | 71 ++++++++++++++++++++++++++++++++---
+ include/linux/wl12xx.h                |  3 +-
+ 2 files changed, 67 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/wireless/ti/wlcore/sdio.c
++++ b/drivers/net/wireless/ti/wlcore/sdio.c
+@@ -34,6 +34,7 @@
+ #include <linux/wl12xx.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/printk.h>
++#include <linux/of.h>
+ #include "wlcore.h"
+ #include "wl12xx_80211.h"
+@@ -214,6 +215,61 @@ static struct wl1271_if_operations sdio_
+       .set_block_size = wl1271_sdio_set_block_size,
+ };
++static const struct of_device_id wlcore_of_match[] = {
++      {
++              .compatible = "wlcore",
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, wlcore_of_match);
++
++static struct wl12xx_platform_data *get_platform_data(struct device *dev)
++{
++      struct wl12xx_platform_data *pdata;
++      struct device_node *np;
++      u32 gpio;
++
++      pdata = wl12xx_get_platform_data();
++      if (!IS_ERR(pdata))
++              return kmemdup(pdata, sizeof(*pdata), GFP_KERNEL);
++
++      np = of_find_matching_node(NULL, wlcore_of_match);
++      if (!np) {
++              dev_err(dev, "No platform data set\n");
++              return NULL;
++      }
++
++      pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++      if (!pdata) {
++              dev_err(dev, "Can't allocate platform data\n");
++              return NULL;
++      }
++
++      if (of_property_read_u32(np, "irq", &pdata->irq)) {
++              if (!of_property_read_u32(np, "gpio", &gpio) &&
++                  !gpio_request_one(gpio, GPIOF_IN, "wlcore_irq")) {
++                      pdata->gpio = gpio;
++                      pdata->irq = gpio_to_irq(gpio);
++              }
++      }
++
++      /* Optional fields */
++      pdata->use_eeprom = of_property_read_bool(np, "use-eeprom");
++      of_property_read_u32(np, "board-ref-clock", &pdata->board_ref_clock);
++      of_property_read_u32(np, "board-tcxo-clock", &pdata->board_tcxo_clock);
++      of_property_read_u32(np, "platform-quirks", &pdata->platform_quirks);
++
++      return pdata;
++}
++
++static void del_platform_data(struct wl12xx_platform_data *pdata)
++{
++      if (pdata->gpio)
++              gpio_free(pdata->gpio);
++
++      kfree(pdata);
++}
++
+ static int wl1271_probe(struct sdio_func *func,
+                                 const struct sdio_device_id *id)
+ {
+@@ -245,10 +301,10 @@ 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;
+-      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);
++      pdev_data.pdata = get_platform_data(&func->dev);
++      if (!pdev_data.pdata) {
++              ret = -EINVAL;
++              dev_err(glue->dev, "missing wlan platform data\n");
+               goto out_free_glue;
+       }
+@@ -279,7 +335,7 @@ static int wl1271_probe(struct sdio_func
+       if (!glue->core) {
+               dev_err(glue->dev, "can't allocate platform_device");
+               ret = -ENOMEM;
+-              goto out_free_glue;
++              goto out_free_pdata;
+       }
+       glue->core->dev.parent = &func->dev;
+@@ -313,6 +369,9 @@ static int wl1271_probe(struct sdio_func
+ out_dev_put:
+       platform_device_put(glue->core);
++out_free_pdata:
++      del_platform_data(pdev_data->pdata);
++
+ out_free_glue:
+       kfree(glue);
+@@ -323,11 +382,14 @@ out:
+ static void wl1271_remove(struct sdio_func *func)
+ {
+       struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
++      struct wlcore_platdev_data *pdev_data = glue->core->dev.platform_data;
++      struct wl12xx_platform_data *pdata = pdev_data->pdata;
+       /* Undo decrement done above in wl1271_probe */
+       pm_runtime_get_noresume(&func->dev);
+       platform_device_unregister(glue->core);
++      del_platform_data(pdata);
+       kfree(glue);
+ }