xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/ssv6xxx/smac/ssv_pm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3  * Copyright (c) 2015 iComm Corporation
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <ssv6200.h>
18 #include "dev.h"
19 #include "sar.h"
20 #ifdef CONFIG_SSV_SUPPORT_ANDROID
21 #ifdef CONFIG_HAS_WAKELOCK
22 #include <linux/wakelock.h>
23 #endif
24 #ifdef CONFIG_HAS_EARLYSUSPEND
25 #include <linux/earlysuspend.h>
26 #elif LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)
27 #include <linux/notifier.h>
28 #include <linux/fb.h>
29 #endif
30 struct ssv_softc *ssv_notify_sc = NULL;
31 EXPORT_SYMBOL(ssv_notify_sc);
32 #if defined(CONFIG_HAS_EARLYSUSPEND) || (LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0))
33 #ifdef CONFIG_HAS_EARLYSUSPEND
ssv6xxx_early_suspend(struct early_suspend * h)34 void ssv6xxx_early_suspend(struct early_suspend *h)
35 #else
36 void ssv6xxx_early_suspend(void)
37 #endif
38 {
39 #ifdef CONFIG_HAS_EARLYSUSPEND
40     struct ssv_softc *sc = container_of(h, struct ssv_softc, early_suspend);
41 #else
42     struct ssv_softc *sc = ssv_notify_sc;
43 #endif
44     sc->ps_status = PWRSV_PREPARE;
45     if (sc->is_sar_enabled) {
46         cancel_delayed_work(&sc->thermal_monitor_work);
47         flush_workqueue(sc->thermal_wq);
48     }
49     printk(KERN_INFO "ssv6xxx_early_suspend\n");
50     ssv6xxx_watchdog_controller(sc->sh ,(u8)SSV6XXX_HOST_CMD_WATCHDOG_STOP);
51     sc->watchdog_flag = WD_SLEEP;
52 }
53 #define DEAUTH_DISASSOC_LEN (24 + 2 )
ssv6xxx_send_deauth_toself(struct ssv_softc * sc,const u8 * bssid,const u8 * self_addr)54 void ssv6xxx_send_deauth_toself(struct ssv_softc *sc,const u8 *bssid,const u8 *self_addr)
55 {
56     struct sk_buff *deauth_skb ;
57  u8 frame_buf[DEAUTH_DISASSOC_LEN];
58     struct ieee80211_mgmt *mgmt = (void *)frame_buf;
59  mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH);
60  mgmt->duration = 0;
61  mgmt->seq_ctrl = 0;
62  memcpy(mgmt->da, self_addr, ETH_ALEN);
63  memcpy(mgmt->sa, bssid, ETH_ALEN);
64  memcpy(mgmt->bssid, bssid, ETH_ALEN);
65  mgmt->u.deauth.reason_code = cpu_to_le16(2);
66  {
67   deauth_skb = dev_alloc_skb(DEAUTH_DISASSOC_LEN);
68   if (!deauth_skb)
69    return;
70   memcpy(skb_put(deauth_skb, DEAUTH_DISASSOC_LEN),
71          mgmt, DEAUTH_DISASSOC_LEN);
72         #if defined(USE_THREAD_RX) && !defined(IRQ_PROC_RX_DATA)
73         local_bh_disable();
74         ieee80211_rx(sc->hw, deauth_skb);
75         local_bh_enable();
76         #else
77         ieee80211_rx_irqsafe(sc->hw, deauth_skb);
78         #endif
79      return;
80  }
81 }
82 #ifdef CONFIG_HAS_EARLYSUSPEND
ssv6xxx_late_resume(struct early_suspend * h)83 void ssv6xxx_late_resume(struct early_suspend *h)
84 #else
85 void ssv6xxx_late_resume(void)
86 #endif
87 {
88 #ifdef CONFIG_HAS_EARLYSUSPEND
89  struct ssv_softc *sc = container_of(h, struct ssv_softc, early_suspend);
90 #else
91  struct ssv_softc *sc = ssv_notify_sc;
92 #endif
93 	if (!sc)
94 		return;
95     if(sc->ps_status == PWRSV_ENABLE)
96     {
97         if(sc->vif_info[0].vif)
98         {
99             if(sc->vif_info[0].vif->bss_conf.assoc)
100             {
101                 printk("sc->vif_info[0].vif->bss_conf.assoc\n");
102                 if ((sc->vif_info[0].vif->type == NL80211_IFTYPE_STATION) || (sc->vif_info[0].vif->p2p))
103                 {
104                     printk("sc->vif_info[0].vif->bss_conf.assoc ssv6xxx_send_deauth_toself\n");
105                     ssv6xxx_send_deauth_toself(sc, sc->vif_info[0].vif->bss_conf.bssid, sc->vif_info[0].vif->addr);
106                 }
107             }
108         }
109         if(sc->vif_info[1].vif)
110         {
111             if(sc->vif_info[1].vif->bss_conf.assoc)
112             {
113                 printk("sc->vif_info[1].vif->bss_conf.assoc\n");
114                 if ((sc->vif_info[1].vif->type == NL80211_IFTYPE_STATION) || (sc->vif_info[1].vif->p2p))
115                 {
116                     printk("sc->vif_info[1].vif->bss_conf.assoc ssv6xxx_send_deauth_toself\n");
117                     ssv6xxx_send_deauth_toself(sc, sc->vif_info[1].vif->bss_conf.bssid, sc->vif_info[1].vif->addr);
118                 }
119             }
120         }
121     }
122     if(sc)
123         ssv6xxx_disable_ps(sc);
124     else
125         printk(KERN_INFO "ssv6xxx_late_resume,sc=NULL\n");
126     if (sc->is_sar_enabled) {
127         queue_delayed_work(sc->thermal_wq, &sc->thermal_monitor_work, THERMAL_MONITOR_TIME);
128     }
129     ssv6xxx_watchdog_controller(sc->sh ,(u8)SSV6XXX_HOST_CMD_WATCHDOG_START);
130     sc->watchdog_flag = WD_KICKED;
131     printk(KERN_INFO "ssv6xxx_late_resume\n");
132 }
133 #ifndef CONFIG_HAS_EARLYSUSPEND
ssv_wlan_fb_event_notify(struct notifier_block * self,unsigned long action,void * data)134 static int ssv_wlan_fb_event_notify(struct notifier_block *self,
135                        unsigned long action, void *data)
136 {
137         struct fb_event *event = data;
138         int blank_mode = *((int *)event->data);
139         if (action == FB_EARLY_EVENT_BLANK) {
140                 switch (blank_mode) {
141                 case FB_BLANK_UNBLANK:
142                         break;
143                 default:
144       ssv6xxx_early_suspend();
145                         break;
146                 }
147         }
148    else if (action == FB_EVENT_BLANK) {
149                 switch (blank_mode) {
150                 case FB_BLANK_UNBLANK:
151       ssv6xxx_late_resume();
152                         break;
153                 default:
154                         break;
155                 }
156         }
157         return NOTIFY_OK;
158 }
159 struct notifier_block ssv_wlan_fb_notifier = {
160     .notifier_call = ssv_wlan_fb_event_notify,
161 };
162 #endif
163 #endif
ssv_wakelock_init(struct ssv_softc * sc)164 void ssv_wakelock_init(struct ssv_softc *sc)
165 {
166 #ifdef CONFIG_HAS_WAKELOCK
167     wake_lock_init(&sc->ssv_wake_lock_, WAKE_LOCK_SUSPEND, "ssv6051");
168 #endif
169 #ifndef CONFIG_HAS_EARLYSUSPEND
170 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
171  fb_register_client(&ssv_wlan_fb_notifier);
172 #endif
173 #endif
174 }
ssv_wakelock_destroy(struct ssv_softc * sc)175 void ssv_wakelock_destroy(struct ssv_softc *sc)
176 {
177 #ifdef CONFIG_HAS_WAKELOCK
178     wake_lock_destroy(&sc->ssv_wake_lock_);
179 #endif
180 #ifndef CONFIG_HAS_EARLYSUSPEND
181 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
182  fb_unregister_client(&ssv_wlan_fb_notifier);
183 #endif
184 #endif
185 }
ssv_wake_lock(struct ssv_softc * sc)186 void ssv_wake_lock(struct ssv_softc *sc)
187 {
188 #ifdef CONFIG_HAS_WAKELOCK
189     wake_lock(&sc->ssv_wake_lock_);
190 #endif
191 }
ssv_wake_timeout(struct ssv_softc * sc,int secs)192 void ssv_wake_timeout(struct ssv_softc *sc, int secs)
193 {
194 #ifdef CONFIG_HAS_WAKELOCK
195     wake_lock_timeout(&sc->ssv_wake_lock_,secs*HZ);
196 #endif
197 }
ssv_wake_unlock(struct ssv_softc * sc)198 void ssv_wake_unlock(struct ssv_softc *sc)
199 {
200 #ifdef CONFIG_HAS_WAKELOCK
201     wake_unlock(&sc->ssv_wake_lock_);
202 #endif
203 }
204 #endif
205