root/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath_detect_bt_priority
  2. ath_btcoex_period_work
  3. ath_btcoex_duty_cycle_work
  4. ath_htc_init_btcoex_work
  5. ath_htc_resume_btcoex_work
  6. ath_htc_cancel_btcoex_work
  7. ath9k_htc_start_btcoex
  8. ath9k_htc_stop_btcoex
  9. ath9k_htc_init_btcoex
  10. ath9k_led_work
  11. ath9k_led_brightness
  12. ath9k_deinit_leds
  13. ath9k_configure_leds
  14. ath9k_init_leds
  15. ath_is_rfkill_set
  16. ath9k_htc_rfkill_poll_state
  17. ath9k_start_rfkill_poll

   1 /*
   2  * Copyright (c) 2010-2011 Atheros Communications Inc.
   3  *
   4  * Permission to use, copy, modify, and/or distribute this software for any
   5  * purpose with or without fee is hereby granted, provided that the above
   6  * copyright notice and this permission notice appear in all copies.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15  */
  16 
  17 #include "htc.h"
  18 
  19 /******************/
  20 /*     BTCOEX     */
  21 /******************/
  22 
  23 #define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
  24 
  25 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
  26 
  27 /*
  28  * Detects if there is any priority bt traffic
  29  */
  30 static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
  31 {
  32         struct ath_btcoex *btcoex = &priv->btcoex;
  33         struct ath_hw *ah = priv->ah;
  34 
  35         if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
  36                 btcoex->bt_priority_cnt++;
  37 
  38         if (time_after(jiffies, btcoex->bt_priority_time +
  39                         msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
  40                 clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
  41                 clear_bit(OP_BT_SCAN, &priv->op_flags);
  42                 /* Detect if colocated bt started scanning */
  43                 if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
  44                         ath_dbg(ath9k_hw_common(ah), BTCOEX,
  45                                 "BT scan detected\n");
  46                         set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
  47                         set_bit(OP_BT_SCAN, &priv->op_flags);
  48                 } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
  49                         ath_dbg(ath9k_hw_common(ah), BTCOEX,
  50                                 "BT priority traffic detected\n");
  51                         set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
  52                 }
  53 
  54                 btcoex->bt_priority_cnt = 0;
  55                 btcoex->bt_priority_time = jiffies;
  56         }
  57 }
  58 
  59 /*
  60  * This is the master bt coex work which runs for every
  61  * 45ms, bt traffic will be given priority during 55% of this
  62  * period while wlan gets remaining 45%
  63  */
  64 static void ath_btcoex_period_work(struct work_struct *work)
  65 {
  66         struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
  67                                                    coex_period_work.work);
  68         struct ath_btcoex *btcoex = &priv->btcoex;
  69         struct ath_common *common = ath9k_hw_common(priv->ah);
  70         u32 timer_period;
  71         int ret;
  72 
  73         ath_detect_bt_priority(priv);
  74 
  75         ret = ath9k_htc_update_cap_target(priv,
  76                           test_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags));
  77         if (ret) {
  78                 ath_err(common, "Unable to set BTCOEX parameters\n");
  79                 return;
  80         }
  81 
  82         ath9k_hw_btcoex_bt_stomp(priv->ah, test_bit(OP_BT_SCAN, &priv->op_flags) ?
  83                                  ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type);
  84 
  85         ath9k_hw_btcoex_enable(priv->ah);
  86         timer_period = test_bit(OP_BT_SCAN, &priv->op_flags) ?
  87                 btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp;
  88         ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
  89                                      msecs_to_jiffies(timer_period));
  90         ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
  91                                      msecs_to_jiffies(btcoex->btcoex_period));
  92 }
  93 
  94 /*
  95  * Work to time slice between wlan and bt traffic and
  96  * configure weight registers
  97  */
  98 static void ath_btcoex_duty_cycle_work(struct work_struct *work)
  99 {
 100         struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
 101                                                    duty_cycle_work.work);
 102         struct ath_hw *ah = priv->ah;
 103         struct ath_btcoex *btcoex = &priv->btcoex;
 104         struct ath_common *common = ath9k_hw_common(ah);
 105 
 106         ath_dbg(common, BTCOEX, "time slice work for bt and wlan\n");
 107 
 108         if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
 109             test_bit(OP_BT_SCAN, &priv->op_flags))
 110                 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
 111         else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
 112                 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
 113 
 114         ath9k_hw_btcoex_enable(priv->ah);
 115 }
 116 
 117 static void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
 118 {
 119         struct ath_btcoex *btcoex = &priv->btcoex;
 120 
 121         btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
 122         btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
 123                 btcoex->btcoex_period / 100;
 124         btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
 125                                    btcoex->btcoex_period / 100;
 126         INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
 127         INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
 128 }
 129 
 130 /*
 131  * (Re)start btcoex work
 132  */
 133 
 134 static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 135 {
 136         struct ath_btcoex *btcoex = &priv->btcoex;
 137         struct ath_hw *ah = priv->ah;
 138 
 139         ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex work\n");
 140 
 141         btcoex->bt_priority_cnt = 0;
 142         btcoex->bt_priority_time = jiffies;
 143         clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
 144         clear_bit(OP_BT_SCAN, &priv->op_flags);
 145         ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
 146 }
 147 
 148 
 149 /*
 150  * Cancel btcoex and bt duty cycle work.
 151  */
 152 static void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
 153 {
 154         cancel_delayed_work_sync(&priv->coex_period_work);
 155         cancel_delayed_work_sync(&priv->duty_cycle_work);
 156 }
 157 
 158 void ath9k_htc_start_btcoex(struct ath9k_htc_priv *priv)
 159 {
 160         struct ath_hw *ah = priv->ah;
 161 
 162         if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) {
 163                 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
 164                                            AR_STOMP_LOW_WLAN_WGHT, 0);
 165                 ath9k_hw_btcoex_enable(ah);
 166                 ath_htc_resume_btcoex_work(priv);
 167         }
 168 }
 169 
 170 void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv)
 171 {
 172         struct ath_hw *ah = priv->ah;
 173 
 174         if (ah->btcoex_hw.enabled &&
 175             ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) {
 176                 if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
 177                         ath_htc_cancel_btcoex_work(priv);
 178                 ath9k_hw_btcoex_disable(ah);
 179         }
 180 }
 181 
 182 void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
 183 {
 184         struct ath_hw *ah = priv->ah;
 185         struct ath_common *common = ath9k_hw_common(ah);
 186         int qnum;
 187 
 188         /*
 189          * Check if BTCOEX is globally disabled.
 190          */
 191         if (!common->btcoex_enabled) {
 192                 ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_NONE;
 193                 return;
 194         }
 195 
 196         if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
 197                 ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
 198         }
 199 
 200         switch (ath9k_hw_get_btcoex_scheme(priv->ah)) {
 201         case ATH_BTCOEX_CFG_NONE:
 202                 break;
 203         case ATH_BTCOEX_CFG_3WIRE:
 204                 priv->ah->btcoex_hw.btactive_gpio = 7;
 205                 priv->ah->btcoex_hw.btpriority_gpio = 6;
 206                 priv->ah->btcoex_hw.wlanactive_gpio = 8;
 207                 priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
 208                 ath9k_hw_btcoex_init_3wire(priv->ah);
 209                 ath_htc_init_btcoex_work(priv);
 210                 qnum = priv->hwq_map[IEEE80211_AC_BE];
 211                 ath9k_hw_init_btcoex_hw(priv->ah, qnum);
 212                 break;
 213         default:
 214                 WARN_ON(1);
 215                 break;
 216         }
 217 }
 218 
 219 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 220 
 221 /*******/
 222 /* LED */
 223 /*******/
 224 
 225 #ifdef CONFIG_MAC80211_LEDS
 226 void ath9k_led_work(struct work_struct *work)
 227 {
 228         struct ath9k_htc_priv *priv = container_of(work,
 229                                                    struct ath9k_htc_priv,
 230                                                    led_work);
 231 
 232         ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
 233                           (priv->brightness == LED_OFF));
 234 }
 235 
 236 static void ath9k_led_brightness(struct led_classdev *led_cdev,
 237                                  enum led_brightness brightness)
 238 {
 239         struct ath9k_htc_priv *priv = container_of(led_cdev,
 240                                                    struct ath9k_htc_priv,
 241                                                    led_cdev);
 242 
 243         /* Not locked, but it's just a tiny green light..*/
 244         priv->brightness = brightness;
 245         ieee80211_queue_work(priv->hw, &priv->led_work);
 246 }
 247 
 248 void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
 249 {
 250         if (!priv->led_registered)
 251                 return;
 252 
 253         ath9k_led_brightness(&priv->led_cdev, LED_OFF);
 254         led_classdev_unregister(&priv->led_cdev);
 255         cancel_work_sync(&priv->led_work);
 256 
 257         ath9k_hw_gpio_free(priv->ah, priv->ah->led_pin);
 258 }
 259 
 260 
 261 void ath9k_configure_leds(struct ath9k_htc_priv *priv)
 262 {
 263         /* Configure gpio 1 for output */
 264         ath9k_hw_gpio_request_out(priv->ah, priv->ah->led_pin,
 265                                   "ath9k-led",
 266                                   AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 267         /* LED off, active low */
 268         ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
 269 }
 270 
 271 void ath9k_init_leds(struct ath9k_htc_priv *priv)
 272 {
 273         int ret;
 274 
 275         if (AR_SREV_9287(priv->ah))
 276                 priv->ah->led_pin = ATH_LED_PIN_9287;
 277         else if (AR_SREV_9271(priv->ah))
 278                 priv->ah->led_pin = ATH_LED_PIN_9271;
 279         else if (AR_DEVID_7010(priv->ah))
 280                 priv->ah->led_pin = ATH_LED_PIN_7010;
 281         else
 282                 priv->ah->led_pin = ATH_LED_PIN_DEF;
 283 
 284         if (!ath9k_htc_led_blink)
 285                 priv->led_cdev.default_trigger =
 286                         ieee80211_get_radio_led_name(priv->hw);
 287 
 288         ath9k_configure_leds(priv);
 289 
 290         snprintf(priv->led_name, sizeof(priv->led_name),
 291                 "ath9k_htc-%s", wiphy_name(priv->hw->wiphy));
 292         priv->led_cdev.name = priv->led_name;
 293         priv->led_cdev.brightness_set = ath9k_led_brightness;
 294 
 295         ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev);
 296         if (ret < 0)
 297                 return;
 298 
 299         INIT_WORK(&priv->led_work, ath9k_led_work);
 300         priv->led_registered = true;
 301 
 302         return;
 303 }
 304 #endif
 305 
 306 /*******************/
 307 /*      Rfkill     */
 308 /*******************/
 309 
 310 static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
 311 {
 312         bool is_blocked;
 313 
 314         ath9k_htc_ps_wakeup(priv);
 315         is_blocked = ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
 316                                                  priv->ah->rfkill_polarity;
 317         ath9k_htc_ps_restore(priv);
 318 
 319         return is_blocked;
 320 }
 321 
 322 void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
 323 {
 324         struct ath9k_htc_priv *priv = hw->priv;
 325         bool blocked = !!ath_is_rfkill_set(priv);
 326 
 327         wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
 328 }
 329 
 330 void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
 331 {
 332         if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 333                 wiphy_rfkill_start_polling(priv->hw->wiphy);
 334 }

/* [<][>][^][v][top][bottom][index][help] */