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