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