Commit | Line | Data |
---|---|---|
e9348cdd CL |
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 | ||
42 | int 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 | ||
47 | int 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 | ||
60 | out: | |
61 | return err; | |
62 | } | |
63 | ||
64 | #ifdef CONFIG_AR9170_LEDS | |
65 | static 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++) | |
6d7db193 | 77 | if (ar->leds[i].registered && ar->leds[i].toggled) { |
e9348cdd CL |
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 | ||
42935eca LR |
93 | if (!rerun) |
94 | return; | |
95 | ||
96 | ieee80211_queue_delayed_work(ar->hw, | |
97 | &ar->led_work, | |
98 | msecs_to_jiffies(blink_delay)); | |
e9348cdd CL |
99 | } |
100 | ||
101 | static 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 | ||
6d7db193 CL |
107 | if (unlikely(!arl->registered)) |
108 | return ; | |
109 | ||
2431fe9a CL |
110 | if (arl->last_state != !!brightness) { |
111 | arl->toggled++; | |
112 | arl->last_state = !!brightness; | |
113 | } | |
e9348cdd | 114 | |
2431fe9a | 115 | if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) |
42935eca | 116 | ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); |
e9348cdd CL |
117 | } |
118 | ||
119 | static 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) | |
c96c31e4 JP |
136 | wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n", |
137 | ar->leds[i].name, err); | |
e9348cdd CL |
138 | else |
139 | ar->leds[i].registered = true; | |
140 | ||
141 | return err; | |
142 | } | |
143 | ||
144 | void ar9170_unregister_leds(struct ar9170 *ar) | |
145 | { | |
146 | int i; | |
147 | ||
e9348cdd CL |
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; | |
6d7db193 | 152 | ar->leds[i].toggled = 0; |
e9348cdd | 153 | } |
6d7db193 CL |
154 | |
155 | cancel_delayed_work_sync(&ar->led_work); | |
e9348cdd CL |
156 | } |
157 | ||
158 | int 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 | ||
176 | fail: | |
177 | ar9170_unregister_leds(ar); | |
178 | return err; | |
179 | } | |
180 | ||
181 | #endif /* CONFIG_AR9170_LEDS */ |