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