#ifdef CONFIG_PM
+int wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
+{
+       int num_fields = 0, in_field = 0, fields_size = 0;
+       int i, pattern_len = 0;
+
+       if (!p->mask) {
+               wl1271_warning("No mask in WoWLAN pattern");
+               return -EINVAL;
+       }
+
+       /*
+        * The pattern is broken up into segments of bytes at different offsets
+        * that need to be checked by the FW filter. Each segment is called
+        * a field in the FW API. We verify that the total number of fields
+        * required for this pattern won't exceed FW limits (8)
+        * as well as the total fields buffer won't exceed the FW limit.
+        * Note that if there's a pattern which crosses Ethernet/IP header
+        * boundary a new field is required.
+        */
+       for (i = 0; i < p->pattern_len; i++) {
+               if (test_bit(i, (unsigned long *)p->mask)) {
+                       if (!in_field) {
+                               in_field = 1;
+                               pattern_len = 1;
+                       } else {
+                               if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
+                                       num_fields++;
+                                       fields_size += pattern_len +
+                                               RX_FILTER_FIELD_OVERHEAD;
+                                       pattern_len = 1;
+                               } else
+                                       pattern_len++;
+                       }
+               } else {
+                       if (in_field) {
+                               in_field = 0;
+                               fields_size += pattern_len +
+                                       RX_FILTER_FIELD_OVERHEAD;
+                               num_fields++;
+                       }
+               }
+       }
+
+       if (in_field) {
+               fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
+               num_fields++;
+       }
+
+       if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
+               wl1271_warning("RX Filter too complex. Too many segments");
+               return -EINVAL;
+       }
+
+       if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
+               wl1271_warning("RX filter pattern is too big");
+               return -E2BIG;
+       }
+
+       return 0;
+}
+
 struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
 {
        return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
        }
 }
 
+/*
+ * Allocates an RX filter returned through f
+ * which needs to be freed using rx_filter_free()
+ */
+int wl1271_convert_wowlan_pattern_to_rx_filter(
+       struct cfg80211_wowlan_trig_pkt_pattern *p,
+       struct wl12xx_rx_filter **f)
+{
+       int i, j, ret = 0;
+       struct wl12xx_rx_filter *filter;
+       u16 offset;
+       u8 flags, len;
+
+       filter = wl1271_rx_filter_alloc();
+       if (!filter) {
+               wl1271_warning("Failed to alloc rx filter");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       i = 0;
+       while (i < p->pattern_len) {
+               if (!test_bit(i, (unsigned long *)p->mask)) {
+                       i++;
+                       continue;
+               }
+
+               for (j = i; j < p->pattern_len; j++) {
+                       if (!test_bit(j, (unsigned long *)p->mask))
+                               break;
+
+                       if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
+                           j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
+                               break;
+               }
+
+               if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
+                       offset = i;
+                       flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
+               } else {
+                       offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
+                       flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
+               }
+
+               len = j - i;
+
+               ret = wl1271_rx_filter_alloc_field(filter,
+                                                  offset,
+                                                  flags,
+                                                  &p->pattern[i], len);
+               if (ret)
+                       goto err;
+
+               i = j;
+       }
+
+       filter->action = FILTER_SIGNAL;
+
+       *f = filter;
+       return 0;
+
+err:
+       wl1271_rx_filter_free(filter);
+       *f = NULL;
+
+       return ret;
+}
+
+static int wl1271_configure_wowlan(struct wl1271 *wl,
+                                  struct cfg80211_wowlan *wow)
+{
+       int i, ret;
+
+       if (!wow || wow->any || !wow->n_patterns) {
+               wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
+               wl1271_rx_filter_clear_all(wl);
+               return 0;
+       }
+
+       if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
+               return -EINVAL;
+
+       /* Validate all incoming patterns before clearing current FW state */
+       for (i = 0; i < wow->n_patterns; i++) {
+               ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
+               if (ret) {
+                       wl1271_warning("Bad wowlan pattern %d", i);
+                       return ret;
+               }
+       }
+
+       wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
+       wl1271_rx_filter_clear_all(wl);
+
+       /* Translate WoWLAN patterns into filters */
+       for (i = 0; i < wow->n_patterns; i++) {
+               struct cfg80211_wowlan_trig_pkt_pattern *p;
+               struct wl12xx_rx_filter *filter = NULL;
+
+               p = &wow->patterns[i];
+
+               ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
+               if (ret) {
+                       wl1271_warning("Failed to create an RX filter from "
+                                      "wowlan pattern %d", i);
+                       goto out;
+               }
+
+               ret = wl1271_rx_filter_enable(wl, i, 1, filter);
+
+               wl1271_rx_filter_free(filter);
+               if (ret)
+                       goto out;
+       }
+
+       ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
+
+out:
+       return ret;
+}
+
 static int wl1271_configure_suspend_sta(struct wl1271 *wl,
-                                       struct wl12xx_vif *wlvif)
+                                       struct wl12xx_vif *wlvif,
+                                       struct cfg80211_wowlan *wow)
 {
        int ret = 0;
 
        if (ret < 0)
                goto out;
 
+       wl1271_configure_wowlan(wl, wow);
        ret = wl1271_acx_wake_up_conditions(wl, wlvif,
                                    wl->conf.conn.suspend_wake_up_event,
                                    wl->conf.conn.suspend_listen_interval);
 }
 
 static int wl1271_configure_suspend(struct wl1271 *wl,
-                                   struct wl12xx_vif *wlvif)
+                                   struct wl12xx_vif *wlvif,
+                                   struct cfg80211_wowlan *wow)
 {
        if (wlvif->bss_type == BSS_TYPE_STA_BSS)
-               return wl1271_configure_suspend_sta(wl, wlvif);
+               return wl1271_configure_suspend_sta(wl, wlvif, wow);
        if (wlvif->bss_type == BSS_TYPE_AP_BSS)
                return wl1271_configure_suspend_ap(wl, wlvif);
        return 0;
                return;
 
        if (is_sta) {
+               wl1271_configure_wowlan(wl, NULL);
+
                ret = wl1271_acx_wake_up_conditions(wl, wlvif,
                                    wl->conf.conn.wake_up_event,
                                    wl->conf.conn.listen_interval);
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
-       WARN_ON(!wow || !wow->any);
+       WARN_ON(!wow);
 
        wl1271_tx_flush(wl);
 
        mutex_lock(&wl->mutex);
        wl->wow_enabled = true;
        wl12xx_for_each_wlvif(wl, wlvif) {
-               ret = wl1271_configure_suspend(wl, wlvif);
+               ret = wl1271_configure_suspend(wl, wlvif, wow);
                if (ret < 0) {
                        wl1271_warning("couldn't prepare device to suspend");
                        return ret;
        if (!ret) {
                wl->irq_wake_enabled = true;
                device_init_wakeup(wl->dev, 1);
-               if (pdata->pwr_in_suspend)
+               if (pdata->pwr_in_suspend) {
                        wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
-
+                       wl->hw->wiphy->wowlan.n_patterns =
+                               WL1271_MAX_RX_FILTERS;
+                       wl->hw->wiphy->wowlan.pattern_min_len = 1;
+                       wl->hw->wiphy->wowlan.pattern_max_len =
+                               WL1271_RX_FILTER_MAX_PATTERN_SIZE;
+               }
        }
        disable_irq(wl->irq);