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
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 k125ms (HZ / 8) // ~125 ms
70 #define kFastBlinkCount 0 // ~125ms
71 #define kSlowBlinkCount 1 // ~250ms
73 #define MAX_VIRT_LEDS 12
75 // uncomment // for debug led
79 struct timer_list gLedTimer, gBlinkOnceTimer;
81 int gBlinkOnceTimerOn = FALSE;
84 typedef struct ledinfo
86 unsigned long ledMask; // mask for led: ie. giop 10 = 0x0400
87 unsigned short ledActiveLow; // GPIO bit reset to turn on LED
88 unsigned short ledSerial; // indicated that LED is driven via serial output
89 unsigned long ledMaskFail; // mask for led: ie. giop 10 = 0x0400
90 unsigned short ledActiveLowFail;// GPIO bit reset to turn on LED
91 unsigned short ledSerialFail; // indicated that LED is driven via serial output
92 BOARD_LED_STATE ledState; // current led state
93 BOARD_LED_STATE savedLedState; // used in blink once for restore to the orignal ledState
94 int blinkCountDown; // if == 0, do blink (toggle). Is assgined value and dec by 1 at each timer.
95 } LED_INFO, *PLED_INFO;
97 static PLED_INFO gLed = NULL;
98 static PLED_INFO gpVirtLeds[MAX_VIRT_LEDS];
99 static HANDLE_LED_FUNC gLedHwFunc[MAX_VIRT_LEDS];
100 static HANDLE_LED_FUNC gLedHwFailFunc[MAX_VIRT_LEDS];
102 void blinkOnceTimerExpire(void); // Keven
103 void ledTimerExpire(void);
104 int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed );
106 //**************************************************************************************
108 //**************************************************************************************
110 // turn led on and set the ledState
111 void ledOn(PLED_INFO pLed)
115 if (pLed->ledSerial) {
116 #if defined(CONFIG_BCM96358)
117 while (GPIO->SerialLedCtrl & SER_LED_BUSY);
118 if( pLed->ledActiveLow )
119 GPIO->SerialLed &= ~pLed->ledMask; // turn on the led
121 GPIO->SerialLed |= pLed->ledMask; // turn on the led
125 GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
126 if( pLed->ledActiveLow )
127 GPIO->GPIOio &= ~pLed->ledMask; // turn on the led
129 GPIO->GPIOio |= pLed->ledMask; // turn on the led
131 pLed->ledState = pLed->savedLedState = kLedStateOn;
136 // turn led off and set the ledState
137 void ledOff(PLED_INFO pLed)
141 if (pLed->ledSerial) {
142 #if defined(CONFIG_BCM96358)
143 while (GPIO->SerialLedCtrl & SER_LED_BUSY);
144 if( pLed->ledActiveLow )
145 GPIO->SerialLed |= pLed->ledMask; // turn off the led
147 GPIO->SerialLed &= ~pLed->ledMask; // turn off the led
151 GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
152 if( pLed->ledActiveLow )
153 GPIO->GPIOio |= pLed->ledMask; // turn off the led
155 GPIO->GPIOio &= ~pLed->ledMask; // turn off the led
157 pLed->ledState = pLed->savedLedState = kLedStateOff;
161 // turn led on and set the ledState
162 void ledOnFail(PLED_INFO pLed)
164 if( pLed->ledMaskFail )
166 if (pLed->ledSerialFail) {
167 #if defined(CONFIG_BCM96358)
168 while (GPIO->SerialLedCtrl & SER_LED_BUSY);
169 if( pLed->ledActiveLowFail )
170 GPIO->SerialLed &= ~pLed->ledMaskFail; // turn on the led
172 GPIO->SerialLed |= pLed->ledMaskFail; // turn on the led
176 GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one
177 if( pLed->ledActiveLowFail )
178 GPIO->GPIOio &= ~pLed->ledMaskFail;// turn on the led
180 GPIO->GPIOio |= pLed->ledMaskFail; // turn on the led
182 pLed->ledState = pLed->savedLedState = kLedStateFail;
187 // turn led off and set the ledState
188 void ledOffFail(PLED_INFO pLed)
190 if( pLed->ledMaskFail )
192 if (pLed->ledSerialFail) {
193 #if defined(CONFIG_BCM96358)
194 while (GPIO->SerialLedCtrl & SER_LED_BUSY);
195 if( pLed->ledActiveLowFail )
196 GPIO->SerialLed |= pLed->ledMaskFail; // turn off the led
198 GPIO->SerialLed &= ~pLed->ledMaskFail; // turn off the led
202 GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one
203 if( pLed->ledActiveLowFail )
204 GPIO->GPIOio |= pLed->ledMaskFail; // turn off the led
206 GPIO->GPIOio &= ~pLed->ledMaskFail;// turn off the led
208 pLed->ledState = pLed->savedLedState = kLedStateOff;
213 // toggle the led and return the current ledState
214 BOARD_LED_STATE ledToggle(PLED_INFO pLed)
216 if (pLed->ledSerial) {
217 #if defined(CONFIG_BCM96358)
218 while (GPIO->SerialLedCtrl & SER_LED_BUSY);
219 if (GPIO->SerialLed & pLed->ledMask)
221 GPIO->SerialLed &= ~(pLed->ledMask);
222 return( (pLed->ledActiveLow) ? kLedStateOn : kLedStateOff );
226 GPIO->SerialLed |= pLed->ledMask;
227 return( (pLed->ledActiveLow) ? kLedStateOff : kLedStateOn );
232 GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
233 if (GPIO->GPIOio & pLed->ledMask)
235 GPIO->GPIOio &= ~(pLed->ledMask);
236 return( (pLed->ledActiveLow) ? kLedStateOn : kLedStateOff );
240 GPIO->GPIOio |= pLed->ledMask;
241 return( (pLed->ledActiveLow) ? kLedStateOff : kLedStateOn );
246 // Keven -- LED BlinkOnce timer
247 void blinkOnceTimerStart(void)
249 if(gBlinkOnceTimerOn)
252 init_timer(&gBlinkOnceTimer);
253 gBlinkOnceTimer.function = (void*)blinkOnceTimerExpire;
254 gBlinkOnceTimer.expires = jiffies + k125ms;
255 add_timer(&gBlinkOnceTimer);
256 gBlinkOnceTimerOn = TRUE;
259 void blinkOnceTimerExpire(void)
261 gBlinkOnceTimerOn = FALSE;
264 // led timer. Will return if timer is already on
265 void ledTimerStart(void)
270 #if defined(DEBUG_LED)
271 printk("led: add_timer\n");
274 init_timer(&gLedTimer);
275 gLedTimer.function = (void*)ledTimerExpire;
276 gLedTimer.expires = jiffies + k125ms; // timer expires in ~100ms
277 add_timer (&gLedTimer);
282 // led timer expire kicks in about ~100ms and perform the led operation according to the ledState and
283 // restart the timer according to ledState
284 void ledTimerExpire(void)
291 for (i = 0, pCurLed = gLed; i < gLedCount; i++, pCurLed++)
293 #if defined(DEBUG_LED)
294 printk("led[%d]: Mask=0x%04x, State = %d, blcd=%d\n", i, pCurLed->ledMask, pCurLed->ledState, pCurLed->blinkCountDown);
296 switch (pCurLed->ledState)
301 pCurLed->blinkCountDown = 0; // reset the blink count down
304 case kLedStateBlinkOnce:
305 blinkOnceTimerStart(); // Keven -- Start BlinkOnceTimer
307 pCurLed->blinkCountDown = 0; // reset to 0
308 pCurLed->ledState = pCurLed->savedLedState;
309 if (pCurLed->ledState == kLedStateSlowBlinkContinues ||
310 pCurLed->ledState == kLedStateFastBlinkContinues)
311 ledTimerStart(); // start timer if in blinkContinues stats
314 case kLedStateSlowBlinkContinues:
315 if (pCurLed->blinkCountDown-- == 0)
317 pCurLed->blinkCountDown = kSlowBlinkCount;
323 case kLedStateFastBlinkContinues:
324 if (pCurLed->blinkCountDown-- == 0)
326 pCurLed->blinkCountDown = kFastBlinkCount;
333 printk("Invalid state = %d\n", pCurLed->ledState);
338 // initialize the gLedCount and allocate and fill gLed struct
339 void __init boardLedInit(PLED_MAP_PAIR cLedMapping)
341 PLED_MAP_PAIR p1, p2;
343 int needTimer = FALSE;
346 #if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338) || defined(CONFIG_BCM96358)
347 /* Set blink rate for BCM6348/BCM6338 hardware LEDs. */
348 GPIO->LEDCtrl &= ~LED_INTERVAL_SET_MASK;
349 GPIO->LEDCtrl |= LED_INTERVAL_SET_80MS;
351 #if defined(CONFIG_BCM96358)
352 #ifdef BRCM_ORIGINAL //swda modify,05/30/2006
353 /* Enable LED Outputs */
354 GPIO->GPIOMode |= GPIO_MODE_LED_OVERLAY;
355 GPIO->GPIODir |= 0x000f;
356 /* Enable Serial LED Outputs */
357 GPIO->GPIOMode |= GPIO_MODE_SERIAL_LED_OVERLAY;
358 GPIO->GPIODir |= 0x00c0;
359 #elif defined(IAD_VDSL_6358)
360 /* Disable LED Outputs, use standard GPIO defination */
361 GPIO->GPIOMode &= (~GPIO_MODE_LED_OVERLAY);
362 /* Enable Serial LED Outputs */
363 GPIO->GPIOMode |= GPIO_MODE_SERIAL_LED_OVERLAY;
364 GPIO->GPIODir |= 0x00c0;//gpio6,7 were used to control serial led, so set gpio 6,7 as output pins
365 //turn off VOIP Led,SLIC_ACT1 Led,SLIC_ACT2 Led : Serial LED GPIO 5,6,7(active low)
366 while (GPIO->SerialLedCtrl & SER_LED_BUSY);
367 GPIO->SerialLed |= 0x000000e0;
368 #elif defined(IAD_GPON_6358)
369 /* Disable LED Outputs, use standard GPIO defination */
370 GPIO->GPIOMode &= (~GPIO_MODE_LED_OVERLAY);
371 /* Disable Serial LED Outputs, use standard GPIO defination */
372 GPIO->GPIOMode &= (~GPIO_MODE_SERIAL_LED_OVERLAY);
374 /* Disable LED Outputs, use standard GPIO defination */
375 GPIO->GPIOMode &= (~GPIO_MODE_LED_OVERLAY);
376 /* Disable Serial LED Outputs, use standard GPIO defination */
377 GPIO->GPIOMode &= (~GPIO_MODE_SERIAL_LED_OVERLAY);
378 printk("GPIO->GPIOMode = 0x%08X\n",GPIO->GPIOMode);
379 //turn off FXO Led : GPIO 7(active low)
380 GPIO->GPIODir |= GPIO_NUM_TO_MASK(7);
381 GPIO->GPIOio |= GPIO_NUM_TO_MASK(7);
382 //turn off VOIP Led : GPIO 15(active low)
383 GPIO->GPIODir |= GPIO_NUM_TO_MASK(15);
384 GPIO->GPIOio |= GPIO_NUM_TO_MASK(15);
385 //turn off SLIC_ACT1 Led: GPIO 26(active low)
386 GPIO->GPIODir |= GPIO_NUM_TO_MASK(26);
387 GPIO->GPIOio |= GPIO_NUM_TO_MASK(26);
388 //turn off SLIC_ACT2 Led: GPIO 6(active low)
389 GPIO->GPIODir |= GPIO_NUM_TO_MASK(6);
390 GPIO->GPIOio |= GPIO_NUM_TO_MASK(6);
391 #endif //swda modify end
394 memset( gpVirtLeds, 0x00, sizeof(gpVirtLeds) );
395 memset( gLedHwFunc, 0x00, sizeof(gLedHwFunc) );
396 memset( gLedHwFailFunc, 0x00, sizeof(gLedHwFailFunc) );
400 // Check for multiple LED names and multiple LED GPIO pins that share the
401 // same physical board LED.
402 for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
405 for( p2 = cLedMapping; p2 != p1; p2++ )
407 if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
408 (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
415 if( alreadyUsed == 0 )
419 gLed = (PLED_INFO) kmalloc((gLedCount * sizeof(LED_INFO)), GFP_KERNEL);
422 printk( "LED memory allocation error.\n" );
426 memset( gLed, 0x00, gLedCount * sizeof(LED_INFO) );
428 // initial the gLed with unique ledMask and initial state. If more than 1 ledNames share the physical led
429 // (ledMask) the first defined led's ledInitState will be used.
431 for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
433 if( (int) p1->ledName > MAX_VIRT_LEDS )
437 for( p2 = cLedMapping; p2 != p1; p2++ )
439 if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
440 (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
447 if( alreadyUsed == 0 )
449 // Initialize the board LED for the first time.
450 needTimer = initLedInfo( p1, pCurLed );
451 gpVirtLeds[(int) p1->ledName] = pCurLed;
457 for( pLed = gLed; pLed != pCurLed; pLed++ )
459 // Find the LED_INFO structure that has already been initialized.
460 if((pLed->ledMask && pLed->ledMask == p1->ledMask) ||
461 (pLed->ledMaskFail && pLed->ledMaskFail==p1->ledMaskFail))
463 // The board LED has already been initialized but possibly
464 // not completely initialized.
467 pLed->ledMask = p1->ledMask;
468 pLed->ledActiveLow = p1->ledActiveLow;
469 pLed->ledSerial = p1->ledSerial;
471 if( p1->ledMaskFail )
473 pLed->ledMaskFail = p1->ledMaskFail;
474 pLed->ledActiveLowFail = p1->ledActiveLowFail;
475 pLed->ledSerialFail = p1->ledSerialFail;
477 gpVirtLeds[(int) p1->ledName] = pLed;
487 #if defined(DEBUG_LED)
489 for (i=0; i < gLedCount; i++)
490 printk("initLed: led[%d]: mask=0x%04x, state=%d\n", i,(gLed+i)->ledMask, (gLed+i)->ledState);
495 // Initialize a structure that contains information about a physical board LED
496 // control. The board LED may contain more than one GPIO pin to control a
497 // normal condition (green) or a failure condition (red).
498 int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed )
500 int needTimer = FALSE;
501 pCurLed->ledState = pCurLed->savedLedState = pCurMap->ledInitState;
502 pCurLed->ledMask = pCurMap->ledMask;
503 pCurLed->ledActiveLow = pCurMap->ledActiveLow;
504 pCurLed->ledSerial = pCurMap->ledSerial;
505 pCurLed->ledMaskFail = pCurMap->ledMaskFail;
506 pCurLed->ledActiveLowFail = pCurMap->ledActiveLowFail;
507 pCurLed->ledSerialFail = pCurMap->ledSerialFail;
509 switch (pCurLed->ledState)
512 pCurLed->blinkCountDown = 0; // reset the blink count down
516 pCurLed->blinkCountDown = 0; // reset the blink count down
520 pCurLed->blinkCountDown = 0; // reset the blink count down
523 case kLedStateBlinkOnce:
524 pCurLed->blinkCountDown = 1;
527 case kLedStateSlowBlinkContinues:
528 pCurLed->blinkCountDown = kSlowBlinkCount;
531 case kLedStateFastBlinkContinues:
532 pCurLed->blinkCountDown = kFastBlinkCount;
536 printk("Invalid state = %d\n", pCurLed->ledState);
542 // led ctrl. Maps the ledName to the corresponding ledInfoPtr and perform the led operation
543 void boardLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState)
545 PLED_INFO ledInfoPtr;
547 // do the mapping from virtual to physical led
548 if( (int) ledName < MAX_VIRT_LEDS )
549 ledInfoPtr = gpVirtLeds[(int) ledName];
553 if( ledState != kLedStateFail && gLedHwFunc[(int) ledName] )
555 // First, turn off the complimentary (failure) LED.
556 if( gLedHwFailFunc[(int) ledName] )
557 (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
560 ledOffFail(ledInfoPtr);
562 // Call function to handle hardware LED.
563 (*gLedHwFunc[(int) ledName]) (ledName, ledState);
567 if( ledState == kLedStateFail && gLedHwFailFunc[(int) ledName] )
569 // First, turn off the complimentary (normal) LED.
570 if( gLedHwFunc[(int) ledName] )
571 (*gLedHwFunc[(int) ledName]) (ledName, kLedStateOff);
576 // Call function to handle hardware LED.
577 (*gLedHwFailFunc[(int) ledName]) (ledName, ledState);
581 if (ledInfoPtr == NULL)
584 // If the state is kLedStateFail and there is not a failure LED defined
585 // in the board parameters, change the state to kLedStateSlowBlinkContinues.
586 if( ledState == kLedStateFail && ledInfoPtr->ledMaskFail == 0 )
587 //ledState = kLedStateSlowBlinkContinues;//swda remove,05/03/2005
588 ledState = kLedStateOff;//swda add,05/03/2005
592 // First, turn off the complimentary (failure) LED GPIO.
593 if( ledInfoPtr->ledMaskFail )
594 ledOffFail(ledInfoPtr);
596 if( gLedHwFailFunc[(int) ledName] )
597 (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
599 // Next, turn on the specified LED GPIO.
604 // First, turn off the complimentary (failure) LED GPIO.
605 if( ledInfoPtr->ledMaskFail )
606 ledOffFail(ledInfoPtr);
608 if( gLedHwFailFunc[(int) ledName] )
609 (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
611 // Next, turn off the specified LED GPIO.
616 // First, turn off the complimentary (normal) LED GPIO.
617 if( ledInfoPtr->ledMask )
620 if( gLedHwFunc[(int) ledName] )
621 (*gLedHwFunc[(int) ledName]) (ledName, kLedStateOff);
623 // Next, turn on (red) the specified LED GPIO.
624 ledOnFail(ledInfoPtr);
627 case kLedStateBlinkOnce:
628 // skip blinkOnce if it is already in Slow/Fast blink continues state
629 if (ledInfoPtr->savedLedState == kLedStateSlowBlinkContinues ||
630 ledInfoPtr->savedLedState == kLedStateFastBlinkContinues)
634 if ( ledInfoPtr->blinkCountDown || // skip the call if it is 1
635 gBlinkOnceTimerOn ) // Keven -- skip the call if BlinkOnceTimer is on
639 ledToggle(ledInfoPtr);
640 ledInfoPtr->blinkCountDown = 1; // it will be reset to 0 when timer expires
641 ledInfoPtr->ledState = kLedStateBlinkOnce;
647 case kLedStateSlowBlinkContinues:
648 ledInfoPtr->blinkCountDown = kSlowBlinkCount;
649 ledInfoPtr->ledState = kLedStateSlowBlinkContinues;
650 ledInfoPtr->savedLedState = kLedStateSlowBlinkContinues;
654 case kLedStateFastBlinkContinues:
655 ledInfoPtr->blinkCountDown = kFastBlinkCount;
656 ledInfoPtr->ledState = kLedStateFastBlinkContinues;
657 ledInfoPtr->savedLedState = kLedStateFastBlinkContinues;
662 printk("Invalid led state\n");
666 // This function is called for an LED that is controlled by hardware.
667 void kerSysLedRegisterHwHandler( BOARD_LED_NAME ledName,
668 HANDLE_LED_FUNC ledHwFunc, int ledFailType )
670 if( (int) ledName < MAX_VIRT_LEDS )
672 if( ledFailType == 1 )
673 gLedHwFailFunc[(int) ledName] = ledHwFunc;
675 gLedHwFunc[(int) ledName] = ledHwFunc;