3 Copyright 2002 Broadcom Corp. All Rights Reserved.
5 This program is free software; you can distribute it and/or modify it
6 under the terms of the GNU General Public License (Version 2) as
7 published by the Free Software Foundation.
9 This program is distributed in the hope it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 /***************************************************************************
20 * File Name : bcm63xx_led.c
24 * This file contains bcm963xx board led control API functions.
26 * To use it, do the following
28 * 1). define in the board.c the following led mappping (this is for 6345GW board):
29 * const LED_MAP_PAIR cLedMapping45GW[] =
30 * { // led name Initial state physical pin (ledMask)
31 * {kLedUsb, kLedStateOff, GPIO_LED_PIN_7},
32 * {kLedAdsl, kLedStateOff, GPIO_LED_PIN_8},
33 * {kLedPPP, kLedStateOff, GPIO_LED_PIN_9}, // PPP and WanData share PIN_9
34 * {kLedWanData, kLedStateOff, GPIO_LED_PIN_9},
35 * {kLedWireless, kLedStateOff, GPIO_LED_PIN_10},
36 * {kLedEnd, kLedStateOff, 0 } // NOTE: kLedEnd has to be at the end.
38 * 2). };To initialize led API and initial state of the leds, call the following function with the mapping
39 * pointer from the above struct
41 * boardLedInit((PLED_MAP_PAIR) &cLedMapping45R);
43 * 3). Sample call for kernel mode:
45 * kerSysLedCtrl(kLedAdsl, kLedStateBlinkOnce); // kLedxxx defines in board.h
47 * 4). Sample call for user mode
49 * sysLedCtrl(kLedAdsl, kLedStateBlinkOnce); // kLedxxx defines in board_api.h
52 * Created on : 10/28/2002 seanl
54 ***************************************************************************/
57 #include <linux/init.h>
59 #include <linux/capability.h>
60 #include <linux/slab.h>
61 #include <linux/errno.h>
62 #include <linux/module.h>
63 #include <linux/netdevice.h>
64 #include <asm/uaccess.h>
66 #include <bcm_map_part.h>
69 #define k100ms (HZ / 10) // ~100 ms
70 #define kFastBlinkCount 0 // ~100ms
71 #define kSlowBlinkCount 5 // ~600ms
73 #define MAX_VIRT_LEDS 12
75 // uncomment // for debug led
79 struct timer_list gLedTimer;
83 typedef struct ledinfo
85 unsigned short ledMask; // mask for led: ie. giop 10 = 0x0400
86 unsigned short ledActiveLow; // GPIO bit reset to turn on LED
87 unsigned short ledMaskFail; // mask for led: ie. giop 10 = 0x0400
88 unsigned short ledActiveLowFail;// GPIO bit reset to turn on LED
89 BOARD_LED_STATE ledState; // current led state
90 BOARD_LED_STATE savedLedState; // used in blink once for restore to the orignal ledState
91 int blinkCountDown; // if == 0, do blink (toggle). Is assgined value and dec by 1 at each timer.
92 } LED_INFO, *PLED_INFO;
94 static PLED_INFO gLed = NULL;
95 static PLED_INFO gpVirtLeds[MAX_VIRT_LEDS];
96 static HANDLE_LED_FUNC gLedHwFunc[MAX_VIRT_LEDS];
97 static HANDLE_LED_FUNC gLedHwFailFunc[MAX_VIRT_LEDS];
100 #if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
101 static int gLedOffInBridgeMode = 1;
102 #elif defined(CONFIG_BCM96345)
103 static int gLedOffInBridgeMode = 0;
107 void ledTimerExpire(void);
108 int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed );
110 //**************************************************************************************
112 //**************************************************************************************
114 // turn led on and set the ledState
115 void ledOn(PLED_INFO pLed)
119 GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
120 if( pLed->ledActiveLow )
121 GPIO->GPIOio &= ~pLed->ledMask; // turn on the led
123 GPIO->GPIOio |= pLed->ledMask; // turn on the led
124 pLed->ledState = pLed->savedLedState = kLedStateOn;
129 // turn led off and set the ledState
130 void ledOff(PLED_INFO pLed)
134 GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
135 if( pLed->ledActiveLow )
136 GPIO->GPIOio |= pLed->ledMask; // turn off the led
138 GPIO->GPIOio &= ~pLed->ledMask; // turn off the led
139 pLed->ledState = pLed->savedLedState = kLedStateOff;
143 // turn led on and set the ledState
144 void ledOnFail(PLED_INFO pLed)
146 if( pLed->ledMaskFail )
148 GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one
149 if( pLed->ledActiveLowFail )
150 GPIO->GPIOio &= ~pLed->ledMaskFail;// turn on the led
152 GPIO->GPIOio |= pLed->ledMaskFail; // turn on the led
153 pLed->ledState = pLed->savedLedState = kLedStateFail;
158 // turn led off and set the ledState
159 void ledOffFail(PLED_INFO pLed)
161 if( pLed->ledMaskFail )
163 GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one
164 if( pLed->ledActiveLowFail )
165 GPIO->GPIOio |= pLed->ledMaskFail; // turn off the led
167 GPIO->GPIOio &= ~pLed->ledMaskFail;// turn off the led
168 pLed->ledState = pLed->savedLedState = kLedStateOff;
173 // toggle the led and return the current ledState
174 BOARD_LED_STATE ledToggle(PLED_INFO pLed)
176 GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
177 if (GPIO->GPIOio & pLed->ledMask)
179 GPIO->GPIOio &= ~(pLed->ledMask);
180 return( (pLed->ledActiveLow) ? kLedStateOn : kLedStateOff );
184 GPIO->GPIOio |= pLed->ledMask;
185 return( (pLed->ledActiveLow) ? kLedStateOff : kLedStateOn );
190 // led timer. Will return if timer is already on
191 void ledTimerStart(void)
196 #if defined(DEBUG_LED)
197 printk("led: add_timer\n");
200 init_timer(&gLedTimer);
201 gLedTimer.function = (void*)ledTimerExpire;
202 gLedTimer.expires = jiffies + k100ms; // timer expires in ~100ms
203 add_timer (&gLedTimer);
208 // led timer expire kicks in about ~100ms and perform the led operation according to the ledState and
209 // restart the timer according to ledState
210 void ledTimerExpire(void)
217 for (i = 0, pCurLed = gLed; i < gLedCount; i++, pCurLed++)
219 #if defined(DEBUG_LED)
220 printk("led[%d]: Mask=0x%04x, State = %d, blcd=%d\n", i, pCurLed->ledMask, pCurLed->ledState, pCurLed->blinkCountDown);
222 switch (pCurLed->ledState)
227 pCurLed->blinkCountDown = 0; // reset the blink count down
230 case kLedStateBlinkOnce:
232 pCurLed->blinkCountDown = 0; // reset to 0
233 pCurLed->ledState = pCurLed->savedLedState;
234 if (pCurLed->ledState == kLedStateSlowBlinkContinues ||
235 pCurLed->ledState == kLedStateFastBlinkContinues)
236 ledTimerStart(); // start timer if in blinkContinues stats
239 case kLedStateSlowBlinkContinues:
240 if (pCurLed->blinkCountDown-- == 0)
242 pCurLed->blinkCountDown = kSlowBlinkCount;
248 case kLedStateFastBlinkContinues:
249 if (pCurLed->blinkCountDown-- == 0)
251 pCurLed->blinkCountDown = kFastBlinkCount;
258 printk("Invalid state = %d\n", pCurLed->ledState);
263 // initialize the gLedCount and allocate and fill gLed struct
264 void __init boardLedInit(PLED_MAP_PAIR cLedMapping)
266 PLED_MAP_PAIR p1, p2;
268 int needTimer = FALSE;
271 #if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
272 /* Set blink rate for BCM6348/BCM6338 hardware LEDs. */
273 GPIO->LEDCtrl &= ~LED_INTERVAL_SET_MASK;
274 GPIO->LEDCtrl |= LED_INTERVAL_SET_80MS;
277 memset( gpVirtLeds, 0x00, sizeof(gpVirtLeds) );
278 memset( gLedHwFunc, 0x00, sizeof(gLedHwFunc) );
279 memset( gLedHwFailFunc, 0x00, sizeof(gLedHwFailFunc) );
283 // Check for multiple LED names and multiple LED GPIO pins that share the
284 // same physical board LED.
285 for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
288 for( p2 = cLedMapping; p2 != p1; p2++ )
290 if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
291 (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
298 if( alreadyUsed == 0 )
302 gLed = (PLED_INFO) kmalloc((gLedCount * sizeof(LED_INFO)), GFP_KERNEL);
305 printk( "LED memory allocation error.\n" );
309 memset( gLed, 0x00, gLedCount * sizeof(LED_INFO) );
311 // initial the gLed with unique ledMask and initial state. If more than 1 ledNames share the physical led
312 // (ledMask) the first defined led's ledInitState will be used.
314 for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
316 if( (int) p1->ledName > MAX_VIRT_LEDS )
320 for( p2 = cLedMapping; p2 != p1; p2++ )
322 if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
323 (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
330 if( alreadyUsed == 0 )
332 // Initialize the board LED for the first time.
333 needTimer = initLedInfo( p1, pCurLed );
334 gpVirtLeds[(int) p1->ledName] = pCurLed;
340 for( pLed = gLed; pLed != pCurLed; pLed++ )
342 // Find the LED_INFO structure that has already been initialized.
343 if((pLed->ledMask && pLed->ledMask == p1->ledMask) ||
344 (pLed->ledMaskFail && pLed->ledMaskFail==p1->ledMaskFail))
346 // The board LED has already been initialized but possibly
347 // not completely initialized.
350 pLed->ledMask = p1->ledMask;
351 pLed->ledActiveLow = p1->ledActiveLow;
353 if( p1->ledMaskFail )
355 pLed->ledMaskFail = p1->ledMaskFail;
356 pLed->ledActiveLowFail = p1->ledActiveLowFail;
358 gpVirtLeds[(int) p1->ledName] = pLed;
368 #if defined(DEBUG_LED)
370 for (i=0; i < gLedCount; i++)
371 printk("initLed: led[%d]: mask=0x%04x, state=%d\n", i,(gLed+i)->ledMask, (gLed+i)->ledState);
376 // Initialize a structure that contains information about a physical board LED
377 // control. The board LED may contain more than one GPIO pin to control a
378 // normal condition (green) or a failure condition (red).
379 int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed )
381 int needTimer = FALSE;
382 pCurLed->ledState = pCurLed->savedLedState = pCurMap->ledInitState;
383 pCurLed->ledMask = pCurMap->ledMask;
384 pCurLed->ledActiveLow = pCurMap->ledActiveLow;
385 pCurLed->ledMaskFail = pCurMap->ledMaskFail;
386 pCurLed->ledActiveLowFail = pCurMap->ledActiveLowFail;
388 switch (pCurLed->ledState)
391 pCurLed->blinkCountDown = 0; // reset the blink count down
395 pCurLed->blinkCountDown = 0; // reset the blink count down
399 pCurLed->blinkCountDown = 0; // reset the blink count down
402 case kLedStateBlinkOnce:
403 pCurLed->blinkCountDown = 1;
406 case kLedStateSlowBlinkContinues:
407 pCurLed->blinkCountDown = kSlowBlinkCount;
410 case kLedStateFastBlinkContinues:
411 pCurLed->blinkCountDown = kFastBlinkCount;
415 printk("Invalid state = %d\n", pCurLed->ledState);
422 // Determines if there is at least one interface in bridge mode. Bridge mode
423 // is determined by the cfm convention of naming bridge interfaces nas17
425 static int isBridgedProtocol(void)
427 extern int dev_get(const char *name);
428 const int firstBridgeId = 17;
429 const int lastBridgeId = 24;
434 for( i = firstBridgeId; i <= lastBridgeId; i++ )
436 sprintf( name, "nas%d", i );
449 // led ctrl. Maps the ledName to the corresponding ledInfoPtr and perform the led operation
450 void boardLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState)
452 PLED_INFO ledInfoPtr;
454 // do the mapping from virtual to physical led
455 if( (int) ledName < MAX_VIRT_LEDS )
456 ledInfoPtr = gpVirtLeds[(int) ledName];
460 if (ledInfoPtr == NULL)
463 if( ledState != kLedStateFail && gLedHwFunc[(int) ledName] )
465 (*gLedHwFunc[(int) ledName]) (ledName, ledState);
466 ledOffFail(ledInfoPtr);
470 if( ledState == kLedStateFail && gLedHwFailFunc[(int) ledName] )
472 (*gLedHwFailFunc[(int) ledName]) (ledName, ledState);
478 // Do not blink the WAN Data LED if at least one interface is in bridge mode.
479 if(gLedOffInBridgeMode == 1 && (ledName == kLedWanData || ledName == kLedPPP))
481 static int BridgedProtocol = -1;
483 if( BridgedProtocol == -1 )
484 BridgedProtocol = isBridgedProtocol();
486 if( BridgedProtocol == TRUE )
491 // If the state is kLedStateFail and there is not a failure LED defined
492 // in the board parameters, change the state to kLedStateFastBlinkContinues.
493 if( ledState == kLedStateFail && ledInfoPtr->ledMaskFail == 0 )
494 ledState = kLedStateFastBlinkContinues;
499 // First, turn off the complimentary (failure) LED GPIO.
500 if( ledInfoPtr->ledMaskFail )
501 ledOffFail(ledInfoPtr);
503 if( gLedHwFailFunc[(int) ledName] )
504 (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
506 // Next, turn on the specified LED GPIO.
511 // First, turn off the complimentary (failure) LED GPIO.
512 if( ledInfoPtr->ledMaskFail )
513 ledOffFail(ledInfoPtr);
515 if( gLedHwFailFunc[(int) ledName] )
516 (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
518 // Next, turn off the specified LED GPIO.
523 // First, turn off the complimentary (normal) LED GPIO.
524 if( ledInfoPtr->ledMask )
527 if( gLedHwFunc[(int) ledName] )
528 (*gLedHwFunc[(int) ledName]) (ledName, kLedStateOff);
530 // Next, turn on (red) the specified LED GPIO.
531 ledOnFail(ledInfoPtr);
534 case kLedStateBlinkOnce:
535 // skip blinkOnce if it is already in Slow/Fast blink continues state
536 if (ledInfoPtr->savedLedState == kLedStateSlowBlinkContinues ||
537 ledInfoPtr->savedLedState == kLedStateFastBlinkContinues)
541 if (ledInfoPtr->blinkCountDown == 0) // skip the call if it is 1
543 ledToggle(ledInfoPtr);
544 ledInfoPtr->blinkCountDown = 1; // it will be reset to 0 when timer expires
545 ledInfoPtr->ledState = kLedStateBlinkOnce;
551 case kLedStateSlowBlinkContinues:
552 ledInfoPtr->blinkCountDown = kSlowBlinkCount;
553 ledInfoPtr->ledState = kLedStateSlowBlinkContinues;
554 ledInfoPtr->savedLedState = kLedStateSlowBlinkContinues;
558 case kLedStateFastBlinkContinues:
559 ledInfoPtr->blinkCountDown = kFastBlinkCount;
560 ledInfoPtr->ledState = kLedStateFastBlinkContinues;
561 ledInfoPtr->savedLedState = kLedStateFastBlinkContinues;
566 printk("Invalid led state\n");
570 // This function is called for an LED that is controlled by hardware.
571 void kerSysLedRegisterHwHandler( BOARD_LED_NAME ledName,
572 HANDLE_LED_FUNC ledHwFunc, int ledFailType )
574 if( (int) ledName < MAX_VIRT_LEDS )
576 if( ledFailType == 1 )
577 gLedHwFailFunc[(int) ledName] = ledHwFunc;
579 gLedHwFunc[(int) ledName] = ledHwFunc;