wl1251: add powersave exit logic for transfers
[pandora-kernel.git] / drivers / net / wireless / wl1251 / sdio.c
index f786942..d141d83 100644 (file)
 
 #include "wl1251.h"
 
+static bool force_nvs_file = false;
+module_param(force_nvs_file, bool, 0644);
+MODULE_PARM_DESC(force_nvs_file, "Force loading NVS data from file, "
+                                "not EEPROM. Default: n/N/0");
+static bool dump_eeprom = false;
+module_param(dump_eeprom, bool, 0644);
+MODULE_PARM_DESC(dump_eeprom, "Dump EEPROM on module load and makes it "
+                             "accessable through debugfs. Default: n/N/0");
+
 #ifndef SDIO_VENDOR_ID_TI
 #define SDIO_VENDOR_ID_TI              0x104c
 #endif
@@ -151,16 +160,6 @@ static void wl1251_sdio_disable_irq(struct wl1251 *wl)
        sdio_release_host(func);
 }
 
-/* Interrupts when using dedicated WLAN_IRQ pin */
-static irqreturn_t wl1251_line_irq(int irq, void *cookie)
-{
-       struct wl1251 *wl = cookie;
-
-       ieee80211_queue_work(wl->hw, &wl->irq_work);
-
-       return IRQ_HANDLED;
-}
-
 static void wl1251_enable_line_irq(struct wl1251 *wl)
 {
        return enable_irq(wl->irq);
@@ -218,10 +217,64 @@ static struct wl1251_if_operations wl1251_sdio_ops = {
        .power = wl1251_sdio_set_power,
 };
 
+static ssize_t
+wl1251_show_long_doze(struct device *dev, struct device_attribute *attr,
+       char *buf)
+{
+       struct wl1251 *wl = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", wl->long_doze_mode);
+}
+
+static ssize_t
+wl1251_set_long_doze(struct device *dev, struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct wl1251 *wl = dev_get_drvdata(dev);
+       int val, ret;
+
+       ret = kstrtoint(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       wl->long_doze_mode = !!val;
+       return count;
+}
+
+static ssize_t
+wl1251_show_ps_rate_thr(struct device *dev, struct device_attribute *attr,
+       char *buf)
+{
+       struct wl1251 *wl = dev_get_drvdata(dev);
+       return sprintf(buf, "%u\n", wl->ps_rate_threshold);
+}
+
+static ssize_t
+wl1251_set_ps_rate_thr(struct device *dev, struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct wl1251 *wl = dev_get_drvdata(dev);
+       unsigned int val;
+       int ret;
+
+       ret = kstrtouint(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       wl->ps_rate_threshold = val;
+       return count;
+}
+
+static struct device_attribute wl1251_attrs[] = {
+       __ATTR(long_doze_mode, S_IRUGO | S_IWUGO,
+               wl1251_show_long_doze, wl1251_set_long_doze),
+       __ATTR(ps_rate_threshold, S_IRUGO | S_IWUGO,
+               wl1251_show_ps_rate_thr, wl1251_set_ps_rate_thr),
+};
+
 static int wl1251_sdio_probe(struct sdio_func *func,
                             const struct sdio_device_id *id)
 {
-       int ret;
+       int ret, t;
        struct wl1251 *wl;
        struct ieee80211_hw *hw;
        struct wl1251_sdio *wl_sdio;
@@ -259,15 +312,21 @@ static int wl1251_sdio_probe(struct sdio_func *func,
                wl->use_eeprom = wl12xx_board_data->use_eeprom;
        }
 
+       if (force_nvs_file)
+               wl->use_eeprom = false;
+       wl->dump_eeprom = dump_eeprom;
+
        if (wl->irq) {
-               ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
+               irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
+
+               ret = request_threaded_irq(wl->irq, NULL, wl1251_irq,
+                       IRQF_ONESHOT, "wl1251", wl);
                if (ret < 0) {
                        wl1251_error("request_irq() failed: %d", ret);
                        goto disable;
                }
 
                irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
-               disable_irq(wl->irq);
 
                wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
                wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
@@ -286,6 +345,16 @@ static int wl1251_sdio_probe(struct sdio_func *func,
 
        sdio_set_drvdata(func, wl);
 
+       for (t = 0; t < ARRAY_SIZE(wl1251_attrs); t++) {
+               ret = device_create_file(&func->dev, &wl1251_attrs[t]);
+               if (ret) {
+                       while (--t >= 0)
+                               device_remove_file(&func->dev,
+                                                  &wl1251_attrs[t]);
+                       goto out_free_irq;
+               }
+       }
+
        /* Tell PM core that we don't need the card to be powered now */
        pm_runtime_put_noidle(&func->dev);
 
@@ -309,14 +378,18 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
 {
        struct wl1251 *wl = sdio_get_drvdata(func);
        struct wl1251_sdio *wl_sdio = wl->if_priv;
+       int t;
 
        /* Undo decrement done above in wl1251_probe */
        pm_runtime_get_noresume(&func->dev);
 
+       for (t = 0; t < ARRAY_SIZE(wl1251_attrs); t++)
+               device_remove_file(&func->dev, &wl1251_attrs[t]);
+
        if (wl->irq)
                free_irq(wl->irq, wl);
-       kfree(wl_sdio);
        wl1251_free_hw(wl);
+       kfree(wl_sdio);
 
        sdio_claim_host(func);
        sdio_release_irq(func);