X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=target%2Flinux%2Fbrcm63xx-2.6%2Ffiles%2Farch%2Fmips%2Fbcm963xx%2Fbcm63xx_led.c;fp=target%2Flinux%2Fbrcm63xx-2.6%2Ffiles%2Farch%2Fmips%2Fbcm963xx%2Fbcm63xx_led.c;h=8de0f91db93de5882fce648ecf4d589d5738cbcb;hb=3ce8de018e45b1e92243a50a6bde51a56b994381;hp=0000000000000000000000000000000000000000;hpb=c2d893e8910663ad1b08fbb5e927d0d50b71aed6;p=openwrt%2Fopenwrt.git diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/bcm63xx_led.c b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/bcm63xx_led.c new file mode 100644 index 0000000000..8de0f91db9 --- /dev/null +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/bcm63xx_led.c @@ -0,0 +1,582 @@ +/* +<:copyright-gpl + Copyright 2002 Broadcom Corp. All Rights Reserved. + + This program is free software; you can distribute it and/or modify it + under the terms of the GNU General Public License (Version 2) as + published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +:> +*/ +/*************************************************************************** + * File Name : bcm63xx_led.c + * + * Description: + * + * This file contains bcm963xx board led control API functions. + * + * To use it, do the following + * + * 1). define in the board.c the following led mappping (this is for 6345GW board): + * const LED_MAP_PAIR cLedMapping45GW[] = + * { // led name Initial state physical pin (ledMask) + * {kLedUsb, kLedStateOff, GPIO_LED_PIN_7}, + * {kLedAdsl, kLedStateOff, GPIO_LED_PIN_8}, + * {kLedPPP, kLedStateOff, GPIO_LED_PIN_9}, // PPP and WanData share PIN_9 + * {kLedWanData, kLedStateOff, GPIO_LED_PIN_9}, + * {kLedWireless, kLedStateOff, GPIO_LED_PIN_10}, + * {kLedEnd, kLedStateOff, 0 } // NOTE: kLedEnd has to be at the end. + * + * 2). };To initialize led API and initial state of the leds, call the following function with the mapping + * pointer from the above struct + * + * boardLedInit((PLED_MAP_PAIR) &cLedMapping45R); + * + * 3). Sample call for kernel mode: + * + * kerSysLedCtrl(kLedAdsl, kLedStateBlinkOnce); // kLedxxx defines in board.h + * + * 4). Sample call for user mode + * + * sysLedCtrl(kLedAdsl, kLedStateBlinkOnce); // kLedxxx defines in board_api.h + * + * + * Created on : 10/28/2002 seanl + * + ***************************************************************************/ + +/* Includes. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define k100ms (HZ / 10) // ~100 ms +#define kFastBlinkCount 0 // ~100ms +#define kSlowBlinkCount 5 // ~600ms + +#define MAX_VIRT_LEDS 12 + +// uncomment // for debug led +//#define DEBUG_LED + +// global variables: +struct timer_list gLedTimer; +int gTimerOn = FALSE; +int gLedCount = 0; + +typedef struct ledinfo +{ + unsigned short ledMask; // mask for led: ie. giop 10 = 0x0400 + unsigned short ledActiveLow; // GPIO bit reset to turn on LED + unsigned short ledMaskFail; // mask for led: ie. giop 10 = 0x0400 + unsigned short ledActiveLowFail;// GPIO bit reset to turn on LED + BOARD_LED_STATE ledState; // current led state + BOARD_LED_STATE savedLedState; // used in blink once for restore to the orignal ledState + int blinkCountDown; // if == 0, do blink (toggle). Is assgined value and dec by 1 at each timer. +} LED_INFO, *PLED_INFO; + +static PLED_INFO gLed = NULL; +static PLED_INFO gpVirtLeds[MAX_VIRT_LEDS]; +static HANDLE_LED_FUNC gLedHwFunc[MAX_VIRT_LEDS]; +static HANDLE_LED_FUNC gLedHwFailFunc[MAX_VIRT_LEDS]; + +#if 0 /* BROKEN */ +#if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338) +static int gLedOffInBridgeMode = 1; +#elif defined(CONFIG_BCM96345) +static int gLedOffInBridgeMode = 0; +#endif +#endif + +void ledTimerExpire(void); +int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed ); + +//************************************************************************************** +// LED operations +//************************************************************************************** + +// turn led on and set the ledState +void ledOn(PLED_INFO pLed) +{ + if( pLed->ledMask ) + { + GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one + if( pLed->ledActiveLow ) + GPIO->GPIOio &= ~pLed->ledMask; // turn on the led + else + GPIO->GPIOio |= pLed->ledMask; // turn on the led + pLed->ledState = pLed->savedLedState = kLedStateOn; + } +} + + +// turn led off and set the ledState +void ledOff(PLED_INFO pLed) +{ + if( pLed->ledMask ) + { + GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one + if( pLed->ledActiveLow ) + GPIO->GPIOio |= pLed->ledMask; // turn off the led + else + GPIO->GPIOio &= ~pLed->ledMask; // turn off the led + pLed->ledState = pLed->savedLedState = kLedStateOff; + } +} + +// turn led on and set the ledState +void ledOnFail(PLED_INFO pLed) +{ + if( pLed->ledMaskFail ) + { + GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one + if( pLed->ledActiveLowFail ) + GPIO->GPIOio &= ~pLed->ledMaskFail;// turn on the led + else + GPIO->GPIOio |= pLed->ledMaskFail; // turn on the led + pLed->ledState = pLed->savedLedState = kLedStateFail; + } +} + + +// turn led off and set the ledState +void ledOffFail(PLED_INFO pLed) +{ + if( pLed->ledMaskFail ) + { + GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one + if( pLed->ledActiveLowFail ) + GPIO->GPIOio |= pLed->ledMaskFail; // turn off the led + else + GPIO->GPIOio &= ~pLed->ledMaskFail;// turn off the led + pLed->ledState = pLed->savedLedState = kLedStateOff; + } +} + + +// toggle the led and return the current ledState +BOARD_LED_STATE ledToggle(PLED_INFO pLed) +{ + GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one + if (GPIO->GPIOio & pLed->ledMask) + { + GPIO->GPIOio &= ~(pLed->ledMask); + return( (pLed->ledActiveLow) ? kLedStateOn : kLedStateOff ); + } + else + { + GPIO->GPIOio |= pLed->ledMask; + return( (pLed->ledActiveLow) ? kLedStateOff : kLedStateOn ); + } +} + + +// led timer. Will return if timer is already on +void ledTimerStart(void) +{ + if (gTimerOn) + return; + +#if defined(DEBUG_LED) + printk("led: add_timer\n"); +#endif + + init_timer(&gLedTimer); + gLedTimer.function = (void*)ledTimerExpire; + gLedTimer.expires = jiffies + k100ms; // timer expires in ~100ms + add_timer (&gLedTimer); + gTimerOn = TRUE; +} + + +// led timer expire kicks in about ~100ms and perform the led operation according to the ledState and +// restart the timer according to ledState +void ledTimerExpire(void) +{ + int i; + PLED_INFO pCurLed; + + gTimerOn = FALSE; + + for (i = 0, pCurLed = gLed; i < gLedCount; i++, pCurLed++) + { +#if defined(DEBUG_LED) + printk("led[%d]: Mask=0x%04x, State = %d, blcd=%d\n", i, pCurLed->ledMask, pCurLed->ledState, pCurLed->blinkCountDown); +#endif + switch (pCurLed->ledState) + { + case kLedStateOn: + case kLedStateOff: + case kLedStateFail: + pCurLed->blinkCountDown = 0; // reset the blink count down + break; + + case kLedStateBlinkOnce: + ledToggle(pCurLed); + pCurLed->blinkCountDown = 0; // reset to 0 + pCurLed->ledState = pCurLed->savedLedState; + if (pCurLed->ledState == kLedStateSlowBlinkContinues || + pCurLed->ledState == kLedStateFastBlinkContinues) + ledTimerStart(); // start timer if in blinkContinues stats + break; + + case kLedStateSlowBlinkContinues: + if (pCurLed->blinkCountDown-- == 0) + { + pCurLed->blinkCountDown = kSlowBlinkCount; + ledToggle(pCurLed); + } + ledTimerStart(); + break; + + case kLedStateFastBlinkContinues: + if (pCurLed->blinkCountDown-- == 0) + { + pCurLed->blinkCountDown = kFastBlinkCount; + ledToggle(pCurLed); + } + ledTimerStart(); + break; + + default: + printk("Invalid state = %d\n", pCurLed->ledState); + } + } +} + +// initialize the gLedCount and allocate and fill gLed struct +void __init boardLedInit(PLED_MAP_PAIR cLedMapping) +{ + PLED_MAP_PAIR p1, p2; + PLED_INFO pCurLed; + int needTimer = FALSE; + int alreadyUsed = 0; + +#if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338) + /* Set blink rate for BCM6348/BCM6338 hardware LEDs. */ + GPIO->LEDCtrl &= ~LED_INTERVAL_SET_MASK; + GPIO->LEDCtrl |= LED_INTERVAL_SET_80MS; +#endif + + memset( gpVirtLeds, 0x00, sizeof(gpVirtLeds) ); + memset( gLedHwFunc, 0x00, sizeof(gLedHwFunc) ); + memset( gLedHwFailFunc, 0x00, sizeof(gLedHwFailFunc) ); + + gLedCount = 0; + + // Check for multiple LED names and multiple LED GPIO pins that share the + // same physical board LED. + for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ ) + { + alreadyUsed = 0; + for( p2 = cLedMapping; p2 != p1; p2++ ) + { + if( (p1->ledMask && p1->ledMask == p2->ledMask) || + (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) ) + { + alreadyUsed = 1; + break; + } + } + + if( alreadyUsed == 0 ) + gLedCount++; + } + + gLed = (PLED_INFO) kmalloc((gLedCount * sizeof(LED_INFO)), GFP_KERNEL); + if( gLed == NULL ) + { + printk( "LED memory allocation error.\n" ); + return; + } + + memset( gLed, 0x00, gLedCount * sizeof(LED_INFO) ); + + // initial the gLed with unique ledMask and initial state. If more than 1 ledNames share the physical led + // (ledMask) the first defined led's ledInitState will be used. + pCurLed = gLed; + for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ ) + { + if( (int) p1->ledName > MAX_VIRT_LEDS ) + continue; + + alreadyUsed = 0; + for( p2 = cLedMapping; p2 != p1; p2++ ) + { + if( (p1->ledMask && p1->ledMask == p2->ledMask) || + (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) ) + { + alreadyUsed = 1; + break; + } + } + + if( alreadyUsed == 0 ) + { + // Initialize the board LED for the first time. + needTimer = initLedInfo( p1, pCurLed ); + gpVirtLeds[(int) p1->ledName] = pCurLed; + pCurLed++; + } + else + { + PLED_INFO pLed; + for( pLed = gLed; pLed != pCurLed; pLed++ ) + { + // Find the LED_INFO structure that has already been initialized. + if((pLed->ledMask && pLed->ledMask == p1->ledMask) || + (pLed->ledMaskFail && pLed->ledMaskFail==p1->ledMaskFail)) + { + // The board LED has already been initialized but possibly + // not completely initialized. + if( p1->ledMask ) + { + pLed->ledMask = p1->ledMask; + pLed->ledActiveLow = p1->ledActiveLow; + } + if( p1->ledMaskFail ) + { + pLed->ledMaskFail = p1->ledMaskFail; + pLed->ledActiveLowFail = p1->ledActiveLowFail; + } + gpVirtLeds[(int) p1->ledName] = pLed; + break; + } + } + } + } + + if (needTimer) + ledTimerStart(); + +#if defined(DEBUG_LED) + int i; + for (i=0; i < gLedCount; i++) + printk("initLed: led[%d]: mask=0x%04x, state=%d\n", i,(gLed+i)->ledMask, (gLed+i)->ledState); +#endif + +} + +// Initialize a structure that contains information about a physical board LED +// control. The board LED may contain more than one GPIO pin to control a +// normal condition (green) or a failure condition (red). +int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed ) +{ + int needTimer = FALSE; + pCurLed->ledState = pCurLed->savedLedState = pCurMap->ledInitState; + pCurLed->ledMask = pCurMap->ledMask; + pCurLed->ledActiveLow = pCurMap->ledActiveLow; + pCurLed->ledMaskFail = pCurMap->ledMaskFail; + pCurLed->ledActiveLowFail = pCurMap->ledActiveLowFail; + + switch (pCurLed->ledState) + { + case kLedStateOn: + pCurLed->blinkCountDown = 0; // reset the blink count down + ledOn(pCurLed); + break; + case kLedStateOff: + pCurLed->blinkCountDown = 0; // reset the blink count down + ledOff(pCurLed); + break; + case kLedStateFail: + pCurLed->blinkCountDown = 0; // reset the blink count down + ledOnFail(pCurLed); + break; + case kLedStateBlinkOnce: + pCurLed->blinkCountDown = 1; + needTimer = TRUE; + break; + case kLedStateSlowBlinkContinues: + pCurLed->blinkCountDown = kSlowBlinkCount; + needTimer = TRUE; + break; + case kLedStateFastBlinkContinues: + pCurLed->blinkCountDown = kFastBlinkCount; + needTimer = TRUE; + break; + default: + printk("Invalid state = %d\n", pCurLed->ledState); + } + + return( needTimer ); +} + +#if 0 /* BROKEN */ +// Determines if there is at least one interface in bridge mode. Bridge mode +// is determined by the cfm convention of naming bridge interfaces nas17 +// through nas24. +static int isBridgedProtocol(void) +{ + extern int dev_get(const char *name); + const int firstBridgeId = 17; + const int lastBridgeId = 24; + int i; + int ret = FALSE; + char name[16]; + + for( i = firstBridgeId; i <= lastBridgeId; i++ ) + { + sprintf( name, "nas%d", i ); + + if( dev_get(name) ) + { + ret = TRUE; + break; + } + } + + return(ret); +} +#endif + +// led ctrl. Maps the ledName to the corresponding ledInfoPtr and perform the led operation +void boardLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState) +{ + PLED_INFO ledInfoPtr; + + // do the mapping from virtual to physical led + if( (int) ledName < MAX_VIRT_LEDS ) + ledInfoPtr = gpVirtLeds[(int) ledName]; + else + ledInfoPtr = NULL; + + if (ledInfoPtr == NULL) + return; + + if( ledState != kLedStateFail && gLedHwFunc[(int) ledName] ) + { + (*gLedHwFunc[(int) ledName]) (ledName, ledState); + ledOffFail(ledInfoPtr); + return; + } + else + if( ledState == kLedStateFail && gLedHwFailFunc[(int) ledName] ) + { + (*gLedHwFailFunc[(int) ledName]) (ledName, ledState); + ledOff(ledInfoPtr); + return; + } + +#if 0 /* BROKEN */ + // Do not blink the WAN Data LED if at least one interface is in bridge mode. + if(gLedOffInBridgeMode == 1 && (ledName == kLedWanData || ledName == kLedPPP)) + { + static int BridgedProtocol = -1; + + if( BridgedProtocol == -1 ) + BridgedProtocol = isBridgedProtocol(); + + if( BridgedProtocol == TRUE ) + return; + } +#endif + + // If the state is kLedStateFail and there is not a failure LED defined + // in the board parameters, change the state to kLedStateFastBlinkContinues. + if( ledState == kLedStateFail && ledInfoPtr->ledMaskFail == 0 ) + ledState = kLedStateFastBlinkContinues; + + switch (ledState) + { + case kLedStateOn: + // First, turn off the complimentary (failure) LED GPIO. + if( ledInfoPtr->ledMaskFail ) + ledOffFail(ledInfoPtr); + else + if( gLedHwFailFunc[(int) ledName] ) + (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff); + + // Next, turn on the specified LED GPIO. + ledOn(ledInfoPtr); + break; + + case kLedStateOff: + // First, turn off the complimentary (failure) LED GPIO. + if( ledInfoPtr->ledMaskFail ) + ledOffFail(ledInfoPtr); + else + if( gLedHwFailFunc[(int) ledName] ) + (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff); + + // Next, turn off the specified LED GPIO. + ledOff(ledInfoPtr); + break; + + case kLedStateFail: + // First, turn off the complimentary (normal) LED GPIO. + if( ledInfoPtr->ledMask ) + ledOff(ledInfoPtr); + else + if( gLedHwFunc[(int) ledName] ) + (*gLedHwFunc[(int) ledName]) (ledName, kLedStateOff); + + // Next, turn on (red) the specified LED GPIO. + ledOnFail(ledInfoPtr); + break; + + case kLedStateBlinkOnce: + // skip blinkOnce if it is already in Slow/Fast blink continues state + if (ledInfoPtr->savedLedState == kLedStateSlowBlinkContinues || + ledInfoPtr->savedLedState == kLedStateFastBlinkContinues) + ; + else + { + if (ledInfoPtr->blinkCountDown == 0) // skip the call if it is 1 + { + ledToggle(ledInfoPtr); + ledInfoPtr->blinkCountDown = 1; // it will be reset to 0 when timer expires + ledInfoPtr->ledState = kLedStateBlinkOnce; + ledTimerStart(); + } + } + break; + + case kLedStateSlowBlinkContinues: + ledInfoPtr->blinkCountDown = kSlowBlinkCount; + ledInfoPtr->ledState = kLedStateSlowBlinkContinues; + ledInfoPtr->savedLedState = kLedStateSlowBlinkContinues; + ledTimerStart(); + break; + + case kLedStateFastBlinkContinues: + ledInfoPtr->blinkCountDown = kFastBlinkCount; + ledInfoPtr->ledState = kLedStateFastBlinkContinues; + ledInfoPtr->savedLedState = kLedStateFastBlinkContinues; + ledTimerStart(); + break; + + default: + printk("Invalid led state\n"); + } +} + +// This function is called for an LED that is controlled by hardware. +void kerSysLedRegisterHwHandler( BOARD_LED_NAME ledName, + HANDLE_LED_FUNC ledHwFunc, int ledFailType ) +{ + if( (int) ledName < MAX_VIRT_LEDS ) + { + if( ledFailType == 1 ) + gLedHwFailFunc[(int) ledName] = ledHwFunc; + else + gLedHwFunc[(int) ledName] = ledHwFunc; + } +} +