162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2013 Qualcomm Atheros, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "ath9k.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = {
2062306a36Sopenharmony_ci	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
2162306a36Sopenharmony_ci	.n_patterns = MAX_NUM_USER_PATTERN,
2262306a36Sopenharmony_ci	.pattern_min_len = 1,
2362306a36Sopenharmony_ci	.pattern_max_len = MAX_PATTERN_SIZE,
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic const struct wiphy_wowlan_support ath9k_wowlan_support = {
2762306a36Sopenharmony_ci	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
2862306a36Sopenharmony_ci	.n_patterns = MAX_NUM_PATTERN - 2,
2962306a36Sopenharmony_ci	.pattern_min_len = 1,
3062306a36Sopenharmony_ci	.pattern_max_len = MAX_PATTERN_SIZE,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic u8 ath9k_wow_map_triggers(struct ath_softc *sc,
3462306a36Sopenharmony_ci				 struct cfg80211_wowlan *wowlan)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	u8 wow_triggers = 0;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (wowlan->disconnect)
3962306a36Sopenharmony_ci		wow_triggers |= AH_WOW_LINK_CHANGE |
4062306a36Sopenharmony_ci				AH_WOW_BEACON_MISS;
4162306a36Sopenharmony_ci	if (wowlan->magic_pkt)
4262306a36Sopenharmony_ci		wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (wowlan->n_patterns)
4562306a36Sopenharmony_ci		wow_triggers |= AH_WOW_USER_PATTERN_EN;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	return wow_triggers;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
5362306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
5462306a36Sopenharmony_ci	int pattern_count = 0;
5562306a36Sopenharmony_ci	int ret, i, byte_cnt = 0;
5662306a36Sopenharmony_ci	u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
5762306a36Sopenharmony_ci	u8 dis_deauth_mask[MAX_PATTERN_SIZE];
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
6062306a36Sopenharmony_ci	memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/*
6362306a36Sopenharmony_ci	 * Create Dissassociate / Deauthenticate packet filter
6462306a36Sopenharmony_ci	 *
6562306a36Sopenharmony_ci	 *     2 bytes        2 byte    6 bytes   6 bytes  6 bytes
6662306a36Sopenharmony_ci	 *  +--------------+----------+---------+--------+--------+----
6762306a36Sopenharmony_ci	 *  + Frame Control+ Duration +   DA    +  SA    +  BSSID +
6862306a36Sopenharmony_ci	 *  +--------------+----------+---------+--------+--------+----
6962306a36Sopenharmony_ci	 *
7062306a36Sopenharmony_ci	 * The above is the management frame format for disassociate/
7162306a36Sopenharmony_ci	 * deauthenticate pattern, from this we need to match the first byte
7262306a36Sopenharmony_ci	 * of 'Frame Control' and DA, SA, and BSSID fields
7362306a36Sopenharmony_ci	 * (skipping 2nd byte of FC and Duration feild.
7462306a36Sopenharmony_ci	 *
7562306a36Sopenharmony_ci	 * Disassociate pattern
7662306a36Sopenharmony_ci	 * --------------------
7762306a36Sopenharmony_ci	 * Frame control = 00 00 1010
7862306a36Sopenharmony_ci	 * DA, SA, BSSID = x:x:x:x:x:x
7962306a36Sopenharmony_ci	 * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
8062306a36Sopenharmony_ci	 *			    | x:x:x:x:x:x  -- 22 bytes
8162306a36Sopenharmony_ci	 *
8262306a36Sopenharmony_ci	 * Deauthenticate pattern
8362306a36Sopenharmony_ci	 * ----------------------
8462306a36Sopenharmony_ci	 * Frame control = 00 00 1100
8562306a36Sopenharmony_ci	 * DA, SA, BSSID = x:x:x:x:x:x
8662306a36Sopenharmony_ci	 * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
8762306a36Sopenharmony_ci	 *			    | x:x:x:x:x:x  -- 22 bytes
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Fill out the mask with all FF's */
9162306a36Sopenharmony_ci	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
9262306a36Sopenharmony_ci		dis_deauth_mask[i] = 0xff;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* copy the first byte of frame control field */
9562306a36Sopenharmony_ci	dis_deauth_pattern[byte_cnt] = 0xa0;
9662306a36Sopenharmony_ci	byte_cnt++;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* skip 2nd byte of frame control and Duration field */
9962306a36Sopenharmony_ci	byte_cnt += 3;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/*
10262306a36Sopenharmony_ci	 * need not match the destination mac address, it can be a broadcast
10362306a36Sopenharmony_ci	 * mac address or an unicast to this station
10462306a36Sopenharmony_ci	 */
10562306a36Sopenharmony_ci	byte_cnt += 6;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* copy the source mac address */
10862306a36Sopenharmony_ci	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	byte_cnt += 6;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* copy the bssid, its same as the source mac address */
11362306a36Sopenharmony_ci	memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Create Disassociate pattern mask */
11662306a36Sopenharmony_ci	dis_deauth_mask[0] = 0xfe;
11762306a36Sopenharmony_ci	dis_deauth_mask[1] = 0x03;
11862306a36Sopenharmony_ci	dis_deauth_mask[2] = 0xc0;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
12162306a36Sopenharmony_ci					 pattern_count, byte_cnt);
12262306a36Sopenharmony_ci	if (ret)
12362306a36Sopenharmony_ci		goto exit;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	pattern_count++;
12662306a36Sopenharmony_ci	/*
12762306a36Sopenharmony_ci	 * for de-authenticate pattern, only the first byte of the frame
12862306a36Sopenharmony_ci	 * control field gets changed from 0xA0 to 0xC0
12962306a36Sopenharmony_ci	 */
13062306a36Sopenharmony_ci	dis_deauth_pattern[0] = 0xC0;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
13362306a36Sopenharmony_ci					 pattern_count, byte_cnt);
13462306a36Sopenharmony_ciexit:
13562306a36Sopenharmony_ci	return ret;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int ath9k_wow_add_pattern(struct ath_softc *sc,
13962306a36Sopenharmony_ci				 struct cfg80211_wowlan *wowlan)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
14262306a36Sopenharmony_ci	struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
14362306a36Sopenharmony_ci	u8 wow_pattern[MAX_PATTERN_SIZE];
14462306a36Sopenharmony_ci	u8 wow_mask[MAX_PATTERN_SIZE];
14562306a36Sopenharmony_ci	int mask_len, ret = 0;
14662306a36Sopenharmony_ci	s8 i = 0;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	for (i = 0; i < wowlan->n_patterns; i++) {
14962306a36Sopenharmony_ci		mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
15062306a36Sopenharmony_ci		memset(wow_pattern, 0, MAX_PATTERN_SIZE);
15162306a36Sopenharmony_ci		memset(wow_mask, 0, MAX_PATTERN_SIZE);
15262306a36Sopenharmony_ci		memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len);
15362306a36Sopenharmony_ci		memcpy(wow_mask, patterns[i].mask, mask_len);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		ret = ath9k_hw_wow_apply_pattern(ah,
15662306a36Sopenharmony_ci						 wow_pattern,
15762306a36Sopenharmony_ci						 wow_mask,
15862306a36Sopenharmony_ci						 i + 2,
15962306a36Sopenharmony_ci						 patterns[i].pattern_len);
16062306a36Sopenharmony_ci		if (ret)
16162306a36Sopenharmony_ci			break;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	return ret;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciint ath9k_suspend(struct ieee80211_hw *hw,
16862306a36Sopenharmony_ci		  struct cfg80211_wowlan *wowlan)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct ath_softc *sc = hw->priv;
17162306a36Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
17262306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
17362306a36Sopenharmony_ci	u8 triggers;
17462306a36Sopenharmony_ci	int ret = 0;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	ath9k_deinit_channel_context(sc);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	mutex_lock(&sc->mutex);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
18162306a36Sopenharmony_ci		ath_err(common, "Device not present\n");
18262306a36Sopenharmony_ci		ret = -ENODEV;
18362306a36Sopenharmony_ci		goto fail_wow;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (WARN_ON(!wowlan)) {
18762306a36Sopenharmony_ci		ath_err(common, "None of the WoW triggers enabled\n");
18862306a36Sopenharmony_ci		ret = -EINVAL;
18962306a36Sopenharmony_ci		goto fail_wow;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (sc->cur_chan->nvifs > 1) {
19362306a36Sopenharmony_ci		ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
19462306a36Sopenharmony_ci		ret = 1;
19562306a36Sopenharmony_ci		goto fail_wow;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (ath9k_is_chanctx_enabled()) {
19962306a36Sopenharmony_ci		if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
20062306a36Sopenharmony_ci			ath_dbg(common, WOW,
20162306a36Sopenharmony_ci				"Multi-channel WOW is not supported\n");
20262306a36Sopenharmony_ci			ret = 1;
20362306a36Sopenharmony_ci			goto fail_wow;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
20862306a36Sopenharmony_ci		ath_dbg(common, WOW, "None of the STA vifs are associated\n");
20962306a36Sopenharmony_ci		ret = 1;
21062306a36Sopenharmony_ci		goto fail_wow;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	triggers = ath9k_wow_map_triggers(sc, wowlan);
21462306a36Sopenharmony_ci	if (!triggers) {
21562306a36Sopenharmony_ci		ath_dbg(common, WOW, "No valid WoW triggers\n");
21662306a36Sopenharmony_ci		ret = 1;
21762306a36Sopenharmony_ci		goto fail_wow;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ath_cancel_work(sc);
22162306a36Sopenharmony_ci	ath_stop_ani(sc);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	ath9k_ps_wakeup(sc);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	ath9k_stop_btcoex(sc);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/*
22862306a36Sopenharmony_ci	 * Enable wake up on recieving disassoc/deauth
22962306a36Sopenharmony_ci	 * frame by default.
23062306a36Sopenharmony_ci	 */
23162306a36Sopenharmony_ci	ret = ath9k_wow_add_disassoc_deauth_pattern(sc);
23262306a36Sopenharmony_ci	if (ret) {
23362306a36Sopenharmony_ci		ath_err(common,
23462306a36Sopenharmony_ci			"Unable to add disassoc/deauth pattern: %d\n", ret);
23562306a36Sopenharmony_ci		goto fail_wow;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (triggers & AH_WOW_USER_PATTERN_EN) {
23962306a36Sopenharmony_ci		ret = ath9k_wow_add_pattern(sc, wowlan);
24062306a36Sopenharmony_ci		if (ret) {
24162306a36Sopenharmony_ci			ath_err(common,
24262306a36Sopenharmony_ci				"Unable to add user pattern: %d\n", ret);
24362306a36Sopenharmony_ci			goto fail_wow;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	spin_lock_bh(&sc->sc_pcu_lock);
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * To avoid false wake, we enable beacon miss interrupt only
25062306a36Sopenharmony_ci	 * when we go to sleep. We save the current interrupt mask
25162306a36Sopenharmony_ci	 * so we can restore it after the system wakes up
25262306a36Sopenharmony_ci	 */
25362306a36Sopenharmony_ci	sc->wow_intr_before_sleep = ah->imask;
25462306a36Sopenharmony_ci	ah->imask &= ~ATH9K_INT_GLOBAL;
25562306a36Sopenharmony_ci	ath9k_hw_disable_interrupts(ah);
25662306a36Sopenharmony_ci	ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
25762306a36Sopenharmony_ci	ath9k_hw_set_interrupts(ah);
25862306a36Sopenharmony_ci	ath9k_hw_enable_interrupts(ah);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	spin_unlock_bh(&sc->sc_pcu_lock);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/*
26362306a36Sopenharmony_ci	 * we can now sync irq and kill any running tasklets, since we already
26462306a36Sopenharmony_ci	 * disabled interrupts and not holding a spin lock
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	synchronize_irq(sc->irq);
26762306a36Sopenharmony_ci	tasklet_kill(&sc->intr_tq);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ath9k_hw_wow_enable(ah, triggers);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	ath9k_ps_restore(sc);
27262306a36Sopenharmony_ci	ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	set_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
27562306a36Sopenharmony_cifail_wow:
27662306a36Sopenharmony_ci	mutex_unlock(&sc->mutex);
27762306a36Sopenharmony_ci	return ret;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciint ath9k_resume(struct ieee80211_hw *hw)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct ath_softc *sc = hw->priv;
28362306a36Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
28462306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
28562306a36Sopenharmony_ci	u8 status;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	mutex_lock(&sc->mutex);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ath9k_ps_wakeup(sc);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	spin_lock_bh(&sc->sc_pcu_lock);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	ath9k_hw_disable_interrupts(ah);
29462306a36Sopenharmony_ci	ah->imask = sc->wow_intr_before_sleep;
29562306a36Sopenharmony_ci	ath9k_hw_set_interrupts(ah);
29662306a36Sopenharmony_ci	ath9k_hw_enable_interrupts(ah);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	spin_unlock_bh(&sc->sc_pcu_lock);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	status = ath9k_hw_wow_wakeup(ah);
30162306a36Sopenharmony_ci	ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ath_restart_work(sc);
30462306a36Sopenharmony_ci	ath9k_start_btcoex(sc);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ath9k_ps_restore(sc);
30962306a36Sopenharmony_ci	mutex_unlock(&sc->mutex);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return 0;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_civoid ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct ath_softc *sc = hw->priv;
31762306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mutex_lock(&sc->mutex);
32062306a36Sopenharmony_ci	device_set_wakeup_enable(sc->dev, enabled);
32162306a36Sopenharmony_ci	mutex_unlock(&sc->mutex);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	ath_dbg(common, WOW, "WoW wakeup source is %s\n",
32462306a36Sopenharmony_ci		(enabled) ? "enabled" : "disabled");
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_civoid ath9k_init_wow(struct ieee80211_hw *hw)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct ath_softc *sc = hw->priv;
33062306a36Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) {
33362306a36Sopenharmony_ci		if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah))
33462306a36Sopenharmony_ci			hw->wiphy->wowlan = &ath9k_wowlan_support;
33562306a36Sopenharmony_ci		else
33662306a36Sopenharmony_ci			hw->wiphy->wowlan = &ath9k_wowlan_support_legacy;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		device_init_wakeup(sc->dev, 1);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_civoid ath9k_deinit_wow(struct ieee80211_hw *hw)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	struct ath_softc *sc = hw->priv;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow)
34762306a36Sopenharmony_ci		device_init_wakeup(sc->dev, 0);
34862306a36Sopenharmony_ci}
349