| author | William Roberts <williamr@symbian.org> |
| Fri, 01 Oct 2010 12:45:26 +0100 | |
| changeset 3 | b41049883d87 |
| parent 0 | 5de814552237 |
| permissions | -rw-r--r-- |
/* * 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 <naviengine_priv.h> #include <gpio.h> 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<TUint16>(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<GPIO::TGpioBaseId>((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<TInt>(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<<pinId) != (lastState & 1<<pinId)) { // state has changed so reset count and lastState lastState = AsspRegister::Read32(KHwRoGpio_Port_Value); count = 0; retries--; } } if (retries == 0) { // too many retries return KErrTimedOut; } aVal = state; return KErrNone; } EXPORT_C TInt GPIO::SetPinMode ( TInt aId, TGpioMode aMode ) { TUint16 pinId = DevicePinId(aId); // the chip doesn't support modes, so just store it if (pinId > 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<<pinId); } else { AsspRegister::Write32(KHwRwGpio_Port_Control_Enable, 1<<pinId); } return KErrNone; } EXPORT_C TInt GPIO::GetPinDirection ( TInt aId, TGpioDirection & aDirection ) { TUint16 pinId = DevicePinId(aId); if (pinId > KHwGpioPinMax) { return KErrArgument; } // port enabled means output, disabled means input TUint enabled = AsspRegister::Read32(KHwRwGpio_Port_Control_Enable); if (enabled & 1<<pinId) { aDirection = EOutput; } else { aDirection = EInput; } return KErrNone; } EXPORT_C TInt GPIO::SetPinBias ( TInt aId, TGpioBias /*aBias*/ ) { TUint16 pinId = DevicePinId(aId); // pin bias not supported if (pinId > 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<<pinId); // enable interrupt AsspRegister::Write32(KHwRwGpio_Int_Enable, 1<<pinId); GpioUnlock(irq); return KErrNone; } EXPORT_C TInt GPIO::DisableInterrupt ( 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; } // disable interrupt AsspRegister::Write32(KHwWoGpio_Int_Disable, 1<<pinId); // disable hold TUint32 held = AsspRegister::Read32(KHwRwGpio_Int_Hold); AsspRegister::Write32(KHwRwGpio_Int_Hold, held & !(1<<pinId)); GpioUnlock(irq); return KErrNone; } EXPORT_C TInt GPIO::IsInterruptEnabled ( TInt aId, TBool & aEnable ) { TUint16 pinId = DevicePinId(aId); if (pinId > KHwGpioPinMax) { return KErrArgument; } TInt irq = GpioLock(); if (GpioPins[pinId].iIsr == NULL) { GpioUnlock(irq); // nothing bound return KErrGeneral; } aEnable = AsspRegister::Read32(KHwRwGpio_Int_Enable) & (1<<pinId); GpioUnlock(irq); return KErrNone; } EXPORT_C TInt GPIO::ClearInterrupt ( TInt aId ) { TUint16 pinId = DevicePinId(aId); if (pinId > KHwGpioPinMax) { return KErrArgument; } // clear pin interrupt status AsspRegister::Write32(KHwRwGpio_Int, 1<<pinId); return KErrNone; } EXPORT_C TInt GPIO::GetMaskedInterruptState ( TInt aId, TBool & aActive ) { TUint16 pinId = DevicePinId(aId); if (pinId > KHwGpioPinMax) { return KErrArgument; } TInt irq = GpioLock(); aActive = AsspRegister::Read32(KHwRwGpio_Int_Enable) & AsspRegister::Read32(KHwRwGpio_Int) & (1<<pinId); GpioUnlock(irq); return KErrNone; } EXPORT_C TInt GPIO::GetRawInterruptState ( TInt aId, TBool & aActive ) { TUint16 pinId = DevicePinId(aId); if (pinId > KHwGpioPinMax) { return KErrArgument; } aActive = AsspRegister::Read32(KHwRwGpio_Int) & (1<<pinId); return KErrNone; } EXPORT_C TInt GPIO::SetInterruptTrigger ( TInt aId, TGpioDetectionTrigger aTrigger ) { TUint16 pinId = DevicePinId(aId); if (pinId > 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<<pinId)) // reg will have 0 for input 1 for output { GpioUnlock(irq); return KErrGeneral; } GpioUnlock(irq); TUint32 state; if (GpioPins[pinId].iDebounce == 0) { // just read it if we are not debouncing state = AsspRegister::Read32(KHwRoGpio_Port_Value); } else { // work out debounced state TInt err = GetDebouncedState(aId, state); if (err != KErrNone) { return err; } } if (state & (1<<pinId)) { aState = EHigh; } else { aState = ELow; } return KErrNone; } EXPORT_C TInt GPIO::SetOutputState ( TInt aId, TGpioState aState ) { TUint16 pinId = DevicePinId(aId); if (pinId > 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<<pinId)) { aState = EHigh; } else { aState = ELow; } return KErrNone; } EXPORT_C TInt GPIO::GetInputState ( TInt aId, TGpioCallback * /*aCb*/ ) { TUint16 pinId = DevicePinId(aId); // asynch calls not supported if (pinId > 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; }