Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Atheros CARL9170 driver
0003  *
0004  * LED handling
0005  *
0006  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
0007  * Copyright 2009, 2010, Christian Lamparer <chunkeey@googlemail.com>
0008  *
0009  * This program is free software; you can redistribute it and/or modify
0010  * it under the terms of the GNU General Public License as published by
0011  * the Free Software Foundation; either version 2 of the License, or
0012  * (at your option) any later version.
0013  *
0014  * This program is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017  * GNU General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU General Public License
0020  * along with this program; see the file COPYING.  If not, see
0021  * http://www.gnu.org/licenses/.
0022  *
0023  * This file incorporates work covered by the following copyright and
0024  * permission notice:
0025  *    Copyright (c) 2007-2008 Atheros Communications, Inc.
0026  *
0027  *    Permission to use, copy, modify, and/or distribute this software for any
0028  *    purpose with or without fee is hereby granted, provided that the above
0029  *    copyright notice and this permission notice appear in all copies.
0030  *
0031  *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0032  *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0033  *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0034  *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0035  *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0036  *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0037  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0038  */
0039 
0040 #include "carl9170.h"
0041 #include "cmd.h"
0042 
0043 int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state)
0044 {
0045     return carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_DATA, led_state);
0046 }
0047 
0048 int carl9170_led_init(struct ar9170 *ar)
0049 {
0050     int err;
0051 
0052     /* disable LEDs */
0053     /* GPIO [0/1 mode: output, 2/3: input] */
0054     err = carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
0055     if (err)
0056         goto out;
0057 
0058     /* GPIO 0/1 value: off */
0059     err = carl9170_led_set_state(ar, 0);
0060 
0061 out:
0062     return err;
0063 }
0064 
0065 #ifdef CONFIG_CARL9170_LEDS
0066 static void carl9170_led_update(struct work_struct *work)
0067 {
0068     struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
0069     int i, tmp = 300, blink_delay = 1000;
0070     u32 led_val = 0;
0071     bool rerun = false;
0072 
0073     if (!IS_ACCEPTING_CMD(ar))
0074         return;
0075 
0076     mutex_lock(&ar->mutex);
0077     for (i = 0; i < AR9170_NUM_LEDS; i++) {
0078         if (ar->leds[i].registered) {
0079             if (ar->leds[i].last_state ||
0080                 ar->leds[i].toggled) {
0081 
0082                 if (ar->leds[i].toggled)
0083                     tmp = 70 + 200 / (ar->leds[i].toggled);
0084 
0085                 if (tmp < blink_delay)
0086                     blink_delay = tmp;
0087 
0088                 led_val |= 1 << i;
0089                 ar->leds[i].toggled = 0;
0090                 rerun = true;
0091             }
0092         }
0093     }
0094 
0095     carl9170_led_set_state(ar, led_val);
0096     mutex_unlock(&ar->mutex);
0097 
0098     if (!rerun)
0099         return;
0100 
0101     ieee80211_queue_delayed_work(ar->hw,
0102                      &ar->led_work,
0103                      msecs_to_jiffies(blink_delay));
0104 }
0105 
0106 static void carl9170_led_set_brightness(struct led_classdev *led,
0107                     enum led_brightness brightness)
0108 {
0109     struct carl9170_led *arl = container_of(led, struct carl9170_led, l);
0110     struct ar9170 *ar = arl->ar;
0111 
0112     if (!arl->registered)
0113         return;
0114 
0115     if (arl->last_state != !!brightness) {
0116         arl->toggled++;
0117         arl->last_state = !!brightness;
0118     }
0119 
0120     if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
0121         ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ / 10);
0122 }
0123 
0124 static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
0125                      const char *trigger)
0126 {
0127     int err;
0128 
0129     snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
0130          "carl9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
0131 
0132     ar->leds[i].ar = ar;
0133     ar->leds[i].l.name = ar->leds[i].name;
0134     ar->leds[i].l.brightness_set = carl9170_led_set_brightness;
0135     ar->leds[i].l.brightness = 0;
0136     ar->leds[i].l.default_trigger = trigger;
0137 
0138     err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
0139                     &ar->leds[i].l);
0140     if (err) {
0141         wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
0142             ar->leds[i].name, err);
0143     } else {
0144         ar->leds[i].registered = true;
0145     }
0146 
0147     return err;
0148 }
0149 
0150 void carl9170_led_unregister(struct ar9170 *ar)
0151 {
0152     int i;
0153 
0154     for (i = 0; i < AR9170_NUM_LEDS; i++)
0155         if (ar->leds[i].registered) {
0156             led_classdev_unregister(&ar->leds[i].l);
0157             ar->leds[i].registered = false;
0158             ar->leds[i].toggled = 0;
0159         }
0160 
0161     cancel_delayed_work_sync(&ar->led_work);
0162 }
0163 
0164 int carl9170_led_register(struct ar9170 *ar)
0165 {
0166     int err;
0167 
0168     INIT_DELAYED_WORK(&ar->led_work, carl9170_led_update);
0169 
0170     err = carl9170_led_register_led(ar, 0, "tx",
0171                     ieee80211_get_tx_led_name(ar->hw));
0172     if (err)
0173         goto fail;
0174 
0175     if (ar->features & CARL9170_ONE_LED)
0176         return 0;
0177 
0178     err = carl9170_led_register_led(ar, 1, "assoc",
0179                     ieee80211_get_assoc_led_name(ar->hw));
0180     if (err)
0181         goto fail;
0182 
0183     return 0;
0184 
0185 fail:
0186     carl9170_led_unregister(ar);
0187     return err;
0188 }
0189 
0190 #endif /* CONFIG_CARL9170_LEDS */