linux/drivers/net/wireless/ath/carl9170/led.c
<<
>>
Prefs
   1/*
   2 * Atheros CARL9170 driver
   3 *
   4 * LED handling
   5 *
   6 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
   7 * Copyright 2009, 2010, Christian Lamparer <chunkeey@googlemail.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; see the file COPYING.  If not, see
  21 * http://www.gnu.org/licenses/.
  22 *
  23 * This file incorporates work covered by the following copyright and
  24 * permission notice:
  25 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
  26 *
  27 *    Permission to use, copy, modify, and/or distribute this software for any
  28 *    purpose with or without fee is hereby granted, provided that the above
  29 *    copyright notice and this permission notice appear in all copies.
  30 *
  31 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  32 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  33 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  34 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  35 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  36 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  37 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  38 */
  39
  40#include "carl9170.h"
  41#include "cmd.h"
  42
  43int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state)
  44{
  45        return carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_DATA, led_state);
  46}
  47
  48int carl9170_led_init(struct ar9170 *ar)
  49{
  50        int err;
  51
  52        /* disable LEDs */
  53        /* GPIO [0/1 mode: output, 2/3: input] */
  54        err = carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
  55        if (err)
  56                goto out;
  57
  58        /* GPIO 0/1 value: off */
  59        err = carl9170_led_set_state(ar, 0);
  60
  61out:
  62        return err;
  63}
  64
  65#ifdef CONFIG_CARL9170_LEDS
  66static void carl9170_led_update(struct work_struct *work)
  67{
  68        struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
  69        int i, tmp = 300, blink_delay = 1000;
  70        u32 led_val = 0;
  71        bool rerun = false;
  72
  73        if (!IS_ACCEPTING_CMD(ar))
  74                return;
  75
  76        mutex_lock(&ar->mutex);
  77        for (i = 0; i < AR9170_NUM_LEDS; i++) {
  78                if (ar->leds[i].registered) {
  79                        if (ar->leds[i].last_state ||
  80                            ar->leds[i].toggled) {
  81
  82                                if (ar->leds[i].toggled)
  83                                        tmp = 70 + 200 / (ar->leds[i].toggled);
  84
  85                                if (tmp < blink_delay)
  86                                        blink_delay = tmp;
  87
  88                                led_val |= 1 << i;
  89                                ar->leds[i].toggled = 0;
  90                                rerun = true;
  91                        }
  92                }
  93        }
  94
  95        carl9170_led_set_state(ar, led_val);
  96        mutex_unlock(&ar->mutex);
  97
  98        if (!rerun)
  99                return;
 100
 101        ieee80211_queue_delayed_work(ar->hw,
 102                                     &ar->led_work,
 103                                     msecs_to_jiffies(blink_delay));
 104}
 105
 106static void carl9170_led_set_brightness(struct led_classdev *led,
 107                                        enum led_brightness brightness)
 108{
 109        struct carl9170_led *arl = container_of(led, struct carl9170_led, l);
 110        struct ar9170 *ar = arl->ar;
 111
 112        if (!arl->registered)
 113                return;
 114
 115        if (arl->last_state != !!brightness) {
 116                arl->toggled++;
 117                arl->last_state = !!brightness;
 118        }
 119
 120        if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
 121                ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ / 10);
 122}
 123
 124static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
 125                                     char *trigger)
 126{
 127        int err;
 128
 129        snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
 130                 "carl9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
 131
 132        ar->leds[i].ar = ar;
 133        ar->leds[i].l.name = ar->leds[i].name;
 134        ar->leds[i].l.brightness_set = carl9170_led_set_brightness;
 135        ar->leds[i].l.brightness = 0;
 136        ar->leds[i].l.default_trigger = trigger;
 137
 138        err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
 139                                    &ar->leds[i].l);
 140        if (err) {
 141                wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
 142                        ar->leds[i].name, err);
 143        } else {
 144                ar->leds[i].registered = true;
 145        }
 146
 147        return err;
 148}
 149
 150void carl9170_led_unregister(struct ar9170 *ar)
 151{
 152        int i;
 153
 154        for (i = 0; i < AR9170_NUM_LEDS; i++)
 155                if (ar->leds[i].registered) {
 156                        led_classdev_unregister(&ar->leds[i].l);
 157                        ar->leds[i].registered = false;
 158                        ar->leds[i].toggled = 0;
 159                }
 160
 161        cancel_delayed_work_sync(&ar->led_work);
 162}
 163
 164int carl9170_led_register(struct ar9170 *ar)
 165{
 166        int err;
 167
 168        INIT_DELAYED_WORK(&ar->led_work, carl9170_led_update);
 169
 170        err = carl9170_led_register_led(ar, 0, "tx",
 171                                        ieee80211_get_tx_led_name(ar->hw));
 172        if (err)
 173                goto fail;
 174
 175        if (ar->features & CARL9170_ONE_LED)
 176                return 0;
 177
 178        err = carl9170_led_register_led(ar, 1, "assoc",
 179                                        ieee80211_get_assoc_led_name(ar->hw));
 180        if (err)
 181                goto fail;
 182
 183        return 0;
 184
 185fail:
 186        carl9170_led_unregister(ar);
 187        return err;
 188}
 189
 190#endif /* CONFIG_CARL9170_LEDS */
 191