linux/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 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/*
  24 * Detects if there is any priority bt traffic
  25 */
  26static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
  27{
  28        struct ath_btcoex *btcoex = &priv->btcoex;
  29        struct ath_hw *ah = priv->ah;
  30
  31        if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
  32                btcoex->bt_priority_cnt++;
  33
  34        if (time_after(jiffies, btcoex->bt_priority_time +
  35                        msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
  36                priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
  37                /* Detect if colocated bt started scanning */
  38                if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
  39                        ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
  40                                "BT scan detected\n");
  41                        priv->op_flags |= (OP_BT_SCAN |
  42                                         OP_BT_PRIORITY_DETECTED);
  43                } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
  44                        ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
  45                                "BT priority traffic detected\n");
  46                        priv->op_flags |= OP_BT_PRIORITY_DETECTED;
  47                }
  48
  49                btcoex->bt_priority_cnt = 0;
  50                btcoex->bt_priority_time = jiffies;
  51        }
  52}
  53
  54/*
  55 * This is the master bt coex work which runs for every
  56 * 45ms, bt traffic will be given priority during 55% of this
  57 * period while wlan gets remaining 45%
  58 */
  59static void ath_btcoex_period_work(struct work_struct *work)
  60{
  61        struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
  62                                                   coex_period_work.work);
  63        struct ath_btcoex *btcoex = &priv->btcoex;
  64        struct ath_common *common = ath9k_hw_common(priv->ah);
  65        u32 timer_period;
  66        bool is_btscan;
  67        int ret;
  68        u8 cmd_rsp, aggr;
  69
  70        ath_detect_bt_priority(priv);
  71
  72        is_btscan = !!(priv->op_flags & OP_BT_SCAN);
  73
  74        aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
  75
  76        WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
  77
  78        ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
  79                        btcoex->bt_stomp_type);
  80
  81        timer_period = is_btscan ? btcoex->btscan_no_stomp :
  82                btcoex->btcoex_no_stomp;
  83        ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
  84                                     msecs_to_jiffies(timer_period));
  85        ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
  86                                     msecs_to_jiffies(btcoex->btcoex_period));
  87}
  88
  89/*
  90 * Work to time slice between wlan and bt traffic and
  91 * configure weight registers
  92 */
  93static void ath_btcoex_duty_cycle_work(struct work_struct *work)
  94{
  95        struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
  96                                                   duty_cycle_work.work);
  97        struct ath_hw *ah = priv->ah;
  98        struct ath_btcoex *btcoex = &priv->btcoex;
  99        struct ath_common *common = ath9k_hw_common(ah);
 100        bool is_btscan = priv->op_flags & OP_BT_SCAN;
 101
 102        ath_dbg(common, ATH_DBG_BTCOEX,
 103                "time slice work for bt and wlan\n");
 104
 105        if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
 106                ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
 107        else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
 108                ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
 109}
 110
 111void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
 112{
 113        struct ath_btcoex *btcoex = &priv->btcoex;
 114
 115        btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
 116        btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
 117                btcoex->btcoex_period / 100;
 118        btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
 119                                   btcoex->btcoex_period / 100;
 120        INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
 121        INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
 122}
 123
 124/*
 125 * (Re)start btcoex work
 126 */
 127
 128void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 129{
 130        struct ath_btcoex *btcoex = &priv->btcoex;
 131        struct ath_hw *ah = priv->ah;
 132
 133        ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, "Starting btcoex work\n");
 134
 135        btcoex->bt_priority_cnt = 0;
 136        btcoex->bt_priority_time = jiffies;
 137        priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
 138        ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
 139}
 140
 141
 142/*
 143 * Cancel btcoex and bt duty cycle work.
 144 */
 145void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
 146{
 147        cancel_delayed_work_sync(&priv->coex_period_work);
 148        cancel_delayed_work_sync(&priv->duty_cycle_work);
 149}
 150
 151/*******/
 152/* LED */
 153/*******/
 154
 155static void ath9k_led_blink_work(struct work_struct *work)
 156{
 157        struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
 158                                                   ath9k_led_blink_work.work);
 159
 160        if (!(priv->op_flags & OP_LED_ASSOCIATED))
 161                return;
 162
 163        if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
 164            (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
 165                ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
 166        else
 167                ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
 168                                  (priv->op_flags & OP_LED_ON) ? 1 : 0);
 169
 170        ieee80211_queue_delayed_work(priv->hw,
 171                                     &priv->ath9k_led_blink_work,
 172                                     (priv->op_flags & OP_LED_ON) ?
 173                                     msecs_to_jiffies(priv->led_off_duration) :
 174                                     msecs_to_jiffies(priv->led_on_duration));
 175
 176        priv->led_on_duration = priv->led_on_cnt ?
 177                max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
 178                ATH_LED_ON_DURATION_IDLE;
 179        priv->led_off_duration = priv->led_off_cnt ?
 180                max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
 181                ATH_LED_OFF_DURATION_IDLE;
 182        priv->led_on_cnt = priv->led_off_cnt = 0;
 183
 184        if (priv->op_flags & OP_LED_ON)
 185                priv->op_flags &= ~OP_LED_ON;
 186        else
 187                priv->op_flags |= OP_LED_ON;
 188}
 189
 190static void ath9k_led_brightness_work(struct work_struct *work)
 191{
 192        struct ath_led *led = container_of(work, struct ath_led,
 193                                           brightness_work.work);
 194        struct ath9k_htc_priv *priv = led->priv;
 195
 196        switch (led->brightness) {
 197        case LED_OFF:
 198                if (led->led_type == ATH_LED_ASSOC ||
 199                    led->led_type == ATH_LED_RADIO) {
 200                        ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
 201                                          (led->led_type == ATH_LED_RADIO));
 202                        priv->op_flags &= ~OP_LED_ASSOCIATED;
 203                        if (led->led_type == ATH_LED_RADIO)
 204                                priv->op_flags &= ~OP_LED_ON;
 205                } else {
 206                        priv->led_off_cnt++;
 207                }
 208                break;
 209        case LED_FULL:
 210                if (led->led_type == ATH_LED_ASSOC) {
 211                        priv->op_flags |= OP_LED_ASSOCIATED;
 212                        ieee80211_queue_delayed_work(priv->hw,
 213                                             &priv->ath9k_led_blink_work, 0);
 214                } else if (led->led_type == ATH_LED_RADIO) {
 215                        ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
 216                        priv->op_flags |= OP_LED_ON;
 217                } else {
 218                        priv->led_on_cnt++;
 219                }
 220                break;
 221        default:
 222                break;
 223        }
 224}
 225
 226static void ath9k_led_brightness(struct led_classdev *led_cdev,
 227                                 enum led_brightness brightness)
 228{
 229        struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
 230        struct ath9k_htc_priv *priv = led->priv;
 231
 232        led->brightness = brightness;
 233        if (!(priv->op_flags & OP_LED_DEINIT))
 234                ieee80211_queue_delayed_work(priv->hw,
 235                                             &led->brightness_work, 0);
 236}
 237
 238void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
 239{
 240        cancel_delayed_work_sync(&priv->radio_led.brightness_work);
 241        cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
 242        cancel_delayed_work_sync(&priv->tx_led.brightness_work);
 243        cancel_delayed_work_sync(&priv->rx_led.brightness_work);
 244}
 245
 246static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
 247                              char *trigger)
 248{
 249        int ret;
 250
 251        led->priv = priv;
 252        led->led_cdev.name = led->name;
 253        led->led_cdev.default_trigger = trigger;
 254        led->led_cdev.brightness_set = ath9k_led_brightness;
 255
 256        ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
 257        if (ret)
 258                ath_err(ath9k_hw_common(priv->ah),
 259                        "Failed to register led:%s", led->name);
 260        else
 261                led->registered = 1;
 262
 263        INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
 264
 265        return ret;
 266}
 267
 268static void ath9k_unregister_led(struct ath_led *led)
 269{
 270        if (led->registered) {
 271                led_classdev_unregister(&led->led_cdev);
 272                led->registered = 0;
 273        }
 274}
 275
 276void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
 277{
 278        priv->op_flags |= OP_LED_DEINIT;
 279        ath9k_unregister_led(&priv->assoc_led);
 280        priv->op_flags &= ~OP_LED_ASSOCIATED;
 281        ath9k_unregister_led(&priv->tx_led);
 282        ath9k_unregister_led(&priv->rx_led);
 283        ath9k_unregister_led(&priv->radio_led);
 284}
 285
 286void ath9k_init_leds(struct ath9k_htc_priv *priv)
 287{
 288        char *trigger;
 289        int ret;
 290
 291        if (AR_SREV_9287(priv->ah))
 292                priv->ah->led_pin = ATH_LED_PIN_9287;
 293        else if (AR_SREV_9271(priv->ah))
 294                priv->ah->led_pin = ATH_LED_PIN_9271;
 295        else if (AR_DEVID_7010(priv->ah))
 296                priv->ah->led_pin = ATH_LED_PIN_7010;
 297        else
 298                priv->ah->led_pin = ATH_LED_PIN_DEF;
 299
 300        /* Configure gpio 1 for output */
 301        ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
 302                            AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 303        /* LED off, active low */
 304        ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
 305
 306        INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
 307
 308        trigger = ieee80211_get_radio_led_name(priv->hw);
 309        snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
 310                "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
 311        ret = ath9k_register_led(priv, &priv->radio_led, trigger);
 312        priv->radio_led.led_type = ATH_LED_RADIO;
 313        if (ret)
 314                goto fail;
 315
 316        trigger = ieee80211_get_assoc_led_name(priv->hw);
 317        snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
 318                "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
 319        ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
 320        priv->assoc_led.led_type = ATH_LED_ASSOC;
 321        if (ret)
 322                goto fail;
 323
 324        trigger = ieee80211_get_tx_led_name(priv->hw);
 325        snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
 326                "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
 327        ret = ath9k_register_led(priv, &priv->tx_led, trigger);
 328        priv->tx_led.led_type = ATH_LED_TX;
 329        if (ret)
 330                goto fail;
 331
 332        trigger = ieee80211_get_rx_led_name(priv->hw);
 333        snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
 334                "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
 335        ret = ath9k_register_led(priv, &priv->rx_led, trigger);
 336        priv->rx_led.led_type = ATH_LED_RX;
 337        if (ret)
 338                goto fail;
 339
 340        priv->op_flags &= ~OP_LED_DEINIT;
 341
 342        return;
 343
 344fail:
 345        cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
 346        ath9k_deinit_leds(priv);
 347}
 348
 349/*******************/
 350/*      Rfkill     */
 351/*******************/
 352
 353static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
 354{
 355        return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
 356                priv->ah->rfkill_polarity;
 357}
 358
 359void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
 360{
 361        struct ath9k_htc_priv *priv = hw->priv;
 362        bool blocked = !!ath_is_rfkill_set(priv);
 363
 364        wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
 365}
 366
 367void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
 368{
 369        if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
 370                wiphy_rfkill_start_polling(priv->hw->wiphy);
 371}
 372
 373void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
 374{
 375        struct ath9k_htc_priv *priv = hw->priv;
 376        struct ath_hw *ah = priv->ah;
 377        struct ath_common *common = ath9k_hw_common(ah);
 378        int ret;
 379        u8 cmd_rsp;
 380
 381        if (!ah->curchan)
 382                ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 383
 384        /* Reset the HW */
 385        ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 386        if (ret) {
 387                ath_err(common,
 388                        "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 389                        ret, ah->curchan->channel);
 390        }
 391
 392        ath_update_txpow(priv);
 393
 394        /* Start RX */
 395        WMI_CMD(WMI_START_RECV_CMDID);
 396        ath9k_host_rx_init(priv);
 397
 398        /* Start TX */
 399        htc_start(priv->htc);
 400        spin_lock_bh(&priv->tx_lock);
 401        priv->tx_queues_stop = false;
 402        spin_unlock_bh(&priv->tx_lock);
 403        ieee80211_wake_queues(hw);
 404
 405        WMI_CMD(WMI_ENABLE_INTR_CMDID);
 406
 407        /* Enable LED */
 408        ath9k_hw_cfg_output(ah, ah->led_pin,
 409                            AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 410        ath9k_hw_set_gpio(ah, ah->led_pin, 0);
 411}
 412
 413void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
 414{
 415        struct ath9k_htc_priv *priv = hw->priv;
 416        struct ath_hw *ah = priv->ah;
 417        struct ath_common *common = ath9k_hw_common(ah);
 418        int ret;
 419        u8 cmd_rsp;
 420
 421        ath9k_htc_ps_wakeup(priv);
 422
 423        /* Disable LED */
 424        ath9k_hw_set_gpio(ah, ah->led_pin, 1);
 425        ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
 426
 427        WMI_CMD(WMI_DISABLE_INTR_CMDID);
 428
 429        /* Stop TX */
 430        ieee80211_stop_queues(hw);
 431        htc_stop(priv->htc);
 432        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
 433        skb_queue_purge(&priv->tx_queue);
 434
 435        /* Stop RX */
 436        WMI_CMD(WMI_STOP_RECV_CMDID);
 437
 438        /*
 439         * The MIB counters have to be disabled here,
 440         * since the target doesn't do it.
 441         */
 442        ath9k_hw_disable_mib_counters(ah);
 443
 444        if (!ah->curchan)
 445                ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 446
 447        /* Reset the HW */
 448        ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 449        if (ret) {
 450                ath_err(common,
 451                        "Unable to reset hardware; reset status %d (freq %u MHz)\n",
 452                        ret, ah->curchan->channel);
 453        }
 454
 455        /* Disable the PHY */
 456        ath9k_hw_phy_disable(ah);
 457
 458        ath9k_htc_ps_restore(priv);
 459        ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 460}
 461