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 43 int 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 48 int 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 61 out: 62 return err; 63 } 64 65 #ifdef CONFIG_CARL9170_LEDS 66 static 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 106 static 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 124 static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name, 125 const 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 150 void 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 164 int 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 185 fail: 186 carl9170_led_unregister(ar); 187 return err; 188 } 189 190 #endif /* CONFIG_CARL9170_LEDS */ 191