omap3530/omap3530_drivers/gpio/gpio_interrupts.cpp
changeset 0 6663340f3fc9
equal deleted inserted replaced
-1:000000000000 0:6663340f3fc9
       
     1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // omap3530/omap3530_drivers/gpio/gpio_interrupts.cpp
       
    15 //
       
    16 
       
    17 #include <e32cmn.h>
       
    18 #include <nk_priv.h>
       
    19 #include <assp/omap3530_assp/omap3530_gpio.h>
       
    20 #include <assp/omap3530_assp/omap3530_irqmap.h>
       
    21 #include <assp/omap3530_assp/omap3530_ktrace.h>
       
    22 #include <assp/omap3530_assp/omap3530_assp_priv.h>
       
    23 #include <assp/omap3530_assp/locks.h>
       
    24 
       
    25 NONSHARABLE_CLASS( TGpioDispatcher ) : public MInterruptDispatcher
       
    26 	{
       
    27 	public:
       
    28 		TGpioDispatcher();
       
    29 
       
    30 		TInt Init();
       
    31 
       
    32 		virtual TInt Bind(TInt aId, TIsr aIsr, TAny* aPtr);
       
    33 		virtual TInt Unbind(TInt aId);
       
    34 		virtual TInt Enable(TInt aId);
       
    35 		virtual TInt Disable(TInt aId);
       
    36 		virtual TInt Clear(TInt aId);
       
    37 		virtual TInt SetPriority(TInt aId, TInt aPriority);
       
    38 
       
    39 	private:
       
    40 		static void Spurious( TAny* aParam );
       
    41 		static void DispatchIsr( TAny* aParam );
       
    42 
       
    43 		static TInt GetGPIOPin( TInt aId,GpioPin *aPin );
       
    44 		static TInt SetGPIOPin(TInt aId,GpioPin *aPin);
       
    45 
       
    46 		static FORCE_INLINE TBool IsValidId( TInt aId );
       
    47 	};
       
    48 
       
    49 TSpinLock GPIOpinsDescLock(/*TSpinLock::EOrderGenericIrqLow0*/);
       
    50 static GpioPin	GpioPins[KHwGpioPinMax];
       
    51 
       
    52 
       
    53 TGpioDispatcher::TGpioDispatcher()
       
    54 	{
       
    55 	for (TInt32 i = 0; i < KHwGpioPinMax; i++)
       
    56 		{
       
    57 		GpioPins[i].iMode = GPIO::EIdle;
       
    58 		GpioPins[i].irq.iIsr = Spurious;
       
    59 		GpioPins[i].irq.iPtr = &GpioPins[i];	
       
    60 		GpioPins[i].iBankAddr = GPIO_BASE_ADDRESS(i);
       
    61 		GpioPins[i].iBank = i / KHwGpioPinsPerBank;
       
    62 		GpioPins[i].iIrqVector =  EOmap3530_IRQ29_GPIO1_MPU_IRQ +GpioPins[i].iBank;
       
    63 		}
       
    64 	}
       
    65 
       
    66 
       
    67 TInt TGpioDispatcher::Init()
       
    68 	{
       
    69 	for(TInt i=0; i < KHwGpioBanks; i++)
       
    70 		{		
       
    71 		TInt r = Interrupt::Bind(EOmap3530_IRQ29_GPIO1_MPU_IRQ+i,DispatchIsr,(TAny*) i); 
       
    72 		// Pass in a pointer to the first pin in the bank - shouldn't use addition on the constant here	
       
    73 		__ASSERT_ALWAYS(r==KErrNone,Kern::Fault("ExternalInterrupt::%s Cant Bind to %d",EOmap3530_IRQ29_GPIO1_MPU_IRQ+i));	
       
    74 		}
       
    75 
       
    76 	Register( EIrqRangeBaseGpio );
       
    77 
       
    78 	return KErrNone;
       
    79 	}
       
    80 
       
    81 
       
    82 
       
    83 TInt TGpioDispatcher::GetGPIOPin(TInt aId,GpioPin *aPin)
       
    84 	{
       
    85 	
       
    86 	if(! ( aId >= 0 && aId <  KHwGpioPinMax)  )
       
    87 			return KErrArgument;
       
    88 	
       
    89 	TInt irq = /*NKern::DisableAllInterrupts();*/__SPIN_LOCK_IRQSAVE_R(GPIOpinsDescLock);
       
    90 	memcpy(aPin,&GpioPins[aId],sizeof(GpioPin));
       
    91 	/*NKern::RestoreInterrupts(irq);*/__SPIN_UNLOCK_IRQRESTORE_R(GPIOpinsDescLock,irq);	
       
    92 	
       
    93 	return KErrNone;	
       
    94 	}
       
    95 
       
    96 TInt TGpioDispatcher::SetGPIOPin(TInt aId,GpioPin *aPin)
       
    97 	{
       
    98 		
       
    99 	if(! ( aId >= 0 && aId <  KHwGpioPinMax)  )
       
   100 			return KErrArgument;
       
   101 	
       
   102 	TInt irq = /*NKern::DisableAllInterrupts();*/__SPIN_LOCK_IRQSAVE_W(GPIOpinsDescLock);				
       
   103 	memcpy(&GpioPins[aId],aPin,sizeof(GpioPin ));
       
   104 	/*NKern::RestoreInterrupts(irq);*/__SPIN_UNLOCK_IRQRESTORE_W(GPIOpinsDescLock,irq);
       
   105 	
       
   106 	return KErrNone;
       
   107 	}
       
   108 
       
   109 FORCE_INLINE TBool TGpioDispatcher::IsValidId( TInt aId )
       
   110 	{
       
   111 	return ((TUint)aId < EGPIOIRQ_END && (TUint)aId>=EGPIOIRQ_FIRST);
       
   112 	}
       
   113 
       
   114 
       
   115 void TGpioDispatcher::Spurious(TAny* aId)
       
   116 	{
       
   117 	Kern::Fault("SpuriousExtInt",(TInt)aId);
       
   118 	}
       
   119 
       
   120 
       
   121 void TGpioDispatcher::DispatchIsr(TAny *aPtr)
       
   122 	{
       
   123 	Interrupt::Disable(EOmap3530_IRQ29_GPIO1_MPU_IRQ + (TInt) aPtr);
       
   124 	
       
   125 	//need to spinlock the gpio here.....
       
   126 	TUint32	highVectors = AsspRegister::Read32(KGPIO_BASE_ADDRESSES[(TInt) aPtr] + KGPIO_IRQSTATUS1);
       
   127   	AsspRegister::Write32(KGPIO_BASE_ADDRESSES[(TInt) aPtr] + KGPIO_IRQSTATUS1, highVectors);
       
   128 	
       
   129 	GpioPin pin;
       
   130 	for (TInt i =  0; i < KHwGpioPinsPerBank ; i++,highVectors >>=1)
       
   131 		{
       
   132 		if(highVectors & 0x1)
       
   133 			{		
       
   134 			GetGPIOPin(i+(TInt)aPtr*KHwGpioPinsPerBank, &pin);
       
   135 			(*pin.irq.iIsr)(pin.irq.iPtr); // dispatch this pin's ISR
       
   136 			}
       
   137 		}
       
   138 	Interrupt::Enable(EOmap3530_IRQ29_GPIO1_MPU_IRQ + (TInt)aPtr);
       
   139 	}
       
   140 
       
   141 
       
   142 TInt TGpioDispatcher::Bind(TInt anId, TIsr anIsr, TAny* aPtr)
       
   143 	{
       
   144 	if(IsValidId(anId))
       
   145 		{
       
   146 		//we want to bind the callers isrfunc to the pin dispatch here
       
   147 		GpioPin pin;
       
   148 		GetGPIOPin(anId- EGPIOIRQ_FIRST,&pin);
       
   149 		pin.irq.iIsr = anIsr;
       
   150 		pin.irq.iPtr = aPtr;
       
   151 		SetGPIOPin(anId- EGPIOIRQ_FIRST,&pin);
       
   152 		return KErrNone;
       
   153 		} 
       
   154 	else
       
   155 		{
       
   156 		return KErrArgument;
       
   157 		}
       
   158 	}
       
   159 
       
   160 TInt TGpioDispatcher::Unbind(TInt anId)
       
   161 	{
       
   162 	__KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d",__FUNCTION__,anId));
       
   163 
       
   164 	if(IsValidId(anId))
       
   165 		{
       
   166 		GpioPin pin;
       
   167 		TInt pinNr = anId - EGPIOIRQ_FIRST;
       
   168 		GetGPIOPin(pinNr,&pin);
       
   169 		pin.irq.iIsr=Spurious;
       
   170 		pin.irq.iPtr=NULL;
       
   171 		SetGPIOPin(pinNr,&pin);
       
   172 		return KErrNone;
       
   173 		}
       
   174 	else
       
   175 		{
       
   176 		return KErrArgument;
       
   177 		}
       
   178 	}
       
   179 	
       
   180 
       
   181 TInt TGpioDispatcher::Enable(TInt anId)
       
   182 	{
       
   183 	__KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d +",__FUNCTION__,anId));
       
   184 	CHECK_PRECONDITIONS(MASK_NO_FAST_MUTEX,"GPIO::InterruptEnable Cant Hold Mutex in Blocking function");			
       
   185 	
       
   186 	if(IsValidId(anId))
       
   187 		{
       
   188 		GpioPin pin;
       
   189 		TInt pinNr = anId - EGPIOIRQ_FIRST;	
       
   190 		GetGPIOPin(pinNr,&pin);
       
   191 		
       
   192 		if(Spurious == pin.irq.iIsr)
       
   193 			{
       
   194 			
       
   195 			__KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d NOT BOUND",__FUNCTION__,anId));
       
   196 			return KErrNotReady;
       
   197 			}
       
   198 		AsspRegister::Write32(pin.iBankAddr+KGPIO_SETIRQENABLE1,GPIO_PIN_OFFSET( pinNr));
       
   199 		
       
   200 		if(!Omap3530Interrupt::IsInterruptEnabled(pin.iIrqVector))
       
   201 			Interrupt::Enable(pin.iIrqVector);
       
   202 		
       
   203 		return KErrNone;
       
   204 		}
       
   205 	else
       
   206 		{
       
   207 		return KErrArgument; 
       
   208 		}
       
   209 	}
       
   210 
       
   211 TInt TGpioDispatcher::Disable(TInt anId)
       
   212 	{
       
   213 	
       
   214 	__KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d",__FUNCTION__,anId));
       
   215 	CHECK_PRECONDITIONS(MASK_NO_FAST_MUTEX,"GPIO::InterruptDisable Cant Hold Mutex in Blocking function");
       
   216 	if(IsValidId(anId))
       
   217 		{		
       
   218 		TInt pinNr = anId- EGPIOIRQ_FIRST;
       
   219 		GpioPin pin;
       
   220 		GetGPIOPin(pinNr, &pin);
       
   221 		
       
   222 		AsspRegister::Write32(pin.iBankAddr+KGPIO_CLEARIRQENABLE1, GPIO_PIN_OFFSET(pinNr));
       
   223 		
       
   224 		//is this the last one for this bank ? then unmap
       
   225 		if(0x00 == AsspRegister::Read32(pin.iBankAddr+KGPIO_IRQENABLE1))
       
   226 			{
       
   227 			Interrupt::Disable(pin.iIrqVector);
       
   228 			}
       
   229 		return KErrNone;
       
   230 		}
       
   231 	else
       
   232 		{
       
   233 		return KErrArgument; 
       
   234 		}
       
   235 	}
       
   236 
       
   237 TInt TGpioDispatcher::Clear(TInt anId)
       
   238 	{
       
   239 	
       
   240 	__KTRACE_OPT(KGPIO,Kern::Printf("GPIO:%s id=%d",__FUNCTION__,anId));
       
   241 	CHECK_PRECONDITIONS(MASK_NO_FAST_MUTEX,"GPIO::InterruptDisable Cant Hold Mutex in Blocking function");
       
   242 		
       
   243 	if(IsValidId(anId))
       
   244 		{
       
   245 		TInt pinNr = anId- EGPIOIRQ_FIRST;
       
   246 		GpioPin myPin;
       
   247 		GetGPIOPin(pinNr, &myPin);
       
   248 		
       
   249 		AsspRegister::Write32((myPin.iBankAddr+KGPIO_IRQSTATUS1),  GPIO_PIN_OFFSET(pinNr));
       
   250 		//if that was the only high bit clear the mainline as well
       
   251 		if(0 == AsspRegister::Read32(myPin.iBankAddr+KGPIO_IRQSTATUS1))
       
   252 			{
       
   253 			Interrupt::Clear(myPin.iIrqVector);
       
   254 			}
       
   255 		}
       
   256 	return KErrNone;
       
   257 	}
       
   258 
       
   259 TInt TGpioDispatcher::SetPriority(TInt aId, TInt aPriority)
       
   260 	{
       
   261 	return KErrNotSupported;
       
   262 	}
       
   263 
       
   264 
       
   265 GLDEF_C TInt InitGpioInterrupts()
       
   266 	{
       
   267 	TInt r = KErrNoMemory;
       
   268 
       
   269 	TGpioDispatcher* dispatcher = new TGpioDispatcher;
       
   270 	if( dispatcher )
       
   271 		{
       
   272 		r = dispatcher->Init();
       
   273 		}
       
   274 	return r;
       
   275 	}