diff -r 000000000000 -r 5de814552237 navienginebsp/naviengine_assp/gpio.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/navienginebsp/naviengine_assp/gpio.cpp Tue Sep 28 18:00:05 2010 +0100 @@ -0,0 +1,822 @@ +/* +* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* naviengine_assp\gpio.cpp +* NaviEngine implementation of the MHA GPIO class +* +*/ + + + +#include +#include + +const TInt32 KHwGpioPinMax = 31; +const TInt32 KHwGpioEdgeRising = 0x0; +const TInt32 KHwGpioEdgeFalling = 0x1; +const TInt32 KHwGpioEdgeBoth = 0x2; +const TInt32 KHwGpioLevelLow = 0x3; +const TInt32 KHwGpioLevelHigh = 0x4; + +const TInt32 KGpioDebounceInterval = 1; // (in ticks) +const TInt32 KGpioMaxRetries = 8; + +class GpioPin + { +public: + GPIO::TGpioMode iMode; + TGpioIsr iIsr; + TAny * iPtr; + TInt iDebounce; + }; + +static GpioPin GpioPins[KHwGpioPinMax+1]; +static TInt32 GpioInterruptId; +#ifdef __SMP__ +const TInt32 KGpioLockOrder = TSpinLock::EOrderGenericIrqLow2; +static TSpinLock GpioSpinLock(KGpioLockOrder); +#endif + +inline TInt GpioLock(); +inline void GpioUnlock(TInt irq); + +/** +Calculate 16-bit device pin Id from 32-bit pin Id. Use DeviceId() to +get device Id. +@param aId 32-bit pin Id +@return 16-bit device specific pin Id +*/ +static inline TUint16 DevicePinId(TInt aId) + {return static_cast(aId & 0x0000FFFF);} + + +//Commented out to satisfy compiler(as method is not used in the code) but can +//be usefull later +/** +Calculate and return GPIO device Id(either SOC or one of the extenders) +defined in TGpioBaseId from the 32-bit pin Id +@param aId 32-bit pin Id +@return + - EInternalId SOC GPIO + - EExtender0-15 GPIO extenders from 0-15 + +static inline GPIO::TGpioBaseId ExtenderId(TInt aId) + {return static_cast((aId & 0xFFFF0000));} +*/ + +//Commented out to satisfy compiler(as method is not used in the code) but can +//be usefull later +/** +Generate 32-bit pin Id from the device Id and device specific 16-bit +pin Id. +@param aExtenderId Device Id is defined in TGpioBaseId +@param aPinId 16-bit device pin Id +return 32-bit pin Id + +static inline TInt Id(GPIO::TGpioBaseId aExtenderId, TUint16 aPinId) + {return static_cast(aExtenderId |aPinId);} +*/ + +//Commented out to satisfy compiler(as method is not used in the code) but can +//be usefull later +/** +Find index in extender GPIO device table. +@param aExtenderId Extender Id is defined in TGpioBaseId +@return singned 32-bit integer index device, possible value + from 0 to 15 + +static TInt DeviceIndex(GPIO::TGpioBaseId aExtenderId) + { + TUint16 val = (TUint16)((aExtenderId & 0xFFFF0000) >> 16); + if(val == 0) return GPIO::EInternalId; + + //The algorithm steps througth the value until first non-zero bit is + //found. + // + TInt index = 0; + if(val & 0xFF00) {index = 8; val = val >> 8;} // 2 x 8-bits + if(val & 0x00F0) {index += 4; val = val >> 4;} // 2 x 4-bits + if(val & 0x000C) {index += 2; val = val >> 2;} // 2 x 2 bits + if(val & 0x0002) {index += 1; val = val >> 1;} // 2 x 1 bits + + return index; + } +*/ + +//Commented out to satisfy compiler(as method is not used in the code) but can +//be usefull later +/** +Find index in extender GPIO device table. +@param aId 32-bit GPIO pin Id +@return singned 32-bit integer index device, possible value + from 0 to 15 + +static TInt DeviceIndex(TInt aId){return DeviceIndex(ExtenderId(aId));} +*/ + + + +/** +GPIO interrupt handler +Takes a generic argument (TAny*) +*/ +void GpioIsrDispatch(TAny *aPtr) + { + GpioPin *pins = (GpioPin *)aPtr; + TInt irq = GpioLock(); + TUint32 interrupt = AsspRegister::Read32(KHwRwGpio_Int); + TUint32 enabled = AsspRegister::Read32(KHwRwGpio_Int_Enable); + TUint32 masked = interrupt & enabled; + for (TInt i = 0; i <= KHwGpioPinMax; i++) + { + if ((masked & 0x1) && (pins[i].iIsr != NULL)) + { + (*pins[i].iIsr)(pins[i].iPtr); + } + masked >>= 1; + } + Interrupt::Clear(GpioInterruptId); + GpioUnlock(irq); + } + +#include "gpio.inl" + +// +// work out debounced state +// +TInt GetDebouncedState(TInt aId, TUint32 &aVal) + { + + TUint16 pinId = DevicePinId(aId); + TInt debounceCount = GpioPins[pinId].iDebounce/KGpioDebounceInterval; + TInt count = 0; + TInt retries = debounceCount*KGpioMaxRetries; + TUint lastState = AsspRegister::Read32(KHwRoGpio_Port_Value); + TUint state = lastState; + + for (count = 0; count < debounceCount && retries > 0; count ++) + { + NKern::Sleep(KGpioDebounceInterval); + state = AsspRegister::Read32(KHwRoGpio_Port_Value); + + if ((state & 1< KHwGpioPinMax) + { + return KErrArgument; + } + + __e32_atomic_store_rel32(&GpioPins[pinId].iMode, aMode); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetPinMode + ( + TInt aId, + TGpioMode & aMode + ) + { + TUint16 pinId = DevicePinId(aId); + // the chip doesn't support modes, so just return what we stored earlier + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + aMode = (TGpioMode) __e32_atomic_load_acq32(&GpioPins[pinId].iMode); + return KErrNone; + } + +EXPORT_C TInt GPIO::SetPinDirection + ( + TInt aId, + TGpioDirection aDirection + ) + { + TUint16 pinId = DevicePinId(aId); + // tristate not supported + if (pinId > KHwGpioPinMax || aDirection == ETriStated) + { + return KErrArgument; + } + // port enabled means output, disabled means input + if (aDirection == EInput) + { + AsspRegister::Write32(KHwWoGpio_Port_Control_Disable, 1< KHwGpioPinMax) + { + return KErrArgument; + } + // port enabled means output, disabled means input + TUint enabled = AsspRegister::Read32(KHwRwGpio_Port_Control_Enable); + if (enabled & 1< KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::GetPinBias + ( + TInt aId, + TGpioBias& /*aBias*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // pin bias not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::SetPinIdleConfigurationAndState + ( + TInt aId, + TInt /*aConf*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // pin idle configuration and state not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::GetPinIdleConfigurationAndState + ( + TInt aId, + TInt & /*aBias*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // pin idle configuration and state not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::BindInterrupt + ( + TInt aId, + TGpioIsr aIsr, + TAny * aPtr + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax || aIsr == NULL) + { + return KErrArgument; + } + TInt irq = GpioLock(); + if (GpioPins[pinId].iIsr != NULL) + { + GpioUnlock(irq); + // already bound + return KErrInUse; + } + GpioPins[pinId].iIsr = aIsr; + GpioPins[pinId].iPtr = aPtr; + GpioUnlock(irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::UnbindInterrupt + ( + TInt aId + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + if (GpioPins[pinId].iIsr == NULL) + { + GpioUnlock(irq); + // nothing bound + return KErrGeneral; + } + GpioPins[pinId].iIsr = NULL; + GpioPins[pinId].iPtr = NULL; + GpioUnlock(irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::EnableInterrupt + ( + TInt aId + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + if (GpioPins[pinId].iIsr == NULL) + { + GpioUnlock(irq); + // nothing bound + return KErrGeneral; + } + + // hold value so it can be read after triggering + TUint32 held = AsspRegister::Read32(KHwRwGpio_Int_Hold); + AsspRegister::Write32(KHwRwGpio_Int_Hold, held | 1< KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + if (GpioPins[pinId].iIsr == NULL) + { + GpioUnlock(irq); + // nothing bound + return KErrGeneral; + } + // disable interrupt + AsspRegister::Write32(KHwWoGpio_Int_Disable, 1< KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + if (GpioPins[pinId].iIsr == NULL) + { + GpioUnlock(irq); + // nothing bound + return KErrGeneral; + } + aEnable = AsspRegister::Read32(KHwRwGpio_Int_Enable) & (1< KHwGpioPinMax) + { + return KErrArgument; + } + // clear pin interrupt status + AsspRegister::Write32(KHwRwGpio_Int, 1< KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + aActive = AsspRegister::Read32(KHwRwGpio_Int_Enable) & AsspRegister::Read32(KHwRwGpio_Int) & (1< KHwGpioPinMax) + { + return KErrArgument; + } + aActive = AsspRegister::Read32(KHwRwGpio_Int) & (1< KHwGpioPinMax) + { + return KErrArgument; + } + TUint modeRegister = KHwRwGpio_Int_Mode0 + ((pinId >> 3) << 2); + TUint modeShift = pinId & 0x7; + TUint mode; + switch (aTrigger) + { + case ELevelLow: + mode = KHwGpioLevelLow; + break; + case ELevelHigh: + mode = KHwGpioLevelHigh; + break; + case EEdgeFalling: + mode = KHwGpioEdgeFalling; + break; + case EEdgeRising: + mode = KHwGpioEdgeRising; + break; + case EEdgeBoth: + mode = KHwGpioEdgeBoth; + break; + default: + return KErrArgument; + } + + TInt irq = GpioLock(); + TUint currentMode = AsspRegister::Read32(modeRegister) & !(0xf << modeShift); + AsspRegister::Write32(modeRegister, (mode << modeShift) | currentMode); + GpioUnlock(irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::EnableWakeup + ( + TInt aId + ) + { + TUint16 pinId = DevicePinId(aId); + // wakeup not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::DisableWakeup + ( + TInt aId + ) + { + TUint16 pinId = DevicePinId(aId); + // wakeup not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::IsWakeupEnabled + ( + TInt aId, + TBool & /*aEnable*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // wakeup not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::SetWakeupTrigger + ( + TInt aId, + TGpioDetectionTrigger /*aTrigger*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // wakeup not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::SetDebounceTime + ( + TInt aId, + TInt aTime + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + GpioPins[pinId].iDebounce = NKern::TimerTicks(aTime/1000); + GpioUnlock(irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetDebounceTime + ( + TInt aId, + TInt & aTime + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + aTime = (GpioPins[pinId].iDebounce*1000)/NKern::TimerTicks(1); + GpioUnlock(irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetInputState + ( + TInt aId, + TGpioState & aState + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + // check it is enabled and is an input port + TInt irq = GpioLock(); + if (GpioPins[pinId].iMode != EEnabled || (AsspRegister::Read32(KHwRwGpio_Port_Control_Enable) & 1< KHwGpioPinMax) + { + return KErrArgument; + } + TInt irq = GpioLock(); + if (GpioPins[pinId].iMode != EEnabled) + { + GpioUnlock(irq); + return KErrGeneral; + } + TUint outputReg, value; + if (pinId >= 16) + { + outputReg = KHwWoGpio_Port_Set_Clear_Hi; + pinId = pinId - 16; + } + else + { + outputReg = KHwWoGpio_Port_Set_Clear_Lo; + } + if (aState == EHigh) + { + value = 1 << pinId; // LSW - set.. + } + else + { + value = 1 << (pinId + 16); // MSW - clear.. + } + + AsspRegister::Write32(outputReg, value); + GpioUnlock(irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetOutputState + ( + TInt aId, + TGpioState & aState + ) + { + TUint16 pinId = DevicePinId(aId); + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + // atomic - no lock required + TUint32 state = AsspRegister::Read32(KHwRoGpio_Port_Value); + if(state & (1< KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::SetOutputState + ( + TInt aId, + TGpioState /*aState*/, + TGpioCallback * /*aCb*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // asynch calls not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } + +#ifndef __USE_GPIO_STATIC_EXTENSION__ +EXPORT_C TInt GPIO::StaticExtension + ( + TInt aId, + TInt /*aCmd*/, + TAny * /*aArg1*/, + TAny * /*aArg2*/ + ) + { + TUint16 pinId = DevicePinId(aId); + // static extensions not supported + if (pinId > KHwGpioPinMax) + { + return KErrArgument; + } + return KErrNotSupported; + } +#endif + +DECLARE_STANDARD_EXTENSION() + { + TInt irq = GpioLock(); + // initialise GPIO pins array + for (TInt32 i = 0; i <= KHwGpioPinMax; i++) + { + GpioPins[i].iMode = GPIO::EIdle; + GpioPins[i].iIsr = NULL; + GpioPins[i].iPtr = NULL; + GpioPins[i].iDebounce = 0; + } + GpioUnlock(irq); + TInt r = Interrupt::Bind(KIntIdGpio, GpioIsrDispatch, &GpioPins[0]); + if (r < 0) + { + return r; + } + GpioInterruptId = r; + Interrupt::Clear(GpioInterruptId); + Interrupt::Enable(GpioInterruptId); + return KErrNone; + }