# HG changeset patch # User Lukasz Forynski # Date 1290306191 0 # Node ID 7f1628607b7764421d9351cf0eec9438175199f3 # Parent 0a9dcad6d85645b6e7420289105257f5b1de091c# Parent 8dfd870f0c0f7def67cfa05973f129c38edd95bb merged Beagle_BSP_dev back to default diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/base_beagle.mrp --- 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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/byd_touch/bld.inf --- /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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/byd_touch/common/controller.cpp --- /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 +#include +#include +#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; + } + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/byd_touch/common/controller.h --- /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 +#include + + +// 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 iSpiTransactionHeader; + TBuf8 iSpiWriteBuffer; + TBuf8 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_ */ diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/byd_touch/xyin.mmp --- /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 + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/byd_touch/xyin/mconf.h --- /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 + +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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/byd_touch/xyin/xyin.cpp --- /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 +#include +#include +#include +#include +#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() + { + } + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/led/led.cpp --- 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 { diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagle_drivers/led/led.mmp --- 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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagleboard/bootstrap/beagle.s --- 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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagleboard/rom/base_beagle.iby --- 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 +#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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagleboard/rom/kernel.iby --- 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 // 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 -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 +#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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/beagleboard/src/variant.cpp --- 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 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 +#include +#include +#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 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; + } + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/master.h --- /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 + +_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__ diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/omap3530_spi.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 +#include + +#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::Value; +const TUint MCSPI2 = Omap3530HwBase::TVirtual::Value; +const TUint MCSPI3 = Omap3530HwBase::TVirtual::Value; +const TUint MCSPI4 = Omap3530HwBase::TVirtual::Value; + +// map of SPI base addresses.. +const TUint KMcSpiRegBase[] = + { + Omap3530HwBase::TVirtual::Value, //McSPI module 1 + Omap3530HwBase::TVirtual::Value, //McSPI module 2 + Omap3530HwBase::TVirtual::Value, //McSPI module 3 + Omap3530HwBase::TVirtual::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__ */ diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/omap3530_spi.inl --- /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; + } + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/psl_init.cpp --- /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 +#include + +#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; + } diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/psl_init.h --- /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__*/ diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/slave.cpp --- /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 +#include +#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); + // 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; + } + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/slave.h --- /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 + +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__*/ diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/spi.iby --- /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 + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/spi.mmp --- /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 +//#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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp --- /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 +#include +#include +#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 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 header(KHeader); + + // create transfer object + const TInt KBuffLength = 64; + TBuf8 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 header(KHeader); + + // create transfer objects + const TInt KBuffLength = 64; + TBuf8 txTransferBuf1; + TBuf8 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 header(KHeader); + + // create transfer objects + const TInt KBuffLength = 64; + TBuf8 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 header(KHeader); + + // create transfer objects + const TInt KBuffLength1 = 32; + const TInt KBuffLength2 = 15; + + TBuf8 rxTransferBuf1; + TBuf8 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 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 txTransferBuf1; // txbuffer1.. + TBuf8 txTransferBuf2; // txbuffer2.. + TBuf8 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 header(KHeader); + + // create transfer objects (they SHOULD be of the same size!) + const TInt KBuffLength = 64; + TBuf8 txTransferBuf; // txbuffer.. + TBuf8 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 header(KHeader); + + // create buffers: + // for first duplex transfer + const TInt KBuffLength1 = 24; + TBuf8 txTransferBuf1; + TBuf8 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 rxTransferBuf2; + TBuf8 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 + 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.. + } + + + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/test/d_spi_client_m.h --- /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 +#include + + +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 + +// 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 +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 +#include +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__ */ diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/test/d_spi_client_m.mmp --- /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 +#include + +// 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 diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp --- /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 +#include +#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; + } + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/omap3530_drivers/spi/test/t_spi_client_m.mmp --- /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 + diff -r 0a9dcad6d856 -r 7f1628607b77 omap3530/shared/serialkeyb/serialkeyboard.cpp --- 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)