diff -r 000000000000 -r 6663340f3fc9 omap3530/omap3530_drivers/gpio/gpio.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/omap3530_drivers/gpio/gpio.cpp Thu Oct 15 12:59:54 2009 +0100 @@ -0,0 +1,409 @@ +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "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: +// omap3530/omap3530_drivers/gpio/gpio.cpp +// + +#include +#include +#include +#include + +#include +//#include +#include + +GLREF_C TInt InitGpioInterrupts(); + + +TSpinLock GPIOModeLock(/*TSpinLock::EOrderNone*/); +TSpinLock GPIOWakeLock(/*TSpinLock::EOrderNone*/); +TSpinLock GPIOLevelLock(/*TSpinLock::EOrderNone*/); + +GPIO::TGpioMode ThePinMode[ KHwGpioPinMax ]; +TUint32 ThePinIsEnabled[ KHwGpioBanks ]; +__ASSERT_COMPILE( KHwGpioPinsPerBank <= 32 ); + +#if 0 +static void dumpGpioBank(TUint aBankAddr) + { + Kern::Printf("GPIO_SYSCONFIG at %x is %x",aBankAddr +KGPIO_SYSCONFIG,AsspRegister::Read32(aBankAddr +KGPIO_SYSCONFIG) ); + Kern::Printf("GPIO_SYSSTATUS at %x is %x",aBankAddr +KGPIO_SYSSTATUS,AsspRegister::Read32(aBankAddr +KGPIO_SYSSTATUS)); + Kern::Printf("GPIO_IRQSTATUS1 at %x is %x",aBankAddr +KGPIO_IRQSTATUS1,AsspRegister::Read32(aBankAddr +KGPIO_IRQSTATUS1) ); + Kern::Printf("GPIO_IRQENABLE1 at %x is %x",aBankAddr +KGPIO_IRQENABLE1,AsspRegister::Read32(aBankAddr +KGPIO_IRQENABLE1) ); + Kern::Printf("GPIO_WAKEUPENABLE at %x is %x",aBankAddr +KGPIO_WAKEUPENABLE,AsspRegister::Read32(aBankAddr +KGPIO_WAKEUPENABLE) ); + Kern::Printf("GPIO_CTRL at %x is %x",aBankAddr +KGPIO_CTRL,AsspRegister::Read32(aBankAddr +KGPIO_CTRL) ); + Kern::Printf("GPIO_OE at %x is %x",aBankAddr +KGPIO_CTRL,AsspRegister::Read32(aBankAddr +KGPIO_OE) ); + } +#endif + + +EXPORT_C TInt GPIO::SetPinMode(TInt aId, TGpioMode aMode) + { + TInt irq = __SPIN_LOCK_IRQSAVE(GPIOModeLock); + if(ThePinMode[ aId ] != aMode) + { + ThePinMode[ aId ] = aMode; + TUint bank = GPIO_PIN_BANK( aId ); + TUint pinMask = 1 << GPIO_PIN_OFFSET( aId ); + + if( aMode == GPIO::EEnabled) + { + if( 0 == ThePinIsEnabled[ bank ] ) + { + // First enabled pin in bank + AsspRegister::Modify32(GPIO_BASE_ADDRESS( aId ) +KGPIO_CTRL,KClearNone,0x1); + } + + ThePinIsEnabled[ bank ] |= pinMask; + } + else + { + ThePinIsEnabled[ bank ] &= ~pinMask; + + if( 0 == ThePinIsEnabled[ bank ] ) + { + // Bank can be disabled + AsspRegister::Modify32(GPIO_BASE_ADDRESS( aId ) +KGPIO_CTRL,0x1, KSetNone); + } + } + } + __SPIN_UNLOCK_IRQRESTORE(GPIOModeLock,irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetPinMode(TInt aId, TGpioMode & aMode) + { + aMode = ThePinMode[ aId ]; + return KErrNone; + } + +EXPORT_C TInt GPIO::SetPinDirection(TInt aId, TGpioDirection aDirection) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::SetPinBias OOB ",KErrArgument)); + + if (aDirection == ETriStated) + { + return KErrNotSupported; + } + + if (aDirection == EInput) + { + AsspRegister::Modify32(GPIO_BASE_ADDRESS(aId)+KGPIO_OE, KClearNone, GPIO_PIN_OFFSET(aId)); + } + else + { + AsspRegister::Modify32(GPIO_BASE_ADDRESS(aId)+KGPIO_OE, GPIO_PIN_OFFSET(aId), KSetNone); + } + return KErrNone; + } + +EXPORT_C TInt GPIO::GetPinDirection(TInt aId, TGpioDirection& aDirection) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetPinDirection OOB ",KErrArgument)); + + if(AsspRegister::Read32(GPIO_BASE_ADDRESS(aId)+KGPIO_OE) & GPIO_PIN_OFFSET(aId)) + aDirection=EInput; + else + aDirection=EOutput; + + return KErrNone; + } + +EXPORT_C TInt GPIO::SetPinBias(TInt aId, TGpioBias aBias) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::SetPinBias OOB ",KErrArgument)); + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::GetPinBias(TInt aId, TGpioBias& aBias) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetPinBias OOB ",KErrArgument)); + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::SetPinIdleConfigurationAndState(TInt aId, TInt /*aConf*/) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::SetPinIdleConfigurationAndState OOB ",KErrArgument)); + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::GetPinIdleConfigurationAndState(TInt aId, TInt& aBias) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetPinIdleConfigurationAndState OOB ",KErrArgument)); + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::BindInterrupt(TInt aId, TGpioIsr aIsr, TAny* aPtr) + { + return Interrupt::Bind( EGPIOIRQ_FIRST + aId,aIsr,aPtr); + } + +EXPORT_C TInt GPIO::UnbindInterrupt(TInt aId) + { + return Interrupt::Unbind( EGPIOIRQ_FIRST + aId ); + } + +EXPORT_C TInt GPIO::EnableInterrupt(TInt aId) + { + return Interrupt::Enable( EGPIOIRQ_FIRST + aId ); + } + +EXPORT_C TInt GPIO::DisableInterrupt(TInt aId) + { + return Interrupt::Disable( EGPIOIRQ_FIRST + aId ); + } + +EXPORT_C TInt GPIO::ClearInterrupt(TInt aId) + { + return Interrupt::Clear( EGPIOIRQ_FIRST + aId ); + } + +EXPORT_C TInt GPIO::IsInterruptEnabled(TInt aId, TBool& aEnable) + { + aEnable = AsspRegister::Read32(GPIO_BASE_ADDRESS( aId ) + KGPIO_IRQENABLE1) & GPIO_PIN_OFFSET(aId); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetMaskedInterruptState(TInt aId, TBool& aActive) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetMaskedInterruptState OOB ",KErrArgument)); + aActive = AsspRegister::Read32(GPIO_BASE_ADDRESS(aId)+KGPIO_IRQSTATUS1) & GPIO_PIN_OFFSET(aId); + + return KErrNone; + } + +EXPORT_C TInt GPIO::GetRawInterruptState(TInt aId, TBool& aActive) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetRawInterruptState OOB ",KErrArgument)); + + aActive = AsspRegister::Read32(GPIO_BASE_ADDRESS(aId)+KGPIO_IRQSTATUS1) & GPIO_PIN_OFFSET(aId); + + return KErrNone; + } + +EXPORT_C TInt GPIO::SetInterruptTrigger(TInt aId, TGpioDetectionTrigger aTrigger) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::SetInterruptTrigger OOB ",KErrArgument)); + + TInt baseAddr = GPIO_BASE_ADDRESS(aId); + TUint irqFlags=0; + //first we clear the current trigger(s) + //then set the new for each case + switch (aTrigger) + { + case ELevelLow: + + irqFlags = NKern::DisableAllInterrupts();//__SPIN_LOCK_IRQSAVE_W(GPIOLevelSpinLock); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT1, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_FALLINGDETECT, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_RISINGDETECT, GPIO_PIN_OFFSET(aId),KSetNone); + + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT0, KClearNone, GPIO_PIN_OFFSET(aId)); + NKern::RestoreInterrupts(irqFlags);//__SPIN_UNLOCK_IRQRESTORE_W(GPIOLevelSpinLock,irqFlags); + break; + case ELevelHigh: + + irqFlags = NKern::DisableAllInterrupts();//__SPIN_LOCK_IRQSAVE_W(GPIOLevelSpinLock); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT0, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_FALLINGDETECT, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_RISINGDETECT, GPIO_PIN_OFFSET(aId),KSetNone); + + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT1, KClearNone, GPIO_PIN_OFFSET(aId)); + NKern::RestoreInterrupts(irqFlags);//__SPIN_UNLOCK_IRQRESTORE_W(GPIOLevelSpinLock,irqFlags); + + break; + case EEdgeFalling: + + irqFlags = NKern::DisableAllInterrupts();//__SPIN_LOCK_IRQSAVE_W(GPIOLevelSpinLock); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT0, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT1, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_RISINGDETECT, GPIO_PIN_OFFSET(aId),KSetNone); + + AsspRegister::Modify32(baseAddr+KGPIO_FALLINGDETECT, KClearNone, GPIO_PIN_OFFSET(aId)); + NKern::RestoreInterrupts(irqFlags);//__SPIN_UNLOCK_IRQRESTORE_W(GPIOLevelSpinLock,irqFlags); + break; + case EEdgeRising: + + irqFlags = NKern::DisableAllInterrupts();//__SPIN_LOCK_IRQSAVE_W(GPIOLevelSpinLock); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT0, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT1, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_FALLINGDETECT, GPIO_PIN_OFFSET(aId),KSetNone); + + AsspRegister::Modify32(baseAddr+KGPIO_RISINGDETECT, KClearNone, GPIO_PIN_OFFSET(aId)); + NKern::RestoreInterrupts(irqFlags);//__SPIN_UNLOCK_IRQRESTORE_W(GPIOLevelSpinLock,irqFlags); + break; + case EEdgeBoth: + + irqFlags = NKern::DisableAllInterrupts();//__SPIN_LOCK_IRQSAVE_W(GPIOLevelSpinLock); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT0, GPIO_PIN_OFFSET(aId),KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_LEVELDETECT1, GPIO_PIN_OFFSET(aId),KSetNone); + + AsspRegister::Modify32(baseAddr+KGPIO_FALLINGDETECT, KClearNone, GPIO_PIN_OFFSET(aId)); + AsspRegister::Modify32(baseAddr+KGPIO_RISINGDETECT, KClearNone, GPIO_PIN_OFFSET(aId)); + NKern::RestoreInterrupts(irqFlags);//__SPIN_UNLOCK_IRQRESTORE_W(GPIOLevelSpinLock,irqFlags); + + break; + default: + return KErrArgument; + } + + return KErrNone; + } + + +EXPORT_C TInt GPIO::EnableWakeup(TInt aId) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::EnableWakeup OOB ",KErrArgument)); + + TInt baseAddr = GPIO_BASE_ADDRESS(aId); + + TInt irq = __SPIN_LOCK_IRQSAVE(GPIOWakeLock); + AsspRegister::Modify32(baseAddr+KGPIO_SYSCONFIG,KClearNone, 1 << 2 ); + AsspRegister::Modify32(baseAddr+KGPIO_SETWKUENA,KClearNone ,GPIO_PIN_OFFSET(aId)); + __SPIN_UNLOCK_IRQRESTORE(GPIOWakeLock,irq); + + return KErrNone; + } + +EXPORT_C TInt GPIO::DisableWakeup(TInt aId) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::DisableWakeup OOB ",KErrArgument)); + + TInt baseAddr = GPIO_BASE_ADDRESS(aId); + + TInt irq = __SPIN_LOCK_IRQSAVE(GPIOWakeLock); + AsspRegister::Modify32(baseAddr+KGPIO_SYSCONFIG,1 << 2 ,KSetNone); + AsspRegister::Modify32(baseAddr+KGPIO_CLEARWKUENA,KClearNone,GPIO_PIN_OFFSET(aId)); + __SPIN_UNLOCK_IRQRESTORE(GPIOWakeLock,irq); + return KErrNone; + } + +EXPORT_C TInt GPIO::IsWakeupEnabled(TInt aId, TBool& aEnable) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::IsWakeupEnabled OOB ",KErrArgument)); + + aEnable = AsspRegister::Read32(GPIO_BASE_ADDRESS(aId)+KGPIO_WAKEUPENABLE) & GPIO_PIN_OFFSET(aId); + return KErrNone; + } + +EXPORT_C TInt GPIO::SetWakeupTrigger(TInt aId, TGpioDetectionTrigger aTrigger) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::SetWakeupTrigger OOB ",KErrArgument)); + return KErrNotSupported; + } + +// WARNING: Changing debouncing time will change it for all pins in the bank +EXPORT_C TInt GPIO::SetDebounceTime(TInt aId, TInt aTime) + { + TGpioDirection direction; + GetPinDirection(aId, direction); + + if(direction==EOutput) + { + // The pin must be configured as input. + return KErrNotSupported; + } + + //convert the Ms input time into units of 31us + TInt timeSteps = aTime / 31; + if(timeSteps>127) + { +#ifdef _DEBUG + Kern::Printf("Warning: Tried to set the GPIO debounce time to %dus, \ + which is greater than the maximum supported 3937us.", aTime); +#endif + timeSteps=127; // The maximum debounce value. + } + + TInt baseAddr = GPIO_BASE_ADDRESS(aId); + + TUint irqFlags = __SPIN_LOCK_IRQSAVE(gpio::GPIODebounceSpinLock); + AsspRegister::Write32(baseAddr+KGPIO_DEBOUNCINGTIME, timeSteps & KGPIO_DEBOUNCE_TIME_MASK); + AsspRegister::Modify32(baseAddr+KGPIO_DEBOUNCENABLE, KClearNone, GPIO_PIN_OFFSET(aId)); + __SPIN_UNLOCK_IRQRESTORE(gpio::GPIODebounceSpinLock,irqFlags); + + return KErrNone; + } + +EXPORT_C TInt GPIO::GetDebounceTime(TInt aId, TInt& aTime) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetDebounceTime OOB ",KErrArgument)); + aTime=AsspRegister::Read32(GPIO_BASE_ADDRESS(aId)+KGPIO_DEBOUNCINGTIME); // The time in in multiples of 31 microseconds. We should probably use a nicer unit.. + + return KErrNone; + } + +EXPORT_C TInt GPIO::SetOutputState(TInt aId, TGpioState aState) + { + if(aState==GPIO::ELow) + { + AsspRegister::Modify32(GPIO_BASE_ADDRESS(aId) + KGPIO_DATAOUT, GPIO_PIN_OFFSET(aId), KSetNone); + } + else + { + AsspRegister::Modify32(GPIO_BASE_ADDRESS(aId) + KGPIO_DATAOUT, KClearNone, GPIO_PIN_OFFSET(aId)); + } + return KErrNone; + } + +EXPORT_C TInt GPIO::GetInputState(TInt aId, TGpioState& aState) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetInputState OOB ",KErrArgument)); + + aState= ( AsspRegister::Read32(GPIO_BASE_ADDRESS(aId) + KGPIO_DATAIN) & GPIO_PIN_OFFSET(aId) ? + GPIO::EHigh: + GPIO::ELow); + + return KErrNone; + } + +EXPORT_C TInt GPIO::GetOutputState(TInt aId, TGpioState& aState) + { + __ASSERT_ALWAYS(GPIO_PIN_BOUNDS(aId),Kern::Fault(" GPIO::GetOutputState OOB ",KErrArgument)); + + aState = (AsspRegister::Read32(GPIO_BASE_ADDRESS(aId)+KGPIO_DATAOUT)& GPIO_PIN_OFFSET(aId) ? + aState=GPIO::EHigh: + aState=GPIO::ELow); + return KErrNone; + } + +EXPORT_C TInt GPIO::GetInputState(TInt aId, TGpioCallback* /*aCb*/) + { + return KErrNotSupported; + } + +EXPORT_C TInt GPIO::SetOutputState(TInt aId, TGpioState aState, TGpioCallback* /*aCb*/) + { + return KErrNotSupported; + } + + +DECLARE_STANDARD_EXTENSION() + { + + TInt i=0; + for(;i