--- 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)