Revert "Revert "and added files""
[bcm963xx.git] / bcmdrivers / opensource / char / board / bcm963xx / impl1 / bcm63xx_led.c
1 /*
2 <:copyright-gpl 
3  Copyright 2002 Broadcom Corp. All Rights Reserved. 
4  
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. 
8  
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 
12  for more details. 
13  
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. 
17 :>
18 */
19 /***************************************************************************
20  * File Name  : bcm63xx_led.c
21  *
22  * Description: 
23  *
24  *    This file contains bcm963xx board led control API functions. 
25  *
26  *    To use it, do the following
27  *
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.
37  *
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
40  *
41  *        boardLedInit((PLED_MAP_PAIR) &cLedMapping45R);
42  *
43  *    3). Sample call for kernel mode:
44  *
45  *        kerSysLedCtrl(kLedAdsl, kLedStateBlinkOnce);        // kLedxxx defines in board.h
46  *
47  *    4). Sample call for user mode
48  *
49  *        sysLedCtrl(kLedAdsl, kLedStateBlinkOnce);           // kLedxxx defines in board_api.h
50  *
51  *
52  * Created on :  10/28/2002  seanl
53  *
54  ***************************************************************************/
55
56 /* Includes. */
57 #include <linux/init.h>
58 #include <linux/fs.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>
65
66 #include <bcm_map_part.h>
67 #include <board.h>
68
69 #define k100ms              (HZ / 10)     // ~100 ms
70 #define kFastBlinkCount     0             // ~100ms
71 #define kSlowBlinkCount     5             // ~600ms
72
73 #define MAX_VIRT_LEDS       12
74
75 // uncomment // for debug led
76 //#define DEBUG_LED
77
78 // global variables:
79 struct timer_list gLedTimer;
80 int gTimerOn = FALSE;
81 int gLedCount = 0;
82
83 typedef struct ledinfo
84 {
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;
93
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];
98
99 #if 0 /* BROKEN */
100 #if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
101 static int gLedOffInBridgeMode = 1;
102 #elif defined(CONFIG_BCM96345)
103 static int gLedOffInBridgeMode = 0;
104 #endif
105 #endif
106
107 void ledTimerExpire(void);
108 int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed );
109
110 //**************************************************************************************
111 // LED operations
112 //**************************************************************************************
113
114 // turn led on and set the ledState
115 void ledOn(PLED_INFO pLed)
116 {
117     if( pLed->ledMask )
118     {
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
122         else
123             GPIO->GPIOio  |= pLed->ledMask;     // turn on the led
124         pLed->ledState = pLed->savedLedState = kLedStateOn;
125     }
126 }
127
128
129 // turn led off and set the ledState
130 void ledOff(PLED_INFO pLed)
131 {
132     if( pLed->ledMask )
133     {
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
137         else
138             GPIO->GPIOio  &= ~pLed->ledMask;    // turn off the led
139         pLed->ledState = pLed->savedLedState = kLedStateOff;
140     }
141 }
142
143 // turn led on and set the ledState
144 void ledOnFail(PLED_INFO pLed)
145 {
146     if( pLed->ledMaskFail )
147     {
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
151         else
152             GPIO->GPIOio  |= pLed->ledMaskFail; // turn on the led
153         pLed->ledState = pLed->savedLedState = kLedStateFail;
154     }
155 }
156
157
158 // turn led off and set the ledState
159 void ledOffFail(PLED_INFO pLed)
160 {
161     if( pLed->ledMaskFail )
162     {
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
166         else
167             GPIO->GPIOio  &= ~pLed->ledMaskFail;// turn off the led
168         pLed->ledState = pLed->savedLedState = kLedStateOff;
169     }
170 }
171
172
173 // toggle the led and return the current ledState
174 BOARD_LED_STATE ledToggle(PLED_INFO pLed)
175 {
176     GPIO->GPIODir |= pLed->ledMask;         // turn on the direction bit in case was turned off by some one
177     if (GPIO->GPIOio & pLed->ledMask)
178     {
179         GPIO->GPIOio &= ~(pLed->ledMask);
180         return( (pLed->ledActiveLow) ? kLedStateOn : kLedStateOff );
181     }
182     else
183     {
184         GPIO->GPIOio |= pLed->ledMask;
185         return( (pLed->ledActiveLow) ? kLedStateOff : kLedStateOn );
186     }
187 }   
188
189
190 // led timer.  Will return if timer is already on
191 void ledTimerStart(void)
192 {
193     if (gTimerOn)
194         return;
195
196 #if defined(DEBUG_LED)
197     printk("led: add_timer\n");
198 #endif
199
200     init_timer(&gLedTimer);
201     gLedTimer.function = (void*)ledTimerExpire;
202     gLedTimer.expires = jiffies + k100ms;        // timer expires in ~100ms
203     add_timer (&gLedTimer);
204     gTimerOn = TRUE;
205
206
207
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)
211 {
212     int i;
213     PLED_INFO pCurLed;
214
215     gTimerOn = FALSE;
216
217     for (i = 0, pCurLed = gLed; i < gLedCount; i++, pCurLed++)
218     {
219 #if defined(DEBUG_LED)
220         printk("led[%d]: Mask=0x%04x, State = %d, blcd=%d\n", i, pCurLed->ledMask, pCurLed->ledState, pCurLed->blinkCountDown);
221 #endif
222         switch (pCurLed->ledState)
223         {
224             case kLedStateOn:
225             case kLedStateOff:
226             case kLedStateFail:
227                 pCurLed->blinkCountDown = 0;            // reset the blink count down
228                 break;
229
230             case kLedStateBlinkOnce:
231                 ledToggle(pCurLed);
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
237                 break;
238
239             case kLedStateSlowBlinkContinues:
240                 if (pCurLed->blinkCountDown-- == 0)
241                 {
242                     pCurLed->blinkCountDown = kSlowBlinkCount;
243                     ledToggle(pCurLed);
244                 }
245                 ledTimerStart();
246                 break;
247
248             case kLedStateFastBlinkContinues:
249                 if (pCurLed->blinkCountDown-- == 0)
250                 {
251                     pCurLed->blinkCountDown = kFastBlinkCount;
252                     ledToggle(pCurLed);
253                 }
254                 ledTimerStart();
255                 break;
256
257             default:
258                 printk("Invalid state = %d\n", pCurLed->ledState);
259         }
260     }
261 }
262
263 // initialize the gLedCount and allocate and fill gLed struct
264 void __init boardLedInit(PLED_MAP_PAIR cLedMapping)
265 {
266     PLED_MAP_PAIR p1, p2;
267     PLED_INFO pCurLed;
268     int needTimer = FALSE;
269     int alreadyUsed = 0;
270
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;
275 #endif
276
277     memset( gpVirtLeds, 0x00, sizeof(gpVirtLeds) );
278     memset( gLedHwFunc, 0x00, sizeof(gLedHwFunc) );
279     memset( gLedHwFailFunc, 0x00, sizeof(gLedHwFailFunc) );
280
281     gLedCount = 0;
282
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++ )
286     {
287         alreadyUsed = 0;
288         for( p2 = cLedMapping; p2 != p1; p2++ )
289         {
290             if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
291                 (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
292             {
293                 alreadyUsed = 1;
294                 break;
295             }
296         }
297
298         if( alreadyUsed == 0  )
299             gLedCount++;
300     }
301
302     gLed = (PLED_INFO) kmalloc((gLedCount * sizeof(LED_INFO)), GFP_KERNEL);
303     if( gLed == NULL )
304     {
305         printk( "LED memory allocation error.\n" );
306         return;
307     }
308
309     memset( gLed, 0x00, gLedCount * sizeof(LED_INFO) );
310
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.
313     pCurLed = gLed;
314     for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
315     {
316         if( (int) p1->ledName > MAX_VIRT_LEDS )
317             continue;
318
319         alreadyUsed = 0;
320         for( p2 = cLedMapping; p2 != p1; p2++ )
321         {
322             if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
323                 (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
324             {
325                 alreadyUsed = 1;
326                 break;
327             }
328         }
329
330         if( alreadyUsed == 0 )
331         {
332             // Initialize the board LED for the first time.
333             needTimer = initLedInfo( p1, pCurLed );
334             gpVirtLeds[(int) p1->ledName] = pCurLed;
335             pCurLed++;
336         }
337         else
338         {
339             PLED_INFO pLed;
340             for( pLed = gLed; pLed != pCurLed; pLed++ )
341             {
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))
345                 {
346                     // The board LED has already been initialized but possibly
347                     // not completely initialized.
348                     if( p1->ledMask )
349                     {
350                         pLed->ledMask = p1->ledMask;
351                         pLed->ledActiveLow = p1->ledActiveLow;
352                     }
353                     if( p1->ledMaskFail )
354                     {
355                         pLed->ledMaskFail = p1->ledMaskFail;
356                         pLed->ledActiveLowFail = p1->ledActiveLowFail;
357                     }
358                     gpVirtLeds[(int) p1->ledName] = pLed;
359                     break;
360                 }
361             }
362         }
363     }
364
365     if (needTimer)
366         ledTimerStart();
367
368 #if defined(DEBUG_LED)
369     int i;
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);
372 #endif
373
374 }
375
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 )
380 {
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;
387
388     switch (pCurLed->ledState)
389     {
390         case kLedStateOn:
391             pCurLed->blinkCountDown = 0;            // reset the blink count down
392             ledOn(pCurLed);
393             break;
394         case kLedStateOff:
395             pCurLed->blinkCountDown = 0;            // reset the blink count down
396             ledOff(pCurLed);
397             break;
398         case kLedStateFail:
399             pCurLed->blinkCountDown = 0;            // reset the blink count down
400             ledOnFail(pCurLed);
401             break;
402         case kLedStateBlinkOnce:
403             pCurLed->blinkCountDown = 1;
404             needTimer = TRUE;
405             break;
406         case kLedStateSlowBlinkContinues:
407             pCurLed->blinkCountDown = kSlowBlinkCount;
408             needTimer = TRUE;
409             break;
410         case kLedStateFastBlinkContinues:
411             pCurLed->blinkCountDown = kFastBlinkCount;
412             needTimer = TRUE;
413             break;
414         default:
415             printk("Invalid state = %d\n", pCurLed->ledState);
416     }
417
418     return( needTimer );
419 }
420
421 #if 0 /* BROKEN */
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
424 // through nas24.
425 static int isBridgedProtocol(void)
426 {
427     extern int dev_get(const char *name);
428     const int firstBridgeId = 17;
429     const int lastBridgeId = 24;
430     int i;
431     int ret = FALSE;
432     char name[16];
433
434     for( i = firstBridgeId; i <= lastBridgeId; i++ )
435     {
436         sprintf( name, "nas%d", i );
437
438         if( dev_get(name) )
439         {
440             ret = TRUE;
441             break;
442         }
443     }
444
445     return(ret);
446 }
447 #endif
448
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)
451 {
452     PLED_INFO ledInfoPtr;
453
454     // do the mapping from virtual to physical led
455     if( (int) ledName < MAX_VIRT_LEDS )
456         ledInfoPtr = gpVirtLeds[(int) ledName];
457     else
458         ledInfoPtr = NULL;
459
460     if (ledInfoPtr == NULL)
461         return;
462
463     if( ledState != kLedStateFail && gLedHwFunc[(int) ledName] )
464     {
465         (*gLedHwFunc[(int) ledName]) (ledName, ledState);
466         ledOffFail(ledInfoPtr);
467         return;
468     }
469     else
470         if( ledState == kLedStateFail && gLedHwFailFunc[(int) ledName] )
471         {
472             (*gLedHwFailFunc[(int) ledName]) (ledName, ledState);
473             ledOff(ledInfoPtr);
474             return;
475         }
476
477 #if 0 /* BROKEN */
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))
480     {
481         static int BridgedProtocol = -1;
482
483         if( BridgedProtocol == -1 )
484             BridgedProtocol = isBridgedProtocol();
485
486         if( BridgedProtocol == TRUE )
487             return;
488     }
489 #endif
490
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;
495 //#define USR9108
496 #ifdef USR9108    
497     if( ledName != kLedWanData )
498         printk("LEDCTRL: Led %d state %d mask %x\n", 
499                ledName, ledState, ledInfoPtr->ledMask);
500 #endif
501     switch (ledState)
502     {
503         case kLedStateOn:
504             // First, turn off the complimentary (failure) LED GPIO.
505             if( ledInfoPtr->ledMaskFail )
506                 ledOffFail(ledInfoPtr);
507             else
508                 if( gLedHwFailFunc[(int) ledName] )
509                     (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
510
511             // Next, turn on the specified LED GPIO.
512             ledOn(ledInfoPtr);
513             break;
514
515         case kLedStateOff: 
516             // First, turn off the complimentary (failure) LED GPIO.
517             if( ledInfoPtr->ledMaskFail )
518                 ledOffFail(ledInfoPtr);
519             else
520                 if( gLedHwFailFunc[(int) ledName] )
521                     (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
522
523             // Next, turn off the specified LED GPIO.
524             ledOff(ledInfoPtr);
525             break;
526
527         case kLedStateFail:
528             // First, turn off the complimentary (normal) LED GPIO.
529             if( ledInfoPtr->ledMask )
530                 ledOff(ledInfoPtr);
531             else
532                 if( gLedHwFunc[(int) ledName] )
533                     (*gLedHwFunc[(int) ledName]) (ledName, kLedStateOff);
534
535             // Next, turn on (red) the specified LED GPIO.
536             ledOnFail(ledInfoPtr);
537             break;
538
539         case kLedStateBlinkOnce:
540             // USR9108 Blink only if Led is On! 
541             // skip blinkOnce if it is already in Slow/Fast blink continues state
542 //            if (ledInfoPtr->savedLedState == kLedStateSlowBlinkContinues ||
543 //                ledInfoPtr->savedLedState == kLedStateFastBlinkContinues)
544 //                ;
545 //            else
546             if ( ledInfoPtr->savedLedState == kLedStateOn )
547             {
548                 if (ledInfoPtr->blinkCountDown == 0)  // skip the call if it is 1
549                 {
550                     ledToggle(ledInfoPtr);
551                     ledInfoPtr->blinkCountDown = 1;  // it will be reset to 0 when timer expires
552                     ledInfoPtr->ledState = kLedStateBlinkOnce;
553                     ledTimerStart();
554                 }
555             }
556             break;
557
558         case kLedStateSlowBlinkContinues:
559             ledInfoPtr->blinkCountDown = kSlowBlinkCount;
560             ledInfoPtr->ledState = kLedStateSlowBlinkContinues;
561             ledInfoPtr->savedLedState = kLedStateSlowBlinkContinues;
562             ledTimerStart();
563             break;
564
565         case kLedStateFastBlinkContinues:
566             ledInfoPtr->blinkCountDown = kFastBlinkCount;
567             ledInfoPtr->ledState = kLedStateFastBlinkContinues;
568             ledInfoPtr->savedLedState = kLedStateFastBlinkContinues;
569             ledTimerStart();
570             break;
571
572         default:
573             printk("Invalid led state\n");
574     }
575 }
576
577 // This function is called for an LED that is controlled by hardware.
578 void kerSysLedRegisterHwHandler( BOARD_LED_NAME ledName,
579     HANDLE_LED_FUNC ledHwFunc, int ledFailType )
580 {
581     if( (int) ledName < MAX_VIRT_LEDS )
582     {
583         if( ledFailType == 1 )
584             gLedHwFailFunc[(int) ledName] = ledHwFunc;
585         else
586             gLedHwFunc[(int) ledName] = ledHwFunc;
587     }
588 }
589