283ff97ed446512db27da5747832f0ac9733af1d
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / htc_drv_gpio.c
1 #include "htc.h"
2
3 /******************/
4 /*     BTCOEX     */
5 /******************/
6
7 /*
8  * Detects if there is any priority bt traffic
9  */
10 static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
11 {
12         struct ath_btcoex *btcoex = &priv->btcoex;
13         struct ath_hw *ah = priv->ah;
14
15         if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
16                 btcoex->bt_priority_cnt++;
17
18         if (time_after(jiffies, btcoex->bt_priority_time +
19                         msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
20                 priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
21                 /* Detect if colocated bt started scanning */
22                 if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
23                         ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
24                                 "BT scan detected\n");
25                         priv->op_flags |= (OP_BT_SCAN |
26                                          OP_BT_PRIORITY_DETECTED);
27                 } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
28                         ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
29                                 "BT priority traffic detected\n");
30                         priv->op_flags |= OP_BT_PRIORITY_DETECTED;
31                 }
32
33                 btcoex->bt_priority_cnt = 0;
34                 btcoex->bt_priority_time = jiffies;
35         }
36 }
37
38 /*
39  * This is the master bt coex work which runs for every
40  * 45ms, bt traffic will be given priority during 55% of this
41  * period while wlan gets remaining 45%
42  */
43 static void ath_btcoex_period_work(struct work_struct *work)
44 {
45         struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
46                                                    coex_period_work.work);
47         struct ath_btcoex *btcoex = &priv->btcoex;
48         struct ath_common *common = ath9k_hw_common(priv->ah);
49         u32 timer_period;
50         bool is_btscan;
51         int ret;
52         u8 cmd_rsp, aggr;
53
54         ath_detect_bt_priority(priv);
55
56         is_btscan = !!(priv->op_flags & OP_BT_SCAN);
57
58         aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
59
60         WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
61
62         ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
63                         btcoex->bt_stomp_type);
64
65         timer_period = is_btscan ? btcoex->btscan_no_stomp :
66                 btcoex->btcoex_no_stomp;
67         ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
68                                      msecs_to_jiffies(timer_period));
69         ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
70                                      msecs_to_jiffies(btcoex->btcoex_period));
71 }
72
73 /*
74  * Work to time slice between wlan and bt traffic and
75  * configure weight registers
76  */
77 static void ath_btcoex_duty_cycle_work(struct work_struct *work)
78 {
79         struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
80                                                    duty_cycle_work.work);
81         struct ath_hw *ah = priv->ah;
82         struct ath_btcoex *btcoex = &priv->btcoex;
83         struct ath_common *common = ath9k_hw_common(ah);
84         bool is_btscan = priv->op_flags & OP_BT_SCAN;
85
86         ath_dbg(common, ATH_DBG_BTCOEX,
87                 "time slice work for bt and wlan\n");
88
89         if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
90                 ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
91         else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
92                 ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
93 }
94
95 void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
96 {
97         struct ath_btcoex *btcoex = &priv->btcoex;
98
99         btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
100         btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
101                 btcoex->btcoex_period / 100;
102         btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
103                                    btcoex->btcoex_period / 100;
104         INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
105         INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
106 }
107
108 /*
109  * (Re)start btcoex work
110  */
111
112 void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
113 {
114         struct ath_btcoex *btcoex = &priv->btcoex;
115         struct ath_hw *ah = priv->ah;
116
117         ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work\n");
118
119         btcoex->bt_priority_cnt = 0;
120         btcoex->bt_priority_time = jiffies;
121         priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
122         ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
123 }
124
125
126 /*
127  * Cancel btcoex and bt duty cycle work.
128  */
129 void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
130 {
131         cancel_delayed_work_sync(&priv->coex_period_work);
132         cancel_delayed_work_sync(&priv->duty_cycle_work);
133 }