merged Beagle_BSP_dev back to default
authorLukasz Forynski <lukasz.forynski@gmail.com>
Sun, 21 Nov 2010 02:23:11 +0000
changeset 118 7f1628607b77
parent 115 0a9dcad6d856 (current diff)
parent 117 8dfd870f0c0f (diff)
child 119 2c1b345d77c2
merged Beagle_BSP_dev back to default
--- a/omap3530/base_beagle.mrp	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/base_beagle.mrp	Sun Nov 21 02:23:11 2010 +0000
@@ -15,6 +15,7 @@
 binary	omap3530_drivers\gpio all
 binary	omap3530_drivers\i2c all
 binary	omap3530_drivers\prcm all
+# binary omap3530\omap3530_drivers\spi all
 # binary	omap3530_drivers\prm all
 binary	omap3530_drivers\uart all
 binary	omap3530_drivers\usbcc all
@@ -23,6 +24,7 @@
 binary	shared\serialkeyb all
 binary	shared\tps65950 all
 
+
 exports	assp
 exports	beagleboard
 exports	beagle_drivers\hal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/byd_touch/bld.inf	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,20 @@
+// Copyright (c) 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:
+//
+
+PRJ_PLATFORMS
+ARMV5
+
+PRJ_MMPFILES
+xyin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/byd_touch/common/controller.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,389 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+// Description:
+// omap3530/beagle_drivers/byd_touch/common/controller.cpp
+//
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include <assp/omap3530_assp/omap3530_gpio.h>
+#include "controller.h"
+
+//#define VERBOSE_DEBUG
+#ifdef VERBOSE_DEBUG
+#define LOG_FUNCTION_CALL Kern::Printf("%s()", __FUNCTION__)
+#else
+#define LOG_FUNCTION_CALL
+#endif
+
+TTouchControllerInterface::TTouchControllerInterface() :
+	iSpiTransactionHeader(KHeader),
+	iSpiTxTransfer(TIicBusTransfer::EMasterWrite, KBufGranulatity, &iSpiWriteBuffer),
+	iSpiRxTransfer(TIicBusTransfer::EMasterRead, KBufGranulatity, &iSpiReadBuffer),
+	iSpiTransaction(&iSpiTransactionHeader, &iSpiTxTransfer)
+	{
+	// after all above - make the transaction full duplex using the Rx buffer
+	iSpiTransaction.SetFullDuplexTrans(&iSpiRxTransfer);
+
+	// set buffer length only once..
+	iSpiWriteBuffer.SetLength(iSpiWriteBuffer.MaxLength());
+	iSpiReadBuffer.SetLength(iSpiReadBuffer.MaxLength());
+
+	// and set SPI addressing / bus configuration
+	iSpiBusId = 0;
+	SET_BUS_TYPE(iSpiBusId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(iSpiBusId, KSpiModule);
+	SET_SLAVE_ADDR(iSpiBusId, KSpiSlaveAddr);
+	}
+
+
+// Writes number of bytes stored in the write buffer - to the controller.
+// aNumOfBytes specifies number of bytes including first byte of address.
+// The write buffer should contain the data from index=1 and it's length should be set
+// to number of registers to update + 1 (one byte for the address / command)
+TInt TTouchControllerInterface::WriteMultiple(TUint8 aStartAddress, TInt aNumBytes)
+	{
+	LOG_FUNCTION_CALL;
+	if(aNumBytes != iSpiWriteBuffer.Length())
+		{
+#ifdef VERBOSE_DEBUG
+		Kern::Printf("Transfer buffers are not properly set, line: %d", __LINE__);
+#endif
+		return KErrArgument;
+		}
+	iSpiReadBuffer.SetLength(aNumBytes);
+	iSpiWriteBuffer[0] = KWriteCommand | (aStartAddress << 1);
+	return IicBus::QueueTransaction(iSpiBusId, &iSpiTransaction);
+	}
+
+
+// Reads number of bytes and stores them into the read buffer
+// aNumOfBytes specifies number of bytes (excluding first byte of address)
+// The read buffer will contain the received data starting from index=1 (TODO: consider MidTPtr)
+TInt TTouchControllerInterface::ReadMultiple(TUint8 aStartAddress, TInt aNumBytes)
+	{
+	LOG_FUNCTION_CALL;
+	TInt r = KErrNone;
+
+	// if trying to read from address different that currently stored - first update the read register..
+	if(iCurrentReadStart != aStartAddress)
+		{
+		r = Write(KMasterReadStartAddr, aStartAddress);
+		if(r != KErrNone)
+			{
+			return r;
+			}
+		iCurrentReadStart = aStartAddress;
+		}
+
+	// make sure buffers are set to the requested size
+	iSpiReadBuffer.SetLength(aNumBytes + 1);
+	iSpiWriteBuffer.SetLength(aNumBytes + 1);
+	iSpiWriteBuffer[0] = KReadCommand;
+
+	return IicBus::QueueTransaction(iSpiBusId, &iSpiTransaction);
+	}
+
+TInt TTouchControllerInterface::Write(TUint8 aRegAddress, TUint8 aValue)
+	{
+	LOG_FUNCTION_CALL;
+	iSpiWriteBuffer.SetLength(2);
+	iSpiReadBuffer.SetLength(2);
+	iSpiWriteBuffer[0] = KWriteCommand | (aRegAddress << 1);
+	iSpiWriteBuffer[1] = aValue;
+
+
+#ifdef VERBOSE_DEBUG
+	for (int i = 0; i < iSpiWriteBuffer.Length(); i++)
+		Kern::Printf("WR0[i]: %d", iSpiWriteBuffer[i]);
+
+	for (int i = 0; i < iSpiReadBuffer.Length(); i++)
+		Kern::Printf("W0[i]: %d", iSpiReadBuffer[i]);
+#endif
+	TInt r = IicBus::QueueTransaction(iSpiBusId, &iSpiTransaction);
+
+#ifdef VERBOSE_DEBUG
+	for (int i = 0; i < iSpiReadBuffer.Length(); i++)
+		Kern::Printf("W1[i]: %d", iSpiReadBuffer[i]);
+#endif
+	return r;
+	}
+
+
+TInt TTouchControllerInterface::Read(TUint8 aRegAddress, TUint8& aValue)
+	{
+	LOG_FUNCTION_CALL;
+	TInt r = ReadMultiple(aRegAddress, 2);
+
+	if(r == KErrNone)
+		{
+		aValue = iSpiReadBuffer[1];
+		}
+	return r;
+	}
+
+
+//(TODO: consider MidTPtr)
+inline TDes& TTouchControllerInterface::ReadBuff()
+	{
+	return iSpiReadBuffer;
+	}
+
+//(TODO: consider MidTPtr)
+inline TDes& TTouchControllerInterface::WriteBuff()
+	{
+	return iSpiWriteBuffer;
+	}
+
+
+// Touch controller implementation
+TouchController::TouchController() :
+	iCallback(NULL)
+	{
+	}
+
+TouchController::TouchController(TVoidCallback aCallback) :
+	iCallback(aCallback)
+	{
+	}
+
+TInt TouchController::HardReset()
+	{
+	LOG_FUNCTION_CALL;
+	TInt r = GPIO::SetPinMode(KResetPin, GPIO::EEnabled);
+	if(r == KErrNone)
+		{
+		r = GPIO::SetPinDirection(KResetPin, GPIO::EOutput);
+		if(r == KErrNone)
+			{
+#ifdef RESET_LOW
+			GPIO::SetOutputState(KResetPin, GPIO::ELow);
+#else
+			GPIO::SetOutputState(KResetPin, GPIO::EHigh);
+#endif
+			Kern::NanoWait(25000); // should be > 10us
+#ifdef RESET_LOW
+
+			GPIO::SetOutputState(KResetPin, GPIO::EHigh);
+#else
+			GPIO::SetOutputState(KResetPin, GPIO::ELow);
+#endif
+			}
+		}
+	return r;
+	}
+TInt TouchController::SoftReset()
+	{
+	return iInterface.Write(KControl_0, KControl_0_SWRST);
+	}
+
+TInt TouchController::Configure(TTouchMode aMode)
+	{
+	LOG_FUNCTION_CALL;
+	TDes& writeBuffer = iInterface.WriteBuff();
+	writeBuffer.SetLength(14);
+
+	// value for KControl_0 register in writeBuffer[1]
+	switch(aMode)
+		{
+		case EModeSingle:
+			writeBuffer[1] = KControl_0_MODE_SINGLE;
+			break;
+		case EModeMulti:
+			writeBuffer[1] = KControl_0_MODE_MULTI;
+			break;
+		case EModeGesture:
+			writeBuffer[1] = KControl_0_MODE_GESTURE;
+			break;
+		}
+
+//	const TUint8 KWindowXStart_Msb = 0x4; // R/W
+//	const TUint8 KWindowXStart_Lsb = 0x5; // R/W
+//	const TUint8 KWindowXStop_Msb  = 0x6; // R/W
+//	const TUint8 KWindowXStop_Lsb  = 0x7; // R/W
+//	const TUint8 KWindowYStart_Msb = 0x8; // R/W
+//	const TUint8 KWindowYStart_Lsb = 0x9; // R/W
+//	const TUint8 KWindowYStop_Msb  = 0xa; // R/W
+//	const TUint8 KWindowYStop_Lsb  = 0xb; // R/W
+//	const TUint8 KMasterReadStartAddr = 0xc; // R/W
+
+	writeBuffer[2] = (TInt8)(KControl_1_PAT_100 | KControl_1_PVT_200); // KControl_1 // TODO: update these values..
+	writeBuffer[3] = (TInt8)(KNumColumns << KControl_2_C_SHIFT);       // KControl_2 // TODO: update these values..
+	writeBuffer[4] = (TInt8)(KNumRows    << KControl_3_R_SHIFT);       // KControl_3 // TODO: update these values..
+
+	writeBuffer[5] = 0; // KWindowXStart_Msb // TODO: update these values..
+	writeBuffer[6] = 0; // KWindowXStart_Lsb // TODO: update these values..
+	writeBuffer[7] = 0; // KWindowXStop_Msb // TODO: update these values..
+	writeBuffer[8] = 0; // KWindowXStop_Lsb // TODO: update these values..
+
+	writeBuffer[9] = 0; // KWindowYStart_Msb // TODO: update these values..
+	writeBuffer[10] = 0; // KWindowYStart_Lsb // TODO: update these values..
+	writeBuffer[11] = 0; // KWindowYStop_Msb // TODO: update these values..
+	writeBuffer[12] = 0; // KWindowYStop_Lsb // TODO: update these values..
+	writeBuffer[13] = 0; // KMasterReadStartAddr // TODO: update these values..
+
+	return iInterface.WriteMultiple(KControl_0, 14);
+	}
+
+TInt TouchController::SetTouchMode(TTouchMode aMode)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[0] &= ~KControl_0_MODE_MASK; // clear all mode bits
+	switch(aMode)
+		{
+		case EModeSingle:
+			iCtrlRegsCache[0] |= KControl_0_MODE_SINGLE;
+			break;
+		case EModeMulti:
+			iCtrlRegsCache[0] |= KControl_0_MODE_MULTI;
+			break;
+		case EModeGesture:
+			iCtrlRegsCache[0] |= KControl_0_MODE_GESTURE;
+			break;
+		}
+
+	return iInterface.Write(KControl_0, iCtrlRegsCache[0]);
+	}
+
+
+TInt TouchController::SetResolution(TResolution aResolution)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[0] &= ~KControl_0_RM_12; // clear all mode bits
+	if(aResolution == ERes12Bits)
+		{
+		iCtrlRegsCache[0] |= KControl_0_RM_12; // set bit
+		}
+	return iInterface.Write(KControl_0, iCtrlRegsCache[0]);
+	}
+
+
+TInt TouchController::SetLongerSamplingRate(TUint aRate)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[0] &= ~KControl_0_LST_MASK; // clear bits..
+	iCtrlRegsCache[0] |= aRate & KControl_0_LST_MASK; // set new value..
+	return iInterface.Write(KControl_0, iCtrlRegsCache[0]);
+	}
+
+
+TInt TouchController::SetIrqActiveTime(TUint aIrqActiveTime)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[1] &= ~KControl_1_PAT_MASK; // clear bits..
+	iCtrlRegsCache[1] |= (aIrqActiveTime << KControl_1_PAT_SHIFT) & KControl_1_PAT_MASK; // set new value..
+	return iInterface.Write(KControl_1, iCtrlRegsCache[1]);
+	}
+
+
+TInt TouchController::SetPanelVoltageStabTime(TUint aVoltageStabilizationTime)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[1] &= ~KControl_1_PVT_MASK; // clear bits..
+	iCtrlRegsCache[1] |= (aVoltageStabilizationTime << KControl_1_PVT_SHIFT) & KControl_1_PVT_MASK; // set new value..
+	return iInterface.Write(KControl_1, iCtrlRegsCache[1]);
+	}
+
+
+TInt TouchController::SetNumberOfColumns(TUint aNumberOfColumns)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[2] &= ~KControl_2_C_MASK; // clear bits..
+	iCtrlRegsCache[2] |= (aNumberOfColumns << KControl_2_C_SHIFT) & KControl_2_C_MASK;
+	return iInterface.Write(KControl_2, iCtrlRegsCache[2]);
+	}
+
+
+TInt TouchController::SetNumberOfRows(TUint aNumberOfRows)
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[3] &= ~KControl_3_R_SHIFT; // clear bits..
+	iCtrlRegsCache[3] |= (aNumberOfRows << KControl_3_R_SHIFT) & KControl_3_R_MASK; // set new value..
+	return iInterface.Write(KControl_3, iCtrlRegsCache[3]);
+	}
+
+
+TInt TouchController::EnableWindowMode(TPoint aStart, TPoint aStop)
+	{
+	LOG_FUNCTION_CALL;
+	TDes& writeBuffer = iInterface.WriteBuff();
+	writeBuffer.SetLength(9);
+
+	// setup window points
+	writeBuffer[0] = KWriteCommand | (KWindowXStart_Msb << 1); // address of first register to write..
+	writeBuffer[1] = (TUint8)(aStart.iX >> 8); // KWindowXStart_Msb
+	writeBuffer[2] = (TUint8)(aStart.iX);      // KWindowXStart_Lsb
+	writeBuffer[3] = (TUint8)(aStop.iX >> 8);  // KWindowXStop_Msb
+	writeBuffer[4] = (TUint8)(aStop.iX);       // KWindowXStop_Lsb
+	writeBuffer[5] = (TUint8)(aStart.iY >> 8); // KWindowYStart_Msb
+	writeBuffer[6] = (TUint8)(aStart.iY);      // KWindowYStart_Lsb
+	writeBuffer[7] = (TUint8)(aStop.iY >> 8);  // KWindowYStop_Msb
+	writeBuffer[8] = (TUint8)(aStop.iY);       // KWindowYStop_Lsb
+
+	return iInterface.WriteMultiple(KWindowXStart_Msb, 9);
+	}
+
+TInt TouchController::DisableWindowMode()
+	{
+	LOG_FUNCTION_CALL;
+	iCtrlRegsCache[1] &= ~KControl_1_WS; // clear enable bit..
+	return iInterface.Write(KControl_1, iCtrlRegsCache[1]);
+	}
+
+TInt TouchController::NumOfTouches()
+	{
+	TUint8 val = 0;
+	TInt r = iInterface.Read(KTouchNumberAndType, val);
+	if (r == KErrNone)
+		{
+		r = val;
+		}
+	return r;
+	}
+
+TInt TouchController::GetMeasurements(TPoint* aPoints, TInt& aNumPoints)
+	{
+	LOG_FUNCTION_CALL;
+	TInt r = KErrArgument;
+	TInt num_points = 0;
+
+	if(aPoints)
+		{
+		r = iInterface.ReadMultiple(KTouchNumberAndType, 14);
+
+		if(r == KErrNone)
+			{
+			TDes& readBuffer = iInterface.ReadBuff();
+
+			// check how many points is there to read..
+			TUint8 val = readBuffer[1]; // TODO: update this if MidTPtr could be used..
+	//		Kern::Printf("KTouchNumberAndType %x", val);
+
+			// if in multi mode - read all received, but only up to one otherwise..
+			num_points = val & (val & KTouchNumberAndType_MULTI ? KTouchNumberAndType_TouchNMask : 1);
+
+			// read the coordinates..
+			for (TInt i = 0; i < num_points; i++) // if anything was touched at all..
+				{
+				// get X coordinate
+				aPoints[i].iX |= TInt(readBuffer[(i << 2) + 1] << 8); // X_H
+				aPoints[i].iX =  TInt(readBuffer[(i << 2) + 2]);      // X_L
+
+				// get Y coordinate
+				aPoints[i].iY |= TInt(readBuffer[(i << 2) + 3] << 8); // Yx_H
+				aPoints[i].iY =  TInt(readBuffer[(i << 2) + 4]);      // Y_L
+				}
+
+			aNumPoints = num_points;
+			}
+		}
+	return r;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/byd_touch/common/controller.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,236 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+// Description:
+// omap3530/beagle_drivers/byd_touch/common/controller.h
+//
+
+#ifndef TOUCH_KEY_CONTROLLER_H_
+#define TOUCH_KEY_CONTROLLER_H_
+
+#include <drivers/iic.h>
+#include <e32def.h>
+
+
+// controller specific constants..
+const TUint KMaxNumPoints = 3;
+
+
+const TInt KNumColumns = 0x4; // TODO update these values..
+const TInt KNumRows = 0x4;
+
+
+typedef void (*TVoidCallback) (TAny*);
+
+
+// spi specific constants..
+const TUint KMaxPacketLength = 16;
+const TUint KStartByte = 0x80;
+const TUint KWrite     = 0;
+const TUint KRead      = 1;
+const TUint KReadCommand  = KStartByte | KRead;
+const TUint KWriteCommand = KStartByte;
+const TUint KBufGranulatity = 8;
+
+// digitizer specific settings..
+const TUint KResetPin = 93; // This setting does not change (it goes through J4/J5 connectors)
+const TUint KDataReadyPin = 133; // DAV connected to the GPIO133 (Expansion header pin 15)
+
+const TUint KSpiModule = 2; // McSPI3
+const TUint KSpiSlaveAddr = 3; // ..slave address 3=> spi taken to 'dvi_data18-dvi_data_23' pins
+
+
+const TConfigSpiV01 KHeader =
+	{
+	ESpiWordWidth_8, //iWordWidth
+	375000,//,93750, //iClkSpeed
+	ESpiPolarityHighFallingEdge, //iClkMode
+	500, // iTimeoutPeriod
+	EBigEndian, // iEndianness
+	EMsbFirst, //iBitOrder
+	2, //iTransactionWaitCycles
+	ESpiCSPinActiveLow //iCsPinActiveMode
+	};
+
+// spi interface to the controller
+class TTouchControllerInterface
+	{
+public:
+	inline TTouchControllerInterface();
+	inline TInt Read(TUint8 aRegAddress, TUint8& aValue);
+	inline TInt ReadMultiple(TUint8 aStartAddress, TInt aNumBytes);
+	inline TInt Write(TUint8 aRegAddress, TUint8 aValue);
+	inline TInt WriteMultiple(TUint8 aStartAddress, TInt aNumBytes);
+	inline TDes& ReadBuff();
+	inline TDes& WriteBuff();
+
+
+private:
+	TInt iCurrentReadStart;
+	// SPI duplex transaction with two transfers for each direction
+	TPckgBuf<TConfigSpiV01> iSpiTransactionHeader;
+	TBuf8<KMaxPacketLength> iSpiWriteBuffer;
+	TBuf8<KMaxPacketLength> iSpiReadBuffer;
+	TIicBusTransfer         iSpiTxTransfer;
+	TIicBusTransfer         iSpiRxTransfer;
+	TIicBusTransaction      iSpiTransaction;
+	TInt                    iSpiBusId;
+	};
+
+class TouchController
+	{
+public:
+	enum TTouchMode
+		{
+		EModeSingle = 0,
+		EModeMulti,
+		EModeGesture
+		};
+
+	enum TResolution
+		{
+		ERes10Bits = 0,
+		ERes12Bits
+		};
+
+	enum TGestureType
+		{
+		EClockwiseCircumvolve = 3,
+		EDragLeft             = 4,
+		EDragRight            = 5,
+		EDragUp               = 6,
+		EDragDown             = 7,
+		EZoomOut              = 8,
+		EZoomIn               = 9
+		};
+
+	TouchController();
+	TouchController(TVoidCallback aCallback);
+
+
+	TInt HardReset();
+	TInt SoftReset();
+	TInt Configure(TTouchMode aMode);
+	TInt SetTouchMode(TTouchMode aMode);
+	TInt SetResolution(TResolution aResolution);
+	TInt SetLongerSamplingRate(TUint aRate);
+	TInt SetIrqActiveTime(TUint aIrqActiveTime);
+	TInt SetPanelVoltageStabTime(TUint aVoltageStabilizationTime);
+	TInt SetNumberOfColumns(TUint aNumberOfColumns);
+	TInt SetNumberOfRows(TUint aNumberOfRows);
+	TInt EnableWindowMode(TPoint aXpoint, TPoint aYPoint);
+	TInt DisableWindowMode();
+	TInt GetMeasurements(TPoint* aPoints, TInt& aNumPoints);
+	TInt NumOfTouches();
+
+private:
+	TInt iCtrlRegsCache[4];
+	TTouchControllerInterface iInterface;
+	TVoidCallback iCallback;
+	};
+
+
+// BF6917 Register definitions
+const TUint8 KControl_0  = 0x0; // R/W
+const TUint8 KControl_0_SWRST        = 1 << 7;  // SW reset
+const TUint8 KControl_0_RM_12        = 1 << 6; // Resolution mode 12 bits if set, 10bits otherwise
+const TUint8 KControl_0_MODE_SINGLE  = 1 << 3; // single touch mode
+const TUint8 KControl_0_MODE_MULTI   = 5 << 3; // multi-touch mode
+const TUint8 KControl_0_MODE_GESTURE = 6 << 3; // gesture mode
+const TUint8 KControl_0_MODE_MASK    = 7 << 3; // gesture mode
+
+const TUint8 KControl_0_LST_MASK     = 0x7; // Longer sampling rate: from 5 to 120 ADC clocks sampling time
+const TUint8 KControl_0_LST_5        = 0 << 0; // 5   ADC clocks sampling time
+const TUint8 KControl_0_LST_10       = 1 << 0; // 10  ADC clocks sampling time
+const TUint8 KControl_0_LST_20       = 2 << 0; // 20  ADC clocks sampling time
+const TUint8 KControl_0_LST_40       = 3 << 0; // 40  ADC clocks sampling time
+const TUint8 KControl_0_LST_60       = 4 << 0; // 60  ADC clocks sampling time
+const TUint8 KControl_0_LST_80       = 5 << 0; // 80  ADC clocks sampling time
+const TUint8 KControl_0_LST_100      = 6 << 0; // 100 ADC clocks sampling time
+const TUint8 KControl_0_LST_120      = 7 << 0; // 120 ADC clocks sampling time
+
+
+// Pen Irq Active time (sensiveness)
+const TUint8 KControl_1  = 0x1; // R/W
+const TUint8 KControl_1_PAT_SHIFT = 5;
+const TUint8 KControl_1_PAT_MASK  = 7 << 5;
+const TUint8 KControl_1_PAT_100   = 0 << 5;
+const TUint8 KControl_1_PAT_87_5  = 1 << 5;
+const TUint8 KControl_1_PAT_75    = 2 << 5;
+const TUint8 KControl_1_PAT_62_5  = 3 << 5;
+const TUint8 KControl_1_PAT_50    = 4 << 5;
+const TUint8 KControl_1_PAT_37_5  = 5 << 5;
+const TUint8 KControl_1_PAT_25    = 6 << 5;
+const TUint8 KControl_1_PAT_12_5  = 7 << 5;
+
+//  Panel Voltage stabilization Time(sensiveness)
+const TUint8 KControl_1_PVT_SHIFT = 2;
+const TUint8 KControl_1_PVT_MASK = 7 << 2;
+const TUint8 KControl_1_PVT_200  = 0 << 2;
+const TUint8 KControl_1_PVT_175  = 1 << 2;
+const TUint8 KControl_1_PVT_150  = 2 << 2;
+const TUint8 KControl_1_PVT_125  = 3 << 2;
+const TUint8 KControl_1_PVT_100  = 4 << 2;
+const TUint8 KControl_1_PVT_75   = 5 << 2;
+const TUint8 KControl_1_PVT_50   = 6 << 2;
+const TUint8 KControl_1_PVT_25   = 7 << 2;
+const TUint8 KControl_1_WS       = 1 << 0; // Window mode enables
+
+
+const TUint8 KControl_2  = 0x2; // R/W
+const TUint8 KControl_2_C_SHIFT  = 3; // number of columns
+const TUint8 KControl_2_C_MASK = 0xf8;
+const TUint8 KControl_2_PR_SHIFT = 0; // pull-up resistance
+
+
+const TUint8 KControl_3  = 0x3; // R/W
+const TUint8 KControl_3_R_SHIFT  = 4; // number of rows
+const TUint8 KControl_3_R_MASK   = 0xF0; // number of rows
+
+const TUint8 KControl_2_R_TEST   = 1 << 3; // test mode select
+const TUint8 KControl_2_PS_SHIFT = 0; // processing scale (0-7)
+
+const TUint8 KWindowXStart_Msb = 0x4; // R/W
+const TUint8 KWindowXStart_Lsb = 0x5; // R/W
+const TUint8 KWindowXStop_Msb  = 0x6; // R/W
+const TUint8 KWindowXStop_Lsb  = 0x7; // R/W
+const TUint8 KWindowYStart_Msb = 0x8; // R/W
+const TUint8 KWindowYStart_Lsb = 0x9; // R/W
+const TUint8 KWindowYStop_Msb  = 0xa; // R/W
+const TUint8 KWindowYStop_Lsb  = 0xb; // R/W
+const TUint8 KMasterReadStartAddr = 0xc; // R/W
+
+
+//  data registers
+const TUint8 KTouchNumberAndType  = 0xd; //  R, Touch number and touch type
+const TUint8 KTouchNumberAndType_SINGLE = 0 << 3;
+const TUint8 KTouchNumberAndType_MULTI  = 1 << 3;
+const TUint8 KTouchNumberAndType_TouchNMask = 7; // touch number (0 - 3)
+
+
+const TUint8 X1_H   = 0xe; //  R, High byte of x1 measurement
+const TUint8 X1_L   = 0xf; //  R, Low  byte of x1 measurement
+const TUint8 Y1_H   = 0x10; // R, High byte of y1 measurement
+const TUint8 Y1_L   = 0x11; // R, Low  byte of y1 measurement
+const TUint8 X2_H   = 0x12; // R, High byte of x2 measurement
+const TUint8 X2_L   = 0x13; // R, Low  byte of x2 measurement
+const TUint8 Y2_H   = 0x14; // R, High byte of y2 measurement
+const TUint8 Y2_L   = 0x15; // R, Low  byte of y2 measurement
+const TUint8 X3_H   = 0x16; // R, High byte of x3 measurement
+const TUint8 X3_L   = 0x17; // R, Low  byte of x3 measurement
+const TUint8 Y3_H   = 0x18; // R, High byte of y3 measurement
+const TUint8 Y3_L   = 0x19; // R, Low  byte of y3 measurement
+const TUint8 Ges_H  = 0x1a; // R, High byte of gesture information
+const TUint8 Ges_L  = 0x1b; // R, Low  byte of gesture information
+const TUint8 TEST_H = 0x1c; // R, Low byte of the test result
+const TUint8 TEST_L = 0x1d; // R, Low byte of the test result
+
+
+#endif /* TOUCH_KEY_CONTROLLER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/byd_touch/xyin.mmp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,65 @@
+// 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 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// standard driver for a touch screen (digitizer).
+//
+
+
+#define __USING_ASSP_REGISTER_API__
+#define __USING_ASSP_INTERRUPT_API__
+
+#include            "beagle/variant.mmh"
+#include            "kernel/kern_ext.mmh"
+
+target              VariantTarget(byd_xyin,dll)
+targettype          kext
+linkas              byd_xyin.dll
+
+
+USERINCLUDE         inc
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+SYMBIAN_BASE_SYSTEMINCLUDE(assp)
+SYMBIAN_BASE_SYSTEMINCLUDE(drivers)
+SYMBIAN_BASE_SYSTEMINCLUDE(assp/omap3530_assp)
+SYMBIAN_BASE_SYSTEMINCLUDE(assp/omap3530_shared)
+SYMBIAN_BASE_SYSTEMINCLUDE(beagle)
+
+sourcepath         ../../../../../os/kernelhwsrv/kernel/eka/drivers/xyin
+source             d_xyin.cpp
+
+sourcepath         common
+source             controller.cpp
+
+sourcepath         xyin
+source             xyin.cpp
+
+
+library            VariantTarget(ecust,lib) 
+library            AsspTarget(gpio,lib)
+library            AsspTarget(prcm,lib)
+library            iic.lib
+
+// once the PRM is ready..
+//#ifdef USE_SYMBIAN_PRM
+//library          VariantTarget(power,lib)
+//#endif
+
+VENDORID           0x70000001
+
+capability         all
+
+noexportlibrary
+
+EPOCALLOWDLLDATA
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/byd_touch/xyin/mconf.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,56 @@
+// Copyright (c) 1998-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:
+// template\template_variant\inc\mconf.h
+// Template Persistent Machine Configuration
+// 
+// WARNING: This file contains some APIs which are internal and are subject
+//          to change without notice. Such APIs should therefore not be used
+//          outside the Kernel and Hardware Services package.
+//
+
+#ifndef __MCONF_H__
+#define __MCONF_H__
+#include <kernel/kernel.h>
+
+class TDigitizerCalibrateValues
+    {
+public:
+    TInt iR11;
+    TInt iR12;
+    TInt iR21;
+    TInt iR22;
+    TInt iTx;
+    TInt iTy;
+    };
+
+class TTemplateMachineConfig : public TMachineConfig
+	{
+public:
+	TSoundInfoV1 iSoundInfo;
+    TOnOffInfoV1 iOnOffInfo;
+	TTimeK iMainBatteryInsertionTime;
+    Int64 iMainBatteryInUseMicroSeconds;
+	Int64 iExternalPowerInUseMicroSeconds;
+	Int64 iMainBatteryMilliAmpTicks;
+	TDigitizerCalibrateValues iCalibration;
+	TDigitizerCalibrateValues iCalibrationSaved;
+	TDigitizerCalibrateValues iCalibrationFactory;
+	};
+
+typedef TTemplateMachineConfig TActualMachineConfig;
+
+inline TActualMachineConfig& TheActualMachineConfig()
+	{return (TActualMachineConfig&)Kern::MachineConfig();}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/byd_touch/xyin/xyin.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,1083 @@
+// Copyright (c) 2004-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:
+// Implementation of a digitiser (touch-screen) driver.
+// This code assumes that an interrupt is generated on pen-down and pen-up events.
+//
+//
+
+#include <assp.h>
+#include <videodriver.h>
+#include <drivers/xyin.h>
+#include <assp/omap3530_assp/omap3530_gpio.h>
+#include <assp/omap3530_assp/omap3530_scm.h>
+#include "mconf.h"
+#include "../common/controller.h"
+
+
+// TODO replace DEBUG_PRINT(  with  __KTRACE_OPT(KHARDWARE,
+#define DEBUG_PRINT(x) x
+
+const TInt KXyinThreadPriority = 33; // might need to be updated..
+_LIT(KXyinThreadName, "DigitizerThread");
+//
+// TO DO: (mandatory)
+//
+// Define the following constants that describe the digitiser position & dimensions
+// This is only example code... you need to modify it for your hardware
+
+// digitiser origin & size in pixels
+const TUint	KConfigXyOffsetX	= 0;		// digitiser origin - same as display area
+const TUint	KConfigXyOffsetY	= 0;
+const TUint	KConfigXyWidth		= 640;		// 640 pixels per line
+const TUint	KConfigXyHeight		= 480;		// 480 lines per panel
+
+// digitiser dimensions in digitiser co-ordinates
+const TInt KConfigXyBitsX   = 12;
+const TInt KConfigXyBitsY   = 12;
+const TInt KConfigXySpreadX = 1 << KConfigXyBitsX;  // maximum valid X spread
+const TInt KConfigXySpreadY = 1 << KConfigXyBitsY;  // maximum valid Y spread
+const TInt KConfigXyMinX    = 0;                    // minimum valid X value
+const TInt KConfigXyMinY    = 0;                    // minimum valid Y value
+const TInt KConfigXyMaxX    = KConfigXySpreadX - 1; // maximum valid X value
+const TInt KConfigXyMaxY    = KConfigXySpreadY - 1; // maximum valid Y value
+
+
+// Define a 2x2 matrix and two constants Tx and Ty to convert digitiser co-ordinates
+// to pixels such that
+//
+// (X<<16 Y<<16)	=	(x y)	x	(R11 R12)	+	(Tx Ty)
+//									(R21 R22)
+// or :
+//
+// X = (x*R11 + y*R21 + TX) >> 16;
+// Y = (x*R12 + y*R22 + TY) >> 16;
+
+//
+// where x,y are digitiser coordinates, Tx,Ty are constant offsets and X,Y are screen
+// coordinates. Left shifting by 16 bits is used so as not to lose precision.
+//
+// These are default values to be used before calibration has taken place
+// These are best set by observation.
+// The example values given below are for a digitiser whose origin is at bottom left
+// (the screen origin is at top left)
+const TInt		KConfigXyR11		= (KConfigXyWidth << 16) / KConfigXySpreadX;		// 10240
+const TInt		KConfigXyR12		= 0;
+const TInt		KConfigXyR21		= 0;
+const TInt		KConfigXyR22		= - ((KConfigXyHeight << 16) / KConfigXySpreadY);	// -7680
+const TInt		KConfigXyTx			= 0;
+const TInt		KConfigXyTy			= (KConfigXyHeight << 16) / KConfigXySpreadY;
+
+//
+// TO DO: (optional)
+//
+// Define the following constants that describe the digitiser behaviour
+// This is only example code... you need to modify it for your hardware
+
+// After taking a sample, wait for the specified number of nano-kernel ticks (normally 1 ms)
+// before taking the next sample
+const TInt		KInterSampleTime	= 1;
+
+// After a group of samples has been processed by the DDigitiser::ProcessRawSample() DFC,
+// wait for the specified number of nano-kernel ticks before taking the next sample
+const TInt		KInterGroupTime		= 1;
+
+// After a pen-down interrupt,
+// wait for the specified number of nano-kernel ticks before taking the next sample
+const TInt		KPenDownDelayTime	= 2;
+
+// If powering up the device with the pen down,
+// wait for the specified number of nano-kernel ticks before taking the next sample
+const TInt		KPenUpPollTime		= 30;
+
+// After a pen-up interrupt,
+// wait for the specified number of nano-kernel ticks before calling PenUp()
+const TInt		KPenUpDebounceTime	= 10;
+
+// number of samples to discard on pen-down
+const TInt		KConfigXyPenDownDiscard	= 1;
+
+// number of samples to discard on pen-up
+const TInt		KConfigXyPenUpDiscard	= 1;
+
+// offset in pixels to cause movement in X direction
+const TInt		KConfigXyAccThresholdX	= 12;
+
+// offset in pixels to cause movement in Y direction
+const TInt		KConfigXyAccThresholdY	= 12;
+
+// number of samples to average - MUST be <= KMaxXYSamples
+const TInt		KConfigXyNumXYSamples	= 2;
+
+// disregard extremal values in each 4-sample group
+const TBool		KConfigXyDisregardMinMax= EFalse;
+
+
+// obsolete constants :
+const TInt		KConfigXyDriveXRise		= 0;
+const TInt		KConfigXyDriveYRise		= 0;
+const TInt		KConfigXyMaxJumpX		= 0;
+const TInt		KConfigXyMaxJumpY		= 0;
+
+
+
+/******************************************************
+ * Main Digitiser Class
+ ******************************************************/
+
+//
+// TO DO: (optional)
+//
+// Add any private functions and data you require
+//
+NONSHARABLE_CLASS(DTemplateDigitiser) : public DDigitiser
+
+	{
+public:
+	enum TState
+		{
+		E_HW_PowerUp,
+		E_HW_PenUpDebounce,
+		E_HW_CollectSample
+		};
+
+public:
+	// from DDigitiser - initialisation
+	DTemplateDigitiser();
+	virtual TInt DoCreate();
+	void SetDefaultConfig();
+
+	// from DDigitiser - signals to hardware-dependent code
+	virtual void WaitForPenDown();
+	virtual void WaitForPenUp();
+	virtual void WaitForPenUpDebounce();
+	virtual void DigitiserOn();
+	virtual void DigitiserOff();
+	virtual void FilterPenMove(const TPoint& aPoint);
+	virtual void ResetPenMoveFilter();
+
+	// from DDigitiser - machine-configuration related things
+	virtual TInt DigitiserToScreen(const TPoint& aDigitiserPoint, TPoint& aScreenPoint);
+	virtual void ScreenToDigitiser(TInt& aX, TInt& aY);
+	virtual TInt SetXYInputCalibration(const TDigitizerCalibration& aCalibration);
+	virtual TInt CalibrationPoints(TDigitizerCalibration& aCalibration);
+	virtual TInt SaveXYInputCalibration();
+	virtual TInt RestoreXYInputCalibration(TDigitizerCalibrationType aType);
+	virtual void DigitiserInfo(TDigitiserInfoV01& aInfo);
+
+	// from DPowerHandler
+	virtual void PowerDown(TPowerState);
+	virtual void PowerUp();
+
+public:
+	// implementation
+	void TakeSample();
+	void PenInterrupt();
+	void DigitiserPowerUp();
+	void DoPowerUp();
+
+private:
+	static void TimerCallback(TAny* aPtr);
+	static void TimerIntCallback(TAny* aPtr);
+	static void TakeReadingDfc(TAny* aPtr);
+	static void PowerUpDfc(TAny* aPtr);
+	static void PowerDownDfc(TAny* aPtr);
+	static void PenIsr(TAny* aPtr);
+
+	TouchController iController;
+	NTimer iTimer;
+	NTimer iTimerInt;
+	TDfc iTakeReadingDfc;
+	TDfc iPowerDownDfc;
+	TDfc iPowerUpDfc;
+	TInt iSamplesCount;
+	TState iState;
+	TUint8 iPoweringDown;
+
+	TSize iScreenSize;
+	TActualMachineConfig& iMachineConfig;
+	};
+
+/******************************************************
+ * Digitiser main code
+ ******************************************************/
+
+
+/**
+Creates a new instance of DDigitiser.
+Called by extension entry point (PIL) to create a DDigitiser-derived object.
+
+@return	a pointer to a DTemplateDigitiser object
+*/
+DDigitiser* DDigitiser::New()
+	{
+	return new DTemplateDigitiser;
+	}
+
+DTemplateDigitiser::DTemplateDigitiser() :
+		iTimer(TimerCallback,this),
+		iTimerInt(TimerIntCallback,this),
+		iTakeReadingDfc(TakeReadingDfc,this,5),
+		iPowerDownDfc(PowerDownDfc,this,5),
+		iPowerUpDfc(PowerUpDfc,this,5),
+		iMachineConfig(TheActualMachineConfig())
+	{
+	}
+
+
+TInt DTemplateDigitiser::DoCreate()
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("DTemplateDigitiser::DoCreate"));
+	DEBUG_PRINT(Kern::Printf("DTemplateDigitiser::DoCreate"));
+
+	if (Kern::ColdStart())
+		{
+		__KTRACE_OPT(KEXTENSION,Kern::Printf("Resetting digitiser calibration"));
+
+		// Emergency digitiser calibration values
+		iMachineConfig.iCalibration.iR11 = KConfigXyR11;
+		iMachineConfig.iCalibration.iR12 = KConfigXyR12;
+		iMachineConfig.iCalibration.iR21 = KConfigXyR21;
+		iMachineConfig.iCalibration.iR22 = KConfigXyR22;
+		iMachineConfig.iCalibration.iTx = KConfigXyTx;
+		iMachineConfig.iCalibration.iTy = KConfigXyTy;
+		}
+
+	// create a DFCQ for this driver
+	TInt r = Kern::DfcQCreate(iDfcQ, KXyinThreadPriority, &KXyinThreadName);
+	if(r != KErrNone)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("Digitizer: DFC Queue creation failed, ch: %d, r = %d\n", r));
+		return r;
+		}
+	iTakeReadingDfc.SetDfcQ(iDfcQ);
+	iPowerDownDfc.SetDfcQ(iDfcQ);
+	iPowerUpDfc.SetDfcQ(iDfcQ);
+
+
+#ifdef USE_SYMBIAN_PRM
+	// register power handler
+	Add();
+#endif
+
+	// setup the DAV (data ready/available) pin by binding to the GPIO pin..
+	r = GPIO::BindInterrupt(KDataReadyPin, PenIsr, this);
+	if(r != KErrNone)
+		{
+		Kern::Printf("GPIO::BindInterrupt() failed for pin %d, r=%d", KDataReadyPin, r);
+		return r;
+		}
+
+	r = GPIO::SetPinDirection(KDataReadyPin, GPIO::EInput);
+	if(r == KErrNone)
+		{
+		r = GPIO::SetInterruptTrigger(KDataReadyPin, GPIO::EEdgeRising);
+		if(r == KErrNone)
+			{
+			GPIO::SetDebounceTime(KDataReadyPin, 100);
+			SCM::SetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::EMsw, SCM::EMode4 | SCM::EInputEnable); // 133 (mmc2dat1)
+			r = GPIO::SetPinMode(KDataReadyPin, GPIO::EEnabled);
+			}
+		}
+
+	if (r == KErrNone)
+		{
+		// set up the default configuration
+		SetDefaultConfig();
+
+		// some of the pre-configuration of the touch controller could be done here..
+		iController.HardReset();
+		iController.Configure(TouchController::EModeSingle);
+
+		DigitiserPowerUp();
+		}
+	return r;
+	}
+
+/**
+Initialise the DDigitiser::iCfg structure
+*/
+void DTemplateDigitiser::SetDefaultConfig()
+	{
+	iCfg.iPenDownDiscard = KConfigXyPenDownDiscard;		// number of samples to discard on pen-down
+	iCfg.iPenUpDiscard = KConfigXyPenUpDiscard;			// number of samples to discard on pen-up
+	iCfg.iDriveXRise = KConfigXyDriveXRise;				// number of milliseconds to wait when driving horizontal edges
+	iCfg.iDriveYRise = KConfigXyDriveYRise;				// number of milliseconds to wait when driving vertical edges
+	iCfg.iMinX = KConfigXyMinX;							// minimum valid X value
+	iCfg.iMaxX = KConfigXyMaxX;							// maximum valid X value
+	iCfg.iSpreadX = KConfigXySpreadX;					// maximum valid X spread
+	iCfg.iMinY = KConfigXyMinY;							// minimum valid Y value
+	iCfg.iMaxY = KConfigXyMaxY;							// maximum valid Y value
+	iCfg.iSpreadY = KConfigXySpreadY;					// maximum valid Y spread
+	iCfg.iMaxJumpX = KConfigXyMaxJumpX;					// maximum X movement per sample (pixels)
+	iCfg.iMaxJumpY = KConfigXyMaxJumpY;					// maximum Y movement per sample (pixels)
+	iCfg.iAccThresholdX = KConfigXyAccThresholdX;		// offset in pixels to cause movement in X direction
+	iCfg.iAccThresholdY = KConfigXyAccThresholdY;		// offset in pixels to cause movement in Y direction
+	iCfg.iNumXYSamples = KConfigXyNumXYSamples;			// number of samples to average
+	iCfg.iDisregardMinMax = KConfigXyDisregardMinMax;	// disregard extremal values in each 4-sample group
+	}
+
+/**
+Takes a sample from the digitiser.
+Called in the context of a DFC thread.
+*/
+void DTemplateDigitiser::TakeSample()
+	{
+#ifdef USE_SYMBIAN_PRM
+	TTemplatePowerController::WakeupEvent();	// notify of pendown (wakeup event) and let the power controller sort
+							 					// out if it needs propagation
+#endif
+
+	// TO DO: (mandatory)
+	// Read from appropriate hardware register to determine whether digitiser panel is being touched
+	// Set penDown to ETrue if touched or EFalse if not touched.
+	//
+	TPoint points[4];
+	TInt num_points = 0;
+	TInt r = iController.GetMeasurements(points, num_points);
+	Kern::Printf("Num touches: %d", num_points);
+	Kern::Printf("Measurments: (r: %d)", r);
+	for(TInt i = 0; i < num_points; i++)
+		{
+		Kern::Printf("%d: iX: %d, iY: %d",i, points[i].iX, points[i].iY);
+		}
+
+	TInt penDown = num_points;
+
+	//	DEBUG_PRINT(Kern::Printf("TS: S%d PD%d Sp%d", (TInt)iState, penDown?1:0, iSamplesCount));
+
+	if (iState==E_HW_PowerUp)
+		{
+		// waiting for pen to go up after switch on due to pen down or through the HAL
+		// coverity[dead_error_condition]
+		// The next line should be reachable when this template file is edited for use
+		if (!penDown)							// pen has gone up -> transition to new state
+			{
+			iState=E_HW_CollectSample;
+			iSamplesCount=0;						// reset sample buffer
+
+			// TO DO: (mandatory)
+			// Write to the appropriate hardware register to clear the digitiser interrupt
+			//
+
+			// TO DO: (mandatory)
+			// Write to the appropriate hardware register(s) to allow the hardware
+			// to detect when the digitizer panel is touched
+			//
+
+//			Interrupt::Enable(KIntIdDigitiser);		// enable pen-down interrupt
+
+ 			// TO DO: (mandatory)
+			// Write to the appropriate hardware register to enable the digitiser interrupt
+			//
+
+			}
+		else									// pen is still down, wait a bit longer in this state
+			{
+			iTimer.OneShot(KPenUpPollTime);
+			}
+		return;
+		}
+
+	if (!penDown)
+		{
+		if (iState==E_HW_PenUpDebounce)
+			{
+			iState=E_HW_CollectSample;	// back to initial state, no samples collected
+			iSamplesCount=0;			// reset sample buffer
+			// Need to lock the kernel to simulate ISR context and thus defer preemption,
+			// since PenUp() expects an ISR context and calls TDfc::Add().
+			NKern::Lock();
+			PenUp();					// adds DFC
+			NKern::Unlock();
+			}
+		else							// iState=E_HW_CollectSample
+			{
+			iState=E_HW_PenUpDebounce;
+			iTimer.OneShot(KPenUpDebounceTime);		// wait a bit to make sure pen still up
+			}
+		return;
+		}
+	else if (iState==E_HW_PenUpDebounce)	// pen down
+		{
+		// false alarm - pen is down again
+		iState=E_HW_CollectSample;		// take a new set of samples
+		iSamplesCount=0;				// reset sample buffer
+		}
+	// default: pen down and iState=E_HW_CollectSample
+	// TO DO: (mandatory)
+	// Read from appropriate hardware register to get the current digitiser coordinates
+	// of the point that is being touched. Set aResults accordingly.
+	// This is only example code... you need to modify it for your hardware
+	//
+	TPoint aResults;
+
+	// X axis
+	iX[iSamplesCount] = aResults.iX;
+	// Y axis
+	iY[iSamplesCount] = aResults.iY;
+
+	DEBUG_PRINT(Kern::Printf("Raw: X=%d Y=%d",iX[iSamplesCount],iY[iSamplesCount]));
+
+	// Put the hardware back into pen-detect mode
+
+	// TO DO: (mandatory)
+	// Write to the appropriate hardware register(s) to allow the hardware
+	// to detect when the digitizer panel is touched
+	//
+
+	// count samples collected - if it's less than minimum,
+	// schedule the reading of another sample
+	if (++iSamplesCount < iCfg.iNumXYSamples)	// iX[] and iY[] are 4 levels deep in xyin.h...
+		{
+		if(KInterSampleTime > 0)				// need to check this config param as it might be zero!
+			iTimer.OneShot(KInterSampleTime);	// haven't got a complete group yet, so queue timer to sample again
+		else
+			iTakeReadingDfc.Enque();
+		return;
+		}
+
+	// Have a complete group of samples so pass up to processing layer (PIL)
+
+	// Need to lock the kernel to simulate ISR context and thus defer preemption,
+	// since RawSampleValid() expects an ISR context and calls TDfc::Add().
+	NKern::Lock();
+	RawSampleValid();		// adds DFC
+	NKern::Unlock();
+	}
+
+/**
+Request for an interrupt to be generated when the pen is next down
+Called by PIL at startup or when pen leaves digitiser after pen-up event issued
+*/
+void DTemplateDigitiser::WaitForPenDown()
+	{
+	// Called at startup or when pen leaves digitiser after pen-up event issued
+	DEBUG_PRINT(Kern::Printf("WD: PowerDownMask %x",iPoweringDown));
+	if (iPoweringDown)
+		{
+		// powering down
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register(s) to allow the hardware
+		// to detect when the digitizer panel is touched and wakes up the system if in standby
+		//
+
+		//
+		// TO DO: (optional)
+		//
+		// Relinquish request on power resources
+		// This will place the peripheral hardware in a low power "Sleep" mode which is Interrupt detection capable
+		// EXAMPLE ONLY
+#ifdef USE_SYMBIAN_PRM
+		TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
+		aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 50 /* a percentage */);
+		aManager -> SharedBResource1() -> Release();
+#endif
+
+		iPoweringDown = EFalse;
+		PowerDownDone();
+		}
+	else
+		{
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register to clear the digitiser interrupt
+		//
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register(s) to allow the hardware
+		// to detect when the digitizer panel is touched
+		//
+
+		if ((iTimer.iState == NTimer::EIdle) && (iTimerInt.iState == NTimer::EIdle))
+			{
+			GPIO::EnableInterrupt(KDataReadyPin); // enable pen-down interrupt
+			}
+		}
+	}
+
+/**
+Called by PIL after it has processed a group of raw samples while pen is down.
+Used to indicate that the iX, iY buffers may be re-used
+*/
+void DTemplateDigitiser::WaitForPenUp()
+	{
+	DEBUG_PRINT(Kern::Printf("WU"));
+	iState = E_HW_CollectSample;
+	iSamplesCount = 0;					// reset sample buffer
+	if(KInterGroupTime > 0)				// need to check this config param as it might be zero!
+		{
+		iTimer.OneShot(KInterGroupTime);
+		}
+	else
+		{
+		iTakeReadingDfc.Enque();
+		}
+	}
+
+/**
+Called by PIL if the group of samples collected is not good enough
+Used to indicate that the iX, iY buffers may be re-used
+*/
+void DTemplateDigitiser::WaitForPenUpDebounce()
+	{
+	DEBUG_PRINT(Kern::Printf("WUDB"));
+	iState = E_HW_CollectSample;
+	iSamplesCount = 0;			// reset sample buffer
+	if(KInterGroupTime > 0)					// need to check this config param as it might be zero!
+		iTimer.OneShot(KInterGroupTime);
+	else
+		iTakeReadingDfc.Enque();
+	}
+
+/**
+Pen up/down interrupt service routine (ISR)
+*/
+static TUint IsrCnt = 0;
+void DTemplateDigitiser::PenInterrupt()
+    {
+	DEBUG_PRINT(Kern::Printf("I: %d  ", IsrCnt++));
+
+//	Interrupt::Clear(KIntIdDigitiser);	// should already have been cleared
+//	GPIO::DisableInterrupt(KDataReadyPin);
+
+	// TO DO: (mandatory)
+	// Read from appropriate hardware register to determine whether digitiser panel is being touched
+	// Set penDown to ETrue if touched or EFalse if not touched.
+	// This is only example code... you need to modify it for your hardware
+//	GPIO::DisableInterrupt(KDataReadyPin);
+
+
+//	TBool penDown = iController.NumOfTouches();
+	TBool penDown = 1;
+
+	// coverity[dead_error_condition]
+	if(!penDown)					// pen up
+		{
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register to clear the digitiser interrupt
+		//
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register(s) to allow the hardware
+		// to detect when the digitizer panel is touched
+		//
+
+		return;						// ... and exit!
+		}
+
+//	Interrupt::Disable(KIntIdDigitiser);		// do NOT disable the capability to generate interrupts at the source
+
+    // Add the timing of pen interrupts as entropy data for the RNG
+//	Interrupt::AddTimingEntropy();
+
+	if(0)
+//	if (KPenDownDelayTime>0)					// need to check this config param as it might be zero!
+		{
+		iTimerInt.OneShot(KPenDownDelayTime);	// start a debounce timer which will queue a DFC to process the interrupt
+		}
+	else
+		{
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register to clear the digitiser interrupt
+		// This will re-trigger the interrupt mechanism to catch the next interrupt...
+		//
+
+		iTakeReadingDfc.Add();
+		}
+	}
+
+
+
+void DTemplateDigitiser::TimerCallback(TAny* aPtr)
+	{
+	DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
+	DEBUG_PRINT(Kern::Printf("T"));
+	pD->iTakeReadingDfc.Add();
+	}
+
+/**
+Debounce timer callback
+schedules a DFC to process a pen-down interrupt
+
+@param aPtr	a pointer to DTemplateDigitiser
+*/
+void DTemplateDigitiser::TimerIntCallback(TAny* aPtr)
+	{
+	DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
+	DEBUG_PRINT(Kern::Printf("TI"));
+//	GPIO::DisableInterrupt(KDataReadyPin);
+	// clear xy interrupt -> re-triggers the interrupt mechanism to catch the next IRQ
+
+	// TO DO: (mandatory)
+	// Write to the appropriate hardware register to clear the digitiser interrupt
+	//
+
+	pD->iTakeReadingDfc.Add();
+	}
+
+/**
+Pen-up/down interrupt handler
+
+@param aPtr	a pointer to DTemplateDigitiser
+*/
+void DTemplateDigitiser::PenIsr(TAny* aPtr)
+	{
+	DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
+	pD->PenInterrupt();
+	}
+
+/**
+DFC for taking a sample
+
+@param aPtr	a pointer to DTemplateDigitiser
+*/
+void DTemplateDigitiser::TakeReadingDfc(TAny* aPtr)
+	{
+	DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
+	pD->TakeSample();
+	}
+
+
+void DTemplateDigitiser::PowerUp()
+	{
+	iPowerUpDfc.Enque();			// queue a DFC in this driver's context
+	}
+
+void DTemplateDigitiser::PowerUpDfc(TAny* aPtr)
+	{
+	DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
+	pD->DoPowerUp();
+	}
+
+void DTemplateDigitiser::DoPowerUp()
+	{
+	__KTRACE_OPT(KPOWER, Kern::Printf("DTemplateDigitiser::PowerUpDfc()"));
+	DigitiserOn();
+	PowerUpDone();			// must be called from a different thread than PowerUp()
+	}
+
+/**
+Turn the digitiser on
+May be called as a result of a power transition or from the HAL
+If called from HAL, then the digitiser may be already be on (iPointerOn == ETrue)
+*/
+void DTemplateDigitiser::DigitiserOn()
+	{
+	__KTRACE_OPT(KPOWER,Kern::Printf("DTemplateDigitiser::DigitiserOn() iPointerOn=%d", iPointerOn));
+
+	if (!iPointerOn)				// may have been powered up already
+		DigitiserPowerUp();
+	}
+
+/**
+Power-up the digitiser. Assumes digitiser is off.
+*/
+void DTemplateDigitiser::DigitiserPowerUp()
+	{
+	__KTRACE_OPT(KPOWER, Kern::Printf("DigitiserPowerUp"));
+	iPointerOn = ETrue;		// now turned on
+
+	// TO DO: (mandatory)
+	// Write to the appropriate hardware register to clear the digitiser interrupt
+	//
+
+	//
+	// TO DO: (optional)
+	//
+	// Reassert request on power resources
+	// This will move the peripheral hardware out of low power "Sleep" mode back to fully operational
+	// EXAMPLE ONLY
+	//
+#ifdef USE_SYMBIAN_PRM
+	TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
+	aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 100 /* a percentage */);
+	aManager -> SharedBResource1() -> Use();
+#endif
+	// TO DO: (mandatory)
+	// Write to the appropriate hardware register(s) to allow the hardware
+	// to detect when the digitizer panel is touched
+	//
+
+	iState = E_HW_PowerUp;	// so we wait for pen up if necessary
+	iTakeReadingDfc.Enque();
+	}
+
+
+void DTemplateDigitiser::PowerDown(TPowerState /*aPowerState*/)
+	{
+	iPoweringDown = ETrue;
+	iPowerDownDfc.Enque();						// queue a DFC in this driver's context
+	}
+
+
+void DTemplateDigitiser::PowerDownDfc(TAny* aPtr)
+	{
+	DTemplateDigitiser* pD=(DTemplateDigitiser*)aPtr;
+	pD->DigitiserOff();
+	}
+
+
+
+/**
+Turn the digitiser off
+May be called as a result of a power transition or from the HAL
+If called from Power Manager, then the digitiser may be already be off (iPointerOn == EFalse)
+if the platform is in silent running mode
+*/
+void DTemplateDigitiser::DigitiserOff()
+	{
+	__KTRACE_OPT(KPOWER,Kern::Printf("DTemplateDigitiser::DigitiserOff() iPointerOn=%d", iPointerOn));
+	if (iPointerOn)		// can have been powered down from HAL
+		{
+		iPointerOn = EFalse;
+//		Interrupt::Disable(KIntIdDigitiser);
+
+		// TO DO: (mandatory)
+		// Write to the appropriate hardware register to disable the digitiser interrupt
+		//
+
+		iTimer.Cancel();
+		iTimerInt.Cancel();
+		iTakeReadingDfc.Cancel();
+		if (iState != E_HW_CollectSample)
+			{
+			// Need to lock the kernel to simulate ISR context and thus defer preemption,
+			// since PenUp() expects an ISR context and calls TDfc::Add().
+			NKern::Lock();
+			PenUp();		// adds DFC (will call WaitForPenDown)
+			NKern::Unlock();
+			}
+		else
+			{
+
+			// TO DO: (mandatory)
+			// Write to the appropriate hardware register(s) to allow the hardware
+			// to detect when the digitizer panel is touched and wakes up the system if in standby
+			//
+
+			//
+			// TO DO: (optional)
+			//
+			// Relinquish request on power resources as we are being powered down
+			// This will place the peripheral hardware in a low power "Sleep" mode which is Interrupt detection capable
+			// EXAMPLE ONLY
+			//
+#ifdef USE_SYMBIAN_PRM
+			TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
+			aManager -> ModifyToLevel(TemplateResourceManager::AsynchMlResourceUsedByXOnly, 0 /* a percentage */);
+			aManager -> SharedBResource1() -> Release();
+#endif
+			if (iPoweringDown)			// came here through PowerDown
+				{
+				iPoweringDown = EFalse;
+				PowerDownDone();
+				}
+			}
+		}
+	else	// already powered down (by HAL)
+		{
+			if (iPoweringDown)			// came here through PowerDown
+				{
+				iPoweringDown = EFalse;
+				PowerDownDone();
+				}
+		}
+	}
+
+
+
+
+/**
+Convert digitiser coordinates to screen coordinates
+
+@param aDigitiserPoint the digitiser coordinates
+@param aScreenPoint A TPoint supplied by the caller.
+					On return, set to the converted screen coordinates in pixels.
+
+@return KErrNone if successful
+*/
+TInt DTemplateDigitiser::DigitiserToScreen(const TPoint& aDigitiserPoint, TPoint& aScreenPoint)
+	{
+	NKern::LockSystem();
+	TInt R11 = iMachineConfig.iCalibration.iR11;
+	TInt R12 = iMachineConfig.iCalibration.iR12;
+	TInt R21 = iMachineConfig.iCalibration.iR21;
+	TInt R22 = iMachineConfig.iCalibration.iR22;
+	TInt TX = iMachineConfig.iCalibration.iTx;
+	TInt TY = iMachineConfig.iCalibration.iTy;
+	NKern::UnlockSystem();
+	TInt X = aDigitiserPoint.iX;
+	TInt Y = aDigitiserPoint.iY;
+
+	aScreenPoint.iX = (X*R11 + Y*R21 + TX) >> 16;
+	aScreenPoint.iY = (X*R12 + Y*R22 + TY) >> 16;
+
+	DEBUG_PRINT(Kern::Printf("DtS: Dp.x %d, Dp.y %d, Sp.x %d, Sp.y %d", X,Y,aScreenPoint.iX,aScreenPoint.iY));
+
+	return KErrNone;
+	}
+
+/**
+Convert screen coordinates back into digitiser coordinates
+using the current constants from the superpage
+
+@param aX The screen X coordinate in pixels; On return, set to the digitiser X coordinate.
+@param aY The screen Y coordinate in pixels; On return, set to the digitiser Y coordinate.
+*/
+void DTemplateDigitiser::ScreenToDigitiser(TInt& aX, TInt& aY)
+	{
+	NKern::LockSystem();
+	Int64 R11 = iMachineConfig.iCalibration.iR11;
+	Int64 R12 = iMachineConfig.iCalibration.iR12;
+	Int64 R21 = iMachineConfig.iCalibration.iR21;
+	Int64 R22 = iMachineConfig.iCalibration.iR22;
+	Int64 TX = iMachineConfig.iCalibration.iTx;
+	Int64 TY = iMachineConfig.iCalibration.iTy;
+	NKern::UnlockSystem();
+	Int64 X = aX;
+	Int64 Y = aY;
+	//
+	// Xd=(Xs<<16)*R22-(Ys<<16)*R21-(TX*R22)+(TY*R21)
+	//	  -------------------------------------------
+	//				   (R22*R11)-(R21*R12)
+	//
+	//
+	// Yd=(Xs<<16)*R12-(Ys<<16)*R11-(TX*R12)+(TY*R11)
+	//	  -------------------------------------------
+	//				   (R21*R12)-(R22*R11)
+	//
+	// where Xd and Yd are digitiser coordinates
+	//		 Xs and Ys are supplied screen coordinates
+	//
+	X<<=16;
+	Y<<=16;
+
+	Int64 d=Int64(R21)*Int64(R12)-Int64(R22)*Int64(R11);
+
+	Int64 r=(X*R12)-(Y*R11)-(TX*R12)+(TY*R11);
+
+	r=r/d;
+
+	aY=(TInt)r;
+
+	r=(X*R22)-(Y*R21)-(TX*R22)+(TY*R21);
+
+	r=r/(-d);
+
+	aX=(TInt)r;
+	}
+
+/**
+Calculate values for R11, R12, R21, R22, TX and TY
+
+@param aCalibration the screen coordinates of points touched
+@return KErrNone if successful
+*/
+TInt DTemplateDigitiser::SetXYInputCalibration(const TDigitizerCalibration& aCalibration)
+	{
+	TInt R11,R12,R21,R22,TX,TY;
+	//
+	// Get coords of expected points
+	//
+	TDigitizerCalibration cal;
+	TInt ret=CalibrationPoints(cal);
+	if (ret!=KErrNone)
+		return ret;
+
+	TInt Xp1=cal.iTl.iX;
+	TInt Yp1=cal.iTl.iY;
+	TInt Xp2=cal.iBl.iX;
+	TInt Yp2=cal.iBl.iY;
+	TInt Xp3=cal.iBr.iX;
+	TInt Yp3=cal.iBr.iY;
+	//
+	// Get coords of points touched in screen coordinates
+	//
+	TInt X1=aCalibration.iTl.iX;
+	TInt Y1=aCalibration.iTl.iY;
+	TInt X2=aCalibration.iBl.iX;
+	TInt Y2=aCalibration.iBl.iY;
+	TInt X3=aCalibration.iBr.iX;
+	TInt Y3=aCalibration.iBr.iY;
+	//
+	// Convert back to raw digitiser coordinates
+	//
+	ScreenToDigitiser(X1,Y1);
+	ScreenToDigitiser(X2,Y2);
+	ScreenToDigitiser(X3,Y3);
+	//
+	// (Y1-Y2)(Xp1-Xp3) - (Y1-Y3)(Xp1-Xp2)
+	// ----------------------------------- = R11
+	// (Y1-Y2)(X1-X3)	- (Y1-Y3)(X1-X2)
+	//
+	Int64 r=((Int64(Y1-Y2)*Int64(Xp1-Xp3))-(Int64(Y1-Y3)*Int64(Xp1-Xp2)));
+	r<<=16;
+	r/=(Int64(Y1-Y2)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X1-X2));
+	R11=(TInt)r;
+	//
+	// (Y1-Y2)(Yp1-Yp3) - (Y1-Y3)(Yp1-Yp2)
+	// ----------------------------------- = R12
+	// (Y1-Y2)(X1-X3)	- (Y1-Y3)(X1-X2)
+	//
+	r=((Int64(Y1-Y2)*Int64(Yp1-Yp3))-(Int64(Y1-Y3)*Int64(Yp1-Yp2)));
+	r<<=16;
+	r/=(Int64(Y1-Y2)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X1-X2));
+	R12=(TInt)r;
+	//
+	// (X1-X3)(Xp2-Xp3) - (X2-X3)(Xp1-Xp3)
+	// ----------------------------------- = R21
+	// (Y2-Y3)(X1-X3)	- (Y1-Y3)(X2-X3)
+	//
+	r=(((X1-X3)*(Xp2-Xp3))-((X2-X3)*(Xp1-Xp3)));
+	r<<=16;
+	r/=(Int64(Y2-Y3)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X2-X3));
+	R21=(TInt)r;
+	//
+	// (X1-X3)(Yp2-Yp3) - (X2-X3)(Yp1-Yp3)
+	// ----------------------------------- = R22
+	// (Y2-Y3)(X1-X3)	- (Y1-Y3)(X2-X3)
+	//
+	r=((Int64(X1-X3)*Int64(Yp2-Yp3))-(Int64(X2-X3)*Int64(Yp1-Yp3)));
+	r<<=16;
+	r/=(Int64(Y2-Y3)*Int64(X1-X3)-Int64(Y1-Y3)*Int64(X2-X3));
+	R22=(TInt)r;
+	//
+	// TX = Xp1 - X1*R11 - Y1*R21
+	//
+   TX=(Xp1<<16)-(X1*R11)-(Y1*R21);
+	//
+	// TY = Yp1 - X1*R12 - Y1*R22
+	//
+	TY=(Yp1<<16)-(X1*R12)-(Y1*R22);
+
+	//
+	// Write new values into the superpage
+	//
+	NKern::LockSystem();
+	iMachineConfig.iCalibration.iR11 = R11;
+	iMachineConfig.iCalibration.iR12 = R12;
+	iMachineConfig.iCalibration.iR21 = R21;
+	iMachineConfig.iCalibration.iR22 = R22;
+	iMachineConfig.iCalibration.iTx = TX;
+	iMachineConfig.iCalibration.iTy = TY;
+	NKern::UnlockSystem();
+
+	return(KErrNone);
+	}
+
+/**
+Informs the user-side calibration application where to draw
+the cross-hairs on the screen
+
+@param aCalibration On return contains the for points on the screen (in screen coordinates)
+					where the cross-hairs should be drawn
+@return KErrNone if succcessful
+*/
+TInt DTemplateDigitiser::CalibrationPoints(TDigitizerCalibration& aCalibration)
+	{
+	TVideoInfoV01Buf buf;
+	TVideoInfoV01& vidinfo=buf();
+	TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalCurrentModeInfo, (TAny*)&buf, NULL);
+	if (r!=KErrNone)
+		return r;
+	iScreenSize=vidinfo.iSizeInPixels;
+
+    aCalibration.iBl.iX = aCalibration.iTl.iX = iScreenSize.iWidth/10;
+    aCalibration.iTr.iY = aCalibration.iTl.iY = iScreenSize.iHeight/10;
+    aCalibration.iBr.iY = aCalibration.iBl.iY = iScreenSize.iHeight-iScreenSize.iHeight/10;
+    aCalibration.iTr.iX = aCalibration.iBr.iX = iScreenSize.iWidth-iScreenSize.iWidth/10;
+    return r;
+	}
+/**
+Saves the digitiser calibration to the persistent machine configuration area
+so that it can be restored after a power-down/up
+
+@return KErrNone if succcessful
+*/
+TInt DTemplateDigitiser::SaveXYInputCalibration()
+	{
+	NKern::LockSystem();
+	iMachineConfig.iCalibrationSaved = iMachineConfig.iCalibration;
+	NKern::UnlockSystem();
+	return(KErrNone);
+	}
+
+/**
+Restores the digitiser calibration from the persistent machine configuration area
+following a power-up
+
+@param aType indicates whether to restore factory or saved settings
+@return KErrNone if succcessful
+*/
+TInt DTemplateDigitiser::RestoreXYInputCalibration(TDigitizerCalibrationType aType)
+	{
+	TInt r=KErrNone;
+	NKern::LockSystem();
+	switch (aType)
+		{
+		case EFactory:
+			iMachineConfig.iCalibration=iMachineConfig.iCalibrationFactory;
+			break;
+		case ESaved:
+			iMachineConfig.iCalibration=iMachineConfig.iCalibrationSaved;
+			break;
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	NKern::UnlockSystem();
+	return r;
+	}
+
+/**
+Gets the digitiser configuration information
+
+@param aInfo On return, contains information about the digitiser's dimensions etc.
+*/
+void DTemplateDigitiser::DigitiserInfo(TDigitiserInfoV01& aInfo)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("DTemplateDigitiser::DigitiserInfo"));
+	aInfo.iDigitiserSize.iWidth=KConfigXyWidth;
+	aInfo.iDigitiserSize.iHeight=KConfigXyHeight;
+	aInfo.iOffsetToDisplay.iX=KConfigXyOffsetX;
+	aInfo.iOffsetToDisplay.iY=KConfigXyOffsetY;
+	}
+
+/**
+Issues a pen move event if the distance from the last point is greater than the threshold
+
+@param aPoint the pen position in screen coordinates
+*/
+void DTemplateDigitiser::FilterPenMove(const TPoint& aPoint)
+	{
+	TPoint offset=aPoint;
+	offset.iX-=iLastPos.iX;
+	offset.iY-=iLastPos.iY;
+	if (Abs(offset.iX)>=iCfg.iAccThresholdX || Abs(offset.iY)>=iCfg.iAccThresholdY)
+		{
+		iLastPos=aPoint;
+		IssuePenMoveEvent(aPoint);
+		}
+	}
+
+/**
+Reset the pen move filter
+*/
+void DTemplateDigitiser::ResetPenMoveFilter()
+	{
+	}
+
--- a/omap3530/beagle_drivers/led/led.cpp	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/beagle_drivers/led/led.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -41,7 +41,7 @@
 		{
 		GPIO::SetPinMode(KGPIO_LED0, GPIO::EEnabled);
 		GPIO::SetOutputState(KGPIO_LED0, GPIO::ELow);
-		iTimer.OneShot(NKern::TimerTicks(KBeatTimeInSeconds * 1000));		
+		iTimer.OneShot(NKern::TimerTicks(KBeatTimeInSeconds * 1000));
 		}
 	else
 		{
--- a/omap3530/beagle_drivers/led/led.mmp	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/beagle_drivers/led/led.mmp	Sun Nov 21 02:23:11 2010 +0000
@@ -36,11 +36,11 @@
 macro USER_BUTTON_ENTERS_CRASH_DEBUGGER
 
 sourcepath			.
-source				led.cpp
+source  			led.cpp
 
 library				VariantTarget(ecust,lib) 
 library				AsspTarget(gpio,lib)
-library             		AsspTarget(prcm,lib)
+library 			AsspTarget(prcm,lib)
 
 VENDORID 0x70000001
 
--- a/omap3530/beagleboard/bootstrap/beagle.s	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/beagleboard/bootstrap/beagle.s	Sun Nov 21 02:23:11 2010 +0000
@@ -25,7 +25,7 @@
 ;
 ; Platform specific constant definitions
 
-DRamBankBase		EQU		0x80000000 ; 256M of DRAM 
+DRamBankBase		EQU		0x80000000 ; 256M of DRAM
 DRamBankMaxSize		EQU		0x10000000
 
 ; HW used by bootstrap
@@ -415,7 +415,7 @@
 	IF  :DEF: CFG_CPU_ARM1136 :LAND: (:LNOT: :DEF: CFG_CPU_ARM1136_ERRATUM_364296_FIXED)
         DCD     BPR_FinalMMUCRSet,      ExtraMMUCR + MMUCR_FI
         DCD     BPR_AuxCRSet,           DefaultAuxCRSet + 0x80000000
-	ENDIF		
+	ENDIF
 		DCD		-1								; terminator
 
 
@@ -577,7 +577,7 @@
 		MOV     r2, #KUART16XMode
 		STR     r2, [r1, #KHwUartMdr1]
 
-    
+
 		MOV     r1, #0x19000                    ; Set up delay loop to allow line to settle
 		SUBS	r1, r1, #1
 		SUBNE	pc, pc, #12
@@ -637,7 +637,7 @@
 		DCD	ReservePhysicalMemory			; reserve physical RAM if required
 		DCD	GetParameters				; get platform dependent parameters
 		DCD	FinalInitialise				; Final initialisation before booting the kernel
-		DCD HandleAllocRequest				; allocate memory		
+		DCD HandleAllocRequest				; allocate memory
 		DCD	GetPdeValue				; usually in generic code
 		DCD	GetPteValue				; usually in generic code
 		DCD	PageTableUpdate				; usually in generic code
--- a/omap3530/beagleboard/rom/base_beagle.iby	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/beagleboard/rom/base_beagle.iby	Sun Nov 21 02:23:11 2010 +0000
@@ -30,30 +30,30 @@
 #endif
 
 #ifndef _EABI
-#  ifdef _ARM4
-#    define _EABI ARM4
+#ifdef _ARM4
+#define _EABI ARM4
 	 ECHO Defaulting to ARM4
-#  elif defined(_ARMV5)
-#    define _EABI ARMV5
+#elif defined(_ARMV5)
+#define _EABI ARMV5
 	 ECHO Defaulting to ARMV5
-#  elif defined _X86GCC
-#    define _EABI x86gcc
-#  endif
+#elif defined _X86GCC
+#define _EABI x86gcc
+#endif
 #endif
 
-#  ifdef _PLAT
-#    undef _EABI
-#    define _EABI _PLAT
+#ifdef _PLAT
+#undef _EABI
+#define _EABI _PLAT
 	 ECHO Defaulting to _EABI
-#  endif
+#endif
 
-#  ifdef _GCCE
-#    undef _EABI
-#    define _EABI GCCE
-#  elif defined(ABIV2) || defined(ABIv2)
-#    undef _EABI
-#    define _EABI ARMV5_ABIV2
-#  endif
+#ifdef _GCCE
+#undef _EABI
+#define _EABI GCCE
+#elif defined(ABIV2) || defined(ABIv2)
+#undef _EABI
+#define _EABI ARMV5_ABIV2
+#endif
 
 #ifndef _KABI
 #define _KABI _EABI
@@ -104,9 +104,11 @@
 extension[VARID]=\epoc32\release\ARMV5\BUILD_DIR\_omap3530_i2c.dll			\sys\bin\i2c.dll
 
 #include <../omapshared/tps65950.iby>
-
+#ifdef USE_SPI
+#include <rom/omap3530/spi.iby>
+#endif
 #ifdef SYMBIAN_BASE_USE_GCE
-// Use the new GCE compliant display driver  
+// Use the new GCE compliant display driver
 	extension[VARID]=\epoc32\release\ARMV5\BUILD_DIR\_beagle_lcd_gce.dll	\sys\bin\lcd.dll
 	device[VARID]=\epoc32\release\ARMV5\BUILD_DIR\display.ldd			\sys\bin\display0.ldd
 #ifndef EXCLUDE_SERIALKEYBOARD
@@ -151,4 +153,4 @@
 // VFP support
 extension[VARID]= \epoc32\release\ARMV5\BUILD_DIR\EVFP.DLL	\sys\bin\evfp.dll
 
-#endif
\ No newline at end of file
+#endif
--- a/omap3530/beagleboard/rom/kernel.iby	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/beagleboard/rom/kernel.iby	Sun Nov 21 02:23:11 2010 +0000
@@ -19,55 +19,63 @@
 
 
 
-primary[VARID]=		\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EKERN.EXE              \sys\bin\ekern.exe
-extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_omap3530_KAOMAP3530.DLL         \sys\bin\kaomap3530.dll
+primary[VARID]=  \Epoc32\Release\ARMV5\##BUILD##\_omap3530_EKERN.EXE        \sys\bin\ekern.exe
+extension[VARID]= \Epoc32\Release\ARMV5\##BUILD##\_omap3530_KAOMAP3530.DLL  \sys\bin\kaomap3530.dll
 #include <rom/omapshared/mstick.iby>
 
 // Removed BTRACEX
-//extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_omap3530_BTRACEX.LDD            \sys\bin\btracex.ldd
+//extension[VARID]= \Epoc32\Release\ARMV5\##BUILD##\_omap3530_BTRACEX.LDD   \sys\bin\btracex.ldd
 
-extension[VARID]=   \Epoc32\Release\ARMV5\##BUILD##\_omap3530_prcm.dll               \sys\bin\prcm.dll
-extension[VARID]=   \Epoc32\Release\ARMV5\##BUILD##\_omap3530_uart.dll               \sys\bin\uart.dll
-variant[VARID]=		\Epoc32\Release\ARMV5\##BUILD##\_##VARIANT##_ECUST.DLL              \sys\bin\ecust.dll
-extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EXMONCOMMON.DLL        \sys\bin\exmoncommon.dll
-extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EXMONDEBUG.DLL         \sys\bin\exmondebug.dll
-extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_omap3530_GPIO.DLL            	\sys\bin\gpio.dll
-extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_LED.DLL		\sys\bin\led.dll
-extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_omap3530_I2C.DLL                \sys\bin\I2C.DLL
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_prcm.dll         \sys\bin\prcm.dll
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_uart.dll         \sys\bin\uart.dll
+variant[VARID]=  \Epoc32\Release\ARMV5\##BUILD##\_##VARIANT##_ECUST.DLL     \sys\bin\ecust.dll
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EXMONCOMMON.DLL  \sys\bin\exmoncommon.dll
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EXMONDEBUG.DLL   \sys\bin\exmondebug.dll
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_GPIO.DLL         \sys\bin\gpio.dll
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_LED.DLL       \sys\bin\led.dll
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_I2C.DLL          \sys\bin\i2c.DLL
 
-// Uncommnet to include West Bridge Astoria Symbian Storage driver 
-//extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_WB.DLL		\sys\bin\wb.dll
-//extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\wb.dll		\sys\bin\wb.dll
+// Uncommnet to include West Bridge Astoria Symbian Storage driver
+//extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_WB.DLL      \sys\bin\wb.dll
+//extension[VARID]=\epoc32\release\ARMV5\##BUILD##\wb.dll                   \sys\bin\wb.dll
 
-//extension[VARID]=	\Epoc32\Release\ARMV5\##BUILD##\_##VARIANT##_resman.pdd		\sys\bin\resman.pdd
-//extension[VARID]=	\Epoc32\Release\##KMAIN##\##BUILD##\resman.ldd				\sys\bin\resman.ldd
+//extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_##VARIANT##_resman.pdd  \sys\bin\resman.pdd
+//extension[VARID]=\Epoc32\Release\##KMAIN##\##BUILD##\resman.ldd           \sys\bin\resman.ldd
 
 #include <rom/omapshared/tps65950.iby>
 
-device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EUART.PDD				\sys\bin\euart.pdd
-device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\ECOMM.LDD						\sys\bin\ecomm.ldd
+#ifdef USE_SPI
+#include <rom/omap3530/spi.iby>
+#endif
+
+#ifdef BYD_TOUCH
+extension[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_##VARIANT##_byd_xyin.dll  \sys\bin\byd_xyin.dll
+#endif
+
+device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EUART.PDD           \sys\bin\euart.pdd
+device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\ECOMM.LDD                     \sys\bin\ecomm.ldd
 
 #ifdef TSHELL_SERIAL
 //Use VT100 Over Serial
-#define EDISP_DRV	\EDISP_VT100.DLL
+#define EDISP_DRV \EDISP_VT100.DLL
 #else // not TSHELL_SERIAL
-	extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_lcd.dll				\sys\bin\lcd.dll
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_lcd.dll         \sys\bin\lcd.dll
 #ifdef SERIALMOUSE
 #ifdef BASE_ROM
-	extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_serialmouse_tshell.DLL	\sys\bin\eserialmouse.dll
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_serialmouse_tshell.DLL \sys\bin\eserialmouse.dll
 #else
-	extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_serialmouse.DLL		\sys\bin\eserialmouse.dll
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_serialmouse.DLL  \sys\bin\eserialmouse.dll
 #endif
 #else // not SERIALMOUSE
 #ifndef EXCLUDE_SERIALKEYBOARD
-	extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_omap3530_serialkeyboard.DLL	\sys\bin\ekeyb.dll
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_omap3530_serialkeyboard.DLL  \sys\bin\ekeyb.dll
 #endif
 #endif
 #endif
 
-file[VARID]=		\epoc32\release\##KMAIN##\##BUILD##\_##VARIANT##_EKDATA.DLL				\sys\bin\ekdata.dll
-extension[VARID]=	\epoc32\release\##KMAIN##\##BUILD##\ELOCD.LDD							\sys\bin\elocd.ldd
-extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_MEDINT.PDD				\sys\bin\medint.pdd
+file[VARID]=\epoc32\release\##KMAIN##\##BUILD##\_##VARIANT##_EKDATA.DLL   \sys\bin\ekdata.dll
+extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\ELOCD.LDD            \sys\bin\elocd.ldd
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_MEDINT.PDD  \sys\bin\medint.pdd
 
 // Persistent storage
 extension[VARID]=	\epoc32\release\##KMAIN##\##BUILD##\_##VARIANT##_medstaticrd.pdd	    	\sys\bin\medstaticrd.pdd
@@ -75,18 +83,18 @@
 // Estart
 data=               	\epoc32\rom\beagle\estart.txt					    \sys\data\estart.txt
 
-// Uncommnet to include West Bridge Astoria Symbian Storage driver 
-//extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_MEDWB.PDD				\sys\bin\medwb.pdd
-device[VARID]=		\epoc32\release\##KMAIN##\##BUILD##\PIPELIB.LDD							\sys\bin\pipelib.ldd
-extension[VARID]=	\epoc32\release\##KMAIN##\##BUILD##\EXSTART.DLL							\sys\bin\exstart.dll
+// Uncommnet to include West Bridge Astoria Symbian Storage driver
+//extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_MEDWB.PDD \sys\bin\medwb.pdd
+device[VARID]=\epoc32\release\##KMAIN##\##BUILD##\PIPELIB.LDD             \sys\bin\pipelib.ldd
+extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\EXSTART.DLL          \sys\bin\exstart.dll
 
 #ifdef INCLUDE_USB
-extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_omap3530_USBCC.DLL					\sys\bin\USBCC.DLL
-device[VARID]=	\epoc32\release\##KMAIN##\##BUILD##\USBC.LDD							\sys\bin\EUSBC.LDD
-extension[VARID]=	\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_USBV.DLL				\sys\bin\usbv.DLL
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_omap3530_USBCC.DLL      \sys\bin\usbcc.DLL
+device[VARID]=\epoc32\release\##KMAIN##\##BUILD##\USBC.LDD                \sys\bin\eusbc.LDD
+extension[VARID]=\epoc32\release\ARMV5\##BUILD##\_##VARIANT##_USBV.DLL    \sys\bin\usbv.DLL
 #endif
 
-#define	EUSER_DLL	../../ARMV5/##BUILD##/_omap3530_euser.dll
+#define EUSER_DLL ../../ARMV5/##BUILD##/_omap3530_euser.dll
 
 // VFP support
 extension[VARID]= \Epoc32\Release\##KMAIN##\##BUILD##\EVFP.DLL \sys\bin\evfp.dll
--- a/omap3530/beagleboard/src/variant.cpp	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/beagleboard/src/variant.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -37,16 +37,16 @@
 //These constants define Custom Restart Reasons in SuperPage::iHwStartupReason
 const TUint KHtCustomRestartMax	  = 0xff;
 const TUint KHtCustomRestartShift = 8;
-const TUint KHtCustomRestartMask  = KHtCustomRestartMax << KHtCustomRestartShift; 
+const TUint KHtCustomRestartMask  = KHtCustomRestartMax << KHtCustomRestartShift;
 
 //TODO: unncomment when referenced
-const TUint KHtRestartStartupModesMax = 0xf; // Variable, platform dependant 
-//const TUint KHtRestartStartupModesShift = 16; // Variable, platform dependant 
+const TUint KHtRestartStartupModesMax = 0xf; // Variable, platform dependant
+//const TUint KHtRestartStartupModesShift = 16; // Variable, platform dependant
 //const TUint KHtRestartStartupModesMask = KHtRestartStartupModesMax << KHtRestartStartupModesShift;
 
 void BeagleVariantFault(TInt aLine)
 	{
-	Kern::Fault("BeagleVariant",aLine);	
+	Kern::Fault("BeagleVariant",aLine);
 	}
 
 #define V_FAULT()	BeagleVariantFault(__LINE__)
@@ -78,15 +78,15 @@
 //
 // Specify the RAM zone configuration.
 //
-// The lowest addressed zone must have the highest preference as the bootstrap 
+// The lowest addressed zone must have the highest preference as the bootstrap
 // will always allocate from the lowest address up.  Once the kernel has initialised
 // then the zone preferences will decide from which RAM zone memory is allocated.
 //
 // 	const TUint KVariantRamZoneCount = ?;
-//	static const SRamZone KRamZoneConfig[KVariantRamZoneCount+1] = 
+//	static const SRamZone KRamZoneConfig[KVariantRamZoneCount+1] =
 //				 			iBase      iSize   		iID	iPref	iFlags
 //				{
-//				__SRAM_ZONE(0x????????, 0x???????, 	?,	?, 		?), 
+//				__SRAM_ZONE(0x????????, 0x???????, 	?,	?, 		?),
 //				...
 //				__SRAM_ZONE(0x????????, 0x???????, 	?, 	?, 		?),
 //				__SRAM_ZONE_END, // end of zone list
@@ -117,10 +117,10 @@
 	//	ERamZoneOp_PowerUp:		A RAM zone changing from used to empty.
 	//	ERamZoneOp_PowerDown:	A RAM zone changing from empty to used.
 	//
- 
+
 	switch (aOp)
 		{
-		case ERamZoneOp_Init:	
+		case ERamZoneOp_Init:
 			break;
 		case ERamZoneOp_PowerUp:
 			break;
@@ -158,13 +158,13 @@
 EXPORT_C TInt Variant::GetMsTickPeriod()
 	{
 	return TheVariant.MsTickPeriod();
-	
+
 	}
 
 void Beagle::Init3()
 	{
 	__KTRACE_OPT(KBOOT,Kern::Printf("Beagle::Init3()"));
-	
+
 	Omap3530Assp::Init3();
 
 	Variant::Init3();
@@ -197,13 +197,13 @@
 		if( portNumber >= 0 )
 			{
 			Omap3530Uart::TUart uart( portNumber );
-		
+
 			uart.Init();
 			uart.DefineMode( Omap3530Uart::TUart::EUart );
 			uart.SetBaud( Omap3530Uart::TUart::E115200 );
 			uart.SetDataFormat( Omap3530Uart::TUart::E8Data, Omap3530Uart::TUart::E1Stop, Omap3530Uart::TUart::ENone );
 			uart.Enable();
-			
+
 			TheVariant.iDebugInitialised=ETrue;
 			}
 		}
@@ -245,14 +245,14 @@
 	//
 	// TO DO: (optional)
 	//
-	// Idle Tick supression: 
+	// Idle Tick supression:
 	// 1- obtain the number of idle Ticks before the next NTimer expiration (NTimerQ::IdleTime())
 	// 2- if the number of Ticks is large enough (criteria to be defined) reset the Hardware Timer
 	//    to only interrupt again when the corresponding time has expired.
-	//   2.1- the calculation of the new value to program the Hardware Timer with should take in 
+	//   2.1- the calculation of the new value to program the Hardware Timer with should take in
 	//		  consideration the rounding value (NTimerQ::iRounding)
 	//  3- call the low level Sleep function (e'g. Bootstrap: address in iIdleFunction)
-	//  4- on coming back from Idle need to read the Hardware Timer and determine if woken up due to 
+	//  4- on coming back from Idle need to read the Hardware Timer and determine if woken up due to
 	//     timer expiration (system time for new match<=current system time<system time for new match-tick period)
 	//     or some other Interrupt.
 	//	 4.1- if timer expiration, adjust System Time by adding the number of Ticks suppressed to NTimerQ::iMsCount
@@ -260,8 +260,8 @@
 	//		  above
 	//
 	// Support for different Sleep Modes:
-	// Often the Sleep mode a platform can go to depends on how many resources such as clocks/voltages can be 
-	// turned Off or lowered to a suitable level. If different Sleep modes are supported this code may need 
+	// Often the Sleep mode a platform can go to depends on how many resources such as clocks/voltages can be
+	// turned Off or lowered to a suitable level. If different Sleep modes are supported this code may need
 	// to be able to find out what power resources are On or Off or used to what level. This could be achieved by
 	// enquiring the Resource Manager (see \beagle_variant\inc\beagle_power.h).
 	// Then a decision could be made to what Sleep level we go to.
@@ -269,7 +269,7 @@
 	// Example calls:
 	// Obtain the number of Idle Ticks before the next NTimer expiration
 	// TInt aTicksLeft = NTimerQ::IdleTime();
-	// ... 
+	// ...
 	// Find out the deepest Sleep mode available for current resource usage and sleeping time
 	// TemplateResourceManager* aManager = TTemplatePowerController::ResourceManager();
 	// TemplateResourceManager::TSleepModes aMode = aManager -> MapSleepMode(aTicksLeft*MsTickPeriod());
@@ -368,24 +368,47 @@
 			}
 		case EVariantHalLedMaskSet:
 			{
-			//
-			// TO DO: (optional)
-			//
 			// Set the state of any on-board LEDs, e.g:
-			// TUint32 aLedMask=(TUint32)a1;
-			// Variant::ModifyLedState(~aLedMask,aLedMask);
-			//
+			TUint aLedMask=(TUint)a1;
+			GPIO::TGpioState led_state;
+			if(aLedMask & 1)
+				led_state = GPIO::EHigh;
+			else
+				led_state = GPIO::ELow;
+
+			r = GPIO::SetOutputState(KGPIO_LED0, led_state);
+
+			if(r == KErrNone)
+				{
+				if(aLedMask & 2)
+					led_state = GPIO::EHigh;
+				else
+					led_state = GPIO::ELow;
+
+				r = GPIO::SetOutputState(KGPIO_LED1, led_state);
+				}
 			break;
 			}
 		case EVariantHalLedMaskGet:
 			{
-			//
-			// TO DO: (optional)
-			//
-			// Read the state of any on-board LEDs, e.g:
-			// TUint32 x = Variant::LedState();
-			// kumemput32(a1, &x, sizeof(x));
-			//
+			// Read the state of on-board LEDs
+			GPIO::TGpioState led_state;
+			TUint x = 0;
+			r = GPIO::GetOutputState(KGPIO_LED0, led_state);
+			if(r == KErrNone)
+				{
+				if(led_state == GPIO::EHigh)
+					x = 1;
+
+				r = GPIO::GetOutputState(KGPIO_LED1, led_state);
+				if(r == KErrNone)
+					{
+					if(led_state == GPIO::EHigh)
+						x |= 1 << 1;
+
+					kumemput32(a1, &x, sizeof(x));
+					}
+				}
 			break;
 			}
 
@@ -445,7 +468,7 @@
 			// Read the restart startup mode, e.g:
 			// TInt startup = (Kern::SuperPage().iHwStartupReason & KHtRestartStartupModesMask) >> KHtRestartStartupModesShift;
 			// kumemput32(a1, &startup, sizeof(TInt));
-			break; 			
+			break;
 			}
 
 		case EVariantHalGetMaximumCustomRestartReasons:
@@ -468,7 +491,7 @@
 			// kumemput32(a1, &KHtRestartStartupModesMax, sizeof(TUint));
 			break;
 			}
-		
+
 
 		default:
 			r=KErrNotSupported;
@@ -662,8 +685,8 @@
 	aDay=0;
 	aMonth=0;
 	TInt adjyear = aTime % KSecsDaysPer4Years;
-	
-	
+
+
 	if (adjyear<KSecsPerYr + KSecsPerDay)
 		{
 		GetMonthData(adjyear/KSecsPerDay, ETrue, aMonth, aDay);
@@ -679,7 +702,7 @@
 
 TInt  Beagle::SystemTimeInSecondsFrom2000(TInt& aTime)
 	{
-	
+
 	if(!TPS65950::Initialized())
 		{
 		return KErrNotSupported;
@@ -687,7 +710,7 @@
 
 	TPS65950::TRtcTime  time;
 	TPS65950::GetRtcData( time );
-		 
+
 	aTime = time.iSecond;
 	aTime += time.iMinute * KSecsPerMin;
 	aTime += time.iHour * KSecsPerHour;
@@ -708,9 +731,9 @@
 		{
 		aTime += mTab[isLeap][i] * KSecsPerDay;
 		}
-	
+
 	aTime += (yrs/4) * KSecsDaysPer4Years;
-	
+
 	if ( isLeap )
 		{
 		// Add KSecsPerDay, because first year is always a leap year
@@ -725,8 +748,8 @@
 		{
 		return KErrNotSupported;
 		}
-		
-	TPS65950::TRtcTime  rtc;	
+
+	TPS65950::TRtcTime  rtc;
 	TInt secs = aTime % KSecsPerMin;
 	TInt mins_insecs = (aTime % KSecsPerHour) - secs;
 	TInt hours_insecs = (aTime % KSecsPerDay) - mins_insecs - secs;
@@ -736,7 +759,7 @@
 	rtc.iHour = hours_insecs/KSecsPerHour;
 
 	SecondsToYMD( aTime, rtc.iYear, rtc.iMonth, rtc.iDay);
-	
+
 	TPS65950::SetRtcData( rtc );
 
 	return KErrNone;
--- a/omap3530/bld.inf	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/bld.inf	Sun Nov 21 02:23:11 2010 +0000
@@ -30,6 +30,7 @@
 #include "omap3530_drivers/gpio/bld.inf"
 #include "omap3530_drivers/i2c/bld.inf"
 #include "omap3530_drivers/prcm/bld.inf"
+#include "omap3530_drivers/spi/bld.inf"
 // #include "omap3530_drivers/prm/bld.inf"
 #include "omap3530_drivers/uart/bld.inf"
 #include "omap3530_drivers/usbcc/bld.inf"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/bld.inf	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,30 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/bld.inf
+//
+
+
+PRJ_PLATFORMS
+ARMV5
+
+PRJ_EXPORTS
+spi.iby         rom/omap3530/
+
+
+PRJ_MMPFILES
+spi
+
+PRJ_TESTMMPFILES
+test/t_spi_client_m
+test/d_spi_client_m
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/master.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,921 @@
+// Copyright (c) 2010 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// Implementation of IIC master channel for a SPI bus.
+//
+
+
+
+#ifdef _DEBUG
+#define DBGPRINT(x) //x
+#define DEBUG_ONLY(x) //x
+#define DBG_ERR(x) x
+#else
+#define DEBUG_ONLY(x)
+#define DBGPRINT(x)
+#define DBG_ERR(x)
+#endif
+
+
+// DO NOT CHANGE THESE- trying to tune the driver (unless you really know what you're doing)
+// as this this is only for development purpose to tune the driver. Fifo mode is not yet enabled, but this
+// doesn't affect operation. After development has been finished - these macros and #ifdefs will be removed
+// entirely. For now only SINGLE_MODE should ever be defined.
+//#define USE_TX_FIFO
+//#define USING_TX_COUNTER
+//#define PER_TRANSFER_MODE
+#define SINGLE_MODE
+
+#include <assp/omap3530_assp/omap3530_assp_priv.h>
+#include <assp/omap3530_assp/omap3530_prcm.h>
+#include <drivers/iic.h>
+#include "omap3530_spi.h"
+#include "psl_init.h"
+#include "master.h"
+
+DSpiMasterBeagle::DSpiMasterBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
+	DIicBusChannelMaster(aBusType, aChanDuplex),
+	iTransferEndDfc(TransferEndDfc, this, KIicPslDfcPriority)
+	{
+	iChannelNumber = aChannelNumber;
+	iIrqId  = KMcSpiIrqId[iChannelNumber];
+	iHwBase = KMcSpiRegBase[iChannelNumber];
+	iState  = EIdle;
+	iCurrSS = -1; // make sure channel will be fully configured on the first use
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::DSpiMasterBeagle: at 0x%x, iChannelNumber = %d", this, iChannelNumber));
+	}
+
+TInt DSpiMasterBeagle::DoCreate()
+	{
+	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() McSPI%d \n", iChannelNumber+1));
+	DBGPRINT(Kern::Printf("HW revision is %x", AsspRegister::Read32(iHwBase + MCSPI_REVISION)));
+	TInt r = KErrNone;
+
+	// Create the DFCQ to be used by the channel
+	if(!iDfcQ)
+		{
+		TBuf8<KMaxName> threadName (KIicPslThreadName);
+		threadName.AppendNum(iChannelNumber);
+		r = Kern::DfcQCreate(iDfcQ, KIicPslThreadPriority, &threadName);
+		if(r != KErrNone)
+			{
+			DBG_ERR(Kern::Printf("DFC Queue creation failed, channel number: %d, r = %d\n", iChannelNumber, r));
+			return r;
+			}
+		}
+
+	// PIL Base class initialization - this must be called prior to SetDfcQ(iDfcQ)
+	r = Init();
+	if(r == KErrNone)
+		{
+		// Call base class function to set DFCQ pointers in the required objects
+		// This also enables the channel to process transaction requests
+		SetDfcQ(iDfcQ);
+
+		// PSL DFCQ initialisation for local DFC
+		iTransferEndDfc.SetDfcQ(iDfcQ);
+
+		// Bind interrupts.
+		r = Interrupt::Bind(iIrqId, Isr, this);
+		if(r < KErrNone)
+			{
+			DBG_ERR(Kern::Printf("ERROR: InterruptBind error.. %d", r));
+			return r;
+			}
+		}
+
+	// Make sure clocks are enabled (TBD: this could go to 'PowerUp/PowerDown' if using PRM)
+	Prcm::SetClockState( Prcm::EClkMcSpi3_F, Prcm::EClkOn );
+	Prcm::SetClockState( Prcm::EClkMcSpi3_I, Prcm::EClkOn );
+	// TODO:consider auto-idle for PRCM.CM_AUTOIDLE1_CORE
+
+	// setup default spi pins. For channel 2 (McSPI3) it can be configured dynamically
+	SetupSpiPins(iChannelNumber);
+
+	return r;
+	}
+
+// A static method used to construct the DSpiMasterBeagle object.
+DSpiMasterBeagle* DSpiMasterBeagle::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
+	{
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::NewL(): ChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
+	DSpiMasterBeagle *pChan = new DSpiMasterBeagle(aChannelNumber, aBusType, aChanDuplex);
+
+	TInt r = KErrNoMemory;
+	if(pChan)
+		{
+		r = pChan->DoCreate();
+		}
+	if(r != KErrNone)
+		{
+		delete pChan;
+		pChan = NULL;
+		}
+	return pChan;
+	}
+
+// This method is called by the PIL to initiate the transaction. After finishing it's processing,
+// the PSL calls the PIL function CompleteRequest to indicate the success (or otherwise) of the request
+TInt DSpiMasterBeagle::DoRequest(TIicBusTransaction* aTransaction)
+	{
+	DBGPRINT(Kern::Printf("\n=>DSpiMasterBeagle::DoRequest (aTransaction=0x%x)\n", aTransaction));
+
+	// If the pointer to the transaction passed in as a parameter, or its associated pointer to the
+	// header information is NULL, return KErrArgument
+	if(!aTransaction || !GetTransactionHeader(aTransaction))
+		{
+		return KErrArgument;
+		}
+
+	// The PSL operates a simple state machine to ensure that only one transaction is processed
+	// at a time - if the channel is currently busy, reject the request (PIL should not try that!)
+	if(iState != EIdle)
+		{
+		return KErrInUse;
+		}
+
+	// copy pointer to the transaction
+	iCurrTransaction = aTransaction;
+
+	// Configure the hardware to support the transaction
+	TInt r = PrepareConfiguration();
+	if(r == KErrNone)
+		{
+		r = ConfigureInterface();
+		if(r == KErrNone)
+			{
+			// start processing transfers of this transaction.
+			r = ProcessNextTransfers();
+			}
+		}
+	return r;
+	}
+
+TInt DSpiMasterBeagle::PrepareConfiguration()
+	{
+	TConfigSpiV01 &newHeader = (*(TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction)))();
+
+	// get the slave address (i.e. known as a 'channel' for the current SPI module)
+	TInt busId       = iCurrTransaction->GetBusId();
+	TInt slaveAddr   = GET_SLAVE_ADDR(busId);
+	TInt slavePinSet = 0;
+
+	if(slaveAddr >= KMcSpiNumSupportedSlaves[iChannelNumber]) // address is 0-based
+		{
+		DBG_ERR(Kern::Printf("Slave address for McSPI%d should be < %, was: %d !",
+				iChannelNumber + 1, KMcSpiNumSupportedSlaves[iChannelNumber], slaveAddr));
+		return KErrArgument; // Slave address out of range
+		}
+
+	// Slave addresses > 1 for McSPI3 (iChannel2) really means alternative pin settings,
+	// so adjust it in such case. *Pin set indexes are +1 to skip over the pin set for McSPI4
+	// channel in the pin configuration table.
+	if(iChannelNumber == 2 && slaveAddr > 1)
+		{
+		slavePinSet  =  slaveAddr > 3 ?  3 : 2; // slaveAddr: 2-3: pin set 2(1*); 4-5: pin set 3(2*)
+		slaveAddr &= 1; // modulo 2 (i.e. 2 CS for McSPI3)
+		}
+
+	// reconfigure pins if needed..
+	if(slavePinSet != iCurrSlavePinSet)
+		{
+		DeactivateSpiPins(iChannelNumber, iCurrSlavePinSet);
+		SetupSpiPins(iChannelNumber, slavePinSet);
+		iCurrSlavePinSet = slavePinSet;
+		}
+
+	// store configuration parameters
+	iCurrSS          = slaveAddr;
+	iCurrHeader      = newHeader; //copy the header..
+
+	return KErrNone;
+	}
+
+// Init the hardware with the data provided in the transaction and slave-address field
+// (these values are already stored in the iCurrHeader)
+TInt DSpiMasterBeagle::ConfigureInterface()
+	{
+	DBGPRINT(Kern::Printf("ConfigureInterface()"));
+
+	// soft reset the SPI..
+	TUint val = AsspRegister::Read32(iHwBase + MCSPI_SYSCONFIG);
+	val = MCSPI_SYSCONFIG_SOFTRESET;  // issue reset
+
+	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
+
+	val = 0; // TODO will add here this 'smart-wait' stuff that was proposed earlier..
+	while (!(val & MCSPI_SYSSTATUS_RESETDONE))
+		val = AsspRegister::Read32(iHwBase + MCSPI_SYSSTATUS);
+
+	// disable and clear all interrupts..
+	AsspRegister::Write32(iHwBase + MCSPI_IRQENABLE, 0);
+	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS,
+	                      MCSPI_IRQ_RX_FULL(iCurrSS) |
+	                      MCSPI_IRQ_RX_FULL(iCurrSS) |
+	                      MCSPI_IRQ_TX_UNDERFLOW(iCurrSS) |
+	                      MCSPI_IRQ_TX_EMPTY(iCurrSS) |
+	                      MCSPI_IRQ_RX_OVERFLOW);
+
+	// channel configuration
+	//	Set the SPI1.MCSPI_CHxCONF[18] IS bit to 0 for the spi1_somi pin in receive mode.
+	//	val = MCSPI_CHxCONF_IS; // pin selection (somi - simo)
+	// TODO configuration of PINS could also be configurable on a 'per SPI module' basis..
+
+	// Set the SPI1.MCSPI_CHxCONF[17] DPE1 bit to 0 and the SPI1.MCSPI_CHxCONF[16] DPE0 bit to 1 for the spi1.simo pin in transmit mode.
+	val = MCSPI_CHxCONF_DPE0;
+
+	// Set transmit & | receive mode for transmit only mode here. If needed - it will be changed dynamically.
+	val |= MCSPI_CHxCONF_TRM_NO_RECEIVE;
+
+	// set word length.
+	val |= SpiWordWidth(iCurrHeader.iWordWidth);
+
+	// use the appropriate word with (assuming the data is aligned to bytes).
+	if(iCurrHeader.iWordWidth > ESpiWordWidth_16)
+		{
+		iWordSize = 4;
+		}
+	else if (iCurrHeader.iWordWidth > ESpiWordWidth_8)
+		{
+		iWordSize = 2;
+		}
+	else
+		{
+		iWordSize = 1;
+		}
+
+	// set Slave Select / Chip select signal mode
+	val |= iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow ? MCSPI_CHxCONF_EPOL_LOW : 0;
+
+	// set the CLK POL and PHA (clock mode)
+	val |= SpiClkMode(iCurrHeader.iClkMode);
+
+	// Set clock. Note that CheckHdr() will be called prior to this function for this header,
+	// so the value iClkSpeedHz is valid at this point, the KErrNotSupported is not possible
+	// so the return value check can be ommited here
+	val |= SpiClkValue(iCurrHeader.iClkSpeedHz);
+	// __ASSERT_DEBUG(val >= KErrNone, Kern::Fault("spi/master.cpp, line: ", __LINE__));
+
+#ifdef USE_TX_FIFO
+	// enable fifo for transmission..
+	// Update me: this can only set in a 'single' mode.. or for only one channel
+	// but at the momment IIC SPI is used in 'single' mode onlny..
+	val |= MCSPI_CHxCONF_FFEW;
+//	val |= MCSPI_CHxCONF_FFER; // fifo enable for receive.. (TODO)
+#endif
+
+	val |= (iCurrHeader.iTransactionWaitCycles & 3) << MCSPI_CHxCONF_TCS_SHIFT;
+
+	// update the register..
+	AsspRegister::Write32(iHwBase + MCSPI_CHxCONF(iCurrSS), val);
+
+	// set spim_somi pin direction to input
+	val = MCSPI_SYST_SPIDATDIR0;
+
+	// drive csx pin to inactive state
+	if(iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
+		{
+		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 1u << iCurrSS, 0);
+		}
+	else
+		{
+		AsspRegister::Modify32(iHwBase + MCSPI_SYST, 0, (1u << iCurrSS));
+		}
+
+	// Set the MS bit to 0 to provide the clock (ie. to setup as master)
+#ifndef SINGLE_MODE
+	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER);
+	// change the pad config - now the SPI drives the line appropriately..
+	SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
+#else
+	AsspRegister::Write32(iHwBase + MCSPI_MODULCTRL, MCSPI_MODULCTRL_MS_MASTER | MCSPI_MODULCTRL_SINGLE);
+#endif
+
+	return KErrNone;
+	}
+
+TInt DSpiMasterBeagle::ProcessNextTransfers()
+	{
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ProcessNextTransfers():%s", iState==EIdle ? "first" : "next"));
+
+	// Since new transfers are strating, clear exisiting flags
+	iOperation.iValue = TIicOperationType::ENop;
+
+	// If this is the first transfer in the transaction the channel will be in state EIdle
+	if(iState == EIdle)
+		{
+		// Get the pointer to half-duplex transfer object..
+		iHalfDTransfer = GetTransHalfDuplexTferPtr(iCurrTransaction);
+
+		// Get the pointer to full-duplex transfer object..
+		iFullDTransfer = GetTransFullDuplexTferPtr(iCurrTransaction);
+
+		// Update the channel state to EBusy and initialise the transaction status
+		iState = EBusy;
+		iTransactionStatus = KErrNone;
+
+		// start timeout timer for this transaction
+		StartSlaveTimeOutTimer(iCurrHeader.iTimeoutPeriod);
+		}
+	else
+	// If not in state EIdle, get the next transfer in the linked-list held by the transaction
+		{
+		// Get the pointer the next half-duplex transfer object..
+		iHalfDTransfer = GetTferNextTfer(iHalfDTransfer);
+
+		// Get the pointer to the next half-duplex transfer object..
+		if(iFullDTransfer)
+			{
+			iFullDTransfer = GetTferNextTfer(iFullDTransfer);
+			}
+		}
+
+	TInt r = KErrNone;
+	if(!iFullDTransfer && !iHalfDTransfer)
+		{
+		// There is no more to transfer - and all previous were were completed,
+		DBGPRINT(Kern::Printf("All transfers completed successfully"));
+		ExitComplete(KErrNone);
+		}
+	else
+		{
+		// Process next transfers
+		TInt8 hDTrType = (TInt8) GetTferType(iHalfDTransfer);
+
+		if(iFullDTransfer)
+			{
+			// For full-duplex transfer setup the read transfer first, as it doesn't
+			// really start anything - SPI master starts operation when Tx (or clocks)starts..
+
+			if(hDTrType == TIicBusTransfer::EMasterRead)
+				{
+				r = StartTransfer(iHalfDTransfer, TIicBusTransfer::EMasterRead);
+				if(r != KErrNone)
+					{
+					return r;
+					}
+				r = StartTransfer(iFullDTransfer, TIicBusTransfer::EMasterWrite);
+				}
+			else // hDTrType == TIicBusTransfer::EMasterWrite)
+				{
+				r = StartTransfer(iFullDTransfer, TIicBusTransfer::EMasterRead);
+				if(r != KErrNone)
+					{
+					return r;
+					}
+				r = StartTransfer(iHalfDTransfer, TIicBusTransfer::EMasterWrite);
+				}
+			}
+		else
+		// This is a HalfDuplex transfer - so just start it
+			{
+			r = StartTransfer(iHalfDTransfer, hDTrType);
+			}
+		}
+	return r;
+	}
+
+TInt DSpiMasterBeagle::StartTransfer(TIicBusTransfer* aTransferPtr, TUint8 aType)
+	{
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::StartTransfer() @0x%x, aType: %s",
+			               aTransferPtr, aType == TIicBusTransfer::EMasterWrite ? "write" : "read"));
+
+	if(aTransferPtr == NULL)
+		{
+		DBG_ERR(Kern::Printf("DSpiMasterBeagle::StartTransfer - NULL pointer\n"));
+		return KErrArgument;
+		}
+
+	TInt r = KErrNone;
+
+	switch(aType)
+		{
+		case TIicBusTransfer::EMasterWrite:
+			{
+			DBGPRINT(Kern::Printf("Starting EMasterWrite, duplex=%x", iFullDTransfer));
+
+			// Get a pointer to the transfer object's buffer, to facilitate passing arguments to DoTransfer
+			const TDes8* desBufPtr = GetTferBuffer(aTransferPtr);
+
+			DBGPRINT(Kern::Printf("Length %d, iWordSize %d", desBufPtr->Length(), iWordSize));
+
+			// Store the current address and ending address for Transmission - they are required by the ISR and DFC
+			iTxData    = (TInt8*)  desBufPtr->Ptr();
+			iTxDataEnd = (TInt8*) (iTxData + desBufPtr->Length());
+			if (((TInt)iTxDataEnd == (TInt)iTxData) ||  // buffer empty
+			     (TInt)iTxDataEnd % iWordSize) // or wrong size / word length combination
+				{
+				DBG_ERR(if ((TInt)iTxDataEnd == (TInt)iTxData) Kern::Printf("Zero-length buffer used for transfer.."));
+				DBG_ERR(if ((TInt)iTxDataEnd % iWordSize) Kern::Printf("Wrong configuration - word size does not match buffer length"));
+				ExitComplete(KErrArgument, EFalse);
+				return KErrArgument;
+				}
+
+			DBGPRINT(Kern::Printf("Tx: Start: %x, End %x, bytes %d", iTxData, iTxDataEnd, desBufPtr->Length()));
+
+			// Set the flag to indicate that we'll be transmitting data
+			iOperation.iOp.iIsTransmitting = ETrue;
+
+			// initiate the transmission..
+			r = DoTransfer(aType);
+			if(r != KErrNone)
+				{
+				DBG_ERR(Kern::Printf("Starting Write failed, r = %d", r));
+				}
+			break;
+			}
+
+		case TIicBusTransfer::EMasterRead:
+			{
+			DBGPRINT(Kern::Printf("Starting EMasterRead, duplex=%x", iFullDTransfer));
+
+			// Get a pointer to the transfer object's buffer, to facilitate passing arguments to DoTransfer
+			const TDes8* aBufPtr = GetTferBuffer(aTransferPtr);
+
+			// Store the current address and ending address for Reception - they are required by the ISR and DFC
+			iRxData = (TInt8*) aBufPtr->Ptr();
+			iRxDataEnd = (TInt8*) (iRxData + aBufPtr->Length());
+			if (((TInt)iRxDataEnd == (TInt)iRxData) ||  // buffer empty
+			     (TInt)iRxDataEnd % iWordSize) // or wrong size / word length combination
+				{
+				DBG_ERR(if ((TInt)iRxDataEnd == (TInt)iRxData) Kern::Printf("Zero-length buffer used for transfer.."));
+				DBG_ERR(if ((TInt)iRxDataEnd % iWordSize) Kern::Printf("Wrong configuration - word size does not match buffer length"));
+				ExitComplete(KErrArgument, EFalse);
+				return KErrArgument;
+				}
+
+			DBGPRINT(Kern::Printf("Rx: Start: %x, End %x, bytes %d", iRxData, iRxDataEnd, aBufPtr->Length()));
+
+			// Set the flag to indicate that we'll be receiving data
+			iOperation.iOp.iIsReceiving = ETrue;
+
+			// initiate the reception
+			r = DoTransfer(aType);
+			if(r != KErrNone)
+				{
+				DBG_ERR(Kern::Printf("Starting Read failed, r = %d", r));
+				}
+			break;
+			}
+
+		default:
+			{
+			DBG_ERR(Kern::Printf("Unsupported TransactionType %x", aType));
+			r = KErrArgument;
+			break;
+			}
+		}
+
+	return r;
+	}
+
+// Method called by StartTransfer to actually initiate the transfers.
+TInt DSpiMasterBeagle::DoTransfer(TUint8 aType)
+	{
+	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoTransfer()"));
+	TInt r = KErrNone;
+
+	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, ~0);
+
+	switch(aType)
+		{
+		case TIicBusTransfer::EMasterWrite:
+			{
+			// enable the channel here..
+			AsspRegister::Write32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN);
+
+			AsspRegister::Modify32(iHwBase + MCSPI_IRQSTATUS, 0,
+			                       MCSPI_IRQ_TX_EMPTY(iCurrSS) /*| MCSPI_IRQ_TX_UNDERFLOW(iCurrSS)*/);
+
+			AsspRegister::Modify32(iHwBase + MCSPI_IRQENABLE, 0,
+			                       MCSPI_IRQ_TX_EMPTY(iCurrSS) /*| MCSPI_IRQ_TX_UNDERFLOW(iCurrSS)*/);
+
+#ifdef SINGLE_MODE
+			// in SINGLE mode needs to manually assert CS line for current
+			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
+
+			// change the pad config - now the SPI drives the line appropriately..
+			SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
+#endif /*SINGLE_MODE*/
+
+#ifdef USE_TX_FIFO
+			const TInt KTxFifoThreshold = 8;
+			TUint numWordsToTransfer = (iTxDataEnd - iTxData);
+			TUint wordsToWrite = Min(numWordsToTransfer/iWordSize, KTxFifoThreshold/iWordSize);
+
+
+			TInt iAlmostFullLevel = 0;
+			TInt iAlmostEmptyLevel = 1; //KTxFifoThreshold;
+
+			// setup FIFOs
+			AsspRegister::Write32(iHwBase + MCSPI_XFERLEVEL,
+								  MCSPI_XFERLEVEL_WCNT(0) | // total num words
+								  MCSPI_XFERLEVEL_AFL(iAlmostFullLevel)     | // Rx almost full
+								  MCSPI_XFERLEVEL_AEL(iAlmostEmptyLevel) );   // Tx almost empty
+
+			// copy data to fifo..
+			for (TInt i = 0; i < wordsToWrite; i++)
+				{
+				iTxData += iWordSize;
+				AsspRegister::Write32(iHwBase + MCSPI_TXx(iCurrSS), *(iTxData -iWordSize));
+				}
+
+#else /*USE_TX_FIFO*/
+
+			TUint val = 0;
+			for (TInt i = 0; i < iWordSize; i++)
+				{
+				val |= (*iTxData++) << i * 8;
+				}
+
+			DEBUG_ONLY(DumpCurrentStatus("DoTransfer(Write)"));
+			AsspRegister::Write32(iHwBase + MCSPI_TXx(iCurrSS), val);
+#endif /*USE_TX_FIFO*/
+
+			// enable system interrupt
+			Interrupt::Enable(iIrqId);
+			break;
+			}
+		case TIicBusTransfer::EMasterRead:
+			{
+			// enable transmit and receive..
+			AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), MCSPI_CHxCONF_TRM_NO_RECEIVE, 0);
+
+			// for single read (not duplex) one way to to allow clock generation is to enable Tx
+			// and write '0' to Txregister (just like in duplex transaction). We also need to assert Cs line.
+			if(!iFullDTransfer)
+				{
+				// enable the channel..
+				AsspRegister::Write32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN);
+
+				// enable TX and RX Empty interrupts
+				AsspRegister::Modify32(iHwBase + MCSPI_IRQSTATUS, 0, MCSPI_IRQ_TX_EMPTY(iCurrSS) | MCSPI_IRQ_RX_FULL(iCurrSS));
+				AsspRegister::Modify32(iHwBase + MCSPI_IRQENABLE, 0, MCSPI_IRQ_TX_EMPTY(iCurrSS) | MCSPI_IRQ_RX_FULL(iCurrSS));
+#ifdef SINGLE_MODE
+				// in SINGLE mode needs to manually assert CS line for current
+				AsspRegister::Modify32(iHwBase + MCSPI_CHxCONF(iCurrSS), 0, MCSPI_CHxCONF_FORCE);
+
+				// change the pad config - now the SPI drives the line appropriately..
+				SetCsActive(iChannelNumber, iCurrSS, iCurrSlavePinSet);
+#endif /*SINGLE_MODE*/
+				}
+			else
+				{
+				// enable only interrupts for RX here. Tx is handled in EMasterWrite case above.
+				AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, MCSPI_IRQ_RX_FULL(iCurrSS));
+				AsspRegister::Write32(iHwBase + MCSPI_IRQENABLE, MCSPI_IRQ_RX_FULL(iCurrSS));
+				}
+
+			DEBUG_ONLY(DumpCurrentStatus("DoTransfer(Read)"));
+			// and enable system interrupts
+			if(!iFullDTransfer)
+				Interrupt::Enable(iIrqId);
+			break;
+			}
+		default:
+			{
+			DBG_ERR(Kern::Printf("Unsupported TransactionType %x", aType));
+			r = KErrArgument;
+			break;
+			}
+		}
+
+	return r;
+	}
+
+#ifdef _DEBUG
+static TInt IsrCnt = 0;
+void DSpiMasterBeagle::DumpCurrentStatus(const TInt8* aWhere /*=NULL*/)
+	{
+	if(aWhere)
+		Kern::Printf("------ Status (%s)--------", aWhere);
+	else
+		Kern::Printf("------ Status --------");
+	Kern::Printf("\niTransactionStatus: %d", iTransactionStatus);
+	Kern::Printf("iTransferEndDfc %s queued", iTransferEndDfc.Queued() ? "" : "NOT");
+
+	if(iOperation.iOp.iIsTransmitting)
+		{
+		Kern::Printf("TX STATUS:");
+		Kern::Printf("  iTxData    %x", iTxData);
+		Kern::Printf("  iTxDataEnd %x", iTxDataEnd);
+		Kern::Printf("  left to write: %x (words)", (iTxDataEnd - iTxData)/iWordSize);
+		}
+
+	if(iOperation.iOp.iIsReceiving)
+		{
+		Kern::Printf("RX STATUS:");
+		Kern::Printf("  iRxData    %x", iRxData);
+		Kern::Printf("  iRxDataEnd %x", iRxDataEnd);
+		Kern::Printf("  left to read: %x (words)", (iRxDataEnd - iRxData)/iWordSize);
+		}
+	Kern::Printf("  iCurrSS %d",iCurrSS);
+
+	Kern::Printf("IsrCnt %d", IsrCnt);
+	TUint status = AsspRegister::Read32(iHwBase + MCSPI_IRQSTATUS);
+	Kern::Printf("MCSPI_IRQSTATUS (0x%x):", status);
+	if(status & MCSPI_IRQ_TX_EMPTY(iCurrSS))
+		Kern::Printf("   MCSPI_IRQ_TX_EMPTY");
+	if(status & MCSPI_IRQ_TX_UNDERFLOW(iCurrSS))
+		Kern::Printf("   MCSPI_IRQ_TX_UNDERFLOW");
+	if(!iCurrSS && status & MCSPI_IRQ_RX_OVERFLOW)
+		Kern::Printf("   MCSPI_IRQ_RX_OVERFLOW");
+	if(status & MCSPI_IRQ_RX_FULL(iCurrSS))
+		Kern::Printf("   MCSPI_IRQ_RX_FULL");
+
+	Kern::Printf("MCSPI_CHxSTAT(%d):", iCurrSS);
+	status = AsspRegister::Read32(iHwBase + MCSPI_CHxSTAT(iCurrSS));
+	if(status & MCSPI_CHxSTAT_RXFFF)
+		Kern::Printf("   MCSPI_CHxSTAT_RXFFF");
+	if(status & MCSPI_CHxSTAT_RXFFE)
+		Kern::Printf("   MCSPI_CHxSTAT_RXFFE");
+	if(status & MCSPI_CHxSTAT_TXFFF)
+		Kern::Printf("   MCSPI_CHxSTAT_TXFFF");
+	if(status & MCSPI_CHxSTAT_TXFFE)
+		Kern::Printf("   MCSPI_CHxSTAT_TXFFE");
+	if(status & MCSPI_CHxSTAT_EOT)
+		Kern::Printf("   MCSPI_CHxSTAT_EOT");
+	if(status & MCSPI_CHxSTAT_TXS)
+		Kern::Printf("   MCSPI_CHxSTAT_TXS");
+	if(status & MCSPI_CHxSTAT_RXS)
+		Kern::Printf("   MCSPI_CHxSTAT_RXS");
+
+	Kern::Printf("MCSPI_XFERLEVEL:");
+	status = AsspRegister::Read32(iHwBase + MCSPI_XFERLEVEL);
+	Kern::Printf("   MCSPI_XFERLEVEL_WCNT %d", status >> MCSPI_XFERLEVEL_WCNT_OFFSET);
+	Kern::Printf("   MCSPI_XFERLEVEL_AFL %d", (status >> MCSPI_XFERLEVEL_AFL_OFFSET) & 0x3F);
+	Kern::Printf("   MCSPI_XFERLEVEL_AEL %d\n", (status >> MCSPI_XFERLEVEL_AEL_OFFSET) & 0x1F);
+	Kern::Printf("---------------------------------------/*\n\n\n");
+	}
+#endif
+
+void DSpiMasterBeagle::Isr(TAny* aPtr)
+	{
+	DSpiMasterBeagle *a = (DSpiMasterBeagle*) aPtr;
+	DEBUG_ONLY(IsrCnt++);
+	DEBUG_ONLY(a->DumpCurrentStatus("Isr entry"));
+
+	TUint32 status = AsspRegister::Read32(a->iHwBase + MCSPI_IRQSTATUS);
+	AsspRegister::Write32(a->iHwBase + MCSPI_IRQSTATUS, status); // clear status bits..
+
+	// TX_EMPTY - when an item (or number of items if FIFO is used) was transmitted..
+	if(status & MCSPI_IRQ_TX_EMPTY(a->iCurrSS))
+		{
+
+		if(a->iOperation.iOp.iIsTransmitting)
+			{
+#ifdef USE_TX_FIFO
+			// when FIFO is used - should write (at least) the MCSPI_XFERLEVEL_AFL + 1 words to this register..
+			while(a->iTxData != a->iTxDataEnd)
+				{
+				AsspRegister::Write32(a->iHwBase + MCSPI_TXx(a->iCurrSS), *a->iTxData);
+				a->iTxData += a->iWordSize;	// Then increment the pointer to the data.s
+
+				if(AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS)) & MCSPI_CHxSTAT_TXFFF)
+					{
+					break;
+					}
+				}
+#else
+			// transfer next word..
+			if(a->iTxData != a->iTxDataEnd)
+				{
+				TUint val = 0;
+				for (TInt i = 0; i < a->iWordSize; i++)
+					{
+					val |= (*a->iTxData++) << i * 8;
+					}
+				AsspRegister::Write32(a->iHwBase + MCSPI_TXx(a->iCurrSS), val);
+				}
+
+			// check again - if this was the last one..and we're not waiting for rx - end transfer
+			if(a->iTxData == a->iTxDataEnd && !a->iOperation.iOp.iIsReceiving)
+				{
+				Interrupt::Disable(a->iIrqId);
+				a->iTransferEndDfc.Add();
+				}
+#endif
+			}
+		else
+			{
+			// writing a 'dummy' word (for read only transferss (writing 0 doesn't change line state)
+			AsspRegister::Write32(a->iHwBase + MCSPI_TXx(a->iCurrSS), 0);
+			}
+		}
+
+	if(status & MCSPI_IRQ_RX_FULL(a->iCurrSS))
+		{
+		if(a->iOperation.iOp.iIsReceiving)
+			{
+			if(a->iRxDataEnd != a->iRxData)
+				{
+				TUint8 nextRxValue = AsspRegister::Read32(a->iHwBase + MCSPI_RXx(a->iCurrSS));
+				*a->iRxData = nextRxValue;
+				a->iRxData += a->iWordSize;
+				}
+
+			// If the Rx buffer is now full, finish the transmission.
+			if(a->iRxDataEnd == a->iRxData)
+				{
+				Interrupt::Disable(a->iIrqId);
+				a->iTransferEndDfc.Add();
+				}
+			}
+		}
+
+#if 0 // TODO - probably master, as it creates CLK for slave - will never have to bother with this..
+	if(status & MCSPI_IRQ_TX_UNDERFLOW(a->iCurrSS))
+		{
+		DBG_ERR(Kern::Printf("Underflow"));
+		a->iTransactionStatus = KErrUnderflow;
+
+		// disable the channel..
+		AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCTRL(0), MCSPI_CHxCTRL_EN, 0);
+		Interrupt::Disable(a->iIrqId);
+		DEBUG_ONLY(a->DumpCurrentStatus("TxUnderflow"));
+		DBG_ERR(Kern::Fault("TxUnderflow", 0));
+		}
+#endif
+#if defined(USE_TX_FIFO) && defined(USING_TX_COUNTER)
+	if(status & MCSPI_IRQSTATUS_EOW)
+		{
+		Kern::Printf("EOW");
+		// TODO: end of transfer..
+		}
+#endif
+
+	// end of ISR processing
+	DEBUG_ONLY(a->DumpCurrentStatus("Isr end"));
+	}
+
+void DSpiMasterBeagle::TransferEndDfc(TAny* aPtr)
+	{
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::TransferEndDfc"));
+	DSpiMasterBeagle *a = (DSpiMasterBeagle*) aPtr;
+
+	TUint chanStatus = AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS));
+	if(a->iOperation.iOp.iIsTransmitting)
+		{
+		TUint expected = MCSPI_CHxSTAT_EOT | MCSPI_CHxSTAT_TXS;
+
+#ifdef USE_TX_FIFO
+		while(!AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS)) & MCSPI_CHxSTAT_TXFFE);
+#endif
+		while(chanStatus & expected != expected)
+			{
+			chanStatus = AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS));
+			}
+		}
+
+	if(a->iOperation.iOp.iIsReceiving)
+		{
+		TUint expected = MCSPI_CHxSTAT_RXS;
+
+		while(chanStatus & expected != expected)
+			{
+			chanStatus = AsspRegister::Read32(a->iHwBase + MCSPI_CHxSTAT(a->iCurrSS));
+			}
+		__ASSERT_DEBUG(a->iRxDataEnd == a->iRxData,
+		               Kern::Fault("SPI master: exiting not having received all?", 12));
+		}
+
+#ifdef SINGLE_MODE
+	// manually de-assert CS line for this channel
+	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCONF(a->iCurrSS), MCSPI_CHxCONF_FORCE, 0);
+
+	// put the CS signal to 'inactive' state (as on channel disable it would have a glitch)
+	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode, a->iCurrSlavePinSet);
+
+#endif
+
+	// disable the channel
+	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCTRL(0), MCSPI_CHxCTRL_EN, 0);
+
+	// Start the next transfer for this transaction, if any remain
+	if(a->iState == EBusy)
+		{
+		TInt err = a->ProcessNextTransfers();
+		if(err != KErrNone)
+			{
+			// If the next transfer could not be started, complete the transaction with
+			// the returned error code
+			a->ExitComplete(err);
+			}
+		}
+	}
+
+void DSpiMasterBeagle::ExitComplete(TInt aErr, TBool aComplete /*= ETrue*/)
+	{
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::ExitComplete, aErr %d, aComplete %d", aErr, aComplete));
+
+
+	// in the case of error - make sure to reset the channel
+	if(aErr != KErrNone)
+		{
+		// make sure CS is in inactive state (for the current / last transaction) on error
+		// TODO: add extendable transaction support (..i.e. with no de-assertion of CS pin between such transactions)
+		SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode, iCurrSlavePinSet);
+
+		// disable this channel
+		AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
+
+		AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
+		iCurrSS = -1; // make sure the interface will be re-configured at next transaction
+		}
+
+	// Disable interrupts for the channel
+	Interrupt::Disable(iIrqId);
+
+	// Cancel any timers and DFCs..
+	CancelTimeOut();
+	iTransferEndDfc.Cancel();
+
+	// Change the channel state back to EIdle
+	iState = EIdle;
+
+	// Call the PIL method to complete the request
+	if(aComplete)
+		{
+		CompleteRequest(aErr);
+		}
+	}
+
+#ifdef _DEBUG
+void DumpHeader(TConfigSpiV01& aHeader)
+	{
+	Kern::Printf("header:");
+	Kern::Printf("iWordWidth %d (%d bits)", aHeader.iWordWidth, (SpiWordWidth(aHeader.iWordWidth)) >> MCSPI_CHxCONF_WL_OFFSET + 1);
+	Kern::Printf("iClkSpeedHz %d", aHeader.iClkSpeedHz);
+	Kern::Printf("iClkMode %d", aHeader.iClkMode);
+	Kern::Printf("iTimeoutPeriod %d", aHeader.iTimeoutPeriod);
+	Kern::Printf("iBitOrder %d", aHeader.iBitOrder);
+	Kern::Printf("iTransactionWaitCycles %d", aHeader.iTransactionWaitCycles);
+	Kern::Printf("iSSPinActiveMode %d", aHeader.iSSPinActiveMode);
+	}
+#endif
+
+// virtual method called by the PIL when a transaction is queued (with QueueTransaction).
+// This is done in the context of the Client's thread.
+// The PSL is required to check that the transaction header is valid for this channel.
+TInt DSpiMasterBeagle::CheckHdr(TDes8* aHdrBuff)
+	{
+	TInt r = KErrNone;
+	if(!aHdrBuff)
+		{
+		r = KErrArgument;
+		}
+	else
+		{
+		TConfigSpiV01 &header = (*(TConfigSpiBufV01*) (aHdrBuff))();
+
+		// check if word width and clock are supported
+		if(SpiWordWidth(header.iWordWidth) < KMinSpiWordWidth ||
+		   SpiClkValue(header.iClkSpeedHz) < 0 || // == KErrNotSupported
+		   header.iBitOrder == ELsbFirst ||  // this SPI only transmits MSB fist
+		   (TUint)header.iTransactionWaitCycles > KMaxTransactionWaitTime) // max 3(+.5) cycles between words
+			{
+#ifdef _DEBUG
+			if(header.iBitOrder == ELsbFirst)
+				DBG_ERR(Kern::Printf("iClkSpeedHz value (%d) is not supported", header.iClkSpeedHz));
+			if(SpiClkValue(header.iClkSpeedHz) < 0)
+				DBG_ERR(Kern::Printf("iClkSpeedHz: %d is not supported", header.iClkSpeedHz));
+			if((SpiWordWidth(header.iWordWidth)+ 1) >> MCSPI_CHxCONF_WL_OFFSET < KMinSpiWordWidth)
+				DBG_ERR(Kern::Printf("iWordWidth: %d is not supported, min value is: %d",
+						             SpiWordWidth(header.iWordWidth), KMinSpiWordWidth));
+			if((TUint)header.iTransactionWaitCycles > 3)
+				DBG_ERR(Kern::Printf("iTransactionWaitCycles: %d is not supported, value should be from 0 to %d",
+				                     header.iTransactionWaitCycles, KMaxTransactionWaitTime));
+
+			DumpHeader(header);
+#endif
+			r = KErrNotSupported;
+			DBG_ERR(Kern::Printf("DSpiMasterBeagle::CheckHdr()failed, r = %d", r));
+			}
+		}
+	return r;
+	}
+
+// This method is called by the PIL in the case of expiry of a timer for a transaction.
+// TODO: this name is confusing - it could be changed in the PIL to reflect it's real purpose(TBD)
+// It has NOTHING to do with a Slave (i.e. slave might be completely silent for SPI-and master won't notice it!)
+TInt DSpiMasterBeagle::HandleSlaveTimeout()
+	{
+	DBG_ERR(Kern::Printf("HandleSlaveTimeout"));
+
+	// Stop the PSL's operation, and inform the PIL of the timeout
+	ExitComplete(KErrTimedOut, EFalse);
+
+	return KErrTimedOut;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/master.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,94 @@
+// Copyright (c) 2010 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/master.h
+//
+
+
+#ifndef __OMAP3530_SPI_MASTER_H__
+#define __OMAP3530_SPI_MASTER_H__
+
+#include <drivers/iic_channel.h>
+
+_LIT(KIicPslThreadName,"SpiChannelThread_");
+const TInt KIicPslDfcPriority = 0;
+const TInt KIicPslThreadPriority = 24;
+
+// class declaration for SPI master
+class DSpiMasterBeagle : public DIicBusChannelMaster
+	{
+public:
+	static DSpiMasterBeagle* New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex);
+	virtual TInt DoRequest(TIicBusTransaction* aTransaction); // Gateway function for PSL implementation
+
+private:
+	DSpiMasterBeagle(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex);
+
+	// Override base-class pure virtual methods
+	virtual TInt DoCreate();
+	virtual TInt CheckHdr(TDes8* aHdr);
+	virtual TInt HandleSlaveTimeout();
+
+	// Internal methods
+	TInt PrepareConfiguration();
+	TInt ConfigureInterface();
+	TInt ProcessNextTransfers();
+	TInt StartTransfer(TIicBusTransfer* aTransferPtr, TUint8 aType);
+	TInt DoTransfer(TUint8 aType);
+	static void Isr(TAny* aPtr);
+	static void TransferEndDfc(TAny* aPtr);
+	void ExitComplete(TInt aErr, TBool aComplete = ETrue);
+
+#ifdef _DEBUG
+	void DumpCurrentStatus(const TInt8* aWhere = NULL);
+#endif
+
+private:
+	TDfc iTransferEndDfc;
+	TIicOperationType iOperation;
+	TUint8 iWordSize;
+
+	TInt8 iTxFifoThreshold;
+	enum TMyState
+		{
+		EIdle,
+		EBusy
+		};
+	TMyState iState;
+
+	TInt iIrqId;
+	TLinAddr iHwBase;
+
+	// Pointers used to store current transfers information
+	TIicBusTransfer* iHalfDTransfer;
+	TIicBusTransfer* iFullDTransfer;
+
+	// Pointer to the current transaction.
+	TIicBusTransaction* iCurrTransaction;
+
+	// Pointers to buffers used for Rx and Tx transfers
+	TInt8 *iTxData;
+	TInt8 *iRxData;
+	TInt8 *iTxDataEnd;
+	TInt8 *iRxDataEnd;
+
+	// global status of the transaction
+	volatile TInt iTransactionStatus;
+
+	TConfigSpiV01 iCurrHeader;
+	TInt iCurrSS;
+	TInt iCurrSlavePinSet;
+	};
+
+#endif //__OMAP3530_SPI_MASTER_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/omap3530_spi.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,441 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/omap3530_spi.h
+//
+// This file contains definitions to internal SPI implementation and register definitions
+// It is not intended to be exported - SPI registers must not be modified from outside of
+// the driver!
+//
+
+#ifndef __OMAP3530_SPI_H__
+#define __OMAP3530_SPI_H__
+
+#include <assp/omap3530_assp/omap3530_scm.h>
+#include <assp/omap3530_assp/omap3530_gpio.h>
+
+#define BIT_MASK(shift,len)       (((1u << (len)) - 1) << (shift))
+#define GET_BITS(w,shift,len)     (((w) >> (shift)) & ((1 << (len)) - 1))
+#define SET_BITS(w,set,shift,len) ((w) &= ~BIT_MASK(shift, len), (w) |= ((set) << (shift)))
+
+// Device Instance Summary
+const TUint MCSPI1_phys = 0x48098000; // 4Kbytes
+const TUint MCSPI2_phys = 0x4809A000; // 4Kbytes
+const TUint MCSPI3_phys = 0x480B8000; // 4Kbytes
+const TUint MCSPI4_phys = 0x480BA000; // 4Kbytes
+
+const TUint MCSPI1 = Omap3530HwBase::TVirtual<MCSPI1_phys>::Value;
+const TUint MCSPI2 = Omap3530HwBase::TVirtual<MCSPI2_phys>::Value;
+const TUint MCSPI3 = Omap3530HwBase::TVirtual<MCSPI3_phys>::Value;
+const TUint MCSPI4 = Omap3530HwBase::TVirtual<MCSPI4_phys>::Value;
+
+// map of SPI base addresses..
+const TUint KMcSpiRegBase[] =
+	{
+	Omap3530HwBase::TVirtual<MCSPI1_phys>::Value, //McSPI module 1
+	Omap3530HwBase::TVirtual<MCSPI2_phys>::Value, //McSPI module 2
+	Omap3530HwBase::TVirtual<MCSPI3_phys>::Value, //McSPI module 3
+	Omap3530HwBase::TVirtual<MCSPI4_phys>::Value  //McSPI module 4
+	};
+
+//.. and IRQ lines for SPI channels
+const TUint KMcSpiIrqId[] =
+	{
+	EOmap3530_IRQ65_SPI1_IRQ, //McSPI module 1
+	EOmap3530_IRQ66_SPI2_IRQ, //McSPI module 2
+	EOmap3530_IRQ91_SPI3_IRQ, //McSPI module 3
+	EOmap3530_IRQ48_SPI4_IRQ  //McSPI module 4
+	};
+
+// available channels per module i.e. number of 'slave select'  inputs/outpus signals / addresses
+// per module.
+const TUint KMcSpiNumSupportedSlaves[] =
+	{
+	4, // slave address range: 0 - 3
+	2, // slave address range: 0 - 1
+	6, // slave address range: 0 - 5 (0,1: pin option 0; 2,3: pin option 1; 4,5: pin option 2)
+	1  // slave address range: 0 only
+	};
+
+
+//---------------------------------------------------------------
+// MCSPI Registers offsets and bits definitions
+//----------------------------------
+// MCSPI_REVISION
+//----------------------------------
+const TUint MCSPI_REVISION = 0x00;
+
+
+//----------------------------------
+// MCSPI_SYSCONFIG
+//----------------------------------
+const TUint MCSPI_SYSCONFIG = 0x10;
+
+// 9:8 CLOCKACTIVITY Clocks activity during wake up mode period
+//0x0: Interface and Functional clocks may be switched off.
+//0x1: Interface clock is maintained. Functional clock may be switched off.
+//0x2: Functional clock is maintained. Interface clock may be switched off.
+//0x3: Interface and Functional clocks are maintained.
+const TUint MCSPI_SYSCONFIG_CLOCKACTIVITY_ALL_OFF        = 0 << 8;
+const TUint MCSPI_SYSCONFIG_CLOCKACTIVITY_INT_ON_FUN_OFF = 1 << 8;
+const TUint MCSPI_SYSCONFIG_CLOCKACTIVITY_INT_OFF_FUN_ON = 2 << 8;
+const TUint MCSPI_SYSCONFIG_CLOCKACTIVITY_ALL_ON         = 3 << 8;
+
+// 4:3 SIDLEMODE Power management
+const TUint MCSPI_SYSCONFIG_SIDLEMODE_ALWAYS = 0 << 3;
+const TUint MCSPI_SYSCONFIG_SIDLEMODE_IGNORE = 1 << 3;
+const TUint MCSPI_SYSCONFIG_SIDLEMODE_COND   = 2 << 3;
+const TUint MCSPI_SYSCONFIG_ENAWAKEUP = 1 << 2; // 0x1: Wake-up capability enabled
+const TUint MCSPI_SYSCONFIG_SOFTRESET = 1 << 1; // Software reset. Read always returns 0.
+const TUint MCSPI_SYSCONFIG_AUTOIDLE  = 1 << 0; // Internal interface Clock gating strategy
+
+
+//----------------------------------
+// MCSPI_SYSSTATUS
+//----------------------------------
+const TUint MCSPI_SYSSTATUS = 0x14;
+const TUint MCSPI_SYSSTATUS_RESETDONE = 1 << 0;
+
+
+//----------------------------------
+// MCSPI_IRQSTATUS
+//----------------------------------
+const TUint MCSPI_IRQSTATUS = 0x18; // for each bit- write 0x1: reset status, Read 0x1: Event is pending.
+const TUint MCSPI_IRQSTATUS_EOW           = 1 << 17; // End of word count event when a channel is enabled using
+const TUint MCSPI_IRQSTATUS_WKS           = 1 << 16; // Wake-up event in slave mode when an active control signal is detected
+const TUint MCSPI_IRQSTATUS_RX3_FULL      = 1 << 14; // MCSPI_RX3 register is full (only when channel 3 is enabled)
+const TUint MCSPI_IRQSTATUS_TX3_UDERFLOW  = 1 << 13; // MCSPI_TX3 register underflow (only when channel 3 is enabled)(1)
+const TUint MCSPI_IRQSTATUS_TX3_EMPTY     = 1 << 12; // MCSPI_TX3 register is empty (only when channel 3 is enabled)(2)
+const TUint MCSPI_IRQSTATUS_RX2_FULL      = 1 << 10; // MCSPI_RX2 register full (only when channel 2 is enabled)
+const TUint MCSPI_IRQSTATUS_TX2_UNDERFLOW = 1 <<  9; // MCSPI_TX2 register underflow (only when channel 2 is enabled)(1)
+const TUint MCSPI_IRQSTATUS_TX2_EMPTY     = 1 <<  8; // MCSPI_TX2 register empty (only when channel 2 is enabled)(2)
+const TUint MCSPI_IRQSTATUS_RX1_FULL      = 1 <<  6; // MCSPI_RX1 register full (only when channel 1 is enabled)
+const TUint MCSPI_IRQSTATUS_TX1_UNDERFLOW = 1 <<  5; // MCSPI_TX1 register underflow (only when channel 1 is enabled)(1)
+const TUint MCSPI_IRQSTATUS_TX1_EMPTY     = 1 <<  4; // MCSPI_TX1 register empty (only when channel 1 is enabled)(3)
+const TUint MCSPI_IRQSTATUS_RX0_OVERFLOW  = 1 <<  3; // MCSPI_RX0 register overflow (only in slave mode)
+const TUint MCSPI_IRQSTATUS_RX0_FULL      = 1 <<  2; // MCSPI_RX0 register full (only when channel 0 is enabled)
+const TUint MCSPI_IRQSTATUS_TX0_UNDERFLOW = 1 <<  1; // MCSPI_TX0 register underflow (only when channel 0 is
+const TUint MCSPI_IRQSTATUS_TX0_EMPTY     = 1 <<  0; // MCSPI_TX0 register empty (only when channel 0 is enabled)(3)
+
+//----------------------------------
+// MCSPI_IRQENABLE
+//----------------------------------
+//0x0: Interrupt disabled
+//0x1: Interrupt enabled
+const TUint MCSPI_IRQENABLE = 0x1C;
+const TUint MCSPI_IRQENABLE_EOWKE         = 1 << 17; // End of Word count Interrupt Enable.
+const TUint MCSPI_IRQENABLE_WKE           = 1 << 16; // Wake-up event interrupt enable in slave mode when an
+const TUint MCSPI_IRQENABLE_RX3_FULL      = 1 << 14; // MCSPI_RX3 register full interrupt enable (channel 3)
+const TUint MCSPI_IRQENABLE_TX3_UNDERFLOW = 1 << 13; // MCSPI_TX3 register underflow interrupt enable (channel 3)
+const TUint MCSPI_IRQENABLE_TX3_EMPTY     = 1 << 12; // MCSPI_TX3 register empty interrupt enable (channel 3)
+const TUint MCSPI_IRQENABLE_RX2_FULL      = 1 << 10; // MCSPI_RX2 register full interrupt enable (channel 2)
+const TUint MCSPI_IRQENABLE_TX2_UNDERFLOW = 1 << 9;  // MCSPI_TX2 register underflow interrupt enable (channel 2)
+const TUint MCSPI_IRQENABLE_TX2_EMPTY     = 1 << 8;  // MCSPI_TX2 register empty interrupt enable (channel 2)
+const TUint MCSPI_IRQENABLE_RX1_FULL      = 1 << 6;  // MCSPI_RX1 register full interrupt enable (channel 1)
+const TUint MCSPI_IRQENABLE_TX1_UNDERFLOW = 1 << 5;  // MCSPI_TX1 register underflow interrupt enable (channel 1)
+const TUint MCSPI_IRQENABLE_TX1_EMPTY     = 1 << 4;  // MCSPI_TX1 register empty interrupt enable (channel 1)
+const TUint MCSPI_IRQENABLE_RX0_OVERFLOW  = 1 << 3;  // MCSPI_RX0 register overflow interrupt enable (channel 0) (only Slave)
+const TUint MCSPI_IRQENABLE_RX0_FULL      = 1 << 2;  // MCSPI_RX0 register full interrupt enable (channel 0)
+const TUint MCSPI_IRQENABLE_TX0_UNDERFLOW = 1 << 1;  // MCSPI_TX0 register underflow interrupt enable (channel 0)
+const TUint MCSPI_IRQENABLE_TX0_EMPTY     = 1 << 0;  // MCSPI_TX0 register empty interrupt enable (channel 0)
+
+// macros to get these flags depending on the channel number..and ommited ENABLE
+// - as they are the same for MCSPI_IRQSTATUS register
+#define MCSPI_IRQ_RX_OVERFLOW         MCSPI_IRQENABLE_RX0_OVERFLOW  // Channel 0 only / slave mode only
+#define MCSPI_IRQ_RX_FULL(chan)      (MCSPI_IRQENABLE_RX0_FULL      << ((chan)*4))
+#define MCSPI_IRQ_TX_UNDERFLOW(chan) (MCSPI_IRQENABLE_TX0_UNDERFLOW << ((chan)*4))
+#define MCSPI_IRQ_TX_EMPTY(chan)     (MCSPI_IRQENABLE_TX0_EMPTY     << ((chan)*4))
+
+
+//----------------------------------
+// MCSPI_WAKEUPENABL
+//----------------------------------
+const TUint MCSPI_WAKEUPENABL = 0x20;
+const TUint MCSPI_WAKEUPENABL_WKEN = 1 << 0; //0x1: The event is allowed to wake-up the system
+
+
+//----------------------------------
+// MCSPI_SYST
+//----------------------------------
+const TUint MCSPI_SYST = 0x24;
+const TUint MCSPI_SYST_SSB        = 1 << 11; // Set status bit: 0x1: Force to 1 all status bits of MCSPI_ IRQSTATUS
+const TUint MCSPI_SYST_SPIENDIR   = 1 << 10; // spim_cs and spim_clk direction: 0x0: Output (as in master mode), 0x1: Input (as in slave mode)
+const TUint MCSPI_SYST_SPIDATDIR1 = 1 << 9;  // SPIDAT[1] (spim_simo) direction- 0x0: Output, 0x1: Input
+const TUint MCSPI_SYST_SPIDATDIR0 = 1 << 8;  // Set the direction of the SPIDAT[0] (spim_somi) RW 0
+const TUint MCSPI_SYST_WAKD       = 1 << 7;  // SWAKEUP output 0x0: The pin is driven low, 0x1: The pin is driven high.
+const TUint MCSPI_SYST_SPICLK     = 1 << 6;  // spim_clk line (signal data value) RW 0
+const TUint MCSPI_SYST_SPIDAT_1   = 1 << 5;  // spim_somi line (signal data value) RW 0
+const TUint MCSPI_SYST_SPIDAT_0   = 1 << 4;  // spim_simo line (signal data value)
+const TUint MCSPI_SYST_SPIEN_3    = 1 << 3;  // spim_cs3 line (signal data value) RW 0
+const TUint MCSPI_SYST_SPIEN_2    = 1 << 2;  // spim_cs2 line (signal data value) RW 0
+const TUint MCSPI_SYST_SPIEN_1    = 1 << 1;  // spim_cs1 line (signal data value) RW 0
+const TUint MCSPI_SYST_SPIEN_0    = 1 << 0;  // spim_cs0 line (signal data value) RW 0
+
+
+//----------------------------------
+// MCSPI_MODULCTRL
+//----------------------------------
+const TUint MCSPI_MODULCTRL = 0x28;
+const TUint MCSPI_MODULCTRL_SYSTEM_TEST = 1 << 3; // 0x0: Functional mode, 0x1: System test mode (SYSTEST)
+const TUint MCSPI_MODULCTRL_MS_SLAVE    = 1 << 2; // Master / Slave mode 0x0: Master, 0x1: Slave
+const TUint MCSPI_MODULCTRL_MS_MASTER   = 0;      // this is spurious definition -> not to write '0' magic number -defined this..
+const TUint MCSPI_MODULCTRL_SINGLE      = 1 << 0; // Single forced channel/multichannel (master mode only)
+                                                  // MCSPI_CHxCONF_FORCE bit has to be set in this mode, TURBO cleared (recomended)
+
+
+//----------------------------------
+// MCSPI_CHxCONF - channel config
+//----------------------------------
+// x = 0 to 3 for MCSPI1.
+// x = 0 to 1 for MCSPI2 and MCSPI3.
+// x = 0 for MCSPI4.
+#define MCSPI_CHxCONF(x) (0x2C + 0x14 * (x))
+const TUint MCSPI_CHxCONF_CLKG = 1 << 29; //  Clock divider granularity.
+const TUint MCSPI_CHxCONF_FFER = 1 << 28; // FIFO enabled for Receive.
+const TUint MCSPI_CHxCONF_FFEW = 1 << 27; // FIFO enabled for Transmit. Only one channel can have this bit field set.
+
+// [26:25] TCS Chip select time control
+// Defines the number of interface clock cycles between CS toggling and first (or last) edge of SPI clock.
+const TUint MCSPI_CHxCONF_TCS_0_5 = 0 << 25; // 0x0: 0.5 clock cycle
+const TUint MCSPI_CHxCONF_TCS_1_5 = 1 << 25; // 0x1: 1.5 clock cycles
+const TUint MCSPI_CHxCONF_TCS_2_5 = 2 << 25; // 0x2: 2.5 clock cycles
+const TUint MCSPI_CHxCONF_TCS_3_5 = 3 << 25; // 0x3: 3.5 clock cycles
+const TUint MCSPI_CHxCONF_TCS_SHIFT = 25;
+const TUint KMaxTransactionWaitTime = 3;
+
+const TUint MCSPI_CHxCONF_SBPOL = 1 << 24; // Start bit polarity (0: spi word is command, 1: spi word is data)
+const TUint MCSPI_CHxCONF_SBE   = 1 << 23; // Start bit enable - 0x1: Start bit D/CX added before transfer.
+const TUint MCSPI_CHxCONF_FORCE = 1 << 20; // Manual spim_csx assertion to keep spim_csx active between SPI words.
+                                           // (single channel master mode only)- MCSPI_MODULCTRL_SINGLE has to be set
+const TUint MCSPI_CHxCONF_TURBO = 1 << 19; // Turbo mode
+const TUint MCSPI_CHxCONF_IS    = 1 << 18; // Input select- 0x0: (spim_somi), 0x1: (spim_simo) selected for reception
+const TUint MCSPI_CHxCONF_DPE1  = 1 << 17; // Transmission enable for data line 1 (spim_simo) RW 0x1
+const TUint MCSPI_CHxCONF_DPE0  = 1 << 16; // Transmission enable for data line 0 (spim_somi)
+const TUint MCSPI_CHxCONF_DMAR  = 1 << 15; // DMA Read request
+const TUint MCSPI_CHxCONF_DMAW  = 1 << 14; // DMA Write request.
+
+// 13:12 TRM Transmit/receive modes
+const TUint MCSPI_CHxCONF_TRM_TRANSMIT_RECEIVE = 0 << 12;
+const TUint MCSPI_CHxCONF_TRM_RECEIVE_ONLY     = 1 << 12;
+const TUint MCSPI_CHxCONF_TRM_TRANSMIT_ONLY    = 2 << 12;
+// these are to be cleared in the register
+const TUint MCSPI_CHxCONF_TRM_NO_TRANSMIT      = 1 << 12;
+const TUint MCSPI_CHxCONF_TRM_NO_RECEIVE       = 2 << 12;
+
+
+// 11:7 WL SPI word length0
+// values:<0-3> reserved, allowed:<4-31> => word_size = value + 1 (i.e. for 4: word size = 5)
+const TInt KMinSpiWordWidth = 5;
+const TUint MCSPI_CHxCONF_WL_OFFSET = 7;
+#define MCSPI_CHxCONF_WL(x) ( (((x) - 1) & BIT_MASK(0, 5)) << MCSPI_CHxCONF_WL_OFFSET )
+
+const TUint MCSPI_CHxCONF_EPOL_LOW = 1 << 6; // spim_csx polarity 0x0: active high, 0x1: active low
+
+// A programmable clock divider divides the SPI reference clock
+//5:2 CLKD Frequency divider for spim_clk (for master device only)
+const TUint MCSPI_CHxCONF_CLKD_48M   = 0x0 << 2; //0x0: 1    = 48 MHz
+const TUint MCSPI_CHxCONF_CLKD_24M   = 0x1 << 2; //0x1: 2    = 24 MHz
+const TUint MCSPI_CHxCONF_CLKD_12M   = 0x2 << 2; //0x2: 4    = 12 MHz
+const TUint MCSPI_CHxCONF_CLKD_6M    = 0x3 << 2; //0x3: 8    = 6 MHz
+const TUint MCSPI_CHxCONF_CLKD_3M    = 0x4 << 2; //0x4: 16   = 3 MHz
+const TUint MCSPI_CHxCONF_CLKD_1500k = 0x5 << 2; //0x5: 32   = 1.5 MHz
+const TUint MCSPI_CHxCONF_CLKD_750k  = 0x6 << 2; //0x6: 64   = 750 kHz
+const TUint MCSPI_CHxCONF_CLKD_375k  = 0x7 << 2; //0x7: 128  = 375 kHz
+const TUint MCSPI_CHxCONF_CLKD_187k  = 0x8 << 2; //0x8: 256  = 187.5 kHz
+const TUint MCSPI_CHxCONF_CLKD_93k   = 0x9 << 2; //0x9: 512  = 93.75 kHz
+const TUint MCSPI_CHxCONF_CLKD_46k   = 0xA << 2; //0xA: 1024 = 46.875 kHz
+const TUint MCSPI_CHxCONF_CLKD_23k   = 0xB << 2; //0xB: 2048 = 23.437,5 kHz
+const TUint MCSPI_CHxCONF_CLKD_11k   = 0xC << 2; //0xC: 4096 = 11.718,75 kHz
+const TUint MCSPI_K48MHz = 48000000;
+
+const TUint MCSPI_CHxCONF_POL = 1 << 1; // spim_clk polarity 0x0: active high, 0x1: active low
+const TUint MCSPI_CHxCONF_PHA = 1 << 0; // spim_clk phase
+// 0x0: Data are latched on odd-numbered edges of spim_clk.
+// 0x1: Data are latched on even-numbered edges of spim_clk.
+
+
+//----------------------------------
+// MCSPI_CHxSTAT
+//----------------------------------
+// x = 0 to 3 for MCSPI1.
+// x = 0 to 1 for MCSPI2 and MCSPI3.
+// x = 0 for MCSPI4.
+#define MCSPI_CHxSTAT(x) (0x30 + 0x14 * (x))
+const TUint MCSPI_CHxSTAT_RXFFF = 1 << 6; // Channel x FIFO Receive Buffer Full
+const TUint MCSPI_CHxSTAT_RXFFE = 1 << 5; // Channel x FIFO Receive Buffer Empty
+const TUint MCSPI_CHxSTAT_TXFFF = 1 << 4; // Channel x FIFO Transmit Buffer Full
+const TUint MCSPI_CHxSTAT_TXFFE = 1 << 3; // Channel x FIFO Transmit Buffer Empty
+const TUint MCSPI_CHxSTAT_EOT   = 1 << 2; // Channel x end-of-transfer status.
+const TUint MCSPI_CHxSTAT_TXS   = 1 << 1; // Channel x MCSPI_TXx register status R 0x0
+const TUint MCSPI_CHxSTAT_RXS   = 1 << 0; // Channel x MCSPI_RXx register status R 0x0
+
+
+//----------------------------------
+// MCSPI_CHxCTRL
+//----------------------------------
+// x = 0 to 3 for MCSPI1.
+// x = 0 to 1 for MCSPI2 and MCSPI3.
+// x = 0 for MCSPI4.
+#define MCSPI_CHxCTRL(x) (0x34 + 0x14 * (x))
+//15:8 EXTCLK Clock ratio extension: This register is used to concatenate with RW 0x00
+const TUint MCSPI_CHxCTRL_EXTCLK_1      = 0x00 << 8; //0x0: Clock ratio is CLKD + 1
+const TUint MCSPI_CHxCTRL_EXTCLK_1_16   = 0x01 << 8; //0x1: Clock ratio is CLKD + 1 + 16
+const TUint MCSPI_CHxCTRL_EXTCLK_1_4080 = 0xff << 8; //0xFF: Clock ratio is CLKD + 1 + 4080
+const TUint MCSPI_CHxCTRL_EN            = 0x01 << 0; // Channel enable
+
+
+//----------------------------------
+// MCSPI_TXx - Channel x Data to transmit
+//----------------------------------
+// x = 0 to 3 for MCSPI1.
+// x = 0 to 1 for MCSPI2 and MCSPI3.
+// x = 0 for MCSPI4.
+#define MCSPI_TXx(x)     (0x38 + 0x14 * (x)) // Channel x Data to transmit
+
+
+//----------------------------------
+// MCSPI_RXx - Channel x Received Data
+//----------------------------------
+// x = 0 to 3 for MCSPI1.
+// x = 0 to 1 for MCSPI2 and MCSPI3.
+// x = 0 for MCSPI4.
+#define MCSPI_RXx(x)     (0x3C + 0x14 * (x)) // Channel x Received Data
+
+
+//----------------------------------
+// MCSPI_XFERLEVEL
+//----------------------------------
+const TUint MCSPI_XFERLEVEL = 0x7C;
+const TUint MCSPI_XFERLEVEL_WCNT_OFFSET = 16; // [31:16] WCNT Spi word counter -> how many bytes are transfered to FIFO before tx is enabled
+const TUint MCSPI_XFERLEVEL_AFL_OFFSET  = 8;  // 13:8 AFL Buffer Almost Full. 0x0: One byte , 0x1: 2 bytes, x3E: 63 bytes.. etc
+const TUint MCSPI_XFERLEVEL_AEL_OFFSET  = 0;  // 5:0 AEL Buffer Almost Empty (threshold?) 0x0: One byte. 0x1: 2 bytes..
+
+#define MCSPI_XFERLEVEL_WCNT(x) ((x)  << MCSPI_XFERLEVEL_WCNT_OFFSET)
+#define MCSPI_XFERLEVEL_AFL(x)  (((x) << MCSPI_XFERLEVEL_AFL_OFFSET))
+#define MCSPI_XFERLEVEL_AEL(x)  (((x) << MCSPI_XFERLEVEL_AEL_OFFSET))
+
+
+//----------------------------------
+// PAD (PIN) configuration for SPI
+//----------------------------------
+const TUint KMaxSpiChannelsPerModule = 4; // there are max 4 channels (McSPI 1)
+
+struct TPinConfig
+	{
+	TLinAddr              iAddress;
+	SCM::TLowerHigherWord iMswLsw;
+	TUint8                iPinNumber;
+	TUint16               iFlags;
+	};
+
+struct TSpiPinConfig
+	{
+	TPinConfig iClk;
+	TPinConfig iSimo;
+	TPinConfig iSomi;
+	TPinConfig iCs[KMaxSpiChannelsPerModule];
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi1 =
+	{
+	{CONTROL_PADCONF_MCSPI1_CLK,  SCM::ELsw, 171, SCM::EMode0 | SCM::EInputEnable}, // mcspi1_clk
+	{CONTROL_PADCONF_MCSPI1_CLK,  SCM::EMsw, 172, SCM::EMode0 | SCM::EInputEnable}, // mcspi1_simo
+	{CONTROL_PADCONF_MCSPI1_SOMI, SCM::ELsw, 173, SCM::EMode0 | SCM::EInputEnable}, // mcspi1_somi
+		{
+		{CONTROL_PADCONF_MCSPI1_SOMI, SCM::EMsw, 174, SCM::EMode0}, // mcspi1_cs0
+		{CONTROL_PADCONF_MCSPI1_CS1,  SCM::ELsw, 175, SCM::EMode0}, // mcspi1_cs1
+		{CONTROL_PADCONF_MCSPI1_CS1,  SCM::EMsw, 176, SCM::EMode0}, // mcspi1_cs2
+		{CONTROL_PADCONF_MCSPI1_CS3,  SCM::ELsw, 177, SCM::EMode0}, // mcspi1_cs3
+		}
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi2 =
+	{
+	{CONTROL_PADCONF_MCSPI1_CS3,  SCM::EMsw, 178, SCM::EMode0 | SCM::EInputEnable}, // mcspi2_clk
+	{CONTROL_PADCONF_MCSPI2_SIMO, SCM::ELsw, 179, SCM::EMode0 | SCM::EInputEnable}, // mcspi2_simo
+	{CONTROL_PADCONF_MCSPI2_SIMO, SCM::EMsw, 180, SCM::EMode0 | SCM::EInputEnable}, // mcspi2_somi
+		{
+		{CONTROL_PADCONF_MCSPI2_CS0, SCM::ELsw, 181, SCM::EMode0}, // mcspi2_cs0
+		{CONTROL_PADCONF_MCSPI2_CS0, SCM::EMsw, 182, SCM::EMode0}, // mcspi2_cs1
+		{0, SCM::ELsw, 0, 0}, // not supported
+		{0, SCM::ELsw, 0, 0}, // not supported
+		}
+	};
+
+// McSPI3 supports 3 different pin routing settings
+const TSpiPinConfig TSpiPinConfigMcSpi3_0 =
+	{
+	{CONTROL_PADCONF_MMC2_CLK,  SCM::ELsw, 130, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_clk
+	{CONTROL_PADCONF_MMC2_CLK,  SCM::EMsw, 131, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_simo
+	{CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, 132, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_somi
+		{
+		{CONTROL_PADCONF_MMC2_DAT2, SCM::EMsw, 135, SCM::EMode1}, // mcspi3_cs0
+		{CONTROL_PADCONF_MMC2_DAT2, SCM::ELsw, 134, SCM::EMode1}, // mcspi3_cs1
+		{0, SCM::ELsw, 0, 0}, // not supported
+		{0, SCM::ELsw, 0, 0}, // not supported
+		}
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi3_1 =
+	{
+	{CONTROL_PADCONF_DSS_DATA18, SCM::ELsw, 88, SCM::EMode2 | SCM::EInputEnable}, // mcspi3_clk
+	{CONTROL_PADCONF_DSS_DATA18, SCM::EMsw, 89, SCM::EMode2 | SCM::EInputEnable}, // mcspi3_simo
+	{CONTROL_PADCONF_DSS_DATA20, SCM::ELsw, 90, SCM::EMode2 | SCM::EInputEnable}, // mcspi3_somi
+		{
+		{CONTROL_PADCONF_DSS_DATA20, SCM::EMsw, 91, SCM::EMode2}, // mcspi3_cs0
+		{CONTROL_PADCONF_DSS_DATA22, SCM::ELsw, 92, SCM::EMode2}, // mcspi3_cs1
+		{0, SCM::ELsw, 0, 0}, // not supported
+		{0, SCM::ELsw, 0, 0}, // not supported
+		}
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi3_2 =
+	{
+	{CONTROL_PADCONF_ETK_D2, SCM::EMsw, 17, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_clk
+	{CONTROL_PADCONF_ETK_D0, SCM::ELsw, 14, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_simo
+	{CONTROL_PADCONF_ETK_D0, SCM::EMsw, 15, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_somi
+		{
+		{CONTROL_PADCONF_ETK_D2, SCM::ELsw, 16, SCM::EMode1}, // mcspi3_cs0
+		{CONTROL_PADCONF_ETK_D6, SCM::EMsw, 21, SCM::EMode1}, // mcspi3_cs1
+		{0, SCM::ELsw, 0, 0}, // not supported
+		{0, SCM::ELsw, 0, 0}, // not supported
+		}
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi4 =
+	{
+	{CONTROL_PADCONF_MCBSP1_CLKR, SCM::ELsw, 156, SCM::EMode1 | SCM::EInputEnable}, // mcspi4_clk
+	{CONTROL_PADCONF_MCBSP1_DX,   SCM::ELsw, 158, SCM::EMode1 | SCM::EInputEnable}, // mcspi4_simo
+	{CONTROL_PADCONF_MCBSP1_DX,   SCM::EMsw, 159, SCM::EMode1 | SCM::EInputEnable}, // mcspi4_somi
+		{
+		{CONTROL_PADCONF_MCBSP_CLKS, SCM::EMsw, 161, SCM::EMode1}, // mcspi3_cs0
+		{0, SCM::ELsw, 0, 0}, // not supported
+		{0, SCM::ELsw, 0, 0}, // not supported
+		{0, SCM::ELsw, 0, 0}, // not supported
+		}
+	};
+
+const TSpiPinConfig ModulePinConfig[] =
+	{
+	TSpiPinConfigMcSpi1,
+	TSpiPinConfigMcSpi2,
+	TSpiPinConfigMcSpi3_0, // (default mode for McSPI3 - SPI addresses: 0 and 1)
+	TSpiPinConfigMcSpi4,
+	TSpiPinConfigMcSpi3_1, // other pin mode for McSPI3.. (spi addresses: 2 and 3)
+	TSpiPinConfigMcSpi3_2  // other pin mode for McSPI3.. (spi addresses: 4 and 5)
+	};
+
+
+#include "omap3530_spi.inl"
+
+
+#endif /* __OMAP3530_SPI_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/omap3530_spi.inl	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,156 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+// Description:
+// omap3530/omap3530_drivers/spi/omap3530_spi.inl
+//
+// This file contains definitions to internal SPI implementation.
+// It is not intended to be exported - SPI registers must not be modified from outside of
+// the driver!
+//
+
+
+// This sets the CS line to inactive mode (Specify aActiveMode as appropriate for configuration)
+// The CS pin will be put back to the opposite mode - using GPIO.. THis is in order to always keep
+// the CS line in an 'inactive' state (de-asserted) when the SPI is disabled.
+inline void SetCsInactive(TInt aModule, TInt aChannel, TSpiSsPinMode aActiveMode, TUint aPinSetId = 0)
+	{
+	__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	__ASSERT_DEBUG( aModule != 2 ? !aPinSetId : ETrue, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // only channel 3 supports other pin configurations
+
+	// set the pin to the opposite to the currently active CS mode..
+	const TPinConfig& csConf = ModulePinConfig[aModule + aPinSetId].iCs[aChannel];
+	__ASSERT_DEBUG(csConf.iAddress, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // don't try to use non-existing CS!
+
+	// now switch the pin mode..(making sure it is at the proper level before that)
+	GPIO::SetOutputState(csConf.iPinNumber, aActiveMode == ESpiCSPinActiveLow ? GPIO::EHigh : GPIO::ELow);
+	SCM::SetPadConfig(csConf.iAddress, csConf.iMswLsw, SCM::EMode4); // always go to mode 4 (gpio)
+	}
+
+
+inline void SetCsActive(TInt aModule, TInt aChannel, TUint aPinSetId = 0)
+	{
+	__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	__ASSERT_DEBUG( aModule != 2 ? !aPinSetId : ETrue, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // only channel 3 supports other pin configurations
+
+	const TPinConfig &csConf = ModulePinConfig[aModule + aPinSetId].iCs[aChannel];
+	__ASSERT_DEBUG(csConf.iAddress, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // don't try to use non-existing CS!
+
+	// now switch the pin mode back to the SPI
+	SCM::SetPadConfig(csConf.iAddress, csConf.iMswLsw, csConf.iFlags);
+	}
+
+
+// Setup pad function for SPI pins..
+inline void SetupSpiPins(TUint aModule, TUint aPinSetId = 0)
+	{
+	__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	__ASSERT_DEBUG(aModule != 2 ? !aPinSetId : ETrue, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // only channel 3 supports other pin configurations
+
+	const TSpiPinConfig& pinCnf = ModulePinConfig[aModule + aPinSetId];
+
+	SCM::SetPadConfig(pinCnf.iClk.iAddress, pinCnf.iClk.iMswLsw, pinCnf.iClk.iFlags);
+	SCM::SetPadConfig(pinCnf.iSimo.iAddress, pinCnf.iSimo.iMswLsw, pinCnf.iSimo.iFlags);
+	SCM::SetPadConfig(pinCnf.iSomi.iAddress, pinCnf.iSomi.iMswLsw, pinCnf.iSomi.iFlags);
+
+	// Setup GPIO mode/direction for all CS pins only once - here.
+	for(TInt i = 0; i < KMaxSpiChannelsPerModule; i++)
+		{
+		if(pinCnf.iCs[i].iPinNumber)
+			{
+			// pre-set the GPIO..
+			GPIO::SetPinDirection(pinCnf.iCs[i].iPinNumber, GPIO::EOutput);
+			GPIO::SetPinMode(pinCnf.iCs[i].iPinNumber, GPIO::EEnabled);
+			}
+		else
+			{
+			break; // no more channels (cs signals)
+			}
+		}
+	}
+
+// McSPI3 can have 3 different pin configuration, but only one can be active at the time.
+// for that reason, before switching to different mode -at least SOMI has to be deactivated
+// otherwise the newly activated pin does not work (why??). Changing these pins to the GPIO (mode 4)
+inline void DeactivateSpiPins(TUint aModule, TUint aPinSetId = 0)
+	{
+	__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	__ASSERT_DEBUG(aModule != 2 ? !aPinSetId : ETrue, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // only channel 3 supports other pin configurations
+
+	const TSpiPinConfig& pinCnf = ModulePinConfig[aModule + aPinSetId];
+
+	SCM::SetPadConfig(pinCnf.iClk.iAddress, pinCnf.iClk.iMswLsw, SCM::EMode4 | SCM::EInputEnable);
+	SCM::SetPadConfig(pinCnf.iSimo.iAddress, pinCnf.iSimo.iMswLsw, SCM::EMode4 | SCM::EInputEnable);
+	SCM::SetPadConfig(pinCnf.iSomi.iAddress, pinCnf.iSomi.iMswLsw, SCM::EMode4 | SCM::EInputEnable);
+	}
+
+
+// helper function - returns appropriate value for the register for a given mode
+inline TUint32 SpiClkMode(TSpiClkMode aClkMode)
+	{
+	// (POL) (PHA)
+	//	0     0     Mode 0: spim_clk is active high and sampling occurs on the rising edge.
+	//	0     1     Mode 1: spim_clk is active high and sampling occurs on the falling edge.
+	//	1     0     Mode 2: spim_clk is active low and sampling occurs on the falling edge.
+	//	1     1     Mode 3: spim_clk is active low and sampling occurs on the rising edge.
+
+	TUint val = 0;
+	switch(aClkMode)
+		{
+		//case ESpiPolarityLowRisingEdge:	// Active high, odd edges
+			/*val |= MCSPI_CHxCONF_POL;*/ // 0 (not set)
+			/*val |= MCSPI_CHxCONF_PHA;*/ // 0 (not set)
+			//break; // commented out - it's only for  reference - there's nothing to change
+
+		case ESpiPolarityLowFallingEdge: // Active high, even edges
+			/*val |= MCSPI_CHxCONF_POL;*/ // 0 (not set)
+			val |= MCSPI_CHxCONF_PHA;     // 1
+			break;
+
+		case ESpiPolarityHighFallingEdge: // Active low,  odd edges
+			val |= MCSPI_CHxCONF_POL;     // 1
+			/*val |= MCSPI_CHxCONF_PHA;*/ // 0 (not set)
+			break;
+
+		case ESpiPolarityHighRisingEdge: // Active low,  even edges
+			val |= MCSPI_CHxCONF_POL; // 1
+			val |= MCSPI_CHxCONF_PHA; // 1
+			break;
+		}
+	return val;
+	}
+
+// helper function - returns appropriate value for the register for a given frequency (or error->if not found)
+inline TInt SpiClkValue(TInt aClkSpeedHz)
+	{
+	for (TInt val = 0; val < 0xD; val++) // only loop through all possible values..
+		{
+		if(MCSPI_K48MHz >> val == aClkSpeedHz)
+			{
+			return (val << 2); // return value ready for the register
+			}
+		}
+	return KErrNotFound;
+	}
+
+inline TInt SpiWordWidth(TSpiWordWidth aWidth)
+	{
+	TInt val = 0;
+	switch(aWidth)
+		{
+		case ESpiWordWidth_8:  val |= MCSPI_CHxCONF_WL(8); break;
+		case ESpiWordWidth_10: val |= MCSPI_CHxCONF_WL(10); break;
+		case ESpiWordWidth_12: val |= MCSPI_CHxCONF_WL(12); break;
+		case ESpiWordWidth_16: val |= MCSPI_CHxCONF_WL(16); break;
+//		case ESpiWordWidth_32: val |= MCSPI_CHxCONF_WL(32); break; // TODO uncomment when fix for Bug 3665 is released
+		}
+	return val;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/psl_init.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,156 @@
+// Copyright (c) 2010 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/psl_init.cpp
+//
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+
+#include "psl_init.h"
+
+#ifdef MASTER_MODE
+#include "master.h"
+#endif
+#ifdef SLAVE_MODE
+#include "slave.h"
+#endif
+
+#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
+#error "Should select at least one type of SPI channels.."
+#endif
+
+DECLARE_STANDARD_EXTENSION()
+	{
+	// Array of pointers to the Channels that the PSL creates, for registration with the Bus Controller
+	// Use a local array, since the IIC Controller operates on a copy of the array entries.
+	DIicBusChannel* channelPtrArray[KIicPslNumOfChannels];
+
+	TInt r = KErrNone;
+
+#ifdef MASTER_MODE
+#ifndef SLAVE_MODE
+	// If only MASTER_MODE is declared - Create only DIicBusChannelMasterPsl channels
+	__KTRACE_OPT(KIIC, Kern::Printf("\n\nCreating DIicBusChannelMasterPsl only\n"));
+
+	DIicBusChannel* chan = NULL;
+	for (TInt i = 0; i < KIicPslNumOfChannels; ++i)
+		{
+		// The first argument repesents the PSL-assigned channel number
+		// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+//		chan = DSpiMasterBeagle::New(i, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+		if((TInt)KIicPslNumOfChannels == 2)// TODO: hack - only for the time being - enable channel 3
+			chan = DSpiMasterBeagle::New(i+2, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+		else
+			{
+			Kern::Printf("remove hack from here: %s,line %d", __FILE__, __LINE__);
+			return KErrGeneral;
+			}
+
+		if (!chan)
+			{
+			return KErrNoMemory;
+			}
+		channelPtrArray[i] = chan;
+		}
+
+#else /*SLAVE_MODE*/
+	// Master and Slave functionality is available, so create Master, Slave and MasterSlave Channels
+	// Create channel 0 as Master, channel 1 as a Slave, and channel 2 as MasterSlave.
+	__KTRACE_OPT(KIIC, Kern::Printf("\n\nCreating Master, Slave and MasterSlave channels\n"));
+
+	DIicBusChannel* chan = NULL;
+
+	// Master channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chan = DSpiMasterBeagle::New(0, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chan)
+		{
+		return KErrNoMemory;
+		}
+	channelPtrArray[0] = chan;
+
+	// Slave channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chan = DSpiSlaveBeagle::New(1, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chan)
+		{
+		return KErrNoMemory;
+		}
+	channelPtrArray[1] = chan;
+
+	// MasterSlave channel
+	// MasterSlave channels are not for derivation; instead, they have a pointer to a (derived) Master channel
+	// and a pointer to a (derived) Slave channel
+	DIicBusChannel* chanM = NULL;
+	DIicBusChannel* chanS = NULL;
+	// For MasterSlave channel, the channel number for both the Master and Slave channels must be the same
+	TInt msChanNum = 2;
+	// Master channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chanM = DSpiMasterBeagle::New(msChanNum, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chanM)
+		{
+		return KErrNoMemory;
+		}
+	// Slave channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chanS = DSpiSlaveBeagle::New(msChanNum, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chanS)
+		{
+		return KErrNoMemory;
+		}
+	// MasterSlave channel
+	// The first argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chan = new DIicBusChannelMasterSlave(DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex, (DIicBusChannelMaster*)chanM, (DIicBusChannelSlave*)chanS);
+	if (!chan)
+		{
+		return KErrNoMemory;
+		}
+	r = ((DIicBusChannelMasterSlave*)chan)->DoCreate();
+	channelPtrArray[2] = chan;
+
+
+#endif /*SLAVE_MODE*/
+#else /*MASTER_MODE*/
+
+#ifdef SLAVE_MODE
+	// If only SLAVE_MODE is declared - Create all as DSpiSlaveBeagle channels
+	__KTRACE_OPT(KIIC, Kern::Printf("\n\nCreating DSpiSlaveBeagle only\n"));
+
+	DIicBusChannel* chan = NULL;
+	for (TInt i = 0; i < KIicPslNumOfChannels; ++i)
+		{
+		// The first argument repesents the PSL-assigned channel number
+		// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+		chan = DSpiSlaveBeagle::New(i, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+		if (!chan)
+			{
+			return KErrNoMemory;
+			}
+		channelPtrArray[i] = chan;
+		}
+
+#endif
+#endif /*MASTER_MODE*/
+
+	// Register them with the Bus Controller
+	r = DIicBusController::RegisterChannels(channelPtrArray, KIicPslNumOfChannels);
+
+	return r;
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/psl_init.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/psl_init.h
+//
+
+
+#ifndef __OMAP3530_SPI_PSL_H__
+#define __OMAP3530_SPI_PSL_H__
+
+const TInt KIicPslNumOfChannels = 2; // Number of channels supported // TODO only two 3 and 4 for now..
+// FIXME - there is a crash when using channels 1 and 2 - when accesing registers at e.g. 0xc609a000
+
+struct TIicOperationType
+    {
+    enum TOperation
+        {
+        ENop             = 0x00,
+        ETransmitOnly    = 0x01,
+        EReceiveOnly     = 0x02,
+        ETransmitReceive = 0x03
+        };
+
+    struct TOp
+        {
+        TUint8 iIsTransmitting : 1;
+        TUint8 iIsReceiving    : 1;
+        TUint8 iRest           : 6;
+        };
+
+    union
+        {
+        TOp iOp;
+        TUint8 iValue;
+        };
+    };
+
+#endif /*__OMAP3530_SPI_PSL_H__*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/slave.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,804 @@
+// Copyright (c) 2010 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/slave.cpp
+//
+
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include "psl_init.h"
+#include "slave.h"
+
+#error "Trying to use the SPI slave, but it's not implemented yet!"
+
+// The timeout period to wait for a response from the client, expressed in milliseconds
+// This is converted to timer ticks by the PIL, so the maximum value is 2147483.
+// The value should be selected to allow for the longest, slowest transfer
+// const TInt KClientWaitTime = 2; // 2mS, when debugging might set up to KMaxWaitTime
+
+
+// In an SMP system, use a spin lock to guard access to member variables iTrigger and iInProgress
+#ifdef __SMP__
+static TSpinLock IicPslSpinLock = TSpinLock(TSpinLock::EOrderGenericIrqLow3);
+#endif
+
+// Callback function for the iHwGuardTimer timer.
+//
+// Called in ISR context if the iHwGuardTimer expires. Sets iTransactionStatus to KErrTimedOut
+//
+void DSpiSlaveBeagle::TimeoutCallback(TAny* aPtr)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::TimeoutCallback"));
+	DSpiSlaveBeagle *a = (DSpiSlaveBeagle*) aPtr;
+	a->iTransactionStatus = KErrTimedOut;
+	}
+
+
+// Static method called by the ISR when the Master has ended a transfer
+//
+// The method checks and reports the Rx and Tx status to the PIL by calling NotifyClient with a bitmask described as follows:.
+// - If a Tx transfer has ended before all the data was transmitted, bitmask = (ETxAllBytes | ETxOverrun)
+// - If a Tx transfer has ended and all the data was transmitted, bitmask = ETxAllBytes
+// - If a Rx transfer has ended before the expected amount of data was received, bitmask = (ERxAllBytes | ERxUnderrun)
+// - If a Rx transfer has ended and the expected amount of data was received, bitmask = ERxAllBytes
+//
+void DSpiSlaveBeagle::NotifyClientEnd(DSpiSlaveBeagle* aPtr)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("NotifyClientEnd, iTrigger %x", aPtr->iTrigger));
+
+	// Since a transfer has ended, may wish to disable interrupts at this point
+	// This will likely be supported with calls similar to the following:
+	//		AsspRegister::Write32(aPtr->iChannelBase + KBusInterruptEnableOffset, KIicPslBusDisableBitMask);
+	//		Interrupt::Disable(aPtr->iRxInterruptId);
+	//		Interrupt::Disable(aPtr->iTxInterruptId);
+
+	// iTrigger will have bits ETransmit and EReceive set according to the operation requested in the call to DoRequest
+	// Use variable flag for the bitmask to pass into the PIL method NotifyClient
+	TInt flag = 0;
+	if(aPtr->iTrigger & EReceive)
+		{
+		// Requested Rx operation has ended - check for RxUnderrun
+		flag = ERxAllBytes;
+		if(aPtr->iRxDataEnd != aPtr->iRxData)
+			{
+			flag |= ERxUnderrun;
+			}
+		}
+	if(aPtr->iTrigger & ETransmit)
+		{
+		// Requested Tx operation has ended - check for RxOverrun
+		flag |= ETxAllBytes;
+		if(aPtr->iTxDataEnd != aPtr->iTxData)
+			{
+			flag |= ETxOverrun;
+			}
+		}
+	aPtr->NotifyClient(flag);
+	}
+
+
+// ISR Handler
+//
+// The ISR handler identifies the cause of the interrupt that lead to its invocation:
+// if the cause was transfer-related, it calls the PIL function NotifyClient to report a summary of the transfer status;
+// if the cause was completion of asynchronous channel capture, PIL function ChanCaptureCallback is called
+//
+// The ISR also clears the source of the interrupt, and (for transfer-related interrupts) transfers the next data
+// between buffers and the hardware and updates the member variable iInProgress to indicate if a transfer has started or
+// ended. If a transfer has ended before the expected amount of data has been transfered it calls function NotifyClientEnd.
+//
+void DSpiSlaveBeagle::IicPslIsr(TAny* /*aPtr*/)
+	{
+	//		DSpiSlaveBeagle *a = (DSpiSlaveBeagle*) aPtr;
+
+	//		TInt intState = 0;	// Variable to support use of spin lock
+
+	//		TInt trigger = 0; // Record the Rx and Tx transfers
+
+	//		TUint32 intStatus = 0; // Record of the interrupts that are being reported
+
+	// Identify the cause of the interrupt. If this can be achieved by reading a single register,
+	// code similar to the following could be used:
+	//		intStatus = AsspRegister::Read32(a->iChannelBase + KIntStatusOffset);
+
+	// Optional (not required if asynchronous channel capture is not supported)
+	// If the cause of the interrupt is completion of asynchronous channel capture, the ISR will check the appropriate
+	// indicator for confirmation of success - for a real PSL, this may be by querying a bitmask in a register. For the template PSL,
+	// however, a dummy member variable (iAsyncConfig) has been used to represent the asynchronous operation instead.
+	//
+	//		if(iAsyncConfig == 1)	// Replace with a check of the indicator that the interrupt was due to asynchrous channel capture
+	//			{
+	//			// The PIL function ChanCaptureCallback is now to be invoked. It takes as an argument either KErrNone or a
+	//			// system-wide error code to indicate the cause of failure. For a real PSL, the argument would likely be determined
+	//			// by reading a bitmask in a status register - but for the template port, just use KErrNone.
+	//			//
+	//			a->ChanCaptureCallback(KErrNone);
+	//			return;
+	//			}
+
+	// If an interrupt indicates that a transfer has started, or that it has now ended, (such as a chip select
+	// line transition for a SPI bus the member variable iInProgress should be modified accordingly. This should
+	// be done under the guard of spin lock macros since iInProgress can be accessed in the context of the Client
+	// thread (in DoRequest, ProcessData and InitTransfer). The following structure should be adopted:
+	//		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	//		<access a->iInProgress>
+	//		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+	//
+	// If a transfer has ended before the expected amount of data has been transfered, function NotifyClientEnd
+	// should be called, as follows:
+	//		a->NotifyClientEnd(a);
+	//		return;	// Return now - the interrupt indicated transfer end, not receipt or transmission of data.
+
+	// The transfers that had been started are indicated by the bitmask held in member variable iTrigger.
+	// This must be accessed under the guard of a spin lock since it can be accessed in the context of the
+	// Client thread (in DoRequest, ProcessData and InitTransfer). The following structure should be adopted:
+	//		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	//		trigger = a->iTrigger;
+	//		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	// If the interrupt was raised for a Tx event, and a Tx transfer had been started (so the interrupt was not spurious)
+	// then either prepare the next data to send, or, if all the data has been sent, call the PIL function NotifyClient
+	// with bitmask (ETxAllBytes | ETxUnderrun) so that, if the Client specified a ETxUnderrun notification, it will be alerted
+	// and can determine whether another buffer of data should be provide for transmission.
+	// Code similar to the following could be used:
+	//		if(intStatus & KTxInterruptBitMask)
+	//			{
+	//			if(trigger & ETransmit)
+	//				{
+	//				// Interrupt was not spurious
+	//				if(a->iTxData == a->iTxDataEnd)
+	//					{
+	//					// All the data to be transmitted has been sent, so call the PIL method NotifyClient
+	//					a->NotifyClient(ETxAllBytes | ETxUnderrun);
+	//					}
+	//				else
+	//					{
+	//					// There is more data to be sent
+	//					// TUint8 nextTxValue = *iTxData;	// For this example, assumes one byte of data is to be transmitted
+	//														// but if operating in 16-bit mode, bytes may need arranging for
+	//														// endianness
+	//
+	//					// Write to the Tx register with something similar to the following:
+	//					//		AsspRegister::Write32(iChannelBase + KTxFifoOffset, nextTxValue);
+	//
+	//					iTxData += iWordSize;	// Then increment the pointer to the data. In this example, 8-bit mode is assumed
+	//											// (iWordSize=1), but if operating in 16-bit mode iTxData would be incremented
+	//											// by the number of bytes specified in iWordSize
+	//					}
+	//				}
+	//			}
+
+	// If the interrupt was raised for a Rx event, and a Rx transfer had been started (so the interrupt was not spurious)
+	// read the received data from the hardware to the buffer. If a Rx FIFO is being used, use a loop to drain it - until
+	// the FIFO is empty or the buffer is full. If data remains after the buffer is full, an RxOverrun condition has occurred
+	// - so the PIL function NotifyClient should be called with bitmask (ERxAllBytes | ERxOverrun) so that, if the Client specified
+	// a ERxOverrun notification, it will be alerted and can determine whether another buffer should be provided to continue reception.
+	// Code similar to the following could be used:
+	//		if(intStatus & KRxInterruptBitMask)
+	//			{
+	//			if(trigger & EReceive)
+	//				{
+	//				// Interrupt was not spurious
+	//				while(AsspRegister::Read32(a->iChannelBase + KRxFifoLevelOffset))
+	//					{
+	//					if((a->iRxData - a->iRxDataEnd) >= a->iWordSize)
+	//						{
+	//						// Space remains in the buffer, so copy the received data to it
+	//						TUint8 nextRxValue = AsspRegister::Read32(a->iChannelBase + KRxFifoOffset);
+	//						*a->iRxData = nextRxValue;	// For this example, assumes one byte of data is to be transmitted
+	//													// but if operating in 16-bit mode, bytes may need arranging for
+	//													// endianness
+	//
+	//						a->iRxData += a->iWordSize;	// Then increment the pointer to the data. In this example, 8-bit mode is assumed
+	//													// (iWordSize=1), but if operating in 16-bit mode iRxData would be incremented
+	//													// by the number of bytes specified in iWordSize
+	//						}
+	//					else
+	//						{
+	//						// The buffer is full but more data has been received - so there is an RxOverrun condition
+	//						// Disable the hardware from receiving any more data and call the PIL function NotifyClient
+	//						// with bitmask (ERxAllBytes | ERxOverrun).
+	//						AsspRegister::Write32(a->iChannelBase + KRxFifoControl, KRxFifoDisableBitMask);
+	//						a->NotifyClient(ERxAllBytes | ERxOverrun);
+	//						break;
+	//						}
+	//					}
+	//				}
+	//			else
+	//				{
+	//				// If the interrupt was spurious, ignore the data, and reset the FIFO
+	//				AsspRegister::Write32(a->iChannelBase + KRxFifoControl, KRxFifoClearBitMask);
+	//				}
+
+	// Once the interrupts have been processed, clear the source. If this can be achieve by writing to
+	// a single register, code similar to the following could be used:
+	//		AsspRegister::Write32(a->iChannelBase + KIntStatusOffset, KAIntBitMask);
+
+	}
+
+
+// Constructor, first stage
+//
+// The PSL is responsible for setting the channel number - this is passed as the first parameter to
+// this overload of the base class constructor
+//
+DSpiSlaveBeagle::DSpiSlaveBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
+	DIicBusChannelSlave(aBusType, aChanDuplex, 0),	// Base class constructor. Initalise channel ID to zero.
+	iHwGuardTimer(TimeoutCallback, this)			// Timer to guard against hardware timeout
+	{
+	iChannelNumber = aChannelNumber;
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::DSpiSlaveBeagle, iChannelNumber = %d\n", iChannelNumber));
+	}
+
+
+// Second stage construction
+//
+// Allocate and initialise objects required by the PSL channel implementation
+//
+TInt DSpiSlaveBeagle::DoCreate()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("\nDSpiSlaveBeagle::DoCreate, ch: %d \n", iChannelNumber));
+
+	TInt r = KErrNone;
+
+	// PIL Base class initialization.
+	r = Init();
+	if(r == KErrNone)
+		{
+		// At a minimum, this function must set the channel's unique channel ID.
+		// When the channel is captured, this value will be combined with an instance count
+		// provided by the PIL to generate a value that will be used by a client as a unique
+		// identifer in subsequent calls to the Slave API.
+		//
+		// There is no set format for the ID, it just needs to be unique.
+		// Un-comment and complete the following line:
+//		iChannelId =
+
+		// This method may also be concerned with setting the base register address iChannelBase), and allocating
+		// any objects that will be required to support operaton until the channel is deleted.
+		//
+		// Un-comment and complete the following line:
+//		iChannelBase =
+		}
+	return r;
+	}
+
+// static method used to construct the DSpiSlaveBeagle object.
+DSpiSlaveBeagle* DSpiSlaveBeagle::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::NewL(): aChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
+	DSpiSlaveBeagle *pChan = new DSpiSlaveBeagle(aChannelNumber, aBusType, aChanDuplex);
+
+	TInt r = KErrNoMemory;
+	if (pChan)
+		{
+		r = pChan->DoCreate();
+		}
+	if (r != KErrNone)
+		{
+		delete pChan;
+		pChan = NULL;
+		}
+
+	return pChan;
+	}
+
+
+// Validates the configuration information specified by the client when capturing the channel
+//
+// Called by the PIL as part of the Slave CaptureChannel processing
+//
+// If the pointer to the header is NULL, return KErrArgument.
+// If the content of the header is not valid for this channel, return KErrNotSupported.
+//
+TInt DSpiSlaveBeagle::CheckHdr(TDes8* aHdrBuff)
+	{
+	TInt r = KErrNone;
+
+	if(!aHdrBuff)
+		{
+		r = KErrArgument;
+		}
+	else
+		{
+		// Check that the contents of the header are valid
+		//
+		// The header will be specific to a particular bus type. Using a fictional
+		// bus type Abc,code similar to the following could be used to validate each
+		// member of the header:
+		//
+		//		TConfigAbcBufV01* headerBuf = (TConfigAbcBufV01*) aHdrBuff;
+		//		TConfigAbcV01 &abcHeader = (*headerBuf)();
+		//		if(	(abcHeader.iHeaderMember < ESomeMinValue)	||
+		//			(abcHeader.iHeaderMember > ESomeMaxValue))
+		//			{
+		//			__KTRACE_OPT(KIIC, Kern::Printf("iHeaderMember %d not supported",abcHeader.iHeaderMember));
+		//			r = KErrNotSupported;
+		//			}
+
+		}
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::CheckHdr() r %d", r));
+
+	return r;
+	}
+
+
+// Method called in the context of the client thread, as a consequence of the PSL invocation of the
+// PIL method NotifyClient when a bus event occurs.
+//
+// This method updates the bitmask of requested operations (held in member variable iTrigger) and the
+// PIL counts of data received and transmitted. If the event was a bus error, the bitmask of requested operations
+// is cleared.
+//
+void DSpiSlaveBeagle::ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::ProcessData(), trigger: %x\n", aTrigger));
+
+	TInt intState;
+
+	// If using the iInProgress member variable to indicate transitions on a chip-select line, and an interrupt
+	// occurred as a transfer was to end, then must ensure the transmission of data has ceased.
+	//
+	// Must use spin lock to guard access since iInProgress is accessed by the ISR
+	//
+	TInt inProgress;
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	inProgress = iInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+	//
+	if(!inProgress &&								// Transfer has now ended
+	   (aTrigger & (ERxAllBytes | ETxAllBytes)))	// Master has not yet finished transferring data
+		{
+		// Use the guard timer to make sure that transfer ends with an expected time - if this does not cease
+		// before the timer expires, iTransactionStatus will be set to KErrTimedOut by the callback function TimeoutCallback
+		//
+		// Poll the relevant register to check for transfer activity, using code similar to the following:
+		//		TInt8 transferring = AsspRegister::Read32(iChannelBase + KStatusRegisterOffset) & KTransferringBitMask);
+		// For the template port, use a dummy variable instead of the register access (transferring = 1)
+		//
+		TInt8 transferring = 1;
+		iTransactionStatus = KErrNone;
+		iHwGuardTimer.OneShot(NKern::TimerTicks(KTimeoutValue));
+
+		while((iTransactionStatus == KErrNone) &&
+		      transferring);		// Replace transferring with a register read, as described above
+
+		// At this point, either the transfer has ceased, or the timer expired - in either case, may disable the interrupt
+		// for the transfer now, using code similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KIntEnableRegisterOffset, KIntDisableBitMask);
+
+		// Check for guard timer expiry
+		if(iTransactionStatus != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::ProcessData - Transaction timed-out"));
+			return;
+			}
+		else
+			{
+			iHwGuardTimer.Cancel();
+			}
+
+		// If all transfer activity has now ceased, clear iTrigger
+		// Must use spin lock to guard access since iInProgress is accessed by the ISR
+		//
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger = 0;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	// If the PSL called the PIL function NotifyClient to indicate transfer activity (or error), the reason
+	// will be specified as a bitmask in aTrigger
+	//  - if a Rx event occurred, the ERxAllBytes flag will be set
+	//  - if a Tx event occurred, the ETxAllBytes flag will be set
+	//  - if a bus error occurred, the EGeneralBusError flag will be set
+	//
+	if(aTrigger & ERxAllBytes)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Rx Buf:    %x\n", iRxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Rx Bufend: %x\n", iRxDataEnd));
+
+		// Clear the internal EReceive flag
+		// This must be done under guard of a spin lock since iTrigger is accessed by the ISR
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger &= ~EReceive;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+		// Update the PIL count of Rx data (in the Callback object)
+		aCb->SetRxWords(iNumRxWords - ((iRxDataEnd - iRxData) / iWordSize));
+		}
+	//
+	if(aTrigger & ETxAllBytes)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Tx Buf:    %x\n", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Tx Bufend: %x\n", iTxDataEnd));
+
+		// Clear the internal ETransmit flag..
+		// This must be done under guard of a spin lock since iTrigger is accessed by the ISR
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger &= ~ETransmit;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+		// Update the PIL count of Tx data (in the Callback object)
+		aCb->SetTxWords(iNumTxWords - ((iTxDataEnd - iTxData) / iWordSize));
+		}
+	//
+	if(aTrigger & EGeneralBusError)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("BusError.."));
+
+		// Clear and disable relevant interrupts, possibly using code similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KIntEnableRegisterOffset, KIntDisableBitMask);
+
+		// Clear internal flags
+		// This must be done under guard of a spin lock since iTrigger is accessed by the ISR
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger = 0;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	// Set the callback's trigger, for use by the PIL
+	aCb->SetTrigger(aTrigger | aCb->GetTrigger());
+	}
+
+
+
+// Method to initialise the hardware in accordance with the data provided by the Client
+// in the configuration header when capturing the channel
+//
+// This method is called from DoRequest and is expected to return a value to indicate success
+// or a system wide error code to inform of the failure
+//
+TInt DSpiSlaveBeagle::ConfigureInterface()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
+
+	TInt r = KErrNone;
+
+	// The header is stored in member variable iConfigHeader, and will be specific to a particular bus type.
+	// Using a fictional bus type Abc, code similar to the following could be used to access each
+	// member of the header:
+	//
+	//		TConfigAbcBufV01* headerBuf = (TConfigAbcBufV01*) iConfigHeader;
+	//		TConfigAbcV01 &abcHeader = (*headerBuf)();
+	//		TInt value = abcHeader.iTintMember;
+
+	// Initialising the hardware may be achieved with calls similar to the following:
+	//		AsspRegister::Write32(a->iChannelBase + KBusModeControlOffset, KIicPslModeControlBitMask);
+	//		GPIO::SetPinMode(aPinId, GPIO::EEnabled);
+
+	// Binding an ISR may be achieved with calls similar to the following:
+	//		r = Interrupt::Bind(iRxInterruptId, DSpiSlaveBeagle::IicPslIsr, this);
+	//		r = Interrupt::Bind(iTxInterruptId, DSpiSlaveBeagle::IicPslIsr, this);
+	// Enabling interrupts may be achieved with calls similar to the following:
+	//		r = Interrupt::Enable(iRxInterruptId);
+	//		r = Interrupt::Enable(iTxInterruptId);
+
+	// Modifying a hardware register may not be a zero-delay operation. The member variable iHwGuardTimer could be used to guard a
+	// continuous poll of the hardware register that checks for the required change in the setting; TimeoutCallback is already
+	// assigned as the callback function for iHwGaurdTimer, and it modifies member variable iTransactionStatus to indicate a timeout
+	// - so the two could be used together as follows:
+	//		iTransactionStatus = KErrNone;
+	//		iHwGuardTimer.OneShot(NKern::TimerTicks(KTimeoutValue));
+	//		while((iTransactionStatus == KErrNone) &&
+	//		       AsspRegister::Read32(iChannelBase + KRegisterOffset) & KRegisterFlagBitMask);
+	//		if(iTransactionStatus != KErrNone)
+	//			{
+	//			r = KErrGeneral;
+	//			}
+	//		else
+	//			{
+	//			iHwGuardTimer.Cancel();
+	//			}
+
+	// DoRequest checks the return value so the variable r should be modified in the event of failure with a system-wide error code
+	// for example, if a register could not be modified,
+	//			r = KErrGeneral;
+	//			__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface failed with error %d\n",r));
+	return r;
+	}
+
+
+// Method to start asynchronous initialisation of the hardware, in accordance with the data provided by the Client
+// in the configuration header when capturing the channel. This differs from ConfigureInterface in that it
+// merely starts the initialisation, then returns immediately;
+//
+// The PSL is expected to be implemented as an asynchronous state machine, where events (for example hardware
+// interrupts, or timer expiry) invoke callback functions that advance the state machine to the next state. Once
+// all the required states have been transitioned, so that the PSL part of the CaptureChannel processing is
+// complete, the ISR should be invoked, which will then call PIL method ChanCaptureCallback
+//
+// This method is called from DoRequest and is expected to return a value to indicate success
+// or a system wide error code to inform of the failure
+//
+TInt DSpiSlaveBeagle::AsynchConfigureInterface()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
+
+//	TInt r = KErrNone;	// A real implementation would use this as the return value to indicate success / failure
+
+	// Precisely what processing is done to 'start' the asynchronous processing is entirely platform-specific;
+	// it may be the set-up and activation of a long-running operation that completes asynchronously. Regardless of what
+	// is done, its completion is expected to result in the ISR being run.
+	//
+	// Whatever the operation, there must be some means of the ISR recognising that an asynchronous initialisation has
+	// been performed
+	// In a real PSL, this may be be checking a bitmask in a status register. For the template PSL, however,
+	// a dummy class member will be used (iAsyncConfig)
+	// Since this member will be accessed by the ISR, it should, strictly speaking, be accessed under the guard of a spin lock
+	TInt intState;
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	iAsyncConfig = 1;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	return KErrNone;	// A real implementation would return an indication of success / failure
+	}
+
+// Method called from DoRequest to start Tx and-or Rx transfer.
+//
+// The method will initialise the hardware and pointers used to manage transfers, before returning a value to report success
+// (KErrNone) or a system-wide error code that indicates the cause of failure.
+//
+TInt DSpiSlaveBeagle::InitTransfer()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::InitTransfer()"));
+
+	TInt r = KErrNone;
+
+	// Local copies of member variables that must be accessed in a synchronised manner
+	TInt inProgress;
+	TInt trigger;
+
+	TInt intState;
+
+	// Check if a transfer is already in progress.
+	// If variable iInProgress is being used, this must be determined in a synchronised manner because the ISR modifies it.
+	// Bus types that do not rely on chip-select transitions may use an alternative method to indicate if a transfer is in
+	// progress
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	inProgress = iInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	if(!inProgress)
+		{
+		// If no transfers are in progress, it may be necessary to initialise the hardware to support those that
+		// are being requested. This may include FIFO and interrupt initialisation,
+		//
+		// Initialising the hardware may be achieved with calls similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KBusModeControlOffset, KIicPslModeControlBitMask);
+		//		GPIO::SetPinMode(aPinId, GPIO::EEnabled);
+		}
+
+	// Check the current operations. This must be determined in a synchronised manner because ProcessData
+	// runs in the context of the Client thread and it modifies the value of iTrigger
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	trigger = iTrigger;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	if(trigger & ETransmit)
+		{
+		// If Tx transfers were not previously active, it may be necessary to initialise the Tx hardware here, e.g.
+		//		AsspRegister::Write32(iChannelBase + KBusModeControlOffset, KIicPslTxModeBitMask);
+
+		// Initialise the Tx pointers
+		iTxData = iTxBuf + (iWordSize * iTxOffset);
+		iTxDataEnd = iTxData + (iWordSize * iNumTxWords);
+
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Bufend: %x", iTxDataEnd));
+
+		// If using a FIFO, copy the data to it until either the FIFO is full or all the data has been copied
+		// This could be achieved with something similar to the following lines:
+		//		while(AsspRegister::Read32(iChannelBase + KFifoLevelOffset) <= (KFifoMaxLevel - iWordSize) &&
+		//		      iTxData != iTxDataEnd)
+		// For the template port, will just use a dummy variable (dummyFifoLvlChk )in place of the register read
+		TInt dummyFifoLvlChk = 0;
+		while((dummyFifoLvlChk)	&&	// Replace this dummy variable with a read of the hardware
+			(iTxData != iTxDataEnd))
+			{
+			// TUint8 nextTxValue = *iTxData;	// For this example, assumes one byte of data is to be transmitted
+												// but if operating in 16-bit mode, bytes may need arranging for
+												// endianness
+
+			// Write to the Tx register with something similar to the following:
+			//		AsspRegister::Write32(iChannelBase + KTxFifoOffset, nextTxValue);
+
+			iTxData += iWordSize;	// Then increment the pointer to the data. In this example, 8-bit mode is assumed
+									// (iWordSize=1), but if operating in 16-bit mode iTxData would be incremented
+									// by the number of bytes specified in iWordSize
+			}
+		// If a Tx FIFO is not being used, a single Tx value would be written - in which case the above loop would be replaced
+
+		__KTRACE_OPT(KIIC, Kern::Printf("After adding:\n\rTx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Bufend: %x", iTxDataEnd));
+		}
+
+	if(trigger & EReceive)
+		{
+		// Initialise the Rx pointers
+		iRxData = iRxBuf + (iWordSize * iRxOffset);
+		iRxDataEnd = iRxData + (iWordSize * iNumRxWords);
+
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx Buffer:  %x", iRxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx Bufend: %x", iRxDataEnd));
+
+		// If Rx transfers were not previously active, it may be necessary to initialise the Rx hardware here, e.g.
+		//		AsspRegister::Write32(iChannelBase + KBusModeControlOffset, KIicPslRxModeBitMask);
+		}
+
+	// If there is some common configuration required to support Rx, Tx transfers, may do it here
+
+	return r;
+	}
+
+
+// The gateway function for PSL implementation
+//
+// This method is called by the PIL to perform one or more operations indicated in the bitmask aOperation,
+// which corresponds to members of the TPslOperation enumeration.
+//
+TInt DSpiSlaveBeagle::DoRequest(TInt aOperation)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("\nDSpiSlaveBeagle::DoRequest, Operation 0x%x\n", aOperation));
+
+	TInt r = KErrNone;
+	TInt intState;
+
+	if (aOperation & EAsyncConfigPwrUp)
+		{
+		// The PIL has requested asynchronous operation of CaptureChannel.
+		// The PSL should start the processing required for a channel to be captured, and then return immediately with
+		// error code KErrNone (if the processing was started without error), so that the client thread will be unblocked.
+		// The PSL is expected to be implemented as an asynchronous state machine, where events (for example hardware
+		// interrupts, or timer expiry) invoke callback functions that advance the state machine to the next state. Once
+		// all the required states have been transitioned, so that the PSL part of the CaptureChannel processing is
+		// complete, the PSL should call the PIL function ChanCaptureCallback - this will lead to the Client-provided
+		// callback being executed in the context of the client thread
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("EAsyncConfigPwrUp"));
+		r = AsynchConfigureInterface();
+		if (r != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("AsynchConfigureInterface returned %d\n", r));
+			}
+		return r;
+		}
+
+	if (aOperation & ESyncConfigPwrUp)
+		{
+		// The PIL has requested synchronous operation of CaptureChannel.
+		// The PSL should perform the processing required for a channel to be captured, and return a system-wide error
+		// code when this is complete to indicate the status of the capture.
+		// Capturing a channel is expected to include initialisation of the hardware to enable operation in accordance
+		// with the configuration specified in the PIL member variable iConfigHeader, which holds the configuration
+		// specified by the Client.
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("ESyncConfigPwrUp"));
+		r = ConfigureInterface();
+		if (r != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface returned %d\n", r));
+			return r;
+			}
+		}
+
+	if (aOperation & ETransmit)
+		{
+		// The PIL has requested that a Tx operation be started.
+		// Since the SPL may support simultaneous Rx and Tx operations, just set the flag in the iTrigger bitmask to
+		// indicate what has been requested. If both Rx and Tx operations are requested, and one completes ahead of the other,
+		// requiring the Client to provide a new buffer and associated call to DoRequest (as is the case if the Master wishes
+		// to transfer more data than the Slave buffer supported), it is possible that the other transfer could complete while
+		// this function is running; consequently, it may attempt to access iTrigger, and so cause data corruption. To cater for
+		// such situations, use a spin lock to guard access to iTrigger.
+		// When the same check has been performed for Rx, call the InitTransfer function to start the required transfers.
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("ETransmit"));
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger |= ETransmit;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	if (aOperation & EReceive)
+		{
+		// The PIL has requested that a Rx operation be started.
+		// Since the SPL may support simultaneous Rx and Tx operations, just set the flag in the iTrigger bitmask to
+		// indicate what has been requested. If both Rx and Tx operations are requested, and one completes ahead of the other,
+		// requiring the Client to provide a new buffer and associated call to DoRequest (as is the case if the Master wishes
+		// to transfer more data than the Slave buffer supported), it is possible that the other transfer could complete while
+		// this function is running; consequently, it may attempt to access iTrigger, and so cause data corruption. To cater for
+		// such situations, use a spin lock to guard access to iTrigger.
+		// When the same check has been performed for Tx, call the InitTransfer function to start the required transfers.
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("EReceive"));
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger |= EReceive;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	if (aOperation & (EReceive | ETransmit))
+		{
+		// This code should only be executed once it has been checked whether Rx and Tx operations are required.
+		r = InitTransfer();
+		}
+
+	if (aOperation & EAbort)
+		{
+		// The PIL has requested that the current transaction be aborted.
+		// This is the case if the Client has not responded within an expected time to specify the next steps in
+		// the transaction processing. The time allowed is specified by calling PIL function SetClientWaitTime, otherwise
+		// the time defaults to KSlaveDefCWaitTime.
+		// If the PSL is able to satisfy this request it should, at a minimum, disable interrupts and update the member
+		// variables that indicate a transaction is in progress. If the PSL is unable to satisfy the request then the same
+		// behaviour will follow as if this request had not been made, so there is no point in modifying the state variables.
+		// If both Rx and Tx operations had been requested, and one completes ahead of the other, it is possible that the other
+		// transfer could complete while this function is running; consequently, it may attempt to access iTrigger and iInProgress,
+		// and so cause data corruption. To cater for such situations, use a spin lock to guard access to iTrigger.
+		// The PIL makes no assumptions of whether the PSL can support this request or not, and does not check the return
+		// value - so there is no need to set one.
+		//
+		TUint8 dummyCanAbort = 1;	// Dummy variable to represent a check of if it is possible to abort the current transaction
+		__KTRACE_OPT(KIIC, Kern::Printf("EAbort"));
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		if(dummyCanAbort)
+			{
+			// The spin lock has been acquired, so it is safe to modify data and hardware registers that may be accessed as part of
+			// interrupt processing performed by an ISR - this is assuming that the ISR has been written to acquire the same spin lock.
+			// Limit the processing to only that which is necessary to be processed under spin lock control, so as to not delay other
+			// threads of execution that are waiting for the spin lock to be freed.
+			// Hardware may be configured using code similar to the following:
+			//		AsspRegister::Write32(iChannelBase + KBusInterruptEnableOffset, KIicPslBusDisableBitMask);
+			iInProgress = EFalse;
+			iTrigger = 0;
+			}
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		// Having released the spin lock, now perform any actions that are not affected by pre-emption by an ISR, this may include code
+		// such as the following
+		//		Interrupt::Disable(iRxInterruptId);
+		//		Interrupt::Disable(iTxInterruptId);
+		}
+
+	if (aOperation & EPowerDown)
+		{
+		// The PIL has requested that the channel be released.
+		// If this channel is not part of a MasterSlave channel, the next Client will operate in Slave mode. In this case, it may only
+		// be necessary to disable interrupts, and reset the channel hardware.
+		// If this channel represents the Slave of a MasterSlave channel, it is possible that some of the hardware is shared between the
+		// Master and Slave sub-channels. Since it may not be known whether the next Client of the parent channel will require operation
+		// in either Master or Slave mode, some additional processing may be required to allow for subsequent Master operation (for example.
+		// unbinding an interrupt).
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("EPowerDown"));
+
+		// Resetting the hardware may be achieved with calls similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KBusInterruptEnableOffset, KIicPslBusDisableBitMask);
+		//		GPIO::SetPinMode(aPinId, GPIO::EDisabled);
+
+		// Disable interrupts may be achieved with calls similar to the following:
+		//		Interrupt::Disable(iRxInterruptId);
+		//		Interrupt::Disable(iTxInterruptId);
+
+		// Unbinding an ISR may be achieved with calls similar to the following:
+		//		Interrupt::Unbind(iRxInterruptId);
+		//		Interrupt::Unbind(iTxInterruptId);
+
+		// The PIL checks the return value so the variable r should be modified in the event of failure with a system-wide error code
+		// for example, if a register could not be modified,
+		//		r = KErrGeneral;
+		//		__KTRACE_OPT(KIIC, Kern::Printf("EPowerDown failed with error %d\n",r));
+
+		}
+	return r;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/slave.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,87 @@
+// Copyright (c) 2010 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:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/slave.h
+//
+
+
+#ifndef __OMAP3530_SPI_SLAVE_H__
+#define __OMAP3530_SPI_SLAVE_H__
+
+#include <drivers/iic_channel.h>
+
+class DSpiSlaveBeagle: public DIicBusChannelSlave
+	{
+
+public:
+	static DSpiSlaveBeagle* New(TInt aChannelNumber, const TBusType aBusType,
+	                              const TChannelDuplex aChanDuplex);
+
+	// Gateway function for PSL implementation
+	virtual TInt DoRequest(TInt aOperation);
+
+	DSpiSlaveBeagle(TInt aChannelNumber, const TBusType aBusType,
+	                 const TChannelDuplex aChanDuplex);
+
+private:
+	// Overriders for base class pure-virtual methods
+	virtual TInt DoCreate(); // second-stage construction,
+	virtual TInt CheckHdr(TDes8* aHdrBuff);
+	virtual void ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb);
+
+	// Internal methods..
+	TBool TransConfigDiffersFromPrev();
+	TInt ConfigureInterface();
+	TInt AsynchConfigureInterface();
+	TInt InitTransfer();
+
+	// ISR handler and other static methods..
+	static void IicPslIsr(TAny* aPtr);
+	static void TimeoutCallback(TAny* aPtr);
+	static inline void NotifyClientEnd(DSpiSlaveBeagle* aPtr);
+
+	// Register base for the Master channel
+	TUint iSlaveChanBase;
+
+	// Interrupt ID for the Master channel
+	TInt iSlaveIntId;
+
+	// Bit mask of the transfer triggers managed by the channel
+	TUint8 iTrigger;
+
+	// Granularity, expressed as the number of bytes in a word
+	TInt8 iWordSize;
+
+	// Flag indicating transmission activity - optional, may not be required for all bus types
+	// In the template example it is used to indicate transitions on a chip-select line, such as for SPI.
+	TInt8 iInProgress;
+
+	// Dummy variable used merely to demonstrate the asynchronous channel capture mechanism
+	// See method AsynchConfigureInterface
+	TInt8 iAsyncConfig;
+
+	// Pointers to buffers used for Rx and Tx transfers
+	TInt8 *iTxData;
+	TInt8 *iRxData;
+	TInt8 *iTxDataEnd;
+	TInt8 *iRxDataEnd;
+
+	// Timer to guard 'while' loops..
+	NTimer iHwGuardTimer;
+
+	// status of the transaction
+	volatile TInt iTransactionStatus;
+	};
+
+#endif /*__OMAP3530_SPI_SLAVE_H__*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/spi.iby	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,29 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/spi.iby
+// this file defines components to be included in the rom image in order
+// to support IIC SPI implementation.
+
+
+
+#ifndef STANDALONE_CHANNEL 
+extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\iic.dll  \sys\bin\iic.dll
+#endif
+extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\_omap3530_spi.dll  \sys\bin\spi.dll
+
+#ifdef INCLUDE_SPI_TEST
+device[VARID]=\epoc32\release\##KMAIN##\##BUILD##\_beagle_d_spi_client_m.ldd  \sys\bin\d_spi_client_m.ldd
+file=\epoc32\release\##KMAIN##\##BUILD##\t_spi_client_m.exe  \sys\bin\t_spi_client_m.exe
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/spi.mmp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,76 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/spi.mmp
+//
+
+#include <assp/omap3530_assp/assp.mmh>
+//#include "kernel/kern_ext.mmh" // this is already included from iic_channel.mmh
+// ..and probably it shouldn't be
+
+
+// Select the mode to build
+// For Master-Slave mode, uncomment both MASTER and SLAVE defines
+#define __USE_MASTER_MODE__
+//#define __USE_SLAVE_MODE__
+
+
+//macro STANDALONE_CHANNEL
+//#define STANDALONE_CHANNEL /*Only for iic_channel.mmh to pick up the needed source files*/
+
+// PSL source
+SOURCEPATH       .
+SOURCE           psl_init.cpp
+
+#ifdef __USE_MASTER_MODE__
+macro MASTER_MODE
+SOURCE           master.cpp
+#endif
+
+#ifdef __USE_SLAVE_MODE__
+macro SLAVE_MODE
+SOURCE           slave.cpp
+#endif
+
+
+// PIL source
+#include   "../../../../../os/kernelhwsrv/kernel/eka/drivers/iic/iic_channel.mmh"
+sourcepath ../../../../../os/kernelhwsrv/kernel/eka/drivers/iic/
+source		IIC_PIL_SOURCE
+
+
+TARGET           AsspTarget(spi,dll)
+TARGETTYPE       kext
+LINKAS           spi.dll
+
+//DEFFILE          ./def/~/spi.def
+NOSTRICTDEF
+
+
+USERINCLUDE      .
+SYSTEMINCLUDE    +\include\assp\omap3530_assp 
+SYSTEMINCLUDE 	 +\include\drivers 
+SYMBIAN_BASE_SYSTEMINCLUDE(assp/omap3530_assp)
+SYMBIAN_BASE_SYSTEMINCLUDE(drivers)
+
+LIBRARY          AsspTarget(kaomap3530,lib)
+LIBRARY          AsspTarget(prcm,lib)
+LIBRARY          AsspTarget(gpio,lib)
+
+// #ifdef USE_SYMBIAN_PRM?
+//library				resman.lib
+
+EPOCALLOWDLLDATA
+
+CAPABILITY       all
+
+VENDORID         0x70000001
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,1012 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/d_spi_client_m.cpp
+//
+// This test driver is a simple example IIC SPI client implementation - and a test to SPI implementation.
+// It is an LDD but PDD or kernel extension can implement / use the IIC SPI bus exactly the same way.
+// There is a lot of code duplication in this test code, but this is in order to provide clear and separate implementation
+// for each of these use cases, which can serve as example usecases that should be easy to adopt for the real purpose.
+//
+
+// Note: IMPORTANT! -If you intend to make changes to the driver!
+// Obviously the best test is to use the SPI with the real device (and check if it still works after changes).
+// If this is not the case (e.g. as it was when this driver was being created) - to fully test the functionality
+// this test can make use of duplex transactions with local loopback. In such case received data should match the
+// data sent over the bus. (It might be possible to configure local loopback using pad config(not yet confirmed),
+// but until this (and not to complicate the test too much)- here is simple description on how to do it on a
+// beagleboard. If McSPI3 is configured with the default pin option, i.e. to route signals to the expansion
+// hader (see spi driver for details):s
+// following header pins have SPI3 functions:
+// 21 - CLK
+// 19 - SIMO
+// 17 - SOMI
+// 11 - CS0
+// local loopback could be simply made by puttint the jumper between pin 17 and pin 19 of the extension header.
+// This test will automatically detect this configuration and the jumper - so if you want to test it this way
+// it is highly recommended (and it's simple).
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include <kernel/kern_priv.h>
+#include "d_spi_client_m.h"
+
+
+_LIT(KTestDriverName,"d_spi_client_m");
+
+// (un) comment it out for debugging
+//#define LOG_FUNCTION_CALLS
+
+#ifdef LOG_FUNCTION_CALLS
+#define LOG_FUNCTION_ENTRY Kern::Printf("DSpiClientChannel::%s()", __FUNCTION__)
+#define LOG_FUNCTION_RETURN Kern::Printf("DSpiClientChannel::%s() return: %d", __FUNCTION__, r)
+#else
+#define LOG_FUNCTION_ENTRY
+#define LOG_FUNCTION_RETURN
+#endif
+
+
+// === generic (driver related) stuff ===
+
+// this driver only implements one channel
+const TInt KMaxNumChannels = 1;
+
+
+
+// entry point
+DECLARE_STANDARD_LDD()
+	{
+	return new DSpiClientTestFactory;
+	}
+
+DSpiClientTestFactory::DSpiClientTestFactory()
+	{
+	iParseMask = 0;
+	iUnitsMask = 0;  // No info, no PDD, no Units
+	iVersion = TVersion(KIntTestMajorVersionNumber,
+	        KIntTestMinorVersionNumber, KIntTestBuildVersionNumber);
+	}
+
+DSpiClientTestFactory::~DSpiClientTestFactory()
+	{
+	}
+
+// Install the device driver.
+TInt DSpiClientTestFactory::Install()
+	{
+	return (SetName(&KLddFileNameRoot));
+	}
+
+void DSpiClientTestFactory::GetCaps(TDes8& aDes) const
+	{
+	TPckgBuf<TCapsProxyClient> b;
+	b().version = TVersion(KIntTestMajorVersionNumber, KIntTestMinorVersionNumber, KIntTestBuildVersionNumber);
+	Kern::InfoCopy(aDes, b);
+	}
+
+// Create a channel on the device.
+TInt DSpiClientTestFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	if (iOpenChannels >= KMaxNumChannels)
+		{
+		return KErrOverflow;
+		}
+
+	aChannel = new DSpiClientChannel;
+	return aChannel ? KErrNone : KErrNoMemory;
+	}
+
+DSpiClientChannel::DSpiClientChannel()
+	{
+	iClient = &Kern::CurrentThread();
+	// Increase the DThread's ref count so that it does not close without us
+	((DObject*)iClient)->Open();
+	}
+
+DSpiClientChannel::~DSpiClientChannel()
+	{
+	((TDynamicDfcQue*)iDfcQ)->Destroy();
+	// decrement the DThread's reference count
+	Kern::SafeClose((DObject*&) iClient, NULL);
+	}
+
+TInt DSpiClientChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+	TDynamicDfcQue *dfcq = NULL;
+	TInt r = Kern::DynamicDfcQCreate(dfcq, KIntTestThreadPriority, KTestDriverName);
+
+	if(r == KErrNone)
+		{
+		SetDfcQ(dfcq);
+		iMsgQ.Receive();
+		}
+	return r;
+	}
+
+void DSpiClientChannel::HandleMsg(TMessageBase* aMsg)
+	{
+	TThreadMessage& m = *(TThreadMessage*) aMsg;
+	TInt id = m.iValue;
+
+	if (id == ECloseMsg)
+		{
+		iMsgQ.iMessage->Complete(KErrNone, EFalse);
+		return;
+		}
+	else if (id == KMaxTInt)
+		{
+		m.Complete(KErrNone, ETrue);
+		return;
+		}
+
+	if (id < 0)
+		{
+		TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
+		TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+		if (r != KErrNone)
+			{
+			Kern::RequestComplete(iClient, pS, r);
+			}
+		m.Complete(KErrNone, ETrue);
+		}
+	else
+		{
+		TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
+		m.Complete(r, ETrue);
+		}
+	}
+
+// to handle synchronous requests..
+// TODO: There are unimplemented functions - returning KErrNotSupported - treat this as a 'sort of'
+// of test-driven development.. Ideally - they should all be implemented..
+TInt DSpiClientChannel::DoControl(TInt aId, TAny* a1, TAny* a2)
+	{
+	TInt r = KErrNone;
+	switch (aId)
+		{
+		case RSpiClientTest::EHalfDuplexSingleWrite:
+			{
+			r = HalfDuplexSingleWrite();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexMultipleWrite:
+			{
+			r = HalfDuplexMultipleWrite();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexSingleRead:
+			{
+			r = HalfDuplexSingleRead();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexMultipleRead:
+			{
+			r = HalfDuplexMultipleRead();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexMultipleWriteRead:
+			{
+			r = HalfDuplexMultipleWriteRead();
+			break;
+			}
+		case RSpiClientTest::EFullDuplexSingle:
+			{
+			r = FullDuplexSingle();
+			break;
+			}
+		case RSpiClientTest::EFullDuplexMultiple:
+			{
+			r = FullDuplexMultiple();
+			break;
+			}
+
+		default:
+			{
+			Kern::Printf("DSpiClientChannel::DoControl():Unrecognized value for aId=0x%x\n", aId);
+			r = KErrArgument;
+			break;
+			}
+		}
+	return r;
+	}
+
+// to handle asynchronous requests from the client
+TInt DSpiClientChannel::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+	{
+	__KTRACE_OPT(KTESTFAST, Kern::Printf("DSpiClientChannel::DoRequest(aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n",
+					aId, aStatus, a1, a2));
+
+	// TODO: There are unimplemented functions - returning KErrNotSupported - treat this as a 'sort of'
+	// test-driven development.. Ideally - they should all be implemented..
+	TInt r = KErrNone;
+	switch (aId)
+		{
+		case RSpiClientTest::EAsyncHalfDuplexSingleWrite:
+			{
+			r = AsyncHalfDuplexSingleWrite(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexMultipleWrite:
+			{
+			r = AsyncHalfDuplexMultipleWrite(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexSingleRead:
+			{
+			r = AsyncHalfDuplexSingleRead(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexMultipleRead:
+			{
+			r = AsyncHalfDuplexMultipleRead(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexMultipleWriteRead:
+			{
+			r = AsyncHalfDuplexMultipleWriteRead(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncFullDuplexSingle:
+			{
+			r = AsyncFullDuplexSingle(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncFullDuplexMultiple:
+			{
+			r = AsyncFullDuplexMultiple(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexExtendable:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexExtendable(aStatus);   TODO Not implemented yet..
+			break;
+			}
+		case RSpiClientTest::EAsyncFullDuplexExtendable:
+			{
+			r = KErrNotSupported; // AsyncFullDuplexExtendable(aStatus);  TODO Not implemented yet..
+			break;
+			}
+		default:
+			{
+			Kern::Printf("DSpiClientChannel::DoRequest(): unrecognized value for aId=0x%x\n", aId);
+			r = KErrArgument;
+			break;
+			}
+		}
+
+	// complete request from here if there was an error creating it..
+	if(r != KErrNone)
+		{
+		Kern::RequestComplete(iClient, aStatus, r);
+		}
+
+	return r;
+	}
+// ====== (end of driver related stuff) ===
+
+
+// test half duplex write:
+// - one transaction with one write transfer
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as the simplest example of a single write
+TInt DSpiClientChannel::HalfDuplexSingleWrite()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 2); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer object
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> txTransferBuf; // txbuffer..
+
+	// fill it with some data..(this will also set the length of the buffer)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf.Append(i+1);
+		}
+
+	// create tranfer object
+	TIicBusTransfer txTransfer(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf);
+
+	// Create a transaction using header and list of transfers..
+	TIicBusTransaction transaction(&header, &txTransfer);
+
+	// queue the transaction synchronously
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+
+// test half duplex write:
+// - one transaction with more write transfers
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as the simplest example of a multiple writes
+// Note, that ALWAYS (not only in this example) - each of the transfers is separated
+// with SS signals assertion / deassertion
+TInt DSpiClientChannel::HalfDuplexMultipleWrite()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 3);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> txTransferBuf1;
+	TBuf8<KBuffLength> txTransferBuf2;
+
+	// put some data into these buffers..(this will also set their length)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf1.Append(i+1);
+		txTransferBuf2.Append(63-i);
+		}
+
+	// create two transfers and link them (transfer2 after transfer1)
+	TIicBusTransfer txTransfer1(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf1);
+	TIicBusTransfer txTransfer2(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf2);
+	txTransfer1.LinkAfter(&txTransfer2); // will link txTransfer2 after txTransfer1..
+
+	// Create a transaction using header and linked transfers (using first in one)
+	TIicBusTransaction transaction(&header, &txTransfer1);
+
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test half duplex read:
+// - one transaction with one read transfer
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as the simplest example of a single read transfer.
+// (e.g. for a potential use with a Slave device that is only capable of sending data)
+TInt DSpiClientChannel::HalfDuplexSingleRead()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed 3MHz (could use SpiFreqHz(16))
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> rxTransferBuf;
+
+	// put some data into the buffer..(this will also set its length)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		rxTransferBuf.Append(i+1);
+		}
+
+	// create transfer
+	TIicBusTransfer rxTransfer(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf);
+
+	// And a transaction
+	TIicBusTransaction transaction(&header, &rxTransfer);
+
+	// queue transaction synchronously
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now, we has non-zero data in the buffer, but we know, that there was nothing connected
+	// so we should either receive 0x0 (or 0xff if line was driven high- unlikely)- but we'll check
+	// if rx buffer has simply different data in it..
+	for (int i = 0; i < KBuffLength; i++)
+		{
+		if(rxTransferBuf[i] == i+1)
+			{
+			r = KErrCorrupt;
+			break;
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test half duplex multiple transfer read:
+// - one transaction with two read transfers
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// this is simmilar to write transactions with multiple transfers (e.g. HalfDuplexMultipleWrite)
+TInt DSpiClientChannel::HalfDuplexMultipleRead()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8,           // iWordWidth
+		3000000,                   // iClkSpeed 3MHz
+		ESpiPolarityLowRisingEdge, // iClkMode
+		500,                       // iTimeoutPeriod
+		EBigEndian,                // iEndianness
+		EMsbFirst,                 // iBitOrder
+		0,                         // iTransactionWaitCycles
+		ESpiCSPinActiveLow         // iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	const TInt KBuffLength1 = 32;
+	const TInt KBuffLength2 = 15;
+
+	TBuf8<KBuffLength1> rxTransferBuf1;
+	TBuf8<KBuffLength2> rxTransferBuf2;
+
+	// put some data into these buffers..(this will also set their lengths)
+	for (TInt i = 0; i < KBuffLength1; ++i)
+		{
+		rxTransferBuf1.Append(i+1);
+		}
+
+	for (TInt i = 0; i < KBuffLength2; ++i)
+		{
+		rxTransferBuf2.Append(i+1);
+		}
+
+	// create two transfers and link them (transfer2 after transfer1)
+	TIicBusTransfer rxTransfer1(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf1);
+	TIicBusTransfer rxTransfer2(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf2);
+	rxTransfer1.LinkAfter(&rxTransfer2);
+
+	// Create a transaction using header and linked transfers (using first in one)
+	TIicBusTransaction transaction(&header, &rxTransfer1);
+
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now, we has non-zero data in the buffer, but we know, that there was nothing connected
+	// so we should either receive 0x0 (or 0xff if line was driven high- unlikely)- but we'll check
+	// if rx buffer has simply different data in it..
+	for (int i = 0; i < KBuffLength1; i++)
+		{
+		if(rxTransferBuf1[i] == i+1)
+			{
+			r = KErrCorrupt;
+			break;
+			}
+		}
+
+	if(r == KErrNone)
+		{
+		for (int i = 0; i < KBuffLength2; i++)
+			{
+			if(rxTransferBuf2[i] == i+1)
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+
+// test half duplex read / write:
+// - one transaction with more transfers - intermixed read / write
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as a simple example of a common spi usage for peripherals configuration, i.e.:
+// write data - e.g. address of register and / or command(s) followed by read of their value(s)
+TInt DSpiClientChannel::HalfDuplexMultipleWriteRead()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	// (they don't have to be of the same size-it's just for simplicity here!)
+	const TInt KBuffLength = 32;
+	TBuf8<KBuffLength> txTransferBuf1; // txbuffer1..
+	TBuf8<KBuffLength> txTransferBuf2; // txbuffer2..
+	TBuf8<KBuffLength> rxTransferBuf; // rxbuffer..
+
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf1.Append(i+1);
+		txTransferBuf2.Append(63-i);
+		rxTransferBuf.Append(0xa5); // append some non-zero data-will check, if it's overwritten by read..
+		}
+	// The above will also set size of buffers - and this is checked by the driver!
+
+	// create two transfers and link them (transfer2 after transfer1)
+	TIicBusTransfer txTransfer1(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf1);
+	TIicBusTransfer txTransfer2(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf2);
+	txTransfer1.LinkAfter(&txTransfer2); // will link txTransfer2 after txTransfer1..
+
+	// create read transfer and link it after above two transfers
+	TIicBusTransfer rxTransfer(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf);
+	txTransfer2.LinkAfter(&rxTransfer); // will link rxTransfer after txTransfer2..
+
+	// Create a transaction using header and first of linked transfers
+	TIicBusTransaction transaction(&header, &txTransfer1);
+
+	// and queue it synchronously..
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test full duplex with single* transfer i,e. simultenous write and read.
+// - one half duplex transaction with one write transfer (for first direction-like usually)
+// - one read buffer - that will be used to 'setup' a full duplex transaction (for the other direction)
+// (Data on stack - recommended for small transfers).
+// This could serve as a simple example of simultenous write and read from a bus
+TInt DSpiClientChannel::FullDuplexSingle()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects (they SHOULD be of the same size!)
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> txTransferBuf; // txbuffer..
+	TBuf8<KBuffLength> rxTransferBuf; // rxbuffer..
+
+	// fill TX buffer with some data to send..
+	// and the RX buffer - with some other data - to check if it's overwritten by read
+	// (this will also set buffers length's)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf.Append(i+1);
+		rxTransferBuf.Append(0x55);
+		}
+
+	// create transfer objects..
+	TIicBusTransfer txTransfer(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf);
+	TIicBusTransfer rxTransfer(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf);
+
+	// Create transaction using header and list of transfers..
+	TIicBusTransaction transaction(&header, &txTransfer);
+
+	// setup a full duplex transaction - using Rx buffer
+	transaction.SetFullDuplexTrans(&rxTransfer);
+
+	// queue the transaction
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now confirm the reception..
+	// BEAGLE BOARD only- if using local callback (ideally it should be used to fully test it)
+	// data in rx buffer should match the data in the tx buffer.
+	// otherwise (with no local loopback) - rx buffer should contain ZERO / (or different) data as it was
+	// initially filled with. (i.e. as nothing was driving the SOMI line - rx will count that as 0 sent over the bus)
+	// see top of this file and IsLoobackAvailable() function description for more details.
+	TBool checkReceivedMatchesSent = IsLoopbackAvailable();
+	if(!checkReceivedMatchesSent)
+		{
+		Kern::Printf("!Warning: %s (%d): not using local-loop for duplex test", __FILE__, __LINE__);
+		}
+
+	for (int i = 0; i < KBuffLength; i++)
+		{
+		if(checkReceivedMatchesSent)
+			{
+			if (rxTransferBuf[i] != txTransferBuf[i])
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		else
+			{
+			if (rxTransferBuf[i] == 0x55) // this was the value used..
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+
+// test full duplex with multiple transfers
+// - one half duplex transaction with two transfers: write followed by read
+// - two buffers to form the other direction: read followed by write.
+// (Data on stack - recommended for small transfers only).
+// This could serve as a simple example of multi-transfer full duplex transactions.
+TInt DSpiClientChannel::FullDuplexMultiple()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create buffers:
+	// for first duplex transfer
+	const TInt KBuffLength1 = 24;
+	TBuf8<KBuffLength1> txTransferBuf1;
+	TBuf8<KBuffLength1> rxTransferBuf1;
+
+	// for second duplex transfer..
+	// Note: Buffers for different transfers can have different size like below.
+	// the only requirement is - that for each duplex transfer(tx and rx) they need to have the same.
+	const TInt KBuffLength2 = 32;
+	TBuf8<KBuffLength2> rxTransferBuf2;
+	TBuf8<KBuffLength2> txTransferBuf2;
+
+	// fill them with data..
+	for (TInt i = 0; i < txTransferBuf1.MaxLength(); ++i)
+		{
+		txTransferBuf1.Append(i+1);
+		rxTransferBuf1.Append(0x55);
+		}
+
+	for (TInt i = 0; i < txTransferBuf2.MaxLength(); ++i)
+		{
+		txTransferBuf2.Append(i+1);
+		rxTransferBuf2.Append(0xaa);
+		}
+
+	// Now we want to chain transfers in the following way:
+	// txTransfer1 -> rxTransfer2
+	// rxTransfer1 -> txTransfer2
+	// note, that there could always be a read and write at the same time (in the same column)
+
+	// first direction
+	TIicBusTransfer txTransfer1(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf1);
+	TIicBusTransfer rxTransfer1(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf1);
+
+	// second transfer objects (they will run in parallel after above have finished)
+	TIicBusTransfer txTransfer2(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf2);
+	TIicBusTransfer rxTransfer2(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf2);
+
+	// chain them as described above
+	txTransfer1.LinkAfter(&rxTransfer2); // rxTransfer2 after txTransfer1
+	rxTransfer1.LinkAfter(&txTransfer2); // txTransfer2 after rxTransfer1
+
+	// Create a transaction using header and list of transfers..
+	TIicBusTransaction transaction(&header, &txTransfer1);
+	transaction.SetFullDuplexTrans(&rxTransfer1);
+
+	// and finally queue the transaction
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now confirm the reception..
+	// BEAGLE BOARD only- if using local callback (ideally it should be used to fully test it)
+	// data in rx buffer should match the data in the tx buffer.
+	// otherwise (with no local loopback) - rx buffer should contain zero / (or different) data as it was
+	// initially filled with. See top of this file and IsLoobackAvailable() function description for more details.
+	TBool checkReceivedMatchesSent = IsLoopbackAvailable();
+
+	if(!checkReceivedMatchesSent)
+		Kern::Printf("!Warning: %s (%d): not using local-loop for duplex test", __FILE__, __LINE__);
+
+	// check first transfer
+	for (int i = 0; i < KBuffLength1; i++)
+		{
+		if(checkReceivedMatchesSent)
+			{
+			if (rxTransferBuf1[i] != txTransferBuf1[i])
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		else
+			{
+			if (rxTransferBuf1[i] == 0x55) // this was the value used..
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+
+	// check second transfer
+	for (int i = 0; i < KBuffLength2; i++)
+		{
+		if(checkReceivedMatchesSent)
+			{
+			if (rxTransferBuf2[i] != txTransferBuf2[i])
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		else
+			{
+			if (rxTransferBuf2[i] == 0xaa) // this was the value used..
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test asynchronous transactions.
+// For these transactions - all objects: buffers, transfers and transactions have to be allocated on the heap.
+// At the momment there is no way of extracting pointers to these objects from the transaction
+// pointer by the client (this it TODO and it's currently being addressed as an architectural change).
+// For that reason pointers to these dynamic objects have to be stored by the client, so that
+// he could access these from the request, read the data (for RX request) and de-allocate/re-use them
+// in next transactions.
+// In order to achieve that (until the PIL will support above 'TODO') the templated wrapper class is used
+// to manage all these pointers, i.e.: TTransactionWrapper (see header file)
+
+
+// Callback for Master's asynchronous transactions - called when transaction has been finished
+void DSpiClientChannel::SingleHalfDuplexTransCallback(TIicBusTransaction* aTransaction,
+	                                                  TInt aBusId,
+	                                                  TInt aResult,
+	                                                  TAny* aParam)
+	{
+	LOG_FUNCTION_ENTRY;
+	TTransactionWrapper<1> *twr = (TTransactionWrapper<1>*)aParam;
+
+	if(aResult == KErrNone)
+		{
+		// if this was a read request (AsyncHalfDuplexSingleRead)- read received data:
+		HBuf8* rxBuffer = twr->GetRxBuffer(0);
+		if(rxBuffer)
+			{
+			HBuf8& buffer = *rxBuffer; // a reference to avoid writing:  "(*rxBuffer)[0]" below..
+			for(TInt i= 0; i < rxBuffer->Length(); i++)
+				{
+				// check if the data is correct..
+				if(buffer[i] == 0x55)
+					{
+					aResult = KErrCorrupt;
+					break;
+					}
+				}
+			}
+		}
+
+	// complete request.. informing the client on the result.
+	Kern::RequestComplete(twr->iClient, twr->iReqStatus, aResult);
+
+	// now can finally delete the wrapper- this will release all memory it holds
+	delete twr;
+
+	// and delete transaction
+    delete aTransaction;
+	}
+
+
+// Test Asynchronous Transaction
+TInt DSpiClientChannel::AsyncHalfDuplexSingleWrite(TRequestStatus* aStatus)
+	{
+	TInt r = KErrNoMemory;
+
+	// 0. prepare busId - i.e. select module / channel and bus type
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// 1. create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		5000, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+	// TConfigSpiBufV01 is a TPckgBuf<TConfigSpiV01>
+	TConfigSpiBufV01* spiHeader = new TConfigSpiBufV01(KHeader);
+
+	const TInt KTrasferBufferLength = 64;
+	if(spiHeader)
+		{
+		// 2. create wrapper to store pointers to transfer buffers and objects..
+		TTransactionWrapper<1> *twr = new TTransactionWrapper<1>(iClient, aStatus, spiHeader);
+		if(twr)
+			{
+			// 3. Create the transaction callback object (here we are using this driver's dfcque but it could be any
+			// other one (providing thread synchronization etc..)
+			TIicBusCallback *callback = new TIicBusCallback(SingleHalfDuplexTransCallback, (TAny*)twr, iDfcQ, 5);
+
+			// 4. create buffer for transaction (and store it in a wrapper class)
+			HBuf8* txBuf = HBuf8::New(KTrasferBufferLength);
+			twr->iTxBuffers[0] = txBuf;
+			for(TInt i = 0; i < KTrasferBufferLength; i++)
+				{
+				txBuf->Append(i); // append some data to send..
+				}
+
+			// 5. create transfer (and store it in a wrapper class)
+			TIicBusTransfer* txTransfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, txBuf);
+			twr->iTxTransfers[0] = txTransfer;
+
+			// 6. create transaction (no need to store it in the wrapper - this pointer is always passed to the
+			// callback (TODO: and only this could be really used in the callback...it's annoying that it's not yet!)
+			TIicBusTransaction* transaction = new TIicBusTransaction(spiHeader, txTransfer);
+
+			// lazy approach - check result of all allocations here..
+			if(twr && callback && txBuf && txTransfer && transaction)
+				{
+				r = IicBus::QueueTransaction(busId, transaction, callback);
+				}
+			else // ..and cleanup on error..
+				{
+				r = KErrNoMemory;
+				}
+			}
+
+		if(r != KErrNone)
+			{
+			delete twr; // this will clean all that was allocated already..
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+TInt DSpiClientChannel::AsyncHalfDuplexSingleRead(TRequestStatus* aStatus)
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+TInt DSpiClientChannel::AsyncHalfDuplexMultipleWrite(TRequestStatus* aStatus)
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+
+TInt DSpiClientChannel::AsyncHalfDuplexMultipleRead(TRequestStatus* aStatus)
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+TInt DSpiClientChannel::AsyncHalfDuplexMultipleWriteRead(TRequestStatus* aStatus)
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+TInt DSpiClientChannel::AsyncFullDuplexSingle(TRequestStatus* aStatus)
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+TInt DSpiClientChannel::AsyncFullDuplexMultiple(TRequestStatus* aStatus)
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.h	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,324 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/d_spi_client_m.h
+//
+
+#ifndef __D_SPI_CLIENT_MASTER__
+#define __D_SPI_CLIENT_MASTER__
+
+#include <e32cmn.h>
+#include <e32ver.h>
+
+
+const TInt KIntTestThreadPriority = 24;
+
+const TInt KIntTestMajorVersionNumber = 1;
+const TInt KIntTestMinorVersionNumber = 0;
+const TInt KIntTestBuildVersionNumber = KE32BuildVersionNumber;
+
+_LIT(KLddFileName, "d_spi_client_m.ldd");
+_LIT(KLddFileNameRoot, "d_spi_client_m");
+
+#ifdef __KERNEL_MODE__
+#include <kernel/kernel.h>
+
+// For now - the driver has to know what frequencies are supported and has to specify them directly
+// in the transaction header. This might be changes in the IIC PIL (kernelhwsrv)-in a way, that the driver
+// returns supported frequencies with some 'GetCaps' method. For now - standard frequencies for CLK
+// (that support duty cycle 50-50) are 48MHz divisions per power-of-two.
+const TInt KSpiClkBaseFreqHz = 48000000;
+const TInt KSpiClkMaxDivider = 4096;
+
+inline TInt SpiFreqHz(TInt aDivider)
+	{
+	__ASSERT_DEBUG(aDivider > 0 && aDivider < KSpiClkMaxDivider, Kern::Fault("d_spi_client_master: divider out of range", 13));
+	__ASSERT_DEBUG(!(aDivider &  (aDivider-1)), Kern::Fault("d_spi_client_master: divider not power of two", 14));
+	return KSpiClkBaseFreqHz / aDivider;
+	}
+#endif
+
+class RSpiClientTest: public RBusLogicalChannel
+	{
+public:
+	enum TControl
+		{
+		EHalfDuplexSingleWrite,
+		EHalfDuplexMultipleWrite,
+		EHalfDuplexSingleRead,
+		EHalfDuplexMultipleRead,
+		EHalfDuplexMultipleWriteRead,
+		EFullDuplexSingle,
+		EFullDuplexMultiple,
+		EHalfDuplexExtendable,
+		EFullDuplexExtendable
+		};
+
+	enum TRequest
+		{
+		EAsyncHalfDuplexSingleWrite,
+		EAsyncHalfDuplexMultipleWrite,
+		EAsyncHalfDuplexSingleRead,
+		EAsyncHalfDuplexMultipleRead,
+		EAsyncHalfDuplexMultipleWriteRead,
+		EAsyncFullDuplexSingle,
+		EAsyncFullDuplexMultiple,
+		EAsyncHalfDuplexExtendable,
+		EAsyncFullDuplexExtendable
+		};
+
+#ifndef __KERNEL_MODE__
+public:
+	TInt Open()
+		{
+		return (DoCreate(KLddFileNameRoot,
+		                 TVersion(KIntTestMajorVersionNumber,KIntTestMinorVersionNumber,KIntTestBuildVersionNumber),
+		                 -1,
+		                 NULL,
+		                 NULL,
+		                 EOwnerThread));
+		}
+
+	// Synchronous calls
+	TInt HalfDuplexSingleWrite()
+		{return DoControl(EHalfDuplexSingleWrite);}
+
+	TInt HalfDuplexMultipleWrite()
+		{return DoControl(EHalfDuplexMultipleWrite);}
+
+	TInt HalfDuplexSingleRead()
+		{return DoControl(EHalfDuplexSingleRead);}
+
+	TInt HalfDuplexMultipleRead()
+		{return DoControl(EHalfDuplexMultipleRead);}
+
+	TInt HalfDuplexMultipleWriteRead()
+		{return DoControl(EHalfDuplexMultipleWriteRead);}
+
+	TInt FullDuplexSingle()
+		{return DoControl(EFullDuplexSingle);}
+
+	TInt FullDuplexMultiple()
+		{return DoControl(EFullDuplexMultiple);}
+
+
+	// Asynchronous calls..
+	void HalfDuplexSingleWrite(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexSingleWrite, aStatus, NULL);}
+
+	void HalfDuplexMultipleWrite(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexMultipleWrite, aStatus, NULL);}
+
+	void HalfDuplexSingleRead(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexSingleRead, aStatus, NULL);}
+
+	void HalfDuplexMultipleRead(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexMultipleRead, aStatus, NULL);}
+
+	void HalfDuplexMultipleWriteRead(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexMultipleWriteRead, aStatus, NULL);}
+
+	void FullDuplexSingle(TRequestStatus& aStatus)
+		{DoRequest(EAsyncFullDuplexSingle, aStatus, NULL);}
+
+	void FullDuplexMultiple(TRequestStatus& aStatus)
+		{DoRequest(EAsyncFullDuplexMultiple, aStatus, NULL);}
+
+#endif
+	};
+
+#ifdef __KERNEL_MODE__
+struct TCapsProxyClient
+	{
+	TVersion version;
+	};
+
+class DSpiClientTestFactory: public DLogicalDevice
+	{
+public:
+	DSpiClientTestFactory();
+	~DSpiClientTestFactory();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8 &aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+// declaration for the client channel
+class DSpiClientChannel: public DLogicalChannel
+	{
+public:
+	DSpiClientChannel();
+	~DSpiClientChannel();
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+
+protected:
+	static void Handler(TAny *aParam);
+	virtual void HandleMsg(TMessageBase* aMsg); // Note: this is a pure virtual in DLogicalChannel
+	TInt DoControl(TInt aId, TAny* a1, TAny* a2);
+	TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2);
+
+	// set of example transfers with transactions queued synchronously
+	TInt HalfDuplexSingleWrite();
+	TInt HalfDuplexMultipleWrite();
+	TInt HalfDuplexSingleRead();
+	TInt HalfDuplexMultipleRead();
+	TInt HalfDuplexMultipleWriteRead();
+	TInt FullDuplexSingle();
+	TInt FullDuplexMultiple();
+
+	// set of example transfers with transactions queued asynchronously
+	// callback for asynchronous transactions..
+	static void SingleHalfDuplexTransCallback(TIicBusTransaction* aTransaction,
+	                                          TInt aBusId,
+	                                          TInt aResult,
+	                                          TAny* aParam);
+	// test functions..
+	TInt AsyncHalfDuplexSingleWrite(TRequestStatus* aStatus);
+	TInt AsyncHalfDuplexSingleRead(TRequestStatus* aStatus);
+	TInt AsyncHalfDuplexMultipleWrite(TRequestStatus* aStatus);
+	TInt AsyncHalfDuplexMultipleRead(TRequestStatus* aStatus);
+	TInt AsyncHalfDuplexMultipleWriteRead(TRequestStatus* aStatus);
+	TInt AsyncFullDuplexSingle(TRequestStatus* aStatus);
+	TInt AsyncFullDuplexMultiple(TRequestStatus* aStatus);
+
+private:
+	DThread* iClient;
+	};
+
+// template for wrapper class used in asynchronous transactions in order to manage
+// pointers to buffers and allocated objects (to further access the data/release memory)
+
+template <int Size>
+class TTransactionWrapper
+	{
+public:
+	TTransactionWrapper(DThread* aClient, TRequestStatus* aReqStatus, TConfigSpiBufV01* aHeader) :
+	  iHeader(aHeader),
+	  iCallback(NULL),
+	  iClient(aClient),
+	  iReqStatus(aReqStatus)
+	  {
+	  }
+
+	TTransactionWrapper() : iHeader(NULL), iCallback(NULL), iClient(NULL), iReqStatus(NULL)
+		{
+		for(TUint i = 0; i < Size; ++i)
+			{
+			iTxBuffers[i]   = NULL;
+			iRxBuffers[i]   = NULL;
+			iTxTransfers[i] = NULL;
+			iRxTransfers[i] = NULL;
+			}
+		}
+
+	inline HBuf8* GetRxBuffer(TInt index)
+		{
+		__ASSERT_DEBUG(index < Size, Kern::Fault("d_spi_client.h, line: %d", __LINE__));
+		return iRxBuffers[index];
+		}
+
+	// destructor - to clean up all the objects..
+	inline ~TTransactionWrapper()
+		{
+		// it is safe to call delete on a 'NULL' pointer
+		delete iHeader;
+		delete iCallback;
+		for(TUint i = 0; i < Size; ++i)
+			{
+			delete iTxBuffers[i];
+			delete iTxTransfers[i];
+			delete iRxBuffers[i];
+			delete iRxTransfers[i];
+			}
+		}
+
+	// store all object used by transaction
+	TConfigSpiBufV01* iHeader;
+	TIicBusCallback *iCallback;
+	HBuf8* iTxBuffers[Size];
+	HBuf8* iRxBuffers[Size];
+	TIicBusTransfer* iTxTransfers[Size];
+	TIicBusTransfer* iRxTransfers[Size];
+
+	// also store client and request information
+	DThread* iClient;
+	TRequestStatus* iReqStatus;
+	};
+
+
+// Below is additional stuff for testing with local loopback
+// the IsLoopbackAvailable function checks if McSPI3 is configured to use pins from extension header
+// (Beagleboard) and if these pins are physically connected (e.g. with jumper)- in order to determine
+// if duplex transfers should receive the same data that was sent to the bus..
+#include <assp/omap3530_assp/omap3530_scm.h>
+#include <assp/omap3530_assp/omap3530_gpio.h>
+const TInt KSpi3_SIMO_Pin = 131;
+const TInt KSpi3_SOMI_Pin = 132;
+
+inline TBool IsLoopbackAvailable()
+	{
+	// first check, if pad is configured to use SPI (this will confirm, if pins are used that way)
+	// this is their configuration (EMode1)
+	//	CONTROL_PADCONF_MMC2_CLK,  SCM::EMsw, SCM::EMode1, // mcspi3_simo
+	//  CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, SCM::EMode1, // mcspi3_somi
+	TUint mode_MMC2_CLK = SCM::GetPadConfig(CONTROL_PADCONF_MMC2_CLK, SCM::EMsw);
+	TUint mode_MMC2_DAT0 = SCM::GetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw);
+
+	if(!(mode_MMC2_CLK & SCM::EMode1) ||
+	   !(mode_MMC2_DAT0 & SCM::EMode1))
+		{
+		return EFalse; // either other pins are used or SPI3 is not configured at all..
+		}
+
+	// swap pins to be GPIO (EMode4)
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_CLK, SCM::EMsw, SCM::EMode4 | SCM::EInputEnable);
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, SCM::EMode4 | SCM::EInputEnable);
+
+	// set SIMO pin as output
+	GPIO::SetPinDirection(KSpi3_SIMO_Pin, GPIO::EOutput);
+	GPIO::SetPinMode(KSpi3_SIMO_Pin, GPIO::EEnabled);
+
+	// and SOMI pin as input
+	GPIO::SetPinDirection(KSpi3_SOMI_Pin, GPIO::EInput);
+	GPIO::SetPinMode(KSpi3_SOMI_Pin, GPIO::EEnabled);
+
+	TBool result = ETrue;
+	GPIO::TGpioState pinState = GPIO::EHigh;
+
+	// test 1: set SIMO to ELow and check if SOMI is the same
+	GPIO::SetOutputState(KSpi3_SIMO_Pin, GPIO::ELow);
+	GPIO::GetInputState(KSpi3_SOMI_Pin, pinState);
+	if(pinState != GPIO::ELow)
+		{
+		result = EFalse;
+		}
+	else
+		{
+		// test 2: set SIMO to EHigh and check if SOMI is the same
+		GPIO::SetOutputState(KSpi3_SIMO_Pin, GPIO::EHigh);
+		GPIO::GetInputState(KSpi3_SOMI_Pin, pinState);
+		if(pinState != GPIO::EHigh)
+			{
+			result = EFalse;
+			}
+		}
+
+	// restore back oryginal pad configuration for these pins
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_CLK,  SCM::EMsw, mode_MMC2_CLK);
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, mode_MMC2_DAT0);
+
+	return result;
+	}
+
+#endif /* __KERNEL_MODE__ */
+
+#endif /* __D_SPI_CLIENT_MASTER__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.mmp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,49 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/d_spi_client_m.mmp
+//
+
+#define __USING_ASSP_REGISTER_API__
+#define __USING_ASSP_INTERRUPT_API__
+
+#include <beagle/variant.mmh>
+#include <kernel/kern_ext.mmh>
+
+// link against the IIC controller library..
+library       iic.lib
+
+target        VariantTarget(d_spi_client_m,ldd)
+romtarget     d_spi_client_m.ldd
+
+// for testing only (for local loop-back detection) - link agains GPIO..
+library       AsspTarget(gpio,lib)
+
+targettype     ldd
+sourcepath     ./
+source         d_spi_client_m.cpp
+
+OS_LAYER_SYSTEMINCLUDE
+SYSTEMINCLUDE    +\include\assp\omap3530_assp
+SYSTEMINCLUDE 	 +\include\drivers
+SYMBIAN_BASE_SYSTEMINCLUDE(assp/omap3530_assp)
+SYMBIAN_BASE_SYSTEMINCLUDE(drivers)
+SYMBIAN_BASE_SYSTEMINCLUDE(kernel)
+
+
+uid		0x100000af
+vendorid 0x70000001
+
+capability		all
+epocallowdlldata
+
+SMPSAFE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,126 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/t_spi_client_master.cpp
+//
+// user-side application for the simple SPI client (master) test driver.
+//
+
+#include <e32test.h>
+#include <e32cmn.h>
+#include "d_spi_client_m.h"
+
+
+// global data..
+_LIT(testName,"T_SPI_CLIENT_M");
+GLDEF_D RTest test(testName);
+
+GLDEF_D RSpiClientTest testLdd; // the actual driver..
+
+void PrepareDriver()
+	{
+	// Load the Test Driver
+	TInt r = User::LoadLogicalDevice(KLddFileName);
+	if(r != KErrNone && r != KErrAlreadyExists)
+		{
+		// fail..
+		test.Printf(_L("\nFailed to load the driver, r=%d"), r);
+		test(EFalse);
+		}
+
+	// Open the driver
+	r = testLdd.Open();
+	if(r != KErrNone)
+		{
+		test.Printf(_L("Failed to open the driver..\n\r"));
+		test(EFalse);
+		}
+	}
+
+void ReleaseDriver()
+	{
+	// Close the driver
+	testLdd.Close();
+
+	// unload the driver
+	User::FreeLogicalDevice(KLddFileName);
+	}
+
+inline void TestError(TInt r)
+	{
+	if(r == KErrNotSupported) // this is to warn stuf not yet implemented (TDD)
+		{
+		test.Printf(_L("!! Warning: not implemented yet..\n\r"));
+		}
+	else
+		{
+		test(r == KErrNone);
+		}
+	}
+
+void TestSynchronousOperation()
+	{
+	test.Next(_L("TestSynchronousOperations:"));
+
+	test.Next(_L("HalfDuplexSingleWrite()"));
+	TestError(testLdd.HalfDuplexSingleWrite());
+
+	test.Next(_L("HalfDuplexMultipleWrite()"));
+	TestError(testLdd.HalfDuplexMultipleWrite());
+
+	test.Next(_L("HalfDuplexSingleRead()"));
+	TestError(testLdd.HalfDuplexSingleRead());
+
+	test.Next(_L("HalfDuplexMultipleRead()"));
+	TestError(testLdd.HalfDuplexMultipleRead());
+
+	test.Next(_L("HalfDuplexMultipleWriteRead()"));
+	TestError(testLdd.HalfDuplexMultipleWriteRead());
+
+	test.Next(_L("FullDuplexSingle()"));
+	TestError(testLdd.FullDuplexSingle());
+
+	test.Next(_L("FullDuplexMultiple()"));
+	TestError(testLdd.FullDuplexMultiple());
+	}
+
+void TestAsynchronousOperation()
+	{
+	test.Next(_L("Test_AsynchronousOperations:"));
+
+	TRequestStatus status;
+
+	test.Next(_L("HalfDuplexSingleWrite()"));
+	testLdd.HalfDuplexSingleWrite(status);
+	User::WaitForRequest(status); // wait for completion..
+	if(status != KErrNone)
+		{
+		test.Printf(_L("Error was %d"), status.Int());
+		test(EFalse);
+		}
+
+	}
+
+TInt E32Main()
+	{
+	test.Title();
+	test.Start(_L("Testing SPI.."));
+	PrepareDriver();
+
+	TestSynchronousOperation();
+	TestAsynchronousOperation();
+
+	ReleaseDriver();
+	test.End();
+	return KErrNone;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/t_spi_client_m.mmp	Sun Nov 21 02:23:11 2010 +0000
@@ -0,0 +1,31 @@
+// 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:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/t_spi_client_m.mmp
+//
+
+target			t_spi_client_m.exe
+targettype		exe
+
+sourcepath      .
+source  		t_spi_client_m.cpp
+
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+SYMBIAN_BASE_SYSTEMINCLUDE(nkern)
+
+library 	euser.lib hal.lib
+
+capability 	all
+
+
+VENDORID 0x70000001
+
--- a/omap3530/shared/serialkeyb/serialkeyboard.cpp	Sun Nov 21 00:50:10 2010 +0000
+++ b/omap3530/shared/serialkeyb/serialkeyboard.cpp	Sun Nov 21 02:23:11 2010 +0000
@@ -378,7 +378,6 @@
  			}
 
 		__KTRACE_OPT(KEXTENSION,Kern::Printf("+TSerialKeyboard::Create bound to interrupt" ));
-
 #ifdef USE_SYMBIAN_PRM
 		// Ask power resource manager to turn on clocks to the UART
 		// (this could take some time but we're not in any hurry)