remove asm/bitops.h includes
[linux-2.6-block.git] / drivers / net / wireless / bcm43xx / bcm43xx_leds.c
CommitLineData
f222313a
JL
1/*
2
3 Broadcom BCM43xx wireless driver
4
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; see the file COPYING. If not, write to
23 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
24 Boston, MA 02110-1301, USA.
25
26*/
27
28#include "bcm43xx_leds.h"
01917382 29#include "bcm43xx_radio.h"
f222313a
JL
30#include "bcm43xx.h"
31
1977f032 32#include <linux/bitops.h>
f222313a
JL
33
34
35static void bcm43xx_led_changestate(struct bcm43xx_led *led)
36{
37 struct bcm43xx_private *bcm = led->bcm;
38 const int index = bcm43xx_led_index(led);
dcfd720b 39 const u16 mask = (1 << index);
f222313a
JL
40 u16 ledctl;
41
42 assert(index >= 0 && index < BCM43xx_NR_LEDS);
43 assert(led->blink_interval);
44 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
dcfd720b 45 ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
f222313a
JL
46 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
47}
48
49static void bcm43xx_led_blink(unsigned long d)
50{
51 struct bcm43xx_led *led = (struct bcm43xx_led *)d;
52 struct bcm43xx_private *bcm = led->bcm;
53 unsigned long flags;
54
efa6a370 55 spin_lock_irqsave(&bcm->leds_lock, flags);
f222313a
JL
56 if (led->blink_interval) {
57 bcm43xx_led_changestate(led);
58 mod_timer(&led->blink_timer, jiffies + led->blink_interval);
59 }
efa6a370 60 spin_unlock_irqrestore(&bcm->leds_lock, flags);
f222313a
JL
61}
62
63static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
64 unsigned long interval)
65{
dcfd720b
MB
66 if (led->blink_interval)
67 return;
f222313a
JL
68 led->blink_interval = interval;
69 bcm43xx_led_changestate(led);
70 led->blink_timer.expires = jiffies + interval;
71 add_timer(&led->blink_timer);
72}
73
74static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
75{
76 struct bcm43xx_private *bcm = led->bcm;
77 const int index = bcm43xx_led_index(led);
78 u16 ledctl;
79
80 if (!led->blink_interval)
81 return;
82 if (unlikely(sync))
83 del_timer_sync(&led->blink_timer);
84 else
85 del_timer(&led->blink_timer);
86 led->blink_interval = 0;
87
88 /* Make sure the LED is turned off. */
89 assert(index >= 0 && index < BCM43xx_NR_LEDS);
90 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
91 if (led->activelow)
92 ledctl |= (1 << index);
93 else
94 ledctl &= ~(1 << index);
95 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
96}
97
dcfd720b
MB
98static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
99 struct bcm43xx_led *led,
100 int led_index)
101{
102 /* This function is called, if the behaviour (and activelow)
103 * information for a LED is missing in the SPROM.
104 * We hardcode the behaviour values for various devices here.
105 * Note that the BCM43xx_LED_TEST_XXX behaviour values can
106 * be used to figure out which led is mapped to which index.
107 */
108
109 switch (led_index) {
110 case 0:
111 led->behaviour = BCM43xx_LED_ACTIVITY;
01917382 112 led->activelow = 1;
dcfd720b
MB
113 if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
114 led->behaviour = BCM43xx_LED_RADIO_ALL;
115 break;
116 case 1:
117 led->behaviour = BCM43xx_LED_RADIO_B;
118 if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
119 led->behaviour = BCM43xx_LED_ASSOC;
120 break;
121 case 2:
122 led->behaviour = BCM43xx_LED_RADIO_A;
123 break;
124 case 3:
125 led->behaviour = BCM43xx_LED_OFF;
126 break;
127 default:
128 assert(0);
129 }
130}
131
f222313a
JL
132int bcm43xx_leds_init(struct bcm43xx_private *bcm)
133{
134 struct bcm43xx_led *led;
135 u8 sprom[4];
136 int i;
137
138 sprom[0] = bcm->sprom.wl0gpio0;
139 sprom[1] = bcm->sprom.wl0gpio1;
140 sprom[2] = bcm->sprom.wl0gpio2;
141 sprom[3] = bcm->sprom.wl0gpio3;
142
143 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
144 led = &(bcm->leds[i]);
145 led->bcm = bcm;
dcfd720b
MB
146 setup_timer(&led->blink_timer,
147 bcm43xx_led_blink,
148 (unsigned long)led);
f222313a
JL
149
150 if (sprom[i] == 0xFF) {
dcfd720b 151 bcm43xx_led_init_hardcoded(bcm, led, i);
f222313a
JL
152 } else {
153 led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
154 led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
155 }
156 }
157
158 return 0;
159}
160
161void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
162{
163 struct bcm43xx_led *led;
164 int i;
165
166 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
167 led = &(bcm->leds[i]);
168 bcm43xx_led_blink_stop(led, 1);
169 }
714eece7 170 bcm43xx_leds_switch_all(bcm, 0);
f222313a
JL
171}
172
173void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
174{
175 struct bcm43xx_led *led;
e9357c05
MB
176 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
177 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
f222313a 178 const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
dcfd720b 179 int i, turn_on;
f222313a
JL
180 unsigned long interval = 0;
181 u16 ledctl;
efa6a370 182 unsigned long flags;
f222313a 183
efa6a370 184 spin_lock_irqsave(&bcm->leds_lock, flags);
f222313a
JL
185 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
186 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
187 led = &(bcm->leds[i]);
f222313a 188
dcfd720b 189 turn_on = 0;
f222313a 190 switch (led->behaviour) {
dcfd720b
MB
191 case BCM43xx_LED_INACTIVE:
192 continue;
f222313a 193 case BCM43xx_LED_OFF:
df6d7c94 194 case BCM43xx_LED_BCM4303_3:
f222313a
JL
195 break;
196 case BCM43xx_LED_ON:
197 turn_on = 1;
198 break;
199 case BCM43xx_LED_ACTIVITY:
df6d7c94 200 case BCM43xx_LED_BCM4303_0:
f222313a
JL
201 turn_on = activity;
202 break;
203 case BCM43xx_LED_RADIO_ALL:
01917382 204 turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
f222313a
JL
205 break;
206 case BCM43xx_LED_RADIO_A:
df6d7c94 207 case BCM43xx_LED_BCM4303_2:
01917382
LF
208 turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
209 phy->type == BCM43xx_PHYTYPE_A);
f222313a
JL
210 break;
211 case BCM43xx_LED_RADIO_B:
df6d7c94 212 case BCM43xx_LED_BCM4303_1:
01917382 213 turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
f222313a
JL
214 (phy->type == BCM43xx_PHYTYPE_B ||
215 phy->type == BCM43xx_PHYTYPE_G));
216 break;
217 case BCM43xx_LED_MODE_BG:
01917382 218 if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
f222313a
JL
219 1/*FIXME: using G rates.*/)
220 turn_on = 1;
221 break;
222 case BCM43xx_LED_TRANSFER:
223 if (transferring)
224 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
225 else
226 bcm43xx_led_blink_stop(led, 0);
227 continue;
228 case BCM43xx_LED_APTRANSFER:
229 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
230 if (transferring) {
231 interval = BCM43xx_LEDBLINK_FAST;
232 turn_on = 1;
233 }
234 } else {
235 turn_on = 1;
236 if (0/*TODO: not assoc*/)
237 interval = BCM43xx_LEDBLINK_SLOW;
238 else if (transferring)
239 interval = BCM43xx_LEDBLINK_FAST;
240 else
241 turn_on = 0;
242 }
243 if (turn_on)
244 bcm43xx_led_blink_start(led, interval);
245 else
246 bcm43xx_led_blink_stop(led, 0);
247 continue;
248 case BCM43xx_LED_WEIRD:
249 //TODO
f222313a
JL
250 break;
251 case BCM43xx_LED_ASSOC:
7c28ad2d 252 if (bcm->softmac->associnfo.associated)
f222313a
JL
253 turn_on = 1;
254 break;
dcfd720b
MB
255#ifdef CONFIG_BCM43XX_DEBUG
256 case BCM43xx_LED_TEST_BLINKSLOW:
257 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
258 continue;
259 case BCM43xx_LED_TEST_BLINKMEDIUM:
260 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
261 continue;
262 case BCM43xx_LED_TEST_BLINKFAST:
263 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
264 continue;
265#endif /* CONFIG_BCM43XX_DEBUG */
f222313a 266 default:
df6d7c94
LF
267 dprintkl(KERN_INFO PFX "Bad value in leds_update,"
268 " led->behaviour: 0x%x\n", led->behaviour);
f222313a
JL
269 };
270
271 if (led->activelow)
272 turn_on = !turn_on;
273 if (turn_on)
274 ledctl |= (1 << i);
275 else
276 ledctl &= ~(1 << i);
277 }
278 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
efa6a370 279 spin_unlock_irqrestore(&bcm->leds_lock, flags);
f222313a
JL
280}
281
714eece7 282void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
f222313a
JL
283{
284 struct bcm43xx_led *led;
714eece7 285 u16 ledctl;
f222313a 286 int i;
714eece7 287 int bit_on;
efa6a370 288 unsigned long flags;
f222313a 289
efa6a370 290 spin_lock_irqsave(&bcm->leds_lock, flags);
714eece7 291 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
f222313a
JL
292 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
293 led = &(bcm->leds[i]);
294 if (led->behaviour == BCM43xx_LED_INACTIVE)
295 continue;
714eece7
MB
296 if (on)
297 bit_on = led->activelow ? 0 : 1;
298 else
299 bit_on = led->activelow ? 1 : 0;
300 if (bit_on)
f222313a 301 ledctl |= (1 << i);
714eece7
MB
302 else
303 ledctl &= ~(1 << i);
f222313a
JL
304 }
305 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
efa6a370 306 spin_unlock_irqrestore(&bcm->leds_lock, flags);
f222313a 307}