diff -r 000000000000 -r 6663340f3fc9 omap3530/omap3530_drivers/gpio/gpio_interrupts.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/omap3530_drivers/gpio/gpio_interrupts.cpp Thu Oct 15 12:59:54 2009 +0100 @@ -0,0 +1,275 @@ +// 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_interrupts.cpp +// + +#include +#include +#include +#include +#include +#include +#include + +NONSHARABLE_CLASS( TGpioDispatcher ) : public MInterruptDispatcher + { + public: + TGpioDispatcher(); + + TInt Init(); + + virtual TInt Bind(TInt aId, TIsr aIsr, TAny* aPtr); + virtual TInt Unbind(TInt aId); + virtual TInt Enable(TInt aId); + virtual TInt Disable(TInt aId); + virtual TInt Clear(TInt aId); + virtual TInt SetPriority(TInt aId, TInt aPriority); + + private: + static void Spurious( TAny* aParam ); + static void DispatchIsr( TAny* aParam ); + + static TInt GetGPIOPin( TInt aId,GpioPin *aPin ); + static TInt SetGPIOPin(TInt aId,GpioPin *aPin); + + static FORCE_INLINE TBool IsValidId( TInt aId ); + }; + +TSpinLock GPIOpinsDescLock(/*TSpinLock::EOrderGenericIrqLow0*/); +static GpioPin GpioPins[KHwGpioPinMax]; + + +TGpioDispatcher::TGpioDispatcher() + { + for (TInt32 i = 0; i < KHwGpioPinMax; i++) + { + GpioPins[i].iMode = GPIO::EIdle; + GpioPins[i].irq.iIsr = Spurious; + GpioPins[i].irq.iPtr = &GpioPins[i]; + GpioPins[i].iBankAddr = GPIO_BASE_ADDRESS(i); + GpioPins[i].iBank = i / KHwGpioPinsPerBank; + GpioPins[i].iIrqVector = EOmap3530_IRQ29_GPIO1_MPU_IRQ +GpioPins[i].iBank; + } + } + + +TInt TGpioDispatcher::Init() + { + for(TInt i=0; i < KHwGpioBanks; i++) + { + TInt r = Interrupt::Bind(EOmap3530_IRQ29_GPIO1_MPU_IRQ+i,DispatchIsr,(TAny*) i); + // Pass in a pointer to the first pin in the bank - shouldn't use addition on the constant here + __ASSERT_ALWAYS(r==KErrNone,Kern::Fault("ExternalInterrupt::%s Cant Bind to %d",EOmap3530_IRQ29_GPIO1_MPU_IRQ+i)); + } + + Register( EIrqRangeBaseGpio ); + + return KErrNone; + } + + + +TInt TGpioDispatcher::GetGPIOPin(TInt aId,GpioPin *aPin) + { + + if(! ( aId >= 0 && aId < KHwGpioPinMax) ) + return KErrArgument; + + TInt irq = /*NKern::DisableAllInterrupts();*/__SPIN_LOCK_IRQSAVE_R(GPIOpinsDescLock); + memcpy(aPin,&GpioPins[aId],sizeof(GpioPin)); + /*NKern::RestoreInterrupts(irq);*/__SPIN_UNLOCK_IRQRESTORE_R(GPIOpinsDescLock,irq); + + return KErrNone; + } + +TInt TGpioDispatcher::SetGPIOPin(TInt aId,GpioPin *aPin) + { + + if(! ( aId >= 0 && aId < KHwGpioPinMax) ) + return KErrArgument; + + TInt irq = /*NKern::DisableAllInterrupts();*/__SPIN_LOCK_IRQSAVE_W(GPIOpinsDescLock); + memcpy(&GpioPins[aId],aPin,sizeof(GpioPin )); + /*NKern::RestoreInterrupts(irq);*/__SPIN_UNLOCK_IRQRESTORE_W(GPIOpinsDescLock,irq); + + return KErrNone; + } + +FORCE_INLINE TBool TGpioDispatcher::IsValidId( TInt aId ) + { + return ((TUint)aId < EGPIOIRQ_END && (TUint)aId>=EGPIOIRQ_FIRST); + } + + +void TGpioDispatcher::Spurious(TAny* aId) + { + Kern::Fault("SpuriousExtInt",(TInt)aId); + } + + +void TGpioDispatcher::DispatchIsr(TAny *aPtr) + { + Interrupt::Disable(EOmap3530_IRQ29_GPIO1_MPU_IRQ + (TInt) aPtr); + + //need to spinlock the gpio here..... + TUint32 highVectors = AsspRegister::Read32(KGPIO_BASE_ADDRESSES[(TInt) aPtr] + KGPIO_IRQSTATUS1); + AsspRegister::Write32(KGPIO_BASE_ADDRESSES[(TInt) aPtr] + KGPIO_IRQSTATUS1, highVectors); + + GpioPin pin; + for (TInt i = 0; i < KHwGpioPinsPerBank ; i++,highVectors >>=1) + { + if(highVectors & 0x1) + { + GetGPIOPin(i+(TInt)aPtr*KHwGpioPinsPerBank, &pin); + (*pin.irq.iIsr)(pin.irq.iPtr); // dispatch this pin's ISR + } + } + Interrupt::Enable(EOmap3530_IRQ29_GPIO1_MPU_IRQ + (TInt)aPtr); + } + + +TInt TGpioDispatcher::Bind(TInt anId, TIsr anIsr, TAny* aPtr) + { + if(IsValidId(anId)) + { + //we want to bind the callers isrfunc to the pin dispatch here + GpioPin pin; + GetGPIOPin(anId- EGPIOIRQ_FIRST,&pin); + pin.irq.iIsr = anIsr; + pin.irq.iPtr = aPtr; + SetGPIOPin(anId- EGPIOIRQ_FIRST,&pin); + return KErrNone; + } + else + { + return KErrArgument; + } + } + +TInt TGpioDispatcher::Unbind(TInt anId) + { + __KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d",__FUNCTION__,anId)); + + if(IsValidId(anId)) + { + GpioPin pin; + TInt pinNr = anId - EGPIOIRQ_FIRST; + GetGPIOPin(pinNr,&pin); + pin.irq.iIsr=Spurious; + pin.irq.iPtr=NULL; + SetGPIOPin(pinNr,&pin); + return KErrNone; + } + else + { + return KErrArgument; + } + } + + +TInt TGpioDispatcher::Enable(TInt anId) + { + __KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d +",__FUNCTION__,anId)); + CHECK_PRECONDITIONS(MASK_NO_FAST_MUTEX,"GPIO::InterruptEnable Cant Hold Mutex in Blocking function"); + + if(IsValidId(anId)) + { + GpioPin pin; + TInt pinNr = anId - EGPIOIRQ_FIRST; + GetGPIOPin(pinNr,&pin); + + if(Spurious == pin.irq.iIsr) + { + + __KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d NOT BOUND",__FUNCTION__,anId)); + return KErrNotReady; + } + AsspRegister::Write32(pin.iBankAddr+KGPIO_SETIRQENABLE1,GPIO_PIN_OFFSET( pinNr)); + + if(!Omap3530Interrupt::IsInterruptEnabled(pin.iIrqVector)) + Interrupt::Enable(pin.iIrqVector); + + return KErrNone; + } + else + { + return KErrArgument; + } + } + +TInt TGpioDispatcher::Disable(TInt anId) + { + + __KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d",__FUNCTION__,anId)); + CHECK_PRECONDITIONS(MASK_NO_FAST_MUTEX,"GPIO::InterruptDisable Cant Hold Mutex in Blocking function"); + if(IsValidId(anId)) + { + TInt pinNr = anId- EGPIOIRQ_FIRST; + GpioPin pin; + GetGPIOPin(pinNr, &pin); + + AsspRegister::Write32(pin.iBankAddr+KGPIO_CLEARIRQENABLE1, GPIO_PIN_OFFSET(pinNr)); + + //is this the last one for this bank ? then unmap + if(0x00 == AsspRegister::Read32(pin.iBankAddr+KGPIO_IRQENABLE1)) + { + Interrupt::Disable(pin.iIrqVector); + } + return KErrNone; + } + else + { + return KErrArgument; + } + } + +TInt TGpioDispatcher::Clear(TInt anId) + { + + __KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d",__FUNCTION__,anId)); + CHECK_PRECONDITIONS(MASK_NO_FAST_MUTEX,"GPIO::InterruptDisable Cant Hold Mutex in Blocking function"); + + if(IsValidId(anId)) + { + TInt pinNr = anId- EGPIOIRQ_FIRST; + GpioPin myPin; + GetGPIOPin(pinNr, &myPin); + + AsspRegister::Write32((myPin.iBankAddr+KGPIO_IRQSTATUS1), GPIO_PIN_OFFSET(pinNr)); + //if that was the only high bit clear the mainline as well + if(0 == AsspRegister::Read32(myPin.iBankAddr+KGPIO_IRQSTATUS1)) + { + Interrupt::Clear(myPin.iIrqVector); + } + } + return KErrNone; + } + +TInt TGpioDispatcher::SetPriority(TInt aId, TInt aPriority) + { + return KErrNotSupported; + } + + +GLDEF_C TInt InitGpioInterrupts() + { + TInt r = KErrNoMemory; + + TGpioDispatcher* dispatcher = new TGpioDispatcher; + if( dispatcher ) + { + r = dispatcher->Init(); + } + return r; + }