Added IIC SPI implementation / tests (Master channel only) Beagle_BSP_dev
authorLukasz Forynski <lukasz.forynski@gmail.com>
Tue, 21 Sep 2010 02:30:11 +0100
branchBeagle_BSP_dev
changeset 77 e5fd00cbb70a
parent 76 29b14275133a
child 82 65b40f262685
Added IIC SPI implementation / tests (Master channel only)
omap3530/assp/bld.inf
omap3530/assp/inc/omap3530_scm.h
omap3530/base_beagle.mrp
omap3530/beagle_drivers/led/led.mmp
omap3530/beagleboard/rom/base_beagle.iby
omap3530/beagleboard/rom/kernel.iby
omap3530/bld.inf
omap3530/omap3530_drivers/spi/bld.inf
omap3530/omap3530_drivers/spi/master.cpp
omap3530/omap3530_drivers/spi/master.h
omap3530/omap3530_drivers/spi/omap3530_spi.h
omap3530/omap3530_drivers/spi/omap3530_spi.inl
omap3530/omap3530_drivers/spi/psl_init.cpp
omap3530/omap3530_drivers/spi/psl_init.h
omap3530/omap3530_drivers/spi/slave.cpp
omap3530/omap3530_drivers/spi/slave.h
omap3530/omap3530_drivers/spi/spi.iby
omap3530/omap3530_drivers/spi/spi.mmp
omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp
omap3530/omap3530_drivers/spi/test/d_spi_client_m.h
omap3530/omap3530_drivers/spi/test/d_spi_client_m.mmp
omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp
omap3530/omap3530_drivers/spi/test/t_spi_client_m.mmp
--- a/omap3530/assp/bld.inf	Mon Sep 20 21:28:54 2010 +0100
+++ b/omap3530/assp/bld.inf	Tue Sep 21 02:30:11 2010 +0100
@@ -19,14 +19,15 @@
 
 PRJ_EXPORTS
 
-./inc/assp.mmh				assp/omap3530_assp/		//
-./inc/omap3530_assp_priv.h		assp/omap3530_assp/		//
-./inc/omap3530_irqmap.h			assp/omap3530_assp/		//
-./inc/omap3530_hardware_base.h		assp/omap3530_assp/		//
-./inc/omap3530_timer.h			assp/omap3530_assp/		//
-./inc/omap3530_ktrace.h			assp/omap3530_assp/		//
-./inc/omap3530_asspreg.h			assp/omap3530_assp/		//
-./inc/locks.h			assp/omap3530_assp/		//
+./inc/assp.mmh                  assp/omap3530_assp/    //
+./inc/omap3530_assp_priv.h      assp/omap3530_assp/    //
+./inc/omap3530_irqmap.h         assp/omap3530_assp/    //
+./inc/omap3530_hardware_base.h  assp/omap3530_assp/    //
+./inc/omap3530_timer.h          assp/omap3530_assp/    //
+./inc/omap3530_ktrace.h         assp/omap3530_assp/    //
+./inc/omap3530_asspreg.h        assp/omap3530_assp/    //
+./inc/omap3530_scm.h            assp/omap3530_assp/    //
+./inc/locks.h                   assp/omap3530_assp/    //
 
 
 PRJ_MMPFILES
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/assp/inc/omap3530_scm.h	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,246 @@
+// 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/assp/inc/omap3530_scm.h
+//
+// Contains definitions of SCM pad control registers and
+// helper functions to manipulate PAD configuration
+// (i.e. to change pin functions / modes)
+//
+
+#ifndef __OMAP3530_SCM_H__
+#define __OMAP3530_SCM_H__
+
+#include <assp/omap3530_assp/omap3530_hardware_base.h>
+#include <assp.h>
+
+class SCM
+	{
+public:
+
+	enum TPadConfigFlags
+		{
+		EMode0             = 0x0,
+		EMode1             = 0x1,
+		EMode2             = 0x2,
+		EMode3             = 0x3,
+		EMode4             = 0x4,
+		EMode5             = 0x5,
+		EMode6             = 0x6,
+		ETestMode          = 0x7,
+		EPullUdEnable      = 0x8,
+		EPullTypeSelect    = 0x10,
+		EInputEnable       = 0x100,
+		EOffEnable         = 0x200,
+		EOffOutEnable      = 0x400,
+		EOffOutValue       = 0x800,
+		EOffPullUdEnable   = 0x1000,
+		EOffPullTypeSelect = 0x2000,
+		EWakeUpEnable      = 0x4000,
+		EWakeUpEvent       = 0x8000,
+		};
+
+	enum TLowerHigherWord
+		{
+		ELsw = 0,
+		EMsw
+		};
+
+	/**
+	 Set pad configuration
+	 @param aPadAddr - address of padconf register (one of defined below)
+	 @param aAtMsw   - one of TLowerHigherWords (flag) to specify which 16bit part
+	                    of the register should be updated (i.e. there is one register
+	                    for two pins)
+	 @param aConfig  - a bitmask of TPadConfigFlags (note to only useone of EModeXx values)
+	 */
+	inline static void SetPadConfig(TUint32 aPadAddr, TLowerHigherWord aAtMsw, TUint aConfig)
+		{
+		TUint clear_mask = aAtMsw ? (0xffffu ^ aConfig) << 16 : 0xffffu ^ aConfig;
+		TUint set_mask   = aAtMsw ? (0xffffu & aConfig) << 16 : 0xffffu & aConfig;
+		AsspRegister::Modify32(aPadAddr, clear_mask, set_mask);
+		}
+
+	/**
+	 Get pad configuration
+	 */
+	inline static TUint GetPadConfig(TUint32 aPadAddr, TLowerHigherWord aAtMsw)
+		{
+		TUint val = AsspRegister::Read32(aPadAddr);
+		return aAtMsw ? val >> 16 : val & 0xffffu;
+		}
+	};
+
+const TUint32 CONTROL_PADCONF_SDRC_D0 = Omap3530HwBase::TVirtual<0x48002030>::Value; // sdrc_d0
+const TUint32 CONTROL_PADCONF_SDRC_D2 = Omap3530HwBase::TVirtual<0x48002034>::Value; // sdrc_d2
+const TUint32 CONTROL_PADCONF_SDRC_D4 = Omap3530HwBase::TVirtual<0x48002038>::Value; // sdrc_d4
+const TUint32 CONTROL_PADCONF_SDRC_D6 = Omap3530HwBase::TVirtual<0x4800203C>::Value; // sdrc_d6
+const TUint32 CONTROL_PADCONF_SDRC_D8 = Omap3530HwBase::TVirtual<0x48002040>::Value; // sdrc_d8
+const TUint32 CONTROL_PADCONF_SDRC_D10 = Omap3530HwBase::TVirtual<0x48002044>::Value; // sdrc_d10
+const TUint32 CONTROL_PADCONF_SDRC_D12 = Omap3530HwBase::TVirtual<0x48002048>::Value; // sdrc_d12
+const TUint32 CONTROL_PADCONF_SDRC_D14 = Omap3530HwBase::TVirtual<0x4800204C>::Value; // sdrc_d14
+const TUint32 CONTROL_PADCONF_SDRC_D16 = Omap3530HwBase::TVirtual<0x48002050>::Value; // sdrc_d16
+const TUint32 CONTROL_PADCONF_SDRC_D18 = Omap3530HwBase::TVirtual<0x48002054>::Value; // sdrc_d18
+const TUint32 CONTROL_PADCONF_SDRC_D20 = Omap3530HwBase::TVirtual<0x48002058>::Value; // sdrc_d20
+const TUint32 CONTROL_PADCONF_SDRC_D22 = Omap3530HwBase::TVirtual<0x4800205C>::Value; // sdrc_d22
+const TUint32 CONTROL_PADCONF_SDRC_D24 = Omap3530HwBase::TVirtual<0x48002060>::Value; // sdrc_d24
+const TUint32 CONTROL_PADCONF_SDRC_D26 = Omap3530HwBase::TVirtual<0x48002064>::Value; // sdrc_d26
+const TUint32 CONTROL_PADCONF_SDRC_D28 = Omap3530HwBase::TVirtual<0x48002068>::Value; // sdrc_d28
+const TUint32 CONTROL_PADCONF_SDRC_D30 = Omap3530HwBase::TVirtual<0x4800206C>::Value; // sdrc_d30
+const TUint32 CONTROL_PADCONF_SDRC_CLK = Omap3530HwBase::TVirtual<0x48002070>::Value; // sdrc_clk
+const TUint32 CONTROL_PADCONF_SDRC_CKE1 = Omap3530HwBase::TVirtual<0x48002264>::Value; // sdrc_cke1 safe_mode_
+const TUint32 CONTROL_PADCONF_SDRC_DQS1 = Omap3530HwBase::TVirtual<0x48002074>::Value; // sdrc_dqs1
+const TUint32 CONTROL_PADCONF_SDRC_DQS3 = Omap3530HwBase::TVirtual<0x48002078>::Value; // sdrc_dqs3
+const TUint32 CONTROL_PADCONF_GPMC_A2 = Omap3530HwBase::TVirtual<0x4800207C>::Value; // gpmc_a2 gpio_35 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_A4 = Omap3530HwBase::TVirtual<0x48002080>::Value; // gpmc_a4 gpio_37 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_A6 = Omap3530HwBase::TVirtual<0x48002084>::Value; // gpmc_a6 gpio_39 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_A8 = Omap3530HwBase::TVirtual<0x48002088>::Value; // gpmc_a8 gpio_41 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_A10 = Omap3530HwBase::TVirtual<0x4800208C>::Value; // gpmc_a10 sys_ndmareq3 gpio_43 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_D1 = Omap3530HwBase::TVirtual<0x48002090>::Value; // gpmc_d1
+const TUint32 CONTROL_PADCONF_GPMC_D3 = Omap3530HwBase::TVirtual<0x48002094>::Value; // gpmc_d3
+const TUint32 CONTROL_PADCONF_GPMC_D5 = Omap3530HwBase::TVirtual<0x48002098>::Value; // gpmc_d5
+const TUint32 CONTROL_PADCONF_GPMC_D7 = Omap3530HwBase::TVirtual<0x4800209C>::Value; // gpmc_d7
+const TUint32 CONTROL_PADCONF_GPMC_D9 = Omap3530HwBase::TVirtual<0x480020A0>::Value; // gpmc_d9 gpio_45 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_D11 = Omap3530HwBase::TVirtual<0x480020A4>::Value; // gpmc_d11 gpio_47 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_D13 = Omap3530HwBase::TVirtual<0x480020A8>::Value; // gpmc_d13 gpio_49 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_D15 = Omap3530HwBase::TVirtual<0x480020AC>::Value; // gpmc_d15 gpio_51 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_NCS1 = Omap3530HwBase::TVirtual<0x480020B0>::Value; // gpmc_ncs1 gpio_52 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_NCS3 = Omap3530HwBase::TVirtual<0x480020B4>::Value; // gpmc_ncs3 sys_ndmareq0 gpio_54 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_NCS5 = Omap3530HwBase::TVirtual<0x480020B8>::Value; // gpmc_ncs5 sys_ndmareq2 mcbsp4_dr gpt10_pwm_evt gpio_56 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_NCS7 = Omap3530HwBase::TVirtual<0x480020BC>::Value; // gpmc_ncs7 gpmc_io_dir mcbsp4_fsx gpt8_pwm_evt gpio_58 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_NADV_ALE = Omap3530HwBase::TVirtual<0x480020C0>::Value; // gpmc_nadv_ale
+const TUint32 CONTROL_PADCONF_GPMC_NWE = Omap3530HwBase::TVirtual<0x480020C4>::Value; // gpmc_nwe
+const TUint32 CONTROL_PADCONF_GPMC_NBE1 = Omap3530HwBase::TVirtual<0x480020C8>::Value; // gpmc_nbe1 gpio_61 safe_mode
+const TUint32 CONTROL_PADCONF_GPMC_WAIT0 = Omap3530HwBase::TVirtual<0x480020CC>::Value; // gpmc_wait0
+const TUint32 CONTROL_PADCONF_GPMC_WAIT2 = Omap3530HwBase::TVirtual<0x480020D0>::Value; // gpmc_wait2 gpio_64 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_PCLK = Omap3530HwBase::TVirtual<0x480020D4>::Value; // dss_pclk gpio_66 hw_dbg12 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_VSYNC = Omap3530HwBase::TVirtual<0x480020D8>::Value; // dss_vsync gpio_68 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA0 = Omap3530HwBase::TVirtual<0x480020DC>::Value; // dss_data0 dsi_dx0 uart1_cts dssvenc656_data gpio_70 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA2 = Omap3530HwBase::TVirtual<0x480020E0>::Value; // dss_data2 dsi_dx1 dssvenc656_data gpio_72 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA4 = Omap3530HwBase::TVirtual<0x480020E4>::Value; // dss_data4 dsi_dx2 uart3_rx_irrx dssvenc656_data gpio_74 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA6 = Omap3530HwBase::TVirtual<0x480020E8>::Value; // dss_data6 uart1_tx dssvenc656_data gpio_76 hw_dbg14 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA8 = Omap3530HwBase::TVirtual<0x480020EC>::Value; // dss_data8 gpio_78 hw_dbg16 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA10 = Omap3530HwBase::TVirtual<0x480020F0>::Value; // dss_data10 sdi_dat1n gpio_80 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA12 = Omap3530HwBase::TVirtual<0x480020F4>::Value; // dss_data12 sdi_dat2n gpio_82 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA14 = Omap3530HwBase::TVirtual<0x480020F8>::Value; // dss_data14 sdi_dat3n gpio_84 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA16 = Omap3530HwBase::TVirtual<0x480020FC>::Value; // dss_data16 gpio_86 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA18 = Omap3530HwBase::TVirtual<0x48002100>::Value; // dss_data18 sdi_vsync mcspi3_clk dss_data0 gpio_88 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA20 = Omap3530HwBase::TVirtual<0x48002104>::Value; // dss_data20 sdi_den mcspi3_somi dss_data2 gpio_90 safe_mode
+const TUint32 CONTROL_PADCONF_DSS_DATA22 = Omap3530HwBase::TVirtual<0x48002108>::Value; // dss_data22 sdi_clkp mcspi3_cs1 dss_data4 gpio_92 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_HS = Omap3530HwBase::TVirtual<0x4800210C>::Value; // cam_hs gpio_94 hw_dbg0 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_XCLKA = Omap3530HwBase::TVirtual<0x48002110>::Value; // cam_xclka gpio_96 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_FLD = Omap3530HwBase::TVirtual<0x48002114>::Value; // cam_fld cam_global_rese gpio_98 hw_dbg3 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_D1 = Omap3530HwBase::TVirtual<0x48002118>::Value; // cam_d1 csi2_dy2 gpio_100 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_D3 = Omap3530HwBase::TVirtual<0x4800211C>::Value; // cam_d3 gpio_102 hw_dbg5 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_D5 = Omap3530HwBase::TVirtual<0x48002120>::Value; // cam_d5 gpio_104 hw_dbg7 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_D7 = Omap3530HwBase::TVirtual<0x48002124>::Value; // cam_d7 gpio_106 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_D9 = Omap3530HwBase::TVirtual<0x48002128>::Value; // cam_d9 gpio_108 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_D11 = Omap3530HwBase::TVirtual<0x4800212C>::Value; // cam_d11 gpio_110 hw_dbg9 safe_mode
+const TUint32 CONTROL_PADCONF_CAM_WEN = Omap3530HwBase::TVirtual<0x48002130>::Value; // cam_wen cam_shutter gpio_167 hw_dbg10 safe_mode
+const TUint32 CONTROL_PADCONF_CSI2_DX0 = Omap3530HwBase::TVirtual<0x48002134>::Value; // csi2_dx0 gpio_112 safe_mode
+const TUint32 CONTROL_PADCONF_CSI2_DX1 = Omap3530HwBase::TVirtual<0x48002138>::Value; // csi2_dx1 gpio_114 safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP2_FSX = Omap3530HwBase::TVirtual<0x4800213C>::Value; // mcbsp2_fsx gpio_116 safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP2_DR = Omap3530HwBase::TVirtual<0x48002140>::Value; // mcbsp2_dr gpio_118 safe_mode
+const TUint32 CONTROL_PADCONF_MMC1_CLK = Omap3530HwBase::TVirtual<0x48002144>::Value; // mmc1_clk ms_clk gpio_120 safe_mode
+const TUint32 CONTROL_PADCONF_MMC1_DAT0 = Omap3530HwBase::TVirtual<0x48002148>::Value; // mmc1_dat0 ms_dat0 gpio_122 safe_mode
+const TUint32 CONTROL_PADCONF_MMC1_DAT2 = Omap3530HwBase::TVirtual<0x4800214C>::Value; // mmc1_dat2 ms_dat2 gpio_124 safe_mode
+const TUint32 CONTROL_PADCONF_MMC1_DAT4 = Omap3530HwBase::TVirtual<0x48002150>::Value; // mmc1_dat4 sim_io gpio_126 safe_mode
+const TUint32 CONTROL_PADCONF_MMC1_DAT6 = Omap3530HwBase::TVirtual<0x48002154>::Value; // mmc1_dat6 sim_pwrctrl gpio_128 safe_mode
+const TUint32 CONTROL_PADCONF_MMC2_CLK = Omap3530HwBase::TVirtual<0x48002158>::Value; // mmc2_clk mcspi3_clk gpio_130 safe_mode
+const TUint32 CONTROL_PADCONF_MMC2_DAT0 = Omap3530HwBase::TVirtual<0x4800215C>::Value; // mmc2_dat0 mcspi3_somi gpio_132 safe_mode
+const TUint32 CONTROL_PADCONF_MMC2_DAT2 = Omap3530HwBase::TVirtual<0x48002160>::Value; // mmc2_dat2 mcspi3_cs1 gpio_134 safe_mode
+const TUint32 CONTROL_PADCONF_MMC2_DAT4 = Omap3530HwBase::TVirtual<0x48002164>::Value; // mmc2_dat4 mmc2_dir_dat0 mmc3_dat0 gpio_136 safe_mode
+const TUint32 CONTROL_PADCONF_MMC2_DAT6 = Omap3530HwBase::TVirtual<0x48002168>::Value; // mmc2_dat6 mmc2_dir_cmd cam_shutter mmc3_dat2 gpio_138 hsusb3_tll_dir safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP3_DX = Omap3530HwBase::TVirtual<0x4800216C>::Value; // mcbsp3_dx uart2_cts gpio_140 hsusb3_tll_data4 safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP3_CLKX = Omap3530HwBase::TVirtual<0x48002170>::Value; // mcbsp3_clkx uart2_tx gpio_142 hsusb3_tll_data6 safe_mode
+const TUint32 CONTROL_PADCONF_UART2_CTS = Omap3530HwBase::TVirtual<0x48002174>::Value; // uart2_cts mcbsp3_dx gpt9_pwm_evt gpio_144 safe_mode
+const TUint32 CONTROL_PADCONF_UART2_TX = Omap3530HwBase::TVirtual<0x48002178>::Value; // uart2_tx mcbsp3_clkx gpt11_pwm_evt gpio_146 safe_mode
+const TUint32 CONTROL_PADCONF_UART1_TX = Omap3530HwBase::TVirtual<0x4800217C>::Value; // uart1_tx gpio_148 safe_mode
+const TUint32 CONTROL_PADCONF_UART1_CTS = Omap3530HwBase::TVirtual<0x48002180>::Value; // uart1_cts gpio_150 hsusb3_tll_clk safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP4_CLKX = Omap3530HwBase::TVirtual<0x48002184>::Value; // mcbsp4_clkx gpio_152 hsusb3_tll_data1 mm3_txse0 safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP4_DX = Omap3530HwBase::TVirtual<0x48002188>::Value; // mcbsp4_dx gpio_154 hsusb3_tll_data2 mm3_txdat safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP1_CLKR = Omap3530HwBase::TVirtual<0x4800218C>::Value; // mcbsp1_clkr mcspi4_clk sim_cd gpio_156 safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP1_DX = Omap3530HwBase::TVirtual<0x48002190>::Value; // mcbsp1_dx mcspi4_simo mcbsp3_dx gpio_158 safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP_CLKS = Omap3530HwBase::TVirtual<0x48002194>::Value; // mcbsp_clks cam_shutter gpio_160 uart1_cts safe_mode
+const TUint32 CONTROL_PADCONF_MCBSP1_CLKX = Omap3530HwBase::TVirtual<0x48002198>::Value; // mcbsp1_clkx mcbsp3_clkx gpio_162 safe_mode
+const TUint32 CONTROL_PADCONF_UART3_RTS_SD = Omap3530HwBase::TVirtual<0x4800219C>::Value; // uart3_rts_sd gpio_164 safe_mode
+const TUint32 CONTROL_PADCONF_UART3_TX_IRTX = Omap3530HwBase::TVirtual<0x480021A0>::Value; // uart3_tx_irtx gpio_166 safe_mode
+const TUint32 CONTROL_PADCONF_HSUSB0_STP = Omap3530HwBase::TVirtual<0x480021A4>::Value; // hsusb0_stp gpio_121 safe_mode
+const TUint32 CONTROL_PADCONF_HSUSB0_NXT = Omap3530HwBase::TVirtual<0x480021A8>::Value; // hsusb0_nxt gpio_124 safe_mode
+const TUint32 CONTROL_PADCONF_HSUSB0_DATA1 = Omap3530HwBase::TVirtual<0x480021AC>::Value; // hsusb0_data1 uart3_rx_irrx gpio_130 safe_mode
+const TUint32 CONTROL_PADCONF_HSUSB0_DATA3 = Omap3530HwBase::TVirtual<0x480021B0>::Value; // hsusb0_data3 uart3_cts_rctx gpio_169 safe_mode
+const TUint32 CONTROL_PADCONF_HSUSB0_DATA5 = Omap3530HwBase::TVirtual<0x480021B4>::Value; // hsusb0_data5 gpio_189 safe_mode
+const TUint32 CONTROL_PADCONF_HSUSB0_DATA7 = Omap3530HwBase::TVirtual<0x480021B8>::Value; // hsusb0_data7 gpio_191 safe_mode
+const TUint32 CONTROL_PADCONF_I2C1_SDA = Omap3530HwBase::TVirtual<0x480021BC>::Value; // i2c1_sda
+const TUint32 CONTROL_PADCONF_I2C2_SDA = Omap3530HwBase::TVirtual<0x480021C0>::Value; // i2c2_sda gpio_183 safe_mode
+const TUint32 CONTROL_PADCONF_I2C3_SDA = Omap3530HwBase::TVirtual<0x480021C4>::Value; // i2c3_sda gpio_185 safe_mode
+const TUint32 CONTROL_PADCONF_MCSPI1_CLK = Omap3530HwBase::TVirtual<0x480021C8>::Value; // mcspi1_clk mmc2_dat4 gpio_171 safe_mode
+const TUint32 CONTROL_PADCONF_MCSPI1_SOMI = Omap3530HwBase::TVirtual<0x480021CC>::Value; // mcspi1_somi mmc2_dat6 gpio_173 safe_mode
+const TUint32 CONTROL_PADCONF_MCSPI1_CS1 = Omap3530HwBase::TVirtual<0x480021D0>::Value; // mcspi1_cs1 adpllv2d_dither mmc3_cmd gpio_175 safe_mode
+const TUint32 CONTROL_PADCONF_MCSPI1_CS3 = Omap3530HwBase::TVirtual<0x480021D4>::Value; // mcspi1_cs3 hsusb2_tll_data2 hsusb2_data2 gpio_177 mm2_txdat safe_mode
+const TUint32 CONTROL_PADCONF_MCSPI2_SIMO = Omap3530HwBase::TVirtual<0x480021D8>::Value; // mcspi2_simo gpt9_pwm_evt hsusb2_tll_data4 hsusb2_data4 gpio_179 safe_mode
+const TUint32 CONTROL_PADCONF_MCSPI2_CS0 = Omap3530HwBase::TVirtual<0x480021DC>::Value; // mcspi2_cs0 gpt11_pwm_evt hsusb2_tll_data6 hsusb2_data6 gpio_181 safe_mode
+const TUint32 CONTROL_PADCONF_SYS_NIRQ = Omap3530HwBase::TVirtual<0x480021E0>::Value; // sys_nirq gpio_0 safe_mode
+const TUint32 CONTROL_PADCONF_ETK_CLK = Omap3530HwBase::TVirtual<0x480025D8>::Value; // etk_clk mcbsp5_clkx mmc3_clk hsusb1_stp gpio_12 mm1_rxdp hsusb1_tll_stp hw_dbg0
+const TUint32 CONTROL_PADCONF_ETK_D0 = Omap3530HwBase::TVirtual<0x480025DC>::Value; // etk_d0 mcspi3_simo mmc3_dat4 hsusb1_data0 gpio_14 mm1_rxrcv hsusb1_tll_data0 hw_dbg2
+const TUint32 CONTROL_PADCONF_ETK_D2 = Omap3530HwBase::TVirtual<0x480025E0>::Value; // etk_d2 mcspi3_cs0 hsusb1_data2 gpio_16 mm1_txdat hsusb1_tll_data2 hw_dbg4
+const TUint32 CONTROL_PADCONF_ETK_D4 = Omap3530HwBase::TVirtual<0x480025E4>::Value; // etk_d4 mcbsp5_dr mmc3_dat0 hsusb1_data4 gpio_18 hsusb1_tll_data4 hw_dbg6
+const TUint32 CONTROL_PADCONF_ETK_D6 = Omap3530HwBase::TVirtual<0x480025E8>::Value; // etk_d6 mcbsp5_dx mmc3_dat2 hsusb1_data6 gpio_20 hsusb1_tll_data6 hw_dbg8
+const TUint32 CONTROL_PADCONF_ETK_D8 = Omap3530HwBase::TVirtual<0x480025EC>::Value; // etk_d8 Reserved for mmc3_dat6 hsusb1_dir gpio_22 hsusb1_tll_dir hw_dbg10
+const TUint32 CONTROL_PADCONF_ETK_D10 = Omap3530HwBase::TVirtual<0x480025F0>::Value; // etk_d10 uart1_rx hsusb2_clk gpio_24 hsusb2_tll_clk hw_dbg12
+const TUint32 CONTROL_PADCONF_ETK_D12 = Omap3530HwBase::TVirtual<0x480025F4>::Value; // etk_d12 hsusb2_dir gpio_26 hsusb2_tll_dir hw_dbg14
+const TUint32 CONTROL_PADCONF_ETK_D14 = Omap3530HwBase::TVirtual<0x480025F8>::Value; // etk_d14 hsusb2_data0 gpio_28 mm2_rxrcv hsusb2_tll_data0 hw_dbg16
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD0 = Omap3530HwBase::TVirtual<0x480021E4>::Value; // sad2d_mcad0 mad2d_mcad0
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD2 = Omap3530HwBase::TVirtual<0x480021E8>::Value; // sad2d_mcad2 mad2d_mcad2
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD4 = Omap3530HwBase::TVirtual<0x480021EC>::Value; // sad2d_mcad4 mad2d_mcad4
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD6 = Omap3530HwBase::TVirtual<0x480021F0>::Value; // sad2d_mcad6 mad2d_mcad6
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD8 = Omap3530HwBase::TVirtual<0x480021F4>::Value; // sad2d_mcad8 mad2d_mcad8
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD10 = Omap3530HwBase::TVirtual<0x480021F8>::Value; // sad2d_mcad10 mad2d_mcad10
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD12 = Omap3530HwBase::TVirtual<0x480021FC>::Value; // sad2d_mcad12 mad2d_mcad12
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD14 = Omap3530HwBase::TVirtual<0x48002200>::Value; // sad2d_mcad14 mad2d_mcad14
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD16 = Omap3530HwBase::TVirtual<0x48002204>::Value; // sad2d_mcad16 mad2d_mcad16
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD18 = Omap3530HwBase::TVirtual<0x48002208>::Value; // sad2d_mcad18 mad2d_mcad18
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD20 = Omap3530HwBase::TVirtual<0x4800220C>::Value; // sad2d_mcad20 mad2d_mcad20
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD22 = Omap3530HwBase::TVirtual<0x48002210>::Value; // sad2d_mcad22 mad2d_mcad22
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD24 = Omap3530HwBase::TVirtual<0x48002214>::Value; // sad2d_mcad24 mad2d_mcad24
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD26 = Omap3530HwBase::TVirtual<0x48002218>::Value; // sad2d_mcad26 mad2d_mcad26
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD28 = Omap3530HwBase::TVirtual<0x4800221C>::Value; // sad2d_mcad28 mad2d_mcad28
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD30 = Omap3530HwBase::TVirtual<0x48002220>::Value; // sad2d_mcad30 mad2d_mcad30
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD32 = Omap3530HwBase::TVirtual<0x48002224>::Value; // sad2d_mcad32 mad2d_mcad32
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD34 = Omap3530HwBase::TVirtual<0x48002228>::Value; // sad2d_mcad34 mad2d_mcad34
+const TUint32 CONTROL_PADCONF_SAD2D_MCAD36 = Omap3530HwBase::TVirtual<0x4800222C>::Value; // sad2d_mcad36 mad2d_mcad36
+const TUint32 CONTROL_PADCONF_SAD2D_NRESPWRON = Omap3530HwBase::TVirtual<0x48002230>::Value; // sad2d_nrespwron
+const TUint32 CONTROL_PADCONF_SAD2D_ARMNIRQ = Omap3530HwBase::TVirtual<0x48002234>::Value; // sad2d_armnirq
+const TUint32 CONTROL_PADCONF_SAD2D_SPINT = Omap3530HwBase::TVirtual<0x48002238>::Value; // sad2d_spint gpio_187
+const TUint32 CONTROL_PADCONF_SAD2D_DMAREQ0 = Omap3530HwBase::TVirtual<0x4800223C>::Value; // sad2d_dmareq0 uart2_dma_tx mmc1_dma_tx
+const TUint32 CONTROL_PADCONF_SAD2D_DMAREQ2 = Omap3530HwBase::TVirtual<0x48002240>::Value; // sad2d_dmareq2 uart1_dma_tx uart3_dma_tx
+const TUint32 CONTROL_PADCONF_SAD2D_NTRST = Omap3530HwBase::TVirtual<0x48002244>::Value; // sad2d_ntrst
+const TUint32 CONTROL_PADCONF_SAD2D_TDO = Omap3530HwBase::TVirtual<0x48002248>::Value; // sad2d_tdo
+const TUint32 CONTROL_PADCONF_SAD2D_TCK = Omap3530HwBase::TVirtual<0x4800224C>::Value; // sad2d_tck
+const TUint32 CONTROL_PADCONF_SAD2D_MSTDBY = Omap3530HwBase::TVirtual<0x48002250>::Value; // sad2d_mstdby
+const TUint32 CONTROL_PADCONF_SAD2D_IDLEACK = Omap3530HwBase::TVirtual<0x48002254>::Value; // sad2d_idleack
+const TUint32 CONTROL_PADCONF_SAD2D_SWRITE = Omap3530HwBase::TVirtual<0x48002258>::Value; // sad2d_swrite mad2d_mwrite
+const TUint32 CONTROL_PADCONF_SAD2D_SREAD = Omap3530HwBase::TVirtual<0x4800225C>::Value; // sad2d_sread mad2d_mread
+const TUint32 CONTROL_PADCONF_SAD2D_SBUSFLAG = Omap3530HwBase::TVirtual<0x48002260>::Value; // sad2d_sbusflag mad2d_mbusflag
+const TUint32 CONTROL_PADCONF_I2C4_SCL = Omap3530HwBase::TVirtual<0x48002A00>::Value; // i2c4_scl sys_nvmode1 safe_mode
+const TUint32 CONTROL_PADCONF_SYS_32K = Omap3530HwBase::TVirtual<0x48002A04>::Value; // sys_32k
+const TUint32 CONTROL_PADCONF_SYS_NRESWARM = Omap3530HwBase::TVirtual<0x48002A08>::Value; // sys_nreswarm gpio_30 safe_mode
+const TUint32 CONTROL_PADCONF_SYS_BOOT1 = Omap3530HwBase::TVirtual<0x48002A0C>::Value; // sys_boot1 gpio_3 safe_mode
+const TUint32 CONTROL_PADCONF_SYS_BOOT3 = Omap3530HwBase::TVirtual<0x48002A10>::Value; // sys_boot3 gpio_5 safe_mode
+const TUint32 CONTROL_PADCONF_SYS_BOOT5 = Omap3530HwBase::TVirtual<0x48002A14>::Value; // sys_boot5 mmc2_dir_dat3 gpio_7 safe_mode
+const TUint32 CONTROL_PADCONF_SYS_OFF_MODE = Omap3530HwBase::TVirtual<0x48002A18>::Value; // sys_off_mode gpio_9 safe_mode
+const TUint32 CONTROL_PADCONF_JTAG_NTRST = Omap3530HwBase::TVirtual<0x48002A1C>::Value; // jtag_ntrst
+const TUint32 CONTROL_PADCONF_JTAG_TMS_TMSC = Omap3530HwBase::TVirtual<0x48002A20>::Value; // jtag_tms_tmsc
+const TUint32 CONTROL_PADCONF_JTAG_EMU0 = Omap3530HwBase::TVirtual<0x48002A24>::Value; // jtag_emu0 gpio_11 safe_mode
+const TUint32 CONTROL_PADCONF_SAD2D_SWAKEUP = Omap3530HwBase::TVirtual<0x48002A4C>::Value; // sad2d_swakeup
+const TUint32 CONTROL_PADCONF_JTAG_TDO = Omap3530HwBase::TVirtual<0x48002A50>::Value; // jtag_tdo
+
+#endif /*__OMAP3530_SCM_H__*/
--- a/omap3530/base_beagle.mrp	Mon Sep 20 21:28:54 2010 +0100
+++ b/omap3530/base_beagle.mrp	Tue Sep 21 02:30:11 2010 +0100
@@ -14,6 +14,7 @@
 binary	\sf\adaptation\beagleboard\omap3530\kernel all
 binary	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\gpio all
 binary	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\i2c all
+# binary	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\spi all
 binary	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\prcm all
 # binary	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\prm all
 binary	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\uart all
@@ -35,6 +36,7 @@
 exports	\sf\adaptation\beagleboard\omap3530\kernel
 exports	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\gpio
 exports	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\i2c
+
 exports	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\prcm
 # exports	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\prm
 exports	\sf\adaptation\beagleboard\omap3530\omap3530_drivers\uart
--- a/omap3530/beagle_drivers/led/led.mmp	Mon Sep 20 21:28:54 2010 +0100
+++ b/omap3530/beagle_drivers/led/led.mmp	Tue Sep 21 02:30:11 2010 +0100
@@ -36,11 +36,11 @@
 macro USER_BUTTON_ENTERS_CRASH_DEBUGGER
 
 sourcepath			.
-source				led.cpp
+source  			led.cpp
 
 library				VariantTarget(ecust,lib) 
 library				AsspTarget(gpio,lib)
-library             		AsspTarget(prcm,lib)
+library 			AsspTarget(prcm,lib)
 
 VENDORID 0x70000001
 
--- a/omap3530/beagleboard/rom/base_beagle.iby	Mon Sep 20 21:28:54 2010 +0100
+++ b/omap3530/beagleboard/rom/base_beagle.iby	Tue Sep 21 02:30:11 2010 +0100
@@ -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,6 +104,7 @@
 extension[VARID]=\epoc32\release\ARMV5\BUILD_DIR\_omap3530_i2c.dll			\sys\bin\i2c.dll
 
 #include <../omapshared/tps65950.iby>
+#include <rom/omap3530/spi.iby>
 
 #ifdef SYMBIAN_BASE_USE_GCE
 // Use the new GCE compliant display driver  
--- a/omap3530/beagleboard/rom/kernel.iby	Mon Sep 20 21:28:54 2010 +0100
+++ b/omap3530/beagleboard/rom/kernel.iby	Tue Sep 21 02:30:11 2010 +0100
@@ -43,6 +43,7 @@
 //extension[VARID]=	\Epoc32\Release\##KMAIN##\##BUILD##\resman.ldd				\sys\bin\resman.ldd
 
 #include <rom/omapshared/tps65950.iby>
+#include <rom/omap3530/spi.iby>
 
 device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\_omap3530_EUART.PDD				\sys\bin\euart.pdd
 device[VARID]=\Epoc32\Release\ARMV5\##BUILD##\ECOMM.LDD						\sys\bin\ecomm.ldd
--- a/omap3530/bld.inf	Mon Sep 20 21:28:54 2010 +0100
+++ b/omap3530/bld.inf	Tue Sep 21 02:30:11 2010 +0100
@@ -30,6 +30,7 @@
 #include "omap3530_drivers/gpio/bld.inf"
 #include "omap3530_drivers/i2c/bld.inf"
 #include "omap3530_drivers/prcm/bld.inf"
+#include "omap3530_drivers/spi/bld.inf"
 // #include "omap3530_drivers/prm/bld.inf"
 #include "omap3530_drivers/uart/bld.inf"
 #include "omap3530_drivers/usbcc/bld.inf"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/bld.inf	Tue Sep 21 02:30:11 2010 +0100
@@ -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/bld.inf
+//
+
+
+PRJ_PLATFORMS
+ARMV5
+
+PRJ_EXPORTS
+spi.iby  rom/omap3530/
+
+PRJ_MMPFILES
+spi
+
+PRJ_TESTMMPFILES
+test/t_spi_client_m
+test/d_spi_client_m
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/master.cpp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,886 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// Implementation of IIC master channel for a SPI bus.
+//
+
+#define DBGPRINT(x)
+#define DBG_ERR(x) x
+
+
+#ifdef _DEBUG
+#define DEBUG_ONLY(x) //x
+#else
+#define DEBUG_ONLY(x)
+#endif
+
+
+// DO NOT CHANGE THESE- trying to tune the driver (unless you really know what you're doing)
+// as this this is only for development purpose to tune the driver. Fifo mode is not yet enabled, but this
+// doesn't affect operation. After development has been finished - these macros and #ifdefs will be removed
+// entirely. For now only SINGLE_MODE should ever be defined.
+//#define USE_TX_FIFO
+//#define USING_TX_COUNTER
+//#define PER_TRANSFER_MODE
+#define SINGLE_MODE
+
+#include <assp/omap3530_assp/omap3530_assp_priv.h>
+#include <assp/omap3530_assp/omap3530_prcm.h>
+#include <drivers/iic.h>
+#include "omap3530_spi.h"
+#include "psl_init.h"
+#include "master.h"
+
+DSpiMasterBeagle::DSpiMasterBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
+	DIicBusChannelMaster(aBusType, aChanDuplex),
+	iTransferEndDfc(TransferEndDfc, this, KIicPslDfcPriority)
+	{
+	iChannelNumber = aChannelNumber;
+	iIrqId = KMcSpiIrqId[iChannelNumber];
+	iHwBase = KMcSpiRegBase[iChannelNumber];
+	iState = EIdle;
+	DBGPRINT(Kern::Printf("DSpiMasterBeagle::DSpiMasterBeagle: at 0x%x, iChannelNumber = %d", this, iChannelNumber));
+	}
+
+TInt DSpiMasterBeagle::DoCreate()
+	{
+	DBGPRINT(Kern::Printf("\nDSpiMasterBeagle::DoCreate() ch: %d \n", iChannelNumber));
+	DBGPRINT(Kern::Printf("HW revision is %x", AsspRegister::Read32(iHwBase + MCSPI_REVISION)));
+
+	TInt r = KErrNone;
+
+	// Create the DFCQ to be used by the channel
+	if(!iDfcQ)
+		{
+		TBuf8<KMaxName> threadName (KIicPslThreadName);
+		threadName.AppendNum(iChannelNumber);
+		r = Kern::DfcQCreate(iDfcQ, KIicPslThreadPriority, &threadName);
+		if(r != KErrNone)
+			{
+			DBG_ERR(Kern::Printf("DFC Queue creation failed, channel number: %d, r = %d\n", iChannelNumber, r));
+			return r;
+			}
+		}
+
+	// PIL Base class initialization - this must be called prior to SetDfcQ(iDfcQ)
+	r = Init();
+	if(r == KErrNone)
+		{
+		// Call base class function to set DFCQ pointers in the required objects
+		// This also enables the channel to process transaction requests
+		SetDfcQ(iDfcQ);
+
+		// PSL DFCQ initialisation for local DFC
+		iTransferEndDfc.SetDfcQ(iDfcQ);
+
+		// Bind interrupts.
+		r = Interrupt::Bind(iIrqId, Isr, this);
+		if(r < KErrNone)
+			{
+			DBG_ERR(Kern::Printf("ERROR: InterruptBind error.. %d", r));
+			return r;
+			}
+		}
+
+	// Make sure clocks are enabled (TBD: this could go to 'PowerUp/PowerDown' if using PRM)
+	Prcm::SetClockState( Prcm::EClkMcSpi3_F, Prcm::EClkOn );
+	Prcm::SetClockState( Prcm::EClkMcSpi3_I, Prcm::EClkOn );
+	// TODO:consider auto-idle for PRCM.CM_AUTOIDLE1_CORE
+
+	SetupSpiPins(iChannelNumber);
+	// end of system wide settings..
+
+	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 = KErrNone;
+	if(TransConfigDiffersFromPrev())
+		{
+		r = ConfigureInterface();
+		if(r != KErrNone)
+			{
+			return r;
+			}
+		}
+
+	// start processing transfers of this transaction.
+	r = ProcessNextTransfers();
+	return r;
+	}
+
+TBool DSpiMasterBeagle::TransConfigDiffersFromPrev()
+	{
+	TConfigSpiV01 &newHeader = (*(TConfigSpiBufV01*) (GetTransactionHeader(iCurrTransaction)))();
+
+	// get the slave address (i.e. known as a 'channel' for the current SPI module)
+	TInt slaveAddr = GET_SLAVE_ADDR(iCurrTransaction->GetBusId());
+	DBGPRINT(Kern::Printf("slaveAddr %x", slaveAddr));
+
+	// compare it to the previous configuration..
+	if(slaveAddr                        != iCurrSS ||
+	   newHeader.iWordWidth             != iCurrHeader.iWordWidth ||
+	   newHeader.iClkSpeedHz            != iCurrHeader.iClkSpeedHz ||
+	   newHeader.iClkMode               != iCurrHeader.iClkMode ||
+	   newHeader.iTimeoutPeriod         != iCurrHeader.iTimeoutPeriod ||
+	   newHeader.iBitOrder              != iCurrHeader.iBitOrder ||
+	   newHeader.iTransactionWaitCycles != iCurrHeader.iTransactionWaitCycles ||
+	   newHeader.iSSPinActiveMode       != iCurrHeader.iSSPinActiveMode)
+		{
+		iCurrSS = slaveAddr;
+		iCurrHeader = newHeader; //copy the header..
+		return ETrue;
+		}
+	return ETrue;
+	}
+
+// 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..(Channel 3 for now)
+	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);
+
+	//AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_CLOCKACTIVITY_ALL_ON);
+
+	AsspRegister::Write32(iHwBase + MCSPI_IRQSTATUS, ~0); // clear all interrupts (for now) -- normally only for channel..
+
+	// 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
+
+	// update the register..
+	AsspRegister::Write32(iHwBase + MCSPI_CHxCONF(iCurrSS), val);
+
+	// CS (SS) pin direction..
+	val = MCSPI_SYST_SPIDATDIR0;
+
+	// drive csx pin hight or low
+	val |= (iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)? 1 << iCurrSS : 0;
+	AsspRegister::Write32(iHwBase + MCSPI_SYST, val);
+
+	// 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);
+#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 % iWordSize)
+				{
+				DBG_ERR(Kern::Printf("Wrong configuration - word size does not match buffer length"));
+				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());
+
+			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, iCurrHeader.iSSPinActiveMode);
+#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, iCurrHeader.iSSPinActiveMode);
+#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));
+		}
+
+	// make sure the CS pin is asserted..
+	if(a->iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)
+		{
+		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 0, 1 << a->iCurrSS);
+		}
+	else
+		{
+		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 1 << a->iCurrSS, 0);
+		}
+
+#ifdef SINGLE_MODE
+	// manually de-assert CS line for this channel
+	AsspRegister::Modify32(a->iHwBase + MCSPI_CHxCONF(a->iCurrSS), MCSPI_CHxCONF_FORCE, 0);
+
+	// drive csx pin high or low. Doing this here causes, that CS lines are toggled for each transfers.
+	TUint val = (a->iCurrHeader.iSSPinActiveMode == ESpiCSPinActiveLow)? 1 << a->iCurrSS : 0;
+	if (val)
+		{
+		AsspRegister::Modify32(a->iHwBase + MCSPI_SYST, 0, val);
+		}
+	// put the CS signal to 'inactive' state (as on channel disable it would have a glitch)
+	SetCsInactive(a->iChannelNumber, a->iCurrSS, a->iCurrHeader.iSSPinActiveMode);
+
+#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));
+
+	// make sure CS is in inactive state (for the current / last transaction) on error
+	if(!aComplete)
+		{
+		SetCsInactive(iChannelNumber, iCurrSS, iCurrHeader.iSSPinActiveMode);
+		}
+
+	// disable this channel (and reset..)
+	AsspRegister::Modify32(iHwBase + MCSPI_CHxCTRL(iCurrSS), MCSPI_CHxCTRL_EN, 0);
+	AsspRegister::Write32(iHwBase + MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
+
+	// 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
+			{
+#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));
+			DumpHeader(header);
+#endif
+			r = KErrNotSupported;
+			DBG_ERR(Kern::Printf("DSpiMasterBeagle::CheckHdr()failed, r = %d", r));
+			}
+		}
+	return r;
+	}
+
+// This method is called by the PIL in the case of expiry of a timer for a transaction.
+// TODO: this name is confusing - it could be changed in the PIL to reflect it's real purpose(TBD)
+// It has NOTHING to do with a Slave (i.e. slave might be completely silent for SPI-and master won't notice it!)
+TInt DSpiMasterBeagle::HandleSlaveTimeout()
+	{
+	DBG_ERR(Kern::Printf("HandleSlaveTimeout"));
+
+	// Stop the PSL's operation, and inform the PIL of the timeout
+	ExitComplete(KErrTimedOut, EFalse);
+
+	return KErrTimedOut;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/master.h	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,93 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/master.h
+//
+
+
+#ifndef __OMAP3530_SPI_MASTER_H__
+#define __OMAP3530_SPI_MASTER_H__
+
+#include <drivers/iic_channel.h>
+
+_LIT(KIicPslThreadName,"SpiChannelThread_");
+const TInt KIicPslDfcPriority = 0;
+const TInt KIicPslThreadPriority = 24;
+
+// class declaration for SPI master
+class DSpiMasterBeagle : public DIicBusChannelMaster
+	{
+public:
+	static DSpiMasterBeagle* New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex);
+	virtual TInt DoRequest(TIicBusTransaction* aTransaction); // Gateway function for PSL implementation
+
+private:
+	DSpiMasterBeagle(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex);
+
+	// Override base-class pure virtual methods
+	virtual TInt DoCreate();
+	virtual TInt CheckHdr(TDes8* aHdr);
+	virtual TInt HandleSlaveTimeout();
+
+	// Internal methods
+	TInt ConfigureInterface();
+	TBool TransConfigDiffersFromPrev();
+	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;
+	};
+
+#endif //__OMAP3530_SPI_MASTER_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/omap3530_spi.h	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,450 @@
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/omap3530_spi.h
+//
+// This file contains definitions to internal SPI implementation and register definitions
+// It is not intended to be exported - SPI registers must not be modified from outside of
+// the driver!
+//
+
+#ifndef __OMAP3530_SPI_H__
+#define __OMAP3530_SPI_H__
+
+#include <assp/omap3530_assp/omap3530_scm.h>
+
+
+#define BIT_MASK(shift,len)       (((1u << (len)) - 1) << (shift))
+#define GET_BITS(w,shift,len)     (((w) >> (shift)) & ((1 << (len)) - 1))
+#define SET_BITS(w,set,shift,len) ((w) &= ~BIT_MASK(shift, len), (w) |= ((set) << (shift)))
+
+
+// Device Instance Summary
+const TUint MCSPI1_phys = 0x48098000; // 4Kbytes
+const TUint MCSPI2_phys = 0x4809A000; // 4Kbytes
+const TUint MCSPI3_phys = 0x480B8000; // 4Kbytes
+const TUint MCSPI4_phys = 0x480BA000; // 4Kbytes
+
+const TUint MCSPI1 = Omap3530HwBase::TVirtual<MCSPI1_phys>::Value;
+const TUint MCSPI2 = Omap3530HwBase::TVirtual<MCSPI2_phys>::Value;
+const TUint MCSPI3 = Omap3530HwBase::TVirtual<MCSPI3_phys>::Value;
+const TUint MCSPI4 = Omap3530HwBase::TVirtual<MCSPI4_phys>::Value;
+
+// map of SPI base addresses..
+const TUint KMcSpiRegBase[] =
+	{
+	Omap3530HwBase::TVirtual<MCSPI1_phys>::Value, //McSPI module 1
+	Omap3530HwBase::TVirtual<MCSPI2_phys>::Value, //McSPI module 2
+	Omap3530HwBase::TVirtual<MCSPI3_phys>::Value, //McSPI module 3
+	Omap3530HwBase::TVirtual<MCSPI4_phys>::Value  //McSPI module 4
+	};
+
+
+//.. and IRQ lines for SPI channels
+const TUint KMcSpiIrqId[] =
+	{
+	EOmap3530_IRQ65_SPI1_IRQ, //McSPI module 1
+	EOmap3530_IRQ66_SPI2_IRQ, //McSPI module 2
+	EOmap3530_IRQ91_SPI3_IRQ, //McSPI module 3
+	EOmap3530_IRQ48_SPI4_IRQ  //McSPI module 4
+	};
+
+// available channels per module (i.e. number of 'slave select'  inputs/outpus per module)
+const TUint KMcSpiNumChannels[] =
+	{
+	4, // channels 0 - 3
+	2, // channels 0 - 1
+	2, // channels 0 - 1
+	1  // channel 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_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
+//----------------------------------
+
+//#define SPI_CHANNEL_3_PIN_OPTION_2 // TODO - move this to mmp file!
+//#define SPI_CHANNEL_3_PIN_OPTION_3
+
+// flags for CS signal pins - in order to keep them in certain state when SPI is inactive..
+const TUint KCsPinUp = SCM::EPullUdEnable | SCM::EPullTypeSelect; //
+const TUint KCsPinDown = SCM::EPullUdEnable; //
+
+const TUint KCsPinOffHi =  SCM::EOffOutEnable | SCM::EOffOutValue; //
+const TUint KCsPinOffLow = SCM::EOffOutEnable; //
+
+const TUint KCsPinModeUp   = /*KCsPinUp   |*//* KCsPinOffHi |*/ SCM::EInputEnable;
+const TUint KCsPinModeDown = KCsPinDown | KCsPinOffLow;
+
+const TUint KMaxSpiChannelsPerModule = 4; // there are max 4 channels (McSPI 1)
+
+struct TPinConfig
+	{
+	TLinAddr              iAddress;
+	SCM::TLowerHigherWord iMswLsw;
+	TUint16               iFlags;
+	};
+
+struct TSpiPinConfig
+	{
+	TPinConfig iClk;
+	TPinConfig iSimo;
+	TPinConfig iSomi;
+	TPinConfig iCs[KMaxSpiChannelsPerModule];
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi1 =
+	{
+	{CONTROL_PADCONF_MCSPI1_CLK,  SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi1_clk
+	{CONTROL_PADCONF_MCSPI1_CLK,  SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi1_simo
+	{CONTROL_PADCONF_MCSPI1_SOMI, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi1_somi
+		{
+		{CONTROL_PADCONF_MCSPI1_SOMI, SCM::EMsw, SCM::EMode1}, // mcspi1_cs0
+		{CONTROL_PADCONF_MCSPI1_CS1,  SCM::ELsw, SCM::EMode1}, // mcspi1_cs1
+		{CONTROL_PADCONF_MCSPI1_CS1,  SCM::EMsw, SCM::EMode1}, // mcspi1_cs2
+		{CONTROL_PADCONF_MCSPI1_CS3,  SCM::ELsw, SCM::EMode1}, // mcspi1_cs3
+		}
+	};
+
+const TSpiPinConfig TSpiPinConfigMcSpi2 =
+	{
+	{CONTROL_PADCONF_MCSPI1_CS3,  SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi2_clk
+	{CONTROL_PADCONF_MCSPI2_SIMO, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi2_simo
+	{CONTROL_PADCONF_MCSPI2_SIMO, SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi2_somi
+		{
+		{CONTROL_PADCONF_MCSPI2_CS0,  SCM::ELsw, SCM::EMode1}, // mcspi2_cs0
+		{CONTROL_PADCONF_MCSPI2_CS0,  SCM::EMsw, SCM::EMode1}, // mcspi2_cs1
+		{0, SCM::ELsw, 0}, // not supported
+		{0, SCM::ELsw, 0}, // not supported
+		}
+	};
+
+
+#if defined(SPI_CHANNEL_3_PIN_OPTION_2)
+const TSpiPinConfig TSpiPinConfigMcSpi3 =
+	{
+	{CONTROL_PADCONF_DSS_DATA18, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_clk
+	{CONTROL_PADCONF_DSS_DATA18, SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_simo
+	{CONTROL_PADCONF_DSS_DATA20, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_somi
+		{
+		{CONTROL_PADCONF_DSS_DATA20, SCM::EMsw, SCM::EMode1}, // mcspi3_cs0
+		{CONTROL_PADCONF_DSS_DATA20, SCM::ELsw, SCM::EMode1}, // mcspi3_cs1
+		{0, SCM::ELsw, 0}, // not supported
+		{0, SCM::ELsw, 0}, // not supported
+		}
+	};
+#elif defined(SPI_CHANNEL_3_PIN_OPTION_3)
+const TSpiPinConfig TSpiPinConfigMcSpi3 =
+	{
+	{CONTROL_PADCONF_ETK_D2, SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_clk
+	{CONTROL_PADCONF_ETK_D0, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_simo
+	{CONTROL_PADCONF_ETK_D0, SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_somi
+		{
+		{CONTROL_PADCONF_ETK_D2, SCM::ELsw, SCM::EMode1}, // mcspi3_cs0
+		{CONTROL_PADCONF_ETK_D6, SCM::EMsw, SCM::EMode1}, // mcspi3_cs1
+		{0, SCM::ELsw, 0}, // not supported
+		{0, SCM::ELsw, 0}, // not supported
+		}
+	};
+#else // default option (for beagle- these are pins on the extension header)
+const TSpiPinConfig TSpiPinConfigMcSpi3 =
+	{
+	{CONTROL_PADCONF_MMC2_CLK,  SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_clk
+	{CONTROL_PADCONF_MMC2_CLK,  SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_simo
+	{CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi3_somi
+		{
+		{CONTROL_PADCONF_MMC2_DAT2, SCM::EMsw, SCM::EMode1}, // mcspi3_cs0
+		{CONTROL_PADCONF_MMC2_DAT2, SCM::ELsw, SCM::EMode1}, // mcspi3_cs1
+		{0, SCM::ELsw, 0}, // not supported
+		{0, SCM::ELsw, 0}, // not supported
+		}
+	};
+#endif
+
+const TSpiPinConfig TSpiPinConfigMcSpi4 =
+	{
+	{CONTROL_PADCONF_MCBSP1_CLKR, SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi4_clk
+	{CONTROL_PADCONF_MCBSP1_DX,   SCM::ELsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi4_simo
+	{CONTROL_PADCONF_MCBSP1_DX,   SCM::EMsw, SCM::EMode1 | SCM::EInputEnable}, // mcspi4_somi
+		{
+		{CONTROL_PADCONF_MCBSP_CLKS, SCM::EMsw, SCM::EMode1}, // mcspi3_cs0
+		{0, SCM::ELsw, 0}, // not supported
+		{0, SCM::ELsw, 0}, // not supported
+		{0, SCM::ELsw, 0}, // not supported
+		}
+	};
+
+const TSpiPinConfig ModulePinConfig[] =
+	{
+	TSpiPinConfigMcSpi1,
+	TSpiPinConfigMcSpi2,
+	TSpiPinConfigMcSpi3,
+	TSpiPinConfigMcSpi4
+	};
+
+#include "omap3530_spi.inl"
+
+#endif /* __OMAP3530_SPI_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/omap3530_spi.inl	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,118 @@
+// 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..
+inline void SetCsInactive(TInt aModule, TInt aChannel, TSpiSsPinMode aActiveMode)
+	{
+	//__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	// set the pin to the opposite to the currently active CS mode..
+	TUint16 csPinOptions = aActiveMode == ESpiCSPinActiveLow ? KCsPinModeUp : KCsPinModeDown;
+	const TPinConfig& csConf = ModulePinConfig[aModule].iCs[aChannel];
+	__ASSERT_DEBUG(csConf.iAddress, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+
+	// now switch the pin mode..
+	SCM::SetPadConfig(csConf.iAddress, csConf.iMswLsw, SCM::EMode4 | csPinOptions); // always go to mode 4 (gpio)
+	}
+
+void SetCsActive(TInt aModule, TInt aChannel, TSpiSsPinMode aActiveMode)
+	{
+	//__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	TUint16 csPinOptions = aActiveMode == ESpiCSPinActiveLow ? KCsPinModeUp : KCsPinModeDown;
+	const TPinConfig &csConf = ModulePinConfig[aModule].iCs[aChannel];
+	__ASSERT_DEBUG(csConf.iAddress, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+
+	// now switch the pin mode back to the SPI
+	SCM::SetPadConfig(csConf.iAddress, csConf.iMswLsw, csConf.iFlags | csPinOptions); // revert to intended mode
+	}
+
+
+// Setup pad function for SPI pins..
+void SetupSpiPins(TUint aSpiModule)
+	{
+	//__ASSERT_DEBUG(aModule < KMaxSpiChannelsPerModule, Kern::Fault("omap3530_spi.inl, line: ", __LINE__)); // aChannel > module channels
+	const TSpiPinConfig& pinCnf = ModulePinConfig[aSpiModule];
+	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);
+	// Cs pins are set dynamically during operations.
+	}
+
+// helper function - returns appropriate value for the register for a given mode
+inline TUint32 SpiClkMode(TSpiClkMode aClkMode)
+	{
+	// (POL) (PHA)
+	//	0     0     Mode 0: spim_clk is active high and sampling occurs on the rising edge.
+	//	0     1     Mode 1: spim_clk is active high and sampling occurs on the falling edge.
+	//	1     0     Mode 2: spim_clk is active low and sampling occurs on the falling edge.
+	//	1     1     Mode 3: spim_clk is active low and sampling occurs on the rising edge.
+
+	TUint val = 0;
+	switch(aClkMode)
+		{
+		//case ESpiPolarityLowRisingEdge:	// Active high, odd edges
+			/*val |= MCSPI_CHxCONF_POL;*/ // 0 (not set)
+			/*val |= MCSPI_CHxCONF_PHA;*/ // 0 (not set)
+			//break; // commented out - it's only for  reference - there's nothing to change
+
+		case ESpiPolarityLowFallingEdge: // Active high, even edges
+			/*val |= MCSPI_CHxCONF_POL;*/ // 0 (not set)
+			val |= MCSPI_CHxCONF_PHA;     // 1
+			break;
+
+		case ESpiPolarityHighFallingEdge: // Active low,  odd edges
+			val |= MCSPI_CHxCONF_POL;     // 1
+			/*val |= MCSPI_CHxCONF_PHA;*/ // 0 (not set)
+			break;
+
+		case ESpiPolarityHighRisingEdge: // Active low,  even edges
+			val |= MCSPI_CHxCONF_POL; // 1
+			val |= MCSPI_CHxCONF_PHA; // 1
+			break;
+		}
+	return val;
+	}
+
+// helper function - returns appropriate value for the register for a given frequency (or error->if not found)
+inline TInt SpiClkValue(TInt aClkSpeedHz)
+	{
+	for (TInt val = 0; val < 0xD; val++) // only loop through all possible values..
+		{
+		if(MCSPI_K48MHz >> val == aClkSpeedHz)
+			{
+			return (val << 2); // return value ready for the register
+			}
+		}
+	return KErrNotFound;
+	}
+
+inline TInt SpiWordWidth(TSpiWordWidth aWidth)
+	{
+	TInt val = 0;
+	switch(aWidth)
+		{
+		case ESpiWordWidth_8:  val |= MCSPI_CHxCONF_WL(8); break;
+		case ESpiWordWidth_10: val |= MCSPI_CHxCONF_WL(10); break;
+		case ESpiWordWidth_12: val |= MCSPI_CHxCONF_WL(12); break;
+		case ESpiWordWidth_16: val |= MCSPI_CHxCONF_WL(16); break;
+//		case ESpiWordWidth_32: val |= MCSPI_CHxCONF_WL(32); break; // TODO uncomment when fix for Bug 3665 is released
+		}
+	return val;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/psl_init.cpp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,156 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/psl_init.cpp
+//
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+
+#include "psl_init.h"
+
+#ifdef MASTER_MODE
+#include "master.h"
+#endif
+#ifdef SLAVE_MODE
+#include "slave.h"
+#endif
+
+#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
+#error "Should select at least one type of SPI channels.."
+#endif
+
+DECLARE_STANDARD_EXTENSION()
+	{
+	// Array of pointers to the Channels that the PSL creates, for registration with the Bus Controller
+	// Use a local array, since the IIC Controller operates on a copy of the array entries.
+	DIicBusChannel* channelPtrArray[KIicPslNumOfChannels];
+
+	TInt r = KErrNone;
+
+#ifdef MASTER_MODE
+#ifndef SLAVE_MODE
+	// If only MASTER_MODE is declared - Create only DIicBusChannelMasterPsl channels
+	__KTRACE_OPT(KIIC, Kern::Printf("\n\nCreating DIicBusChannelMasterPsl only\n"));
+
+	DIicBusChannel* chan = NULL;
+	for (TInt i = 0; i < KIicPslNumOfChannels; ++i)
+		{
+		// The first argument repesents the PSL-assigned channel number
+		// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+//		chan = DSpiMasterBeagle::New(i, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+		if((TInt)KIicPslNumOfChannels == 1)// TODO: hack - only for the time being - enable channel 3
+			chan = DSpiMasterBeagle::New(2, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+		else
+			{
+			Kern::Printf("remove hack from here: %s,line %d", __FILE__, __LINE__);
+			return KErrGeneral;
+			}
+
+		if (!chan)
+			{
+			return KErrNoMemory;
+			}
+		channelPtrArray[i] = chan;
+		}
+
+#else /*SLAVE_MODE*/
+	// Master and Slave functionality is available, so create Master, Slave and MasterSlave Channels
+	// Create channel 0 as Master, channel 1 as a Slave, and channel 2 as MasterSlave.
+	__KTRACE_OPT(KIIC, Kern::Printf("\n\nCreating Master, Slave and MasterSlave channels\n"));
+
+	DIicBusChannel* chan = NULL;
+
+	// Master channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chan = DSpiMasterBeagle::New(0, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chan)
+		{
+		return KErrNoMemory;
+		}
+	channelPtrArray[0] = chan;
+
+	// Slave channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chan = DSpiSlaveBeagle::New(1, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chan)
+		{
+		return KErrNoMemory;
+		}
+	channelPtrArray[1] = chan;
+
+	// MasterSlave channel
+	// MasterSlave channels are not for derivation; instead, they have a pointer to a (derived) Master channel
+	// and a pointer to a (derived) Slave channel
+	DIicBusChannel* chanM = NULL;
+	DIicBusChannel* chanS = NULL;
+	// For MasterSlave channel, the channel number for both the Master and Slave channels must be the same
+	TInt msChanNum = 2;
+	// Master channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chanM = DSpiMasterBeagle::New(msChanNum, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chanM)
+		{
+		return KErrNoMemory;
+		}
+	// Slave channel
+	// The first argument repesents the PSL-assigned channel number
+	// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chanS = DSpiSlaveBeagle::New(msChanNum, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+	if (!chanS)
+		{
+		return KErrNoMemory;
+		}
+	// MasterSlave channel
+	// The first argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+	chan = new DIicBusChannelMasterSlave(DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex, (DIicBusChannelMaster*)chanM, (DIicBusChannelSlave*)chanS);
+	if (!chan)
+		{
+		return KErrNoMemory;
+		}
+	r = ((DIicBusChannelMasterSlave*)chan)->DoCreate();
+	channelPtrArray[2] = chan;
+
+
+#endif /*SLAVE_MODE*/
+#else /*MASTER_MODE*/
+
+#ifdef SLAVE_MODE
+	// If only SLAVE_MODE is declared - Create all as DSpiSlaveBeagle channels
+	__KTRACE_OPT(KIIC, Kern::Printf("\n\nCreating DSpiSlaveBeagle only\n"));
+
+	DIicBusChannel* chan = NULL;
+	for (TInt i = 0; i < KIicPslNumOfChannels; ++i)
+		{
+		// The first argument repesents the PSL-assigned channel number
+		// The second argument, DIicBusChannel::ESpi, should be replaced with the relevant bus type for the PSL
+		chan = DSpiSlaveBeagle::New(i, DIicBusChannel::ESpi, DIicBusChannel::EFullDuplex);
+		if (!chan)
+			{
+			return KErrNoMemory;
+			}
+		channelPtrArray[i] = chan;
+		}
+
+#endif
+#endif /*MASTER_MODE*/
+
+	// Register them with the Bus Controller
+	r = DIicBusController::RegisterChannels(channelPtrArray, KIicPslNumOfChannels);
+
+	return r;
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/psl_init.h	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,48 @@
+// 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 = 1; // Number of channels supported // TODO only one for now..
+
+struct TIicOperationType
+    {
+    enum TOperation
+        {
+        ENop             = 0x00,
+        ETransmitOnly    = 0x01,
+        EReceiveOnly     = 0x02,
+        ETransmitReceive = 0x03
+        };
+
+    struct TOp
+        {
+        TUint8 iIsTransmitting : 1;
+        TUint8 iIsReceiving    : 1;
+        TUint8 iRest           : 6;
+        };
+
+    union
+        {
+        TOp iOp;
+        TUint8 iValue;
+        };
+    };
+
+#endif /*__OMAP3530_SPI_PSL_H__*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/slave.cpp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,804 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/slave.cpp
+//
+
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include "psl_init.h"
+#include "slave.h"
+
+#error "Trying to use the SPI slave, but it's not implemented yet!"
+
+// The timeout period to wait for a response from the client, expressed in milliseconds
+// This is converted to timer ticks by the PIL, so the maximum value is 2147483.
+// The value should be selected to allow for the longest, slowest transfer
+// const TInt KClientWaitTime = 2; // 2mS, when debugging might set up to KMaxWaitTime
+
+
+// In an SMP system, use a spin lock to guard access to member variables iTrigger and iInProgress
+#ifdef __SMP__
+static TSpinLock IicPslSpinLock = TSpinLock(TSpinLock::EOrderGenericIrqLow3);
+#endif
+
+// Callback function for the iHwGuardTimer timer.
+//
+// Called in ISR context if the iHwGuardTimer expires. Sets iTransactionStatus to KErrTimedOut
+//
+void DSpiSlaveBeagle::TimeoutCallback(TAny* aPtr)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DCsiChannelMaster::TimeoutCallback"));
+	DSpiSlaveBeagle *a = (DSpiSlaveBeagle*) aPtr;
+	a->iTransactionStatus = KErrTimedOut;
+	}
+
+
+// Static method called by the ISR when the Master has ended a transfer
+//
+// The method checks and reports the Rx and Tx status to the PIL by calling NotifyClient with a bitmask described as follows:.
+// - If a Tx transfer has ended before all the data was transmitted, bitmask = (ETxAllBytes | ETxOverrun)
+// - If a Tx transfer has ended and all the data was transmitted, bitmask = ETxAllBytes
+// - If a Rx transfer has ended before the expected amount of data was received, bitmask = (ERxAllBytes | ERxUnderrun)
+// - If a Rx transfer has ended and the expected amount of data was received, bitmask = ERxAllBytes
+//
+void DSpiSlaveBeagle::NotifyClientEnd(DSpiSlaveBeagle* aPtr)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("NotifyClientEnd, iTrigger %x", aPtr->iTrigger));
+
+	// Since a transfer has ended, may wish to disable interrupts at this point
+	// This will likely be supported with calls similar to the following:
+	//		AsspRegister::Write32(aPtr->iChannelBase + KBusInterruptEnableOffset, KIicPslBusDisableBitMask);
+	//		Interrupt::Disable(aPtr->iRxInterruptId);
+	//		Interrupt::Disable(aPtr->iTxInterruptId);
+
+	// iTrigger will have bits ETransmit and EReceive set according to the operation requested in the call to DoRequest
+	// Use variable flag for the bitmask to pass into the PIL method NotifyClient
+	TInt flag = 0;
+	if(aPtr->iTrigger & EReceive)
+		{
+		// Requested Rx operation has ended - check for RxUnderrun
+		flag = ERxAllBytes;
+		if(aPtr->iRxDataEnd != aPtr->iRxData)
+			{
+			flag |= ERxUnderrun;
+			}
+		}
+	if(aPtr->iTrigger & ETransmit)
+		{
+		// Requested Tx operation has ended - check for RxOverrun
+		flag |= ETxAllBytes;
+		if(aPtr->iTxDataEnd != aPtr->iTxData)
+			{
+			flag |= ETxOverrun;
+			}
+		}
+	aPtr->NotifyClient(flag);
+	}
+
+
+// ISR Handler
+//
+// The ISR handler identifies the cause of the interrupt that lead to its invocation:
+// if the cause was transfer-related, it calls the PIL function NotifyClient to report a summary of the transfer status;
+// if the cause was completion of asynchronous channel capture, PIL function ChanCaptureCallback is called
+//
+// The ISR also clears the source of the interrupt, and (for transfer-related interrupts) transfers the next data
+// between buffers and the hardware and updates the member variable iInProgress to indicate if a transfer has started or
+// ended. If a transfer has ended before the expected amount of data has been transfered it calls function NotifyClientEnd.
+//
+void DSpiSlaveBeagle::IicPslIsr(TAny* /*aPtr*/)
+	{
+	//		DSpiSlaveBeagle *a = (DSpiSlaveBeagle*) aPtr;
+
+	//		TInt intState = 0;	// Variable to support use of spin lock
+
+	//		TInt trigger = 0; // Record the Rx and Tx transfers
+
+	//		TUint32 intStatus = 0; // Record of the interrupts that are being reported
+
+	// Identify the cause of the interrupt. If this can be achieved by reading a single register,
+	// code similar to the following could be used:
+	//		intStatus = AsspRegister::Read32(a->iChannelBase + KIntStatusOffset);
+
+	// Optional (not required if asynchronous channel capture is not supported)
+	// If the cause of the interrupt is completion of asynchronous channel capture, the ISR will check the appropriate
+	// indicator for confirmation of success - for a real PSL, this may be by querying a bitmask in a register. For the template PSL,
+	// however, a dummy member variable (iAsyncConfig) has been used to represent the asynchronous operation instead.
+	//
+	//		if(iAsyncConfig == 1)	// Replace with a check of the indicator that the interrupt was due to asynchrous channel capture
+	//			{
+	//			// The PIL function ChanCaptureCallback is now to be invoked. It takes as an argument either KErrNone or a
+	//			// system-wide error code to indicate the cause of failure. For a real PSL, the argument would likely be determined
+	//			// by reading a bitmask in a status register - but for the template port, just use KErrNone.
+	//			//
+	//			a->ChanCaptureCallback(KErrNone);
+	//			return;
+	//			}
+
+	// If an interrupt indicates that a transfer has started, or that it has now ended, (such as a chip select
+	// line transition for a SPI bus the member variable iInProgress should be modified accordingly. This should
+	// be done under the guard of spin lock macros since iInProgress can be accessed in the context of the Client
+	// thread (in DoRequest, ProcessData and InitTransfer). The following structure should be adopted:
+	//		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	//		<access a->iInProgress>
+	//		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+	//
+	// If a transfer has ended before the expected amount of data has been transfered, function NotifyClientEnd
+	// should be called, as follows:
+	//		a->NotifyClientEnd(a);
+	//		return;	// Return now - the interrupt indicated transfer end, not receipt or transmission of data.
+
+	// The transfers that had been started are indicated by the bitmask held in member variable iTrigger.
+	// This must be accessed under the guard of a spin lock since it can be accessed in the context of the
+	// Client thread (in DoRequest, ProcessData and InitTransfer). The following structure should be adopted:
+	//		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	//		trigger = a->iTrigger;
+	//		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	// If the interrupt was raised for a Tx event, and a Tx transfer had been started (so the interrupt was not spurious)
+	// then either prepare the next data to send, or, if all the data has been sent, call the PIL function NotifyClient
+	// with bitmask (ETxAllBytes | ETxUnderrun) so that, if the Client specified a ETxUnderrun notification, it will be alerted
+	// and can determine whether another buffer of data should be provide for transmission.
+	// Code similar to the following could be used:
+	//		if(intStatus & KTxInterruptBitMask)
+	//			{
+	//			if(trigger & ETransmit)
+	//				{
+	//				// Interrupt was not spurious
+	//				if(a->iTxData == a->iTxDataEnd)
+	//					{
+	//					// All the data to be transmitted has been sent, so call the PIL method NotifyClient
+	//					a->NotifyClient(ETxAllBytes | ETxUnderrun);
+	//					}
+	//				else
+	//					{
+	//					// There is more data to be sent
+	//					// TUint8 nextTxValue = *iTxData;	// For this example, assumes one byte of data is to be transmitted
+	//														// but if operating in 16-bit mode, bytes may need arranging for
+	//														// endianness
+	//
+	//					// Write to the Tx register with something similar to the following:
+	//					//		AsspRegister::Write32(iChannelBase + KTxFifoOffset, nextTxValue);
+	//
+	//					iTxData += iWordSize;	// Then increment the pointer to the data. In this example, 8-bit mode is assumed
+	//											// (iWordSize=1), but if operating in 16-bit mode iTxData would be incremented
+	//											// by the number of bytes specified in iWordSize
+	//					}
+	//				}
+	//			}
+
+	// If the interrupt was raised for a Rx event, and a Rx transfer had been started (so the interrupt was not spurious)
+	// read the received data from the hardware to the buffer. If a Rx FIFO is being used, use a loop to drain it - until
+	// the FIFO is empty or the buffer is full. If data remains after the buffer is full, an RxOverrun condition has occurred
+	// - so the PIL function NotifyClient should be called with bitmask (ERxAllBytes | ERxOverrun) so that, if the Client specified
+	// a ERxOverrun notification, it will be alerted and can determine whether another buffer should be provided to continue reception.
+	// Code similar to the following could be used:
+	//		if(intStatus & KRxInterruptBitMask)
+	//			{
+	//			if(trigger & EReceive)
+	//				{
+	//				// Interrupt was not spurious
+	//				while(AsspRegister::Read32(a->iChannelBase + KRxFifoLevelOffset))
+	//					{
+	//					if((a->iRxData - a->iRxDataEnd) >= a->iWordSize)
+	//						{
+	//						// Space remains in the buffer, so copy the received data to it
+	//						TUint8 nextRxValue = AsspRegister::Read32(a->iChannelBase + KRxFifoOffset);
+	//						*a->iRxData = nextRxValue;	// For this example, assumes one byte of data is to be transmitted
+	//													// but if operating in 16-bit mode, bytes may need arranging for
+	//													// endianness
+	//
+	//						a->iRxData += a->iWordSize;	// Then increment the pointer to the data. In this example, 8-bit mode is assumed
+	//													// (iWordSize=1), but if operating in 16-bit mode iRxData would be incremented
+	//													// by the number of bytes specified in iWordSize
+	//						}
+	//					else
+	//						{
+	//						// The buffer is full but more data has been received - so there is an RxOverrun condition
+	//						// Disable the hardware from receiving any more data and call the PIL function NotifyClient
+	//						// with bitmask (ERxAllBytes | ERxOverrun).
+	//						AsspRegister::Write32(a->iChannelBase + KRxFifoControl, KRxFifoDisableBitMask);
+	//						a->NotifyClient(ERxAllBytes | ERxOverrun);
+	//						break;
+	//						}
+	//					}
+	//				}
+	//			else
+	//				{
+	//				// If the interrupt was spurious, ignore the data, and reset the FIFO
+	//				AsspRegister::Write32(a->iChannelBase + KRxFifoControl, KRxFifoClearBitMask);
+	//				}
+
+	// Once the interrupts have been processed, clear the source. If this can be achieve by writing to
+	// a single register, code similar to the following could be used:
+	//		AsspRegister::Write32(a->iChannelBase + KIntStatusOffset, KAIntBitMask);
+
+	}
+
+
+// Constructor, first stage
+//
+// The PSL is responsible for setting the channel number - this is passed as the first parameter to
+// this overload of the base class constructor
+//
+DSpiSlaveBeagle::DSpiSlaveBeagle(TInt aChannelNumber, TBusType aBusType, TChannelDuplex aChanDuplex) :
+	DIicBusChannelSlave(aBusType, aChanDuplex, 0),	// Base class constructor. Initalise channel ID to zero.
+	iHwGuardTimer(TimeoutCallback, this)			// Timer to guard against hardware timeout
+	{
+	iChannelNumber = aChannelNumber;
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::DSpiSlaveBeagle, iChannelNumber = %d\n", iChannelNumber));
+	}
+
+
+// Second stage construction
+//
+// Allocate and initialise objects required by the PSL channel implementation
+//
+TInt DSpiSlaveBeagle::DoCreate()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("\nDSpiSlaveBeagle::DoCreate, ch: %d \n", iChannelNumber));
+
+	TInt r = KErrNone;
+
+	// PIL Base class initialization.
+	r = Init();
+	if(r == KErrNone)
+		{
+		// At a minimum, this function must set the channel's unique channel ID.
+		// When the channel is captured, this value will be combined with an instance count
+		// provided by the PIL to generate a value that will be used by a client as a unique
+		// identifer in subsequent calls to the Slave API.
+		//
+		// There is no set format for the ID, it just needs to be unique.
+		// Un-comment and complete the following line:
+//		iChannelId =
+
+		// This method may also be concerned with setting the base register address iChannelBase), and allocating
+		// any objects that will be required to support operaton until the channel is deleted.
+		//
+		// Un-comment and complete the following line:
+//		iChannelBase =
+		}
+	return r;
+	}
+
+// static method used to construct the DSpiSlaveBeagle object.
+DSpiSlaveBeagle* DSpiSlaveBeagle::New(TInt aChannelNumber, const TBusType aBusType, const TChannelDuplex aChanDuplex)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::NewL(): aChannelNumber = %d, BusType =%d", aChannelNumber, aBusType));
+	DSpiSlaveBeagle *pChan = new DSpiSlaveBeagle(aChannelNumber, aBusType, aChanDuplex);
+
+	TInt r = KErrNoMemory;
+	if (pChan)
+		{
+		r = pChan->DoCreate();
+		}
+	if (r != KErrNone)
+		{
+		delete pChan;
+		pChan = NULL;
+		}
+
+	return pChan;
+	}
+
+
+// Validates the configuration information specified by the client when capturing the channel
+//
+// Called by the PIL as part of the Slave CaptureChannel processing
+//
+// If the pointer to the header is NULL, return KErrArgument.
+// If the content of the header is not valid for this channel, return KErrNotSupported.
+//
+TInt DSpiSlaveBeagle::CheckHdr(TDes8* aHdrBuff)
+	{
+	TInt r = KErrNone;
+
+	if(!aHdrBuff)
+		{
+		r = KErrArgument;
+		}
+	else
+		{
+		// Check that the contents of the header are valid
+		//
+		// The header will be specific to a particular bus type. Using a fictional
+		// bus type Abc,code similar to the following could be used to validate each
+		// member of the header:
+		//
+		//		TConfigAbcBufV01* headerBuf = (TConfigAbcBufV01*) aHdrBuff;
+		//		TConfigAbcV01 &abcHeader = (*headerBuf)();
+		//		if(	(abcHeader.iHeaderMember < ESomeMinValue)	||
+		//			(abcHeader.iHeaderMember > ESomeMaxValue))
+		//			{
+		//			__KTRACE_OPT(KIIC, Kern::Printf("iHeaderMember %d not supported",abcHeader.iHeaderMember));
+		//			r = KErrNotSupported;
+		//			}
+
+		}
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::CheckHdr() r %d", r));
+
+	return r;
+	}
+
+
+// Method called in the context of the client thread, as a consequence of the PSL invocation of the
+// PIL method NotifyClient when a bus event occurs.
+//
+// This method updates the bitmask of requested operations (held in member variable iTrigger) and the
+// PIL counts of data received and transmitted. If the event was a bus error, the bitmask of requested operations
+// is cleared.
+//
+void DSpiSlaveBeagle::ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::ProcessData(), trigger: %x\n", aTrigger));
+
+	TInt intState;
+
+	// If using the iInProgress member variable to indicate transitions on a chip-select line, and an interrupt
+	// occurred as a transfer was to end, then must ensure the transmission of data has ceased.
+	//
+	// Must use spin lock to guard access since iInProgress is accessed by the ISR
+	//
+	TInt inProgress;
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	inProgress = iInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+	//
+	if(!inProgress &&								// Transfer has now ended
+	   (aTrigger & (ERxAllBytes | ETxAllBytes)))	// Master has not yet finished transferring data
+		{
+		// Use the guard timer to make sure that transfer ends with an expected time - if this does not cease
+		// before the timer expires, iTransactionStatus will be set to KErrTimedOut by the callback function TimeoutCallback
+		//
+		// Poll the relevant register to check for transfer activity, using code similar to the following:
+		//		TInt8 transferring = AsspRegister::Read32(iChannelBase + KStatusRegisterOffset) & KTransferringBitMask);
+		// For the template port, use a dummy variable instead of the register access (transferring = 1)
+		//
+		TInt8 transferring = 1;
+		iTransactionStatus = KErrNone;
+		iHwGuardTimer.OneShot(NKern::TimerTicks(KTimeoutValue));
+
+		while((iTransactionStatus == KErrNone) &&
+		      transferring);		// Replace transferring with a register read, as described above
+
+		// At this point, either the transfer has ceased, or the timer expired - in either case, may disable the interrupt
+		// for the transfer now, using code similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KIntEnableRegisterOffset, KIntDisableBitMask);
+
+		// Check for guard timer expiry
+		if(iTransactionStatus != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::ProcessData - Transaction timed-out"));
+			return;
+			}
+		else
+			{
+			iHwGuardTimer.Cancel();
+			}
+
+		// If all transfer activity has now ceased, clear iTrigger
+		// Must use spin lock to guard access since iInProgress is accessed by the ISR
+		//
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger = 0;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	// If the PSL called the PIL function NotifyClient to indicate transfer activity (or error), the reason
+	// will be specified as a bitmask in aTrigger
+	//  - if a Rx event occurred, the ERxAllBytes flag will be set
+	//  - if a Tx event occurred, the ETxAllBytes flag will be set
+	//  - if a bus error occurred, the EGeneralBusError flag will be set
+	//
+	if(aTrigger & ERxAllBytes)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Rx Buf:    %x\n", iRxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Rx Bufend: %x\n", iRxDataEnd));
+
+		// Clear the internal EReceive flag
+		// This must be done under guard of a spin lock since iTrigger is accessed by the ISR
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger &= ~EReceive;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+		// Update the PIL count of Rx data (in the Callback object)
+		aCb->SetRxWords(iNumRxWords - ((iRxDataEnd - iRxData) / iWordSize));
+		}
+	//
+	if(aTrigger & ETxAllBytes)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Tx Buf:    %x\n", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("ProcessData - Tx Bufend: %x\n", iTxDataEnd));
+
+		// Clear the internal ETransmit flag..
+		// This must be done under guard of a spin lock since iTrigger is accessed by the ISR
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger &= ~ETransmit;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+		// Update the PIL count of Tx data (in the Callback object)
+		aCb->SetTxWords(iNumTxWords - ((iTxDataEnd - iTxData) / iWordSize));
+		}
+	//
+	if(aTrigger & EGeneralBusError)
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("BusError.."));
+
+		// Clear and disable relevant interrupts, possibly using code similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KIntEnableRegisterOffset, KIntDisableBitMask);
+
+		// Clear internal flags
+		// This must be done under guard of a spin lock since iTrigger is accessed by the ISR
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger = 0;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	// Set the callback's trigger, for use by the PIL
+	aCb->SetTrigger(aTrigger | aCb->GetTrigger());
+	}
+
+
+
+// Method to initialise the hardware in accordance with the data provided by the Client
+// in the configuration header when capturing the channel
+//
+// This method is called from DoRequest and is expected to return a value to indicate success
+// or a system wide error code to inform of the failure
+//
+TInt DSpiSlaveBeagle::ConfigureInterface()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
+
+	TInt r = KErrNone;
+
+	// The header is stored in member variable iConfigHeader, and will be specific to a particular bus type.
+	// Using a fictional bus type Abc, code similar to the following could be used to access each
+	// member of the header:
+	//
+	//		TConfigAbcBufV01* headerBuf = (TConfigAbcBufV01*) iConfigHeader;
+	//		TConfigAbcV01 &abcHeader = (*headerBuf)();
+	//		TInt value = abcHeader.iTintMember;
+
+	// Initialising the hardware may be achieved with calls similar to the following:
+	//		AsspRegister::Write32(a->iChannelBase + KBusModeControlOffset, KIicPslModeControlBitMask);
+	//		GPIO::SetPinMode(aPinId, GPIO::EEnabled);
+
+	// Binding an ISR may be achieved with calls similar to the following:
+	//		r = Interrupt::Bind(iRxInterruptId, DSpiSlaveBeagle::IicPslIsr, this);
+	//		r = Interrupt::Bind(iTxInterruptId, DSpiSlaveBeagle::IicPslIsr, this);
+	// Enabling interrupts may be achieved with calls similar to the following:
+	//		r = Interrupt::Enable(iRxInterruptId);
+	//		r = Interrupt::Enable(iTxInterruptId);
+
+	// Modifying a hardware register may not be a zero-delay operation. The member variable iHwGuardTimer could be used to guard a
+	// continuous poll of the hardware register that checks for the required change in the setting; TimeoutCallback is already
+	// assigned as the callback function for iHwGaurdTimer, and it modifies member variable iTransactionStatus to indicate a timeout
+	// - so the two could be used together as follows:
+	//		iTransactionStatus = KErrNone;
+	//		iHwGuardTimer.OneShot(NKern::TimerTicks(KTimeoutValue));
+	//		while((iTransactionStatus == KErrNone) &&
+	//		       AsspRegister::Read32(iChannelBase + KRegisterOffset) & KRegisterFlagBitMask);
+	//		if(iTransactionStatus != KErrNone)
+	//			{
+	//			r = KErrGeneral;
+	//			}
+	//		else
+	//			{
+	//			iHwGuardTimer.Cancel();
+	//			}
+
+	// DoRequest checks the return value so the variable r should be modified in the event of failure with a system-wide error code
+	// for example, if a register could not be modified,
+	//			r = KErrGeneral;
+	//			__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface failed with error %d\n",r));
+	return r;
+	}
+
+
+// Method to start asynchronous initialisation of the hardware, in accordance with the data provided by the Client
+// in the configuration header when capturing the channel. This differs from ConfigureInterface in that it
+// merely starts the initialisation, then returns immediately;
+//
+// The PSL is expected to be implemented as an asynchronous state machine, where events (for example hardware
+// interrupts, or timer expiry) invoke callback functions that advance the state machine to the next state. Once
+// all the required states have been transitioned, so that the PSL part of the CaptureChannel processing is
+// complete, the ISR should be invoked, which will then call PIL method ChanCaptureCallback
+//
+// This method is called from DoRequest and is expected to return a value to indicate success
+// or a system wide error code to inform of the failure
+//
+TInt DSpiSlaveBeagle::AsynchConfigureInterface()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface()"));
+
+//	TInt r = KErrNone;	// A real implementation would use this as the return value to indicate success / failure
+
+	// Precisely what processing is done to 'start' the asynchronous processing is entirely platform-specific;
+	// it may be the set-up and activation of a long-running operation that completes asynchronously. Regardless of what
+	// is done, its completion is expected to result in the ISR being run.
+	//
+	// Whatever the operation, there must be some means of the ISR recognising that an asynchronous initialisation has
+	// been performed
+	// In a real PSL, this may be be checking a bitmask in a status register. For the template PSL, however,
+	// a dummy class member will be used (iAsyncConfig)
+	// Since this member will be accessed by the ISR, it should, strictly speaking, be accessed under the guard of a spin lock
+	TInt intState;
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	iAsyncConfig = 1;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	return KErrNone;	// A real implementation would return an indication of success / failure
+	}
+
+// Method called from DoRequest to start Tx and-or Rx transfer.
+//
+// The method will initialise the hardware and pointers used to manage transfers, before returning a value to report success
+// (KErrNone) or a system-wide error code that indicates the cause of failure.
+//
+TInt DSpiSlaveBeagle::InitTransfer()
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DSpiSlaveBeagle::InitTransfer()"));
+
+	TInt r = KErrNone;
+
+	// Local copies of member variables that must be accessed in a synchronised manner
+	TInt inProgress;
+	TInt trigger;
+
+	TInt intState;
+
+	// Check if a transfer is already in progress.
+	// If variable iInProgress is being used, this must be determined in a synchronised manner because the ISR modifies it.
+	// Bus types that do not rely on chip-select transitions may use an alternative method to indicate if a transfer is in
+	// progress
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	inProgress = iInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	if(!inProgress)
+		{
+		// If no transfers are in progress, it may be necessary to initialise the hardware to support those that
+		// are being requested. This may include FIFO and interrupt initialisation,
+		//
+		// Initialising the hardware may be achieved with calls similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KBusModeControlOffset, KIicPslModeControlBitMask);
+		//		GPIO::SetPinMode(aPinId, GPIO::EEnabled);
+		}
+
+	// Check the current operations. This must be determined in a synchronised manner because ProcessData
+	// runs in the context of the Client thread and it modifies the value of iTrigger
+	intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+	trigger = iTrigger;
+	__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+
+	if(trigger & ETransmit)
+		{
+		// If Tx transfers were not previously active, it may be necessary to initialise the Tx hardware here, e.g.
+		//		AsspRegister::Write32(iChannelBase + KBusModeControlOffset, KIicPslTxModeBitMask);
+
+		// Initialise the Tx pointers
+		iTxData = iTxBuf + (iWordSize * iTxOffset);
+		iTxDataEnd = iTxData + (iWordSize * iNumTxWords);
+
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Bufend: %x", iTxDataEnd));
+
+		// If using a FIFO, copy the data to it until either the FIFO is full or all the data has been copied
+		// This could be achieved with something similar to the following lines:
+		//		while(AsspRegister::Read32(iChannelBase + KFifoLevelOffset) <= (KFifoMaxLevel - iWordSize) &&
+		//		      iTxData != iTxDataEnd)
+		// For the template port, will just use a dummy variable (dummyFifoLvlChk )in place of the register read
+		TInt dummyFifoLvlChk = 0;
+		while((dummyFifoLvlChk)	&&	// Replace this dummy variable with a read of the hardware
+			(iTxData != iTxDataEnd))
+			{
+			// TUint8 nextTxValue = *iTxData;	// For this example, assumes one byte of data is to be transmitted
+												// but if operating in 16-bit mode, bytes may need arranging for
+												// endianness
+
+			// Write to the Tx register with something similar to the following:
+			//		AsspRegister::Write32(iChannelBase + KTxFifoOffset, nextTxValue);
+
+			iTxData += iWordSize;	// Then increment the pointer to the data. In this example, 8-bit mode is assumed
+									// (iWordSize=1), but if operating in 16-bit mode iTxData would be incremented
+									// by the number of bytes specified in iWordSize
+			}
+		// If a Tx FIFO is not being used, a single Tx value would be written - in which case the above loop would be replaced
+
+		__KTRACE_OPT(KIIC, Kern::Printf("After adding:\n\rTx Buf:    %x", iTxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Tx Bufend: %x", iTxDataEnd));
+		}
+
+	if(trigger & EReceive)
+		{
+		// Initialise the Rx pointers
+		iRxData = iRxBuf + (iWordSize * iRxOffset);
+		iRxDataEnd = iRxData + (iWordSize * iNumRxWords);
+
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx Buffer:  %x", iRxData));
+		__KTRACE_OPT(KIIC, Kern::Printf("Rx Bufend: %x", iRxDataEnd));
+
+		// If Rx transfers were not previously active, it may be necessary to initialise the Rx hardware here, e.g.
+		//		AsspRegister::Write32(iChannelBase + KBusModeControlOffset, KIicPslRxModeBitMask);
+		}
+
+	// If there is some common configuration required to support Rx, Tx transfers, may do it here
+
+	return r;
+	}
+
+
+// The gateway function for PSL implementation
+//
+// This method is called by the PIL to perform one or more operations indicated in the bitmask aOperation,
+// which corresponds to members of the TPslOperation enumeration.
+//
+TInt DSpiSlaveBeagle::DoRequest(TInt aOperation)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("\nDSpiSlaveBeagle::DoRequest, Operation 0x%x\n", aOperation));
+
+	TInt r = KErrNone;
+	TInt intState;
+
+	if (aOperation & EAsyncConfigPwrUp)
+		{
+		// The PIL has requested asynchronous operation of CaptureChannel.
+		// The PSL should start the processing required for a channel to be captured, and then return immediately with
+		// error code KErrNone (if the processing was started without error), so that the client thread will be unblocked.
+		// The PSL is expected to be implemented as an asynchronous state machine, where events (for example hardware
+		// interrupts, or timer expiry) invoke callback functions that advance the state machine to the next state. Once
+		// all the required states have been transitioned, so that the PSL part of the CaptureChannel processing is
+		// complete, the PSL should call the PIL function ChanCaptureCallback - this will lead to the Client-provided
+		// callback being executed in the context of the client thread
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("EAsyncConfigPwrUp"));
+		r = AsynchConfigureInterface();
+		if (r != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("AsynchConfigureInterface returned %d\n", r));
+			}
+		return r;
+		}
+
+	if (aOperation & ESyncConfigPwrUp)
+		{
+		// The PIL has requested synchronous operation of CaptureChannel.
+		// The PSL should perform the processing required for a channel to be captured, and return a system-wide error
+		// code when this is complete to indicate the status of the capture.
+		// Capturing a channel is expected to include initialisation of the hardware to enable operation in accordance
+		// with the configuration specified in the PIL member variable iConfigHeader, which holds the configuration
+		// specified by the Client.
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("ESyncConfigPwrUp"));
+		r = ConfigureInterface();
+		if (r != KErrNone)
+			{
+			__KTRACE_OPT(KIIC, Kern::Printf("ConfigureInterface returned %d\n", r));
+			return r;
+			}
+		}
+
+	if (aOperation & ETransmit)
+		{
+		// The PIL has requested that a Tx operation be started.
+		// Since the SPL may support simultaneous Rx and Tx operations, just set the flag in the iTrigger bitmask to
+		// indicate what has been requested. If both Rx and Tx operations are requested, and one completes ahead of the other,
+		// requiring the Client to provide a new buffer and associated call to DoRequest (as is the case if the Master wishes
+		// to transfer more data than the Slave buffer supported), it is possible that the other transfer could complete while
+		// this function is running; consequently, it may attempt to access iTrigger, and so cause data corruption. To cater for
+		// such situations, use a spin lock to guard access to iTrigger.
+		// When the same check has been performed for Rx, call the InitTransfer function to start the required transfers.
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("ETransmit"));
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger |= ETransmit;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	if (aOperation & EReceive)
+		{
+		// The PIL has requested that a Rx operation be started.
+		// Since the SPL may support simultaneous Rx and Tx operations, just set the flag in the iTrigger bitmask to
+		// indicate what has been requested. If both Rx and Tx operations are requested, and one completes ahead of the other,
+		// requiring the Client to provide a new buffer and associated call to DoRequest (as is the case if the Master wishes
+		// to transfer more data than the Slave buffer supported), it is possible that the other transfer could complete while
+		// this function is running; consequently, it may attempt to access iTrigger, and so cause data corruption. To cater for
+		// such situations, use a spin lock to guard access to iTrigger.
+		// When the same check has been performed for Tx, call the InitTransfer function to start the required transfers.
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("EReceive"));
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		iTrigger |= EReceive;
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		}
+
+	if (aOperation & (EReceive | ETransmit))
+		{
+		// This code should only be executed once it has been checked whether Rx and Tx operations are required.
+		r = InitTransfer();
+		}
+
+	if (aOperation & EAbort)
+		{
+		// The PIL has requested that the current transaction be aborted.
+		// This is the case if the Client has not responded within an expected time to specify the next steps in
+		// the transaction processing. The time allowed is specified by calling PIL function SetClientWaitTime, otherwise
+		// the time defaults to KSlaveDefCWaitTime.
+		// If the PSL is able to satisfy this request it should, at a minimum, disable interrupts and update the member
+		// variables that indicate a transaction is in progress. If the PSL is unable to satisfy the request then the same
+		// behaviour will follow as if this request had not been made, so there is no point in modifying the state variables.
+		// If both Rx and Tx operations had been requested, and one completes ahead of the other, it is possible that the other
+		// transfer could complete while this function is running; consequently, it may attempt to access iTrigger and iInProgress,
+		// and so cause data corruption. To cater for such situations, use a spin lock to guard access to iTrigger.
+		// The PIL makes no assumptions of whether the PSL can support this request or not, and does not check the return
+		// value - so there is no need to set one.
+		//
+		TUint8 dummyCanAbort = 1;	// Dummy variable to represent a check of if it is possible to abort the current transaction
+		__KTRACE_OPT(KIIC, Kern::Printf("EAbort"));
+		intState = __SPIN_LOCK_IRQSAVE(IicPslSpinLock);
+		if(dummyCanAbort)
+			{
+			// The spin lock has been acquired, so it is safe to modify data and hardware registers that may be accessed as part of
+			// interrupt processing performed by an ISR - this is assuming that the ISR has been written to acquire the same spin lock.
+			// Limit the processing to only that which is necessary to be processed under spin lock control, so as to not delay other
+			// threads of execution that are waiting for the spin lock to be freed.
+			// Hardware may be configured using code similar to the following:
+			//		AsspRegister::Write32(iChannelBase + KBusInterruptEnableOffset, KIicPslBusDisableBitMask);
+			iInProgress = EFalse;
+			iTrigger = 0;
+			}
+		__SPIN_UNLOCK_IRQRESTORE(IicPslSpinLock, intState);
+		// Having released the spin lock, now perform any actions that are not affected by pre-emption by an ISR, this may include code
+		// such as the following
+		//		Interrupt::Disable(iRxInterruptId);
+		//		Interrupt::Disable(iTxInterruptId);
+		}
+
+	if (aOperation & EPowerDown)
+		{
+		// The PIL has requested that the channel be released.
+		// If this channel is not part of a MasterSlave channel, the next Client will operate in Slave mode. In this case, it may only
+		// be necessary to disable interrupts, and reset the channel hardware.
+		// If this channel represents the Slave of a MasterSlave channel, it is possible that some of the hardware is shared between the
+		// Master and Slave sub-channels. Since it may not be known whether the next Client of the parent channel will require operation
+		// in either Master or Slave mode, some additional processing may be required to allow for subsequent Master operation (for example.
+		// unbinding an interrupt).
+		//
+		__KTRACE_OPT(KIIC, Kern::Printf("EPowerDown"));
+
+		// Resetting the hardware may be achieved with calls similar to the following:
+		//		AsspRegister::Write32(iChannelBase + KBusInterruptEnableOffset, KIicPslBusDisableBitMask);
+		//		GPIO::SetPinMode(aPinId, GPIO::EDisabled);
+
+		// Disable interrupts may be achieved with calls similar to the following:
+		//		Interrupt::Disable(iRxInterruptId);
+		//		Interrupt::Disable(iTxInterruptId);
+
+		// Unbinding an ISR may be achieved with calls similar to the following:
+		//		Interrupt::Unbind(iRxInterruptId);
+		//		Interrupt::Unbind(iTxInterruptId);
+
+		// The PIL checks the return value so the variable r should be modified in the event of failure with a system-wide error code
+		// for example, if a register could not be modified,
+		//		r = KErrGeneral;
+		//		__KTRACE_OPT(KIIC, Kern::Printf("EPowerDown failed with error %d\n",r));
+
+		}
+	return r;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/slave.h	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,87 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+// lukasz.forynski@gmail.com
+//
+// Description:
+// omap3530/omap3530_drivers/spi/slave.h
+//
+
+
+#ifndef __OMAP3530_SPI_SLAVE_H__
+#define __OMAP3530_SPI_SLAVE_H__
+
+#include <drivers/iic_channel.h>
+
+class DSpiSlaveBeagle: public DIicBusChannelSlave
+	{
+
+public:
+	static DSpiSlaveBeagle* New(TInt aChannelNumber, const TBusType aBusType,
+	                              const TChannelDuplex aChanDuplex);
+
+	// Gateway function for PSL implementation
+	virtual TInt DoRequest(TInt aOperation);
+
+	DSpiSlaveBeagle(TInt aChannelNumber, const TBusType aBusType,
+	                 const TChannelDuplex aChanDuplex);
+
+private:
+	// Overriders for base class pure-virtual methods
+	virtual TInt DoCreate(); // second-stage construction,
+	virtual TInt CheckHdr(TDes8* aHdrBuff);
+	virtual void ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb);
+
+	// Internal methods..
+	TBool TransConfigDiffersFromPrev();
+	TInt ConfigureInterface();
+	TInt AsynchConfigureInterface();
+	TInt InitTransfer();
+
+	// ISR handler and other static methods..
+	static void IicPslIsr(TAny* aPtr);
+	static void TimeoutCallback(TAny* aPtr);
+	static inline void NotifyClientEnd(DSpiSlaveBeagle* aPtr);
+
+	// Register base for the Master channel
+	TUint iSlaveChanBase;
+
+	// Interrupt ID for the Master channel
+	TInt iSlaveIntId;
+
+	// Bit mask of the transfer triggers managed by the channel
+	TUint8 iTrigger;
+
+	// Granularity, expressed as the number of bytes in a word
+	TInt8 iWordSize;
+
+	// Flag indicating transmission activity - optional, may not be required for all bus types
+	// In the template example it is used to indicate transitions on a chip-select line, such as for SPI.
+	TInt8 iInProgress;
+
+	// Dummy variable used merely to demonstrate the asynchronous channel capture mechanism
+	// See method AsynchConfigureInterface
+	TInt8 iAsyncConfig;
+
+	// Pointers to buffers used for Rx and Tx transfers
+	TInt8 *iTxData;
+	TInt8 *iRxData;
+	TInt8 *iTxDataEnd;
+	TInt8 *iRxDataEnd;
+
+	// Timer to guard 'while' loops..
+	NTimer iHwGuardTimer;
+
+	// status of the transaction
+	volatile TInt iTransactionStatus;
+	};
+
+#endif /*__OMAP3530_SPI_SLAVE_H__*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/spi.iby	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,29 @@
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/spi.iby
+// this file defines components to be included in the rom image in order
+// to support IIC SPI implementation.
+
+
+
+#ifndef STANDALONE_CHANNEL 
+extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\iic.dll  \sys\bin\iic.dll
+#endif
+extension[VARID]=\epoc32\release\##KMAIN##\##BUILD##\_omap3530_spi.dll  \sys\bin\spi.dll
+
+#ifdef INCLUDE_SPI_TEST
+device[VARID]=\epoc32\release\##KMAIN##\##BUILD##\_beagle_d_spi_client_m.ldd  \sys\bin\d_spi_client_m.ldd
+file=\epoc32\release\##KMAIN##\##BUILD##\t_spi_client_m.exe  \sys\bin\t_spi_client_m.exe
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/spi.mmp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,75 @@
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530/omap3530_drivers/spi/spi.mmp
+//
+
+#include <assp/omap3530_assp/assp.mmh>
+//#include "kernel/kern_ext.mmh" // this is already included from iic_channel.mmh
+// ..and probably it shouldn't be
+
+
+// Select the mode to build
+// For Master-Slave mode, uncomment both MASTER and SLAVE defines
+#define __USE_MASTER_MODE__
+//#define __USE_SLAVE_MODE__
+
+
+//macro STANDALONE_CHANNEL
+//#define STANDALONE_CHANNEL /*Only for iic_channel.mmh to pick up the needed source files*/
+
+// PSL source
+SOURCEPATH       .
+SOURCE           psl_init.cpp
+
+#ifdef __USE_MASTER_MODE__
+macro MASTER_MODE
+SOURCE           master.cpp
+#endif
+
+#ifdef __USE_SLAVE_MODE__
+macro SLAVE_MODE
+SOURCE           slave.cpp
+#endif
+
+
+// PIL source
+#include   "../../../../../os/kernelhwsrv/kernel/eka/drivers/iic/iic_channel.mmh"
+sourcepath ../../../../../os/kernelhwsrv/kernel/eka/drivers/iic/
+source		IIC_PIL_SOURCE
+
+
+TARGET           AsspTarget(spi,dll)
+TARGETTYPE       kext
+LINKAS           spi.dll
+//DEFFILE          ./def/~/spi.def
+NOSTRICTDEF
+
+
+USERINCLUDE      .
+SYSTEMINCLUDE    +\include\assp\omap3530_assp 
+SYSTEMINCLUDE 	 +\include\drivers 
+SYMBIAN_BASE_SYSTEMINCLUDE(assp/omap3530_assp)
+SYMBIAN_BASE_SYSTEMINCLUDE(drivers)
+
+LIBRARY          AsspTarget(kaomap3530,lib)
+LIBRARY          AsspTarget(prcm,lib)
+LIBRARY          AsspTarget(gpio,lib)
+
+// #ifdef USE_SYMBIAN_PRM?
+//library				resman.lib
+
+EPOCALLOWDLLDATA
+
+CAPABILITY       all
+
+VENDORID         0x70000001
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.cpp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,869 @@
+// 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.
+//
+
+// Note: IMPORTANT! -If you intend to make changes to the driver!
+// Obviously the best test is to use the SPI with the real device (and check if it still works after changes).
+// If this is not the case (e.g. as it was when this driver was being created) - to fully test the functionality
+// this test can make use of duplex transactions with local loopback. In such case received data should match the
+// data sent over the bus. (It might be possible to configure local loopback using pad config(not yet confirmed),
+// but until this (and not to complicate the test too much)- here is simple description on how to do it on a
+// beagleboard. If McSPI3 is configured with the default pin option, i.e. to route signals to the expansion
+// hader (see spi driver for details):s
+// following header pins have SPI3 functions:
+// 21 - CLK
+// 19 - SIMO
+// 17 - SOMI
+// 11 - CS0
+// local loopback could be simply made by puttint the jumper between pin 17 and pin 19 of the extension header.
+// This test will automatically detect this configuration and the jumper - so if you want to test it this way
+// it is highly recommended (and it's simple).
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include <kernel/kern_priv.h>
+#include "d_spi_client_m.h"
+
+
+_LIT(KTestDriverName,"d_spi_client_m");
+
+// (un) comment it out for debugging
+//#define LOG_FUNCTION_CALLS
+
+#ifdef LOG_FUNCTION_CALLS
+#define LOG_FUNCTION_ENTRY Kern::Printf("DSpiClientChannel::%s()", __FUNCTION__)
+#define LOG_FUNCTION_RETURN Kern::Printf("DSpiClientChannel::%s() return: %d", __FUNCTION__, r)
+#else
+#define LOG_FUNCTION_ENTRY
+#define LOG_FUNCTION_RETURN
+#endif
+
+
+// === generic (driver related) stuff ===
+
+// this driver only implements one channel
+const TInt KMaxNumChannels = 1;
+
+
+
+// entry point
+DECLARE_STANDARD_LDD()
+	{
+	return new DSpiClientTestFactory;
+	}
+
+DSpiClientTestFactory::DSpiClientTestFactory()
+	{
+	iParseMask = 0;
+	iUnitsMask = 0;  // No info, no PDD, no Units
+	iVersion = TVersion(KIntTestMajorVersionNumber,
+	        KIntTestMinorVersionNumber, KIntTestBuildVersionNumber);
+	}
+
+DSpiClientTestFactory::~DSpiClientTestFactory()
+	{
+	}
+
+// Install the device driver.
+TInt DSpiClientTestFactory::Install()
+	{
+	return (SetName(&KLddFileNameRoot));
+	}
+
+void DSpiClientTestFactory::GetCaps(TDes8& aDes) const
+	{
+	TPckgBuf<TCapsProxyClient> b;
+	b().version = TVersion(KIntTestMajorVersionNumber, KIntTestMinorVersionNumber, KIntTestBuildVersionNumber);
+	Kern::InfoCopy(aDes, b);
+	}
+
+// Create a channel on the device.
+TInt DSpiClientTestFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	if (iOpenChannels >= KMaxNumChannels)
+		return KErrOverflow;
+
+	aChannel = new DSpiClientChannel;
+	return aChannel ? KErrNone : KErrNoMemory;
+	}
+
+DSpiClientChannel::DSpiClientChannel()
+	{
+	iClient = &Kern::CurrentThread();
+	// Increase the DThread's ref count so that it does not close without us
+	((DObject*)iClient)->Open();
+	}
+
+DSpiClientChannel::~DSpiClientChannel()
+	{
+	((TDynamicDfcQue*)iDfcQ)->Destroy();
+	// decrement the DThread's reference count
+	Kern::SafeClose((DObject*&) iClient, NULL);
+	}
+
+TInt DSpiClientChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+	TDynamicDfcQue *dfcq = NULL;
+	TInt r = Kern::DynamicDfcQCreate(dfcq, KIntTestThreadPriority, KTestDriverName);
+
+	if(r == KErrNone)
+		{
+		SetDfcQ(dfcq);
+		iMsgQ.Receive();
+		}
+	return r;
+	}
+
+void DSpiClientChannel::HandleMsg(TMessageBase* aMsg)
+	{
+	TThreadMessage& m = *(TThreadMessage*) aMsg;
+	TInt id = m.iValue;
+
+	if (id == ECloseMsg)
+		{
+		iMsgQ.iMessage->Complete(KErrNone, EFalse);
+		return;
+		}
+	else if (id == KMaxTInt)
+		{
+		m.Complete(KErrNone, ETrue);
+		return;
+		}
+
+	if (id < 0)
+		{
+		TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
+		TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+		if (r != KErrNone)
+			{
+			Kern::RequestComplete(iClient, pS, r);
+			}
+		m.Complete(KErrNone, ETrue);
+		}
+	else
+		{
+		TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
+		m.Complete(r, ETrue);
+		}
+	}
+
+// to handle synchronous requests..
+// TODO: There are unimplemented functions - returning KErrNotSupported - treat this as a 'sort of'
+// of test-driven development.. Ideally - they should all be implemented..
+TInt DSpiClientChannel::DoControl(TInt aId, TAny* a1, TAny* a2)
+	{
+	TInt r = KErrNone;
+	switch (aId)
+		{
+		case RSpiClientTest::EHalfDuplexSingleWrite:
+			{
+			r = HalfDuplexSingleWrite();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexMultipleWrite:
+			{
+			r = HalfDuplexMultipleWrite();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexSingleRead:
+			{
+			r = HalfDuplexSingleRead();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexMultipleRead:
+			{
+			r = HalfDuplexMultipleRead();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexMultipleWriteRead:
+			{
+			r = HalfDuplexMultipleWriteRead();
+			break;
+			}
+		case RSpiClientTest::EFullDuplexSingle:
+			{
+			r = FullDuplexSingle();
+			break;
+			}
+		case RSpiClientTest::EFullDuplexMultiple:
+			{
+			r = FullDuplexMultiple();
+			break;
+			}
+		case RSpiClientTest::EHalfDuplexExtendable:
+			{
+			r = HalfDuplexExtendable();
+			break;
+			}
+		case RSpiClientTest::EFullDuplexExtendable:
+			{
+			r = FullDuplexExtendable();
+			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'
+	// of test-driven development.. Ideally - they should all be implemented..
+	TInt r = KErrNone;
+	switch (aId)
+		{
+		case RSpiClientTest::EAsyncHalfDuplexSingleWrite:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexSingleWrite(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexMultipleWrite:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexMultipleWrite(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexSingleRead:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexSingleRead(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexMultipleRead:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexMultipleRead(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexMultipleWriteRead:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexMultipleWriteRead(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncFullDuplexSingle:
+			{
+			r = KErrNotSupported; // AsyncFullDuplexSingle(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncFullDuplexMultiple:
+			{
+			r = KErrNotSupported; // AsyncFullDuplexMultiple(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncHalfDuplexExtendable:
+			{
+			r = KErrNotSupported; // AsyncHalfDuplexExtendable(aStatus);
+			break;
+			}
+		case RSpiClientTest::EAsyncFullDuplexExtendable:
+			{
+			r = KErrNotSupported; // AsyncFullDuplexExtendable(aStatus);
+			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, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer object
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> txTransferBuf; // txbuffer..
+
+	// fill it with some data..(this will also set the length of the buffer)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf.Append(i+1);
+		}
+
+	// create tranfer object
+	TIicBusTransfer txTransfer(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf);
+
+	// Create a transaction using header and list of transfers..
+	TIicBusTransaction transaction(&header, &txTransfer);
+
+	// queue the transaction synchronously
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test half duplex write:
+// - one transaction with more write transfers
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as the simplest example of a multiple writes
+// Note, that ALWAYS (not only in this example) - each of the transfers is separated
+// with SS signals assertion / deassertion
+TInt DSpiClientChannel::HalfDuplexMultipleWrite()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> txTransferBuf1;
+	TBuf8<KBuffLength> txTransferBuf2;
+
+	// put some data into these buffers..(this will also set their length)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf1.Append(i+1);
+		txTransferBuf2.Append(63-i);
+		}
+
+	// create two transfers and link them (transfer2 after transfer1)
+	TIicBusTransfer txTransfer1(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf1);
+	TIicBusTransfer txTransfer2(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf2);
+	txTransfer1.LinkAfter(&txTransfer2); // will link txTransfer2 after txTransfer1..
+
+	// Create a transaction using header and linked transfers (using first in one)
+	TIicBusTransaction transaction(&header, &txTransfer1);
+
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test half duplex read:
+// - one transaction with one read transfer
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as the simplest example of a single read transfer.
+// (e.g. for a potential use with a Slave device that is only capable of sending data)
+TInt DSpiClientChannel::HalfDuplexSingleRead()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed 3MHz (could use SpiFreqHz(16))
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> rxTransferBuf;
+
+	// put some data into the buffer..(this will also set its length)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		rxTransferBuf.Append(i+1);
+		}
+
+	// create transfer
+	TIicBusTransfer rxTransfer(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf);
+
+	// And a transaction
+	TIicBusTransaction transaction(&header, &rxTransfer);
+
+	// queue transaction synchronously
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now, we has non-zero data in the buffer, but we know, that there was nothing connected
+	// so we should either receive 0x0 (or 0xff if line was driven high- unlikely)- but we'll check
+	// if rx buffer has simply different data in it..
+	for (int i = 0; i < KBuffLength; i++)
+		{
+		if(rxTransferBuf[i] == i+1)
+			{
+			r = KErrCorrupt;
+			break;
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test half duplex multiple transfer read:
+// - one transaction with two read transfers
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// this is simmilar to write transactions with multiple transfers (e.g. HalfDuplexMultipleWrite)
+TInt DSpiClientChannel::HalfDuplexMultipleRead()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		1500000, //iClkSpeed 3MHz (could use SpiFreqHz(32))
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	const TInt KBuffLength1 = 32;
+	const TInt KBuffLength2 = 15;
+
+	TBuf8<KBuffLength1> rxTransferBuf1;
+	TBuf8<KBuffLength2> rxTransferBuf2;
+
+	// put some data into these buffers..(this will also set their lengths)
+	for (TInt i = 0; i < KBuffLength1; ++i)
+		{
+		rxTransferBuf1.Append(i+1);
+		}
+
+	for (TInt i = 0; i < KBuffLength2; ++i)
+		{
+		rxTransferBuf2.Append(i+1);
+		}
+
+	// create two transfers and link them (transfer2 after transfer1)
+	TIicBusTransfer rxTransfer1(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf1);
+	TIicBusTransfer rxTransfer2(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf2);
+	rxTransfer1.LinkAfter(&rxTransfer2);
+
+	// Create a transaction using header and linked transfers (using first in one)
+	TIicBusTransaction transaction(&header, &rxTransfer1);
+
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now, we has non-zero data in the buffer, but we know, that there was nothing connected
+	// so we should either receive 0x0 (or 0xff if line was driven high- unlikely)- but we'll check
+	// if rx buffer has simply different data in it..
+	for (int i = 0; i < KBuffLength1; i++)
+		{
+		if(rxTransferBuf1[i] == i+1)
+			{
+			r = KErrCorrupt;
+			break;
+			}
+		}
+
+	if(r == KErrNone)
+		{
+		for (int i = 0; i < KBuffLength2; i++)
+			{
+			if(rxTransferBuf2[i] == i+1)
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+
+// test half duplex read / write:
+// - one transaction with more transfers - intermixed read / write
+// - synchronous use - all buffers / transfer objects / transactions - on the stack
+// (Data on stack - recommended for small transfers).
+// This could serve as a simple example of a common spi usage for peripherals configuration, i.e.:
+// write data - e.g. address of register and / or command(s) followed by read of their value(s)
+TInt DSpiClientChannel::HalfDuplexMultipleWriteRead()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects
+	// (they don't have to be of the same size-it's just for simplicity here!)
+	const TInt KBuffLength = 32;
+	TBuf8<KBuffLength> txTransferBuf1; // txbuffer1..
+	TBuf8<KBuffLength> txTransferBuf2; // txbuffer2..
+	TBuf8<KBuffLength> rxTransferBuf; // rxbuffer..
+
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf1.Append(i+1);
+		txTransferBuf2.Append(63-i);
+		rxTransferBuf.Append(0xa5); // append some non-zero data-will check, if it's overwritten by read..
+		}
+	// The above will also set size of buffers - and this is checked by the driver!
+
+	// create two transfers and link them (transfer2 after transfer1)
+	TIicBusTransfer txTransfer1(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf1);
+	TIicBusTransfer txTransfer2(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf2);
+	txTransfer1.LinkAfter(&txTransfer2); // will link txTransfer2 after txTransfer1..
+
+	// create read transfer and link it after above two transfers
+	TIicBusTransfer rxTransfer(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf);
+	txTransfer2.LinkAfter(&rxTransfer); // will link rxTransfer after txTransfer2..
+
+	// Create a transaction using header and first of linked transfers
+	TIicBusTransaction transaction(&header, &txTransfer1);
+
+	// and queue it synchronously..
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+// test full duplex with single* transfer i,e. simultenous write and read.
+// - one half duplex transaction with one write transfer (for first direction-like usually)
+// - one read buffer - that will be used to 'setup' a full duplex transaction (for the other direction)
+// (Data on stack - recommended for small transfers).
+// This could serve as a simple example of simultenous write and read from a bus
+TInt DSpiClientChannel::FullDuplexSingle()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create transfer objects (they SHOULD be of the same size!)
+	const TInt KBuffLength = 64;
+	TBuf8<KBuffLength> txTransferBuf; // txbuffer..
+	TBuf8<KBuffLength> rxTransferBuf; // rxbuffer..
+
+	// fill TX buffer with some data to send..
+	// and the RX buffer - with some other data - to check if it's overwritten by read
+	// (this will also set buffers length's)
+	for (TInt i = 0; i < KBuffLength; ++i)
+		{
+		txTransferBuf.Append(i+1);
+		rxTransferBuf.Append(0x55);
+		}
+
+	// create transfer objects..
+	TIicBusTransfer txTransfer(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf);
+	TIicBusTransfer rxTransfer(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf);
+
+	// Create transaction using header and list of transfers..
+	TIicBusTransaction transaction(&header, &txTransfer);
+
+	// setup a full duplex transaction - using Rx buffer
+	transaction.SetFullDuplexTrans(&rxTransfer);
+
+	// queue the transaction
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now confirm the reception..
+	// BEAGLE BOARD only- if using local callback (ideally it should be used to fully test it)
+	// data in rx buffer should match the data in the tx buffer.
+	// otherwise (with no local loopback) - rx buffer should contain ZERO / (or different) data as it was
+	// initially filled with. (i.e. as nothing was driving the SOMI line - rx will count that as 0 sent over the bus)
+	// see top of this file and IsLoobackAvailable() function description for more details.
+	TBool checkReceivedMatchesSent = IsLoopbackAvailable();
+
+	if(!checkReceivedMatchesSent)
+		Kern::Printf("!Warning: %s (%d): not using local-loop for duplex test", __FILE__, __LINE__);
+
+	for (int i = 0; i < KBuffLength; i++)
+		{
+		if(checkReceivedMatchesSent)
+			{
+			if (rxTransferBuf[i] != txTransferBuf[i])
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		else
+			{
+			if (rxTransferBuf[i] == 0x55) // this was the value used..
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+
+// test full duplex with multiple transfers
+// - one half duplex transaction with two transfers: write followed by read
+// - two buffers to form the other direction: read followed by write.
+// (Data on stack - recommended for small transfers only).
+// This could serve as a simple example of multi-transfer full duplex transactions.
+TInt DSpiClientChannel::FullDuplexMultiple()
+	{
+	LOG_FUNCTION_ENTRY;
+	TInt r = KErrNone;
+
+	TUint32 busId = 0;
+	SET_BUS_TYPE(busId, DIicBusChannel::ESpi);
+	SET_CHAN_NUM(busId, 2);   // THis is the ModuleNumber, i.e. McSPIx (minus one), e.g. 2 for McSPI3
+	SET_SLAVE_ADDR(busId, 0); // THis is the ChannelNumber (Slave number of the above McSPIx)
+
+	// create header
+	const TConfigSpiV01 KHeader =
+		{
+		ESpiWordWidth_8, //iWordWidth
+		3000000, //iClkSpeed
+		ESpiPolarityLowRisingEdge, //iClkMode
+		500, // iTimeoutPeriod
+		EBigEndian, // iEndianness
+		EMsbFirst, //iBitOrder
+		0, //iTransactionWaitCycles
+		ESpiCSPinActiveLow //iCsPinActiveMode
+		};
+
+	TPckgBuf<TConfigSpiV01> header(KHeader);
+
+	// create buffers:
+	// for first duplex transfer
+	const TInt KBuffLength1 = 24;
+	TBuf8<KBuffLength1> txTransferBuf1;
+	TBuf8<KBuffLength1> rxTransferBuf1;
+
+	// for second duplex transfer..
+	// Note: Buffers for different transfers can have different size like below.
+	// the only requirement is - that for each duplex transfer(tx and rx) they need to have the same.
+	const TInt KBuffLength2 = 32;
+	TBuf8<KBuffLength2> rxTransferBuf2;
+	TBuf8<KBuffLength2> txTransferBuf2;
+
+	// fill them with data..
+	for (TInt i = 0; i < txTransferBuf1.MaxLength(); ++i)
+		{
+		txTransferBuf1.Append(i+1);
+		rxTransferBuf1.Append(0x55);
+		}
+
+	for (TInt i = 0; i < txTransferBuf2.MaxLength(); ++i)
+		{
+		txTransferBuf2.Append(i+1);
+		rxTransferBuf2.Append(0xaa);
+		}
+
+	// Now we want to chain transfers in the following way:
+	// txTransfer1 -> rxTransfer2
+	// rxTransfer1 -> txTransfer2
+	// note, that there could always be a read and write at the same time (in the same column)
+
+	// first direction
+	TIicBusTransfer txTransfer1(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf1);
+	TIicBusTransfer rxTransfer1(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf1);
+
+	// second transfer objects (they will run in parallel after above have finished)
+	TIicBusTransfer txTransfer2(TIicBusTransfer::EMasterWrite, 8, &txTransferBuf2);
+	TIicBusTransfer rxTransfer2(TIicBusTransfer::EMasterRead, 8, &rxTransferBuf2);
+
+	// chain them as described above
+	txTransfer1.LinkAfter(&rxTransfer2); // rxTransfer2 after txTransfer1
+	rxTransfer1.LinkAfter(&txTransfer2); // txTransfer2 after rxTransfer1
+
+	// Create a transaction using header and list of transfers..
+	TIicBusTransaction transaction(&header, &txTransfer1);
+	transaction.SetFullDuplexTrans(&rxTransfer1);
+
+	// and finally queue the transaction
+	r = IicBus::QueueTransaction(busId, &transaction);
+
+	// now confirm the reception..
+	// BEAGLE BOARD only- if using local callback (ideally it should be used to fully test it)
+	// data in rx buffer should match the data in the tx buffer.
+	// otherwise (with no local loopback) - rx buffer should contain zero / (or different) data as it was
+	// initially filled with. See top of this file and IsLoobackAvailable() function description for more details.
+	TBool checkReceivedMatchesSent = IsLoopbackAvailable();
+
+	if(!checkReceivedMatchesSent)
+		Kern::Printf("!Warning: %s (%d): not using local-loop for duplex test", __FILE__, __LINE__);
+
+	// check first transfer
+	for (int i = 0; i < KBuffLength1; i++)
+		{
+		if(checkReceivedMatchesSent)
+			{
+			if (rxTransferBuf1[i] != txTransferBuf1[i])
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		else
+			{
+			if (rxTransferBuf1[i] == 0x55) // this was the value used..
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+
+	// check second transfer
+	for (int i = 0; i < KBuffLength2; i++)
+		{
+		if(checkReceivedMatchesSent)
+			{
+			if (rxTransferBuf2[i] != txTransferBuf2[i])
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		else
+			{
+			if (rxTransferBuf2[i] == 0xaa) // this was the value used..
+				{
+				r = KErrCorrupt;
+				break;
+				}
+			}
+		}
+
+	LOG_FUNCTION_RETURN;
+	return r;
+	}
+
+TInt DSpiClientChannel::HalfDuplexExtendable()
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
+TInt DSpiClientChannel::FullDuplexExtendable()
+	{
+	return KErrNotSupported; // TODO: not implemented yet..
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.h	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,252 @@
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/d_spi_client_m.h
+//
+
+#ifndef __D_SPI_CLIENT_MASTER__
+#define __D_SPI_CLIENT_MASTER__
+
+#include <e32cmn.h>
+#include <e32ver.h>
+
+
+const TInt KIntTestThreadPriority = 24;
+
+const TInt KIntTestMajorVersionNumber = 1;
+const TInt KIntTestMinorVersionNumber = 0;
+const TInt KIntTestBuildVersionNumber = KE32BuildVersionNumber;
+
+_LIT(KLddFileName, "d_spi_client_m.ldd");
+_LIT(KLddFileNameRoot, "d_spi_client_m");
+
+#ifdef __KERNEL_MODE__
+#include <kernel/kernel.h>
+
+// For now - the driver has to know what frequencies are supported and has to specify them directly
+// in the transaction header. This might be changes in the IIC PIL (kernelhwsrv)-in a way, that the driver
+// returns supported frequencies with some 'GetCaps' method. For now - standard frequencies for CLK
+// (that support duty cycle 50-50) are 48MHz divisions per power-of-two.
+const TInt KSpiClkBaseFreqHz = 48000000;
+const TInt KSpiClkMaxDivider = 4096;
+
+inline TInt SpiFreqHz(TInt aDivider)
+	{
+	__ASSERT_DEBUG(aDivider > 0 && aDivider < KSpiClkMaxDivider, Kern::Fault("d_spi_client_master: divider out of range", 13));
+	__ASSERT_DEBUG(!(aDivider &  (aDivider-1)), Kern::Fault("d_spi_client_master: divider not power of two", 14));
+	return KSpiClkBaseFreqHz / aDivider;
+	}
+#endif
+
+class RSpiClientTest: public RBusLogicalChannel
+	{
+public:
+	enum TControl
+		{
+		EHalfDuplexSingleWrite,
+		EHalfDuplexMultipleWrite,
+		EHalfDuplexSingleRead,
+		EHalfDuplexMultipleRead,
+		EHalfDuplexMultipleWriteRead,
+		EFullDuplexSingle,
+		EFullDuplexMultiple,
+		EHalfDuplexExtendable,
+		EFullDuplexExtendable
+		};
+
+	enum TRequest
+		{
+		EAsyncHalfDuplexSingleWrite,
+		EAsyncHalfDuplexMultipleWrite,
+		EAsyncHalfDuplexSingleRead,
+		EAsyncHalfDuplexMultipleRead,
+		EAsyncHalfDuplexMultipleWriteRead,
+		EAsyncFullDuplexSingle,
+		EAsyncFullDuplexMultiple,
+		EAsyncHalfDuplexExtendable,
+		EAsyncFullDuplexExtendable
+		};
+
+#ifndef __KERNEL_MODE__
+public:
+	TInt Open()
+		{
+		return (DoCreate(KLddFileNameRoot,
+		                 TVersion(KIntTestMajorVersionNumber,KIntTestMinorVersionNumber,KIntTestBuildVersionNumber),
+		                 -1,
+		                 NULL,
+		                 NULL,
+		                 EOwnerThread));
+		}
+
+	// Synchronous calls
+	TInt HalfDuplexSingleWrite()
+		{return DoControl(EHalfDuplexSingleWrite);}
+
+	TInt HalfDuplexMultipleWrite()
+		{return DoControl(EHalfDuplexMultipleWrite);}
+
+	TInt HalfDuplexSingleRead()
+		{return DoControl(EHalfDuplexSingleRead);}
+
+	TInt HalfDuplexMultipleRead()
+		{return DoControl(EHalfDuplexMultipleRead);}
+
+	TInt HalfDuplexMultipleWriteRead()
+		{return DoControl(EHalfDuplexMultipleWriteRead);}
+
+	TInt FullDuplexSingle()
+		{return DoControl(EFullDuplexSingle);}
+
+	TInt FullDuplexMultiple()
+		{return DoControl(EFullDuplexMultiple);}
+
+
+	// Asynchronous calls..
+	void HalfDuplexSingleWrite(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexSingleWrite, aStatus, NULL);}
+
+	void HalfDuplexMultipleWrite(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexMultipleWrite, aStatus, NULL);}
+
+	void HalfDuplexSingleRead(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexSingleRead, aStatus, NULL);}
+
+	void HalfDuplexMultipleRead(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexMultipleRead, aStatus, NULL);}
+
+	void HalfDuplexMultipleWriteRead(TRequestStatus& aStatus)
+		{DoRequest(EAsyncHalfDuplexMultipleWriteRead, aStatus, NULL);}
+
+	void FullDuplexSingle(TRequestStatus& aStatus)
+		{DoRequest(EAsyncFullDuplexSingle, aStatus, NULL);}
+
+	void FullDuplexMultiple(TRequestStatus& aStatus)
+		{DoRequest(EAsyncFullDuplexMultiple, aStatus, NULL);}
+
+#endif
+	};
+
+#ifdef __KERNEL_MODE__
+struct TCapsProxyClient
+	{
+	TVersion version;
+	};
+
+class DSpiClientTestFactory: public DLogicalDevice
+	{
+public:
+	DSpiClientTestFactory();
+	~DSpiClientTestFactory();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8 &aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+// declaration for the client channel
+class DSpiClientChannel: public DLogicalChannel
+	{
+public:
+	DSpiClientChannel();
+	~DSpiClientChannel();
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+
+protected:
+	static void Handler(TAny *aParam);
+	virtual void HandleMsg(TMessageBase* aMsg); // Note: this is a pure virtual in DLogicalChannel
+	TInt DoControl(TInt aId, TAny* a1, TAny* a2);
+	TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2);
+
+	// set of example transfers with transactions queued synchronously
+	TInt HalfDuplexSingleWrite();
+	TInt HalfDuplexMultipleWrite();
+	TInt HalfDuplexSingleRead();
+	TInt HalfDuplexMultipleRead();
+	TInt HalfDuplexMultipleWriteRead();
+	TInt FullDuplexSingle();
+	TInt FullDuplexMultiple();
+	TInt HalfDuplexExtendable();
+	TInt FullDuplexExtendable();
+
+
+private:
+	TRequestStatus iStatus;
+	DThread* iClient;
+	};
+
+// Below is additional stuff for testing with local loopback
+// the IsLoopbackAvailable function checks if McSPI3 is configured to use pins from extension header
+// (Beagleboard) and if these pins are physically connected (e.g. with jumper)- in order to determine
+// if duplex transfers should receive the same data that was sent to the bus..
+#include <assp/omap3530_assp/omap3530_scm.h>
+#include <assp/omap3530_assp/omap3530_gpio.h>
+const TInt KSpi3_SIMO_Pin = 131;
+const TInt KSpi3_SOMI_Pin = 132;
+
+inline TBool IsLoopbackAvailable()
+	{
+	// first check, if pad is configured to use SPI (this will confirm, if pins are used that way)
+	// this is their configuration (EMode1)
+	//	CONTROL_PADCONF_MMC2_CLK,  SCM::EMsw, SCM::EMode1, // mcspi3_simo
+	//  CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, SCM::EMode1, // mcspi3_somi
+	TUint mode_MMC2_CLK = SCM::GetPadConfig(CONTROL_PADCONF_MMC2_CLK, SCM::EMsw);
+	TUint mode_MMC2_DAT0 = SCM::GetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw);
+
+	if(!(mode_MMC2_CLK & SCM::EMode1) ||
+	   !(mode_MMC2_DAT0 & SCM::EMode1))
+		{
+		return EFalse; // either other pins are used or SPI3 is not configured at all..
+		}
+
+	// swap pins to be GPIO (EMode4)
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_CLK, SCM::EMsw, SCM::EMode4 | SCM::EInputEnable);
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, SCM::EMode4 | SCM::EInputEnable);
+
+	// set SIMO pin as output
+	GPIO::SetPinDirection(KSpi3_SIMO_Pin, GPIO::EOutput);
+	GPIO::SetPinMode(KSpi3_SIMO_Pin, GPIO::EEnabled);
+
+	// and SOMI pin as input
+	GPIO::SetPinDirection(KSpi3_SOMI_Pin, GPIO::EInput);
+	GPIO::SetPinMode(KSpi3_SOMI_Pin, GPIO::EEnabled);
+
+	TBool result = ETrue;
+	GPIO::TGpioState pinState = GPIO::EHigh;
+
+	// test 1: set SIMO to ELow and check if SOMI is the same
+	GPIO::SetOutputState(KSpi3_SIMO_Pin, GPIO::ELow);
+	GPIO::GetInputState(KSpi3_SOMI_Pin, pinState);
+	if(pinState != GPIO::ELow)
+		{
+		result = EFalse;
+		}
+	else
+		{
+		// test 2: set SIMO to EHigh and check if SOMI is the same
+		GPIO::SetOutputState(KSpi3_SIMO_Pin, GPIO::EHigh);
+		GPIO::GetInputState(KSpi3_SOMI_Pin, pinState);
+		if(pinState != GPIO::EHigh)
+			{
+			result = EFalse;
+			}
+		}
+
+	// restore back oryginal pad configuration for these pins
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_CLK,  SCM::EMsw, mode_MMC2_CLK);
+	SCM::SetPadConfig(CONTROL_PADCONF_MMC2_DAT0, SCM::ELsw, mode_MMC2_DAT0);
+
+	return result;
+	}
+
+#endif /* __KERNEL_MODE__ */
+
+#endif /* __D_SPI_CLIENT_MASTER__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/d_spi_client_m.mmp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,49 @@
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/d_spi_client_m.mmp
+//
+
+#define __USING_ASSP_REGISTER_API__
+#define __USING_ASSP_INTERRUPT_API__
+
+#include <beagle/variant.mmh>
+#include <kernel/kern_ext.mmh>
+
+// link against the IIC controller library..
+library       iic.lib
+
+target        VariantTarget(d_spi_client_m,ldd)
+romtarget     d_spi_client_m.ldd
+
+// for testing only (for local loop-back detection) - link agains GPIO..
+library       AsspTarget(gpio,lib)
+
+targettype     ldd
+sourcepath     ./
+source         d_spi_client_m.cpp
+
+OS_LAYER_SYSTEMINCLUDE
+SYSTEMINCLUDE    +\include\assp\omap3530_assp
+SYSTEMINCLUDE 	 +\include\drivers
+SYMBIAN_BASE_SYSTEMINCLUDE(assp/omap3530_assp)
+SYMBIAN_BASE_SYSTEMINCLUDE(drivers)
+SYMBIAN_BASE_SYSTEMINCLUDE(kernel)
+
+
+uid		0x100000af
+vendorid 0x70000001
+
+capability		all
+epocallowdlldata
+
+SMPSAFE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/t_spi_client_m.cpp	Tue Sep 21 02:30:11 2010 +0100
@@ -0,0 +1,112 @@
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// lukasz.forynski@gmail.com
+//
+// Contributors:
+//
+//
+// Description:
+// omap3530_drivers/spi/test/t_spi_client_master.cpp
+//
+// user-side application for the simple SPI client (master) test driver.
+//
+
+#include <e32test.h>
+#include <e32cmn.h>
+#include "d_spi_client_m.h"
+
+
+// global data..
+_LIT(testName,"T_SPI_CLIENT_M");
+GLDEF_D RTest test(testName);
+
+GLDEF_D RSpiClientTest testLdd; // the actual driver..
+
+void PrepareDriver()
+	{
+	// Load the Test Driver
+	TInt r = User::LoadLogicalDevice(KLddFileName);
+	if(r != KErrNone && r != KErrAlreadyExists)
+		{
+		// fail..
+		test.Printf(_L("\nFailed to load the driver, r=%d"), r);
+		test(EFalse);
+		}
+
+	// Open the driver
+	r = testLdd.Open();
+	if(r != KErrNone)
+		{
+		test.Printf(_L("Failed to open the driver..\n\r"));
+		test(EFalse);
+		}
+	}
+
+void ReleaseDriver()
+	{
+	// Close the driver
+	testLdd.Close();
+
+	// unload the driver
+	User::FreeLogicalDevice(KLddFileName);
+	}
+
+inline void TestError(TInt r)
+	{
+	if(r == KErrNotSupported) // this is to warn stuf not yet implemented (TDD)
+		{
+		test.Printf(_L("!! Warning: not implemented yet..\n\r"));
+		}
+	else
+		{
+		test(r == KErrNone);
+		}
+	}
+
+void TestSynchronousOperation()
+	{
+	test.Next(_L("TestSynchronousOperation()"));
+
+	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());
+	}
+
+
+TInt E32Main()
+	{
+	test.Title();
+	test.Start(_L("Testing SPI.."));
+
+	PrepareDriver();
+
+	TestSynchronousOperation();
+
+	ReleaseDriver();
+
+	test.End();
+
+	return KErrNone;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/omap3530_drivers/spi/test/t_spi_client_m.mmp	Tue Sep 21 02:30:11 2010 +0100
@@ -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
+