omap3530/omap3530_drivers/gpio/gpio_interrupts.cpp
changeset 0 6663340f3fc9
--- /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 <e32cmn.h>
+#include <nk_priv.h>
+#include <assp/omap3530_assp/omap3530_gpio.h>
+#include <assp/omap3530_assp/omap3530_irqmap.h>
+#include <assp/omap3530_assp/omap3530_ktrace.h>
+#include <assp/omap3530_assp/omap3530_assp_priv.h>
+#include <assp/omap3530_assp/locks.h>
+
+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;
+	}