From: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
Subject: OKI Semiconductor PCH SPI driver

This driver implements SPI controls for PCH.

Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
Acked-by: Wang Qi <qi.wang@intel.com>

---
 drivers/spi/Kconfig                     |    19 ++
 drivers/spi/Makefile                    |    3
 drivers/spi/pch_common.h                |    146
 drivers/spi/pch_spi.h                   |    389
 drivers/spi/pch_spi_hal.h               |    298
 drivers/spi/pch_spi_pci.c               |    812
 drivers/spi/pch_debug.h                 |    60
 drivers/spi/pch_spi_hal.c               |    1208
 drivers/spi/pch_spi_main.c              |    1323
 drivers/spi/pch_spi_platform_devices.c  |    50

+++++++++++++++++++++++++++++++ 10 files changed, yyy insertions(+)
diff -urN linux-2.6.33-rc3/drivers/spi/Kconfig topcliff-2.6.33-rc3/drivers/spi/Kconfig
--- linux-2.6.33-rc3/drivers/spi/Kconfig	2010-01-06 09:02:46.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/Kconfig	2010-03-06 07:48:16.000000000 +0900
@@ -53,6 +53,25 @@
 
 comment "SPI Master Controller Drivers"
 
+config PCH_SPI_PLATFORM_DEVICE
+	bool "PCH SPI Device"
+#	depends on PCH_SPI
+	help
+	  This registers SPI devices for using with PCH SPI controllers.
+
+config PCH_SPI_PLATFORM_DEVICE_COUNT
+	int "PCH SPI Bus count"
+	range 1 2
+	depends on PCH_SPI_PLATFORM_DEVICE
+	help
+	  The number of SPI buses/channels supported by the PCH SPI controller.
+
+config PCH_SPI
+	tristate "PCH SPI Controller"
+	depends on (PCI) && PCH_SPI_PLATFORM_DEVICE
+	help
+	  This selects a driver for the PCH SPI Controller
+
 config SPI_ATMEL
 	tristate "Atmel SPI Controller"
 	depends on (ARCH_AT91 || AVR32)
diff -urN linux-2.6.33-rc3/drivers/spi/Makefile topcliff-2.6.33-rc3/drivers/spi/Makefile
--- linux-2.6.33-rc3/drivers/spi/Makefile	2010-01-06 09:02:46.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/Makefile	2010-03-06 01:52:28.000000000 +0900
@@ -59,3 +59,6 @@
 
 # SPI slave drivers (protocol for that link)
 # 	... add above this line ...
+obj-$(CONFIG_PCH_SPI) += pch_spi.o
+pch_spi-objs := pch_spi_pci.o pch_spi_hal.o pch_spi_main.o
+obj-$(CONFIG_PCH_SPI_PLATFORM_DEVICE) +=pch_spi_platform_devices.o
diff -urN linux-2.6.33-rc3/drivers/spi/pch_common.h topcliff-2.6.33-rc3/drivers/spi/pch_common.h
--- linux-2.6.33-rc3/drivers/spi/pch_common.h	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_common.h	2010-03-09 05:56:11.000000000 +0900
@@ -0,0 +1,146 @@
+/*!
+ * @file ioh_common.h
+ * @brief Provides the macro definitions used by all files.
+ * @version 1.0.0.0
+ * @section
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * History:
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * created:
+ *	WIPRO 03/07/2009
+ * modified:
+ *	WIPRO 05/08/2009
+ *
+ */
+
+#ifndef __IOH_COMMON_H__
+#define __IOH_COMMON_H__
+
+/*! @ingroup	Global
+@def		    IOH_WRITE8
+@brief			Macro for writing 8 bit data to an io/mem address
+*/
+#define IOH_WRITE8(val, addr)   iowrite8((val), (void __iomem *)(addr))
+/*! @ingroup	Global
+@def		    IOH_LOG
+@brief			Macro for writing 16 bit data to an io/mem address
+*/
+#define IOH_WRITE16(val, addr)  iowrite16((val), (void __iomem *)(addr))
+/*! @ingroup	Global
+@def		    IOH_LOG
+@brief			Macro for writing 32 bit data to an io/mem address
+*/
+#define IOH_WRITE32(val, addr)  iowrite32((val), (void __iomem *)(addr))
+
+/*! @ingroup	Global
+@def		    IOH_READ8
+@brief			Macro for reading 8 bit data from an io/mem address
+*/
+#define IOH_READ8(addr)   ioread8((void __iomem *)(addr))
+/*! @ingroup	Global
+@def		    IOH_READ16
+@brief			Macro for reading 16 bit data from an io/mem address
+*/
+#define IOH_READ16(addr)  ioread16((void __iomem *)(addr))
+/*! @ingroup	Global
+@def		    IOH_READ32
+@brief			Macro for reading 32 bit data from an io/mem address
+*/
+#define IOH_READ32(addr)  ioread32((void __iomem *)(addr))
+/*! @ingroup	Global
+@def		    IOH_WRITE32_F
+@brief			Macro for writing 32 bit data to an io/mem address
+*/
+#define IOH_WRITE32_F(val, addr) do \
+	{ IOH_WRITE32((val), (addr)); (void)IOH_READ32((addr)); } while (0);
+
+/*! @ingroup	Global
+@def		    IOH_WRITE_BYTE
+@brief			Macro for writing 1 byte data to an io/mem address
+*/
+#define IOH_WRITE_BYTE IOH_WRITE8
+/*! @ingroup	Global
+@def		    IOH_WRITE_WORD
+@brief			Macro for writing 1 word data to an io/mem address
+*/
+#define IOH_WRITE_WORD IOH_WRITE16
+/*! @ingroup	Global
+@def		    IOH_WRITE_LONG
+@brief			Macro for writing long data to an io/mem address
+*/
+#define IOH_WRITE_LONG IOH_WRITE32
+
+/*! @ingroup	Global
+@def		    IOH_READ_BYTE
+@brief			Macro for reading 1 byte data from an io/mem address
+*/
+#define IOH_READ_BYTE  IOH_READ8
+/*! @ingroup	Global
+@def		    IOH_READ_WORD
+@brief			Macro for reading 1 word data from an io/mem address
+*/
+#define IOH_READ_WORD  IOH_READ16
+/*! @ingroup	Global
+@def		    IOH_READ_LONG
+@brief			Macro for reading long data from an io/mem address
+*/
+#define IOH_READ_LONG  IOH_READ32
+
+/* Bit Manipulation Macros */
+
+/*! @ingroup	Global
+@def		    IOH_READ_LONG
+@brief			macro to set a specified bit(mask) at the
+			specified address
+*/
+#define IOH_SET_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) |\
+							 (bitmask)), (addr))
+
+/*! @ingroup	Global
+@def	    IOH_READ_LONG
+@brief		macro to clear a specified bit(mask) at the specified address
+*/
+#define IOH_CLR_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) &\
+							 ~(bitmask)), (addr))
+
+/*! @ingroup	Global
+@def		    IOH_READ_LONG
+@brief			macro to set a specified bitmask for a variable
+*/
+#define IOH_SET_BITMSK(var, bitmask) ((var) |= (bitmask))
+
+/*! @ingroup	Global
+@def		    IOH_READ_LONG
+@brief			macro to clear a specified bitmask for a variable
+*/
+#define IOH_CLR_BITMSK(var, bitmask) ((var) &= (~(bitmask)))
+
+/*! @ingroup	Global
+@def		    IOH_READ_LONG
+@brief			macro to set a specified bit for a variable
+*/
+#define IOH_SET_BIT(var, bit) ((var) |= (1<<(bit)))
+
+/*! @ingroup	Global
+@def		    IOH_READ_LONG
+@brief			macro to clear a specified bit for a variable
+*/
+#define IOH_CLR_BIT(var, bit) ((var) &= ~(1<<(bit)))
+
+#endif
diff -urN linux-2.6.33-rc3/drivers/spi/pch_debug.h topcliff-2.6.33-rc3/drivers/spi/pch_debug.h
--- linux-2.6.33-rc3/drivers/spi/pch_debug.h	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_debug.h	2010-03-09 05:37:47.000000000 +0900
@@ -0,0 +1,60 @@
+/*!
+ * @file ioh_debug.h
+ * @brief Provides the macro definitions used for debugging.
+ * @version 1.0.0.0
+ * @section
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * History:
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * created:
+ *	WIPRO 03/07/2009
+ * modified:
+ *	WIPRO 05/08/2009
+ *
+ */
+
+#ifndef __IOH_DEBUG_H__
+#define __IOH_DEBUG_H__
+
+#ifdef MODULE
+#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n",\
+						 THIS_MODULE->name, ##args)
+#else
+#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n" ,\
+							 __FILE__, ##args)
+#endif
+
+
+#ifdef DEBUG
+	#define IOH_DEBUG(fmt, args...) IOH_LOG(KERN_DEBUG, fmt, ##args)
+#else
+	#define IOH_DEBUG(fmt, args...)
+#endif
+
+#ifdef IOH_TRACE_ENABLED
+	#define IOH_TRACE IOH_DEBUG
+#else
+	#define IOH_TRACE(fmt, args...)
+#endif
+
+#define IOH_TRACE_ENTER IOH_TRACE("Enter %s", __func__)
+#define IOH_TRACE_EXIT 	IOH_TRACE("Exit %s", __func__)
+
+
+#endif
diff -urN linux-2.6.33-rc3/drivers/spi/pch_spi.h topcliff-2.6.33-rc3/drivers/spi/pch_spi.h
--- linux-2.6.33-rc3/drivers/spi/pch_spi.h	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_spi.h	2010-03-06 09:01:42.000000000 +0900
@@ -0,0 +1,389 @@
+#ifndef __IOH_SPI_H__
+#define __IOH_SPI_H__
+/**
+ * @file	ioh_spi.h
+ *
+ * @brief	This header file contains all macro,structure and function
+ * 							 declarations
+ * 		  	for IOH SPI driver.
+ * @version 0.94
+ *
+ * @par
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * @par
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+
+/*! @defgroup SPI */
+
+/*! @defgroup   SPI_Global
+@ingroup    	SPI
+@brief      	This group describes the global entities within
+		the module.
+@remarks    	This group includes all the global data structures
+		used within the modules. These are mainly used to
+		store the device related information, so that it can
+		be used by other functions of the modules.
+<hr>
+*/
+
+/*! @defgroup   SPI_PCILayer
+@ingroup    	SPI
+@brief      	This group describes the PCI layer interface
+				functionalities.
+@remarks    	This group contains the functions and data structures
+			that are used to interface the module with PCI Layer
+				subsystem of the Kernel.
+<hr>
+*/
+
+/*! @defgroup   SPI_InterfaceLayer
+@ingroup    	SPI
+@brief      	This group describes the Driver interface functionalities.
+@remarks    	This group contains the data structures and functions used
+		to interface the module driver with the kernel subsystem.
+<hr>
+*/
+
+/*! @defgroup   SPI_HALLayer
+@ingroup    	SPI
+@brief      	This group describes the hardware specific functionalities.
+@remarks    	This group contains the functions and data structures used
+		by the module to communicate with the hardware. These
+		functions are device specific and designed according to the
+		device specifications.
+<hr>
+*/
+
+/*! @defgroup   SPI_Utilities
+@ingroup    	SPI
+@brief      	This group describes the utility functionalities.
+@remarks    	This group contains the functions and data structures used
+		to assist the other functionalities in their operations.
+<hr>
+*/
+
+/*! @defgroup   SPI_PCILayerAPI
+@ingroup    	SPI_PCILayer
+@brief      	This group contains the API(functions) used as the PCI
+		interface between the Kernel subsystem and the module.
+<hr>
+*/
+
+/*! @defgroup   SPI_PCILayerFacilitators
+@ingroup    	SPI_PCILayer
+@brief      	This group contains the data structures used by the PCI
+		Layer APIs for their functionalities.
+<hr>
+*/
+
+/*! @defgroup   SPI_InterfaceLayerAPI
+@ingroup    	SPI_InterfaceLayer
+@brief      	This group contains the API(functions) used as the Driver
+		interface between the Kernel subsystem and the module.
+<hr>
+*/
+
+/*! @defgroup   SPI_InterfaceLayerFacilitators
+@ingroup    	SPI_InterfaceLayer
+@brief      	This group contains the data structures used by the Driver
+		interface APIs for their functionalities.
+<hr>
+*/
+
+/*! @defgroup   SPI_HALLayerAPI
+@ingroup    	SPI_HALLayer
+@brief      	This group contains the APIs(functions) used to interact with
+		the hardware. These APIs act as an interface between the
+		hardware and the other driver functions.
+<hr>
+*/
+
+/*! @defgroup   SPI_UtilitiesAPI
+@ingroup    	SPI_Utilities
+@brief      	This group contains the APIs(functions) used by other functions
+		in their operations.
+<hr>
+*/
+
+#include <linux/wait.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+
+/*! @ingroup	SPI_Global
+
+@def			STATUS_RUNNING
+
+@brief			SPI channel is running
+
+@note			The status of SPI channel is set to STATUS_RUNNING,
+			once all resources are acquired and initialized from
+			@ref ioh_spi_get_resources
+
+@see
+				- ioh_spi_get_resources
+
+<hr>
+*/
+#define STATUS_RUNNING           (1)
+
+/*! @ingroup	SPI_Global
+
+@def			STATUS_EXITING
+
+@brief			SPI device is being removed
+
+@note			The status of SPI channel is set to STATUS_EXITING,
+				when SPI device is being removed.
+
+@see
+				- ioh_spi_process_messages
+				- ioh_spi_check_request_pending
+
+<hr>
+*/
+#define STATUS_EXITING           (2)
+
+/*! @ingroup	SPI_Global
+
+@def		    DRIVER_NAME
+
+@brief			Name identifier for IOH SPI driver
+
+@note			This name is used while printing debug logs
+
+<hr>
+*/
+#define DRIVER_NAME 		 	 "ioh_spi"
+
+/*! @ingroup	SPI_Global
+
+@def		    IOH_SPI_SLEEP_TIME
+
+@brief			Sleep time used in @ref ioh_spi_check_request_pending
+
+@see
+				- ioh_spi_check_request_pending
+
+<hr>
+*/
+#define IOH_SPI_SLEEP_TIME        (10)
+
+/*! @ingroup	SPI_Global
+
+@def		    IOH_SPI_MAX_DEV
+
+@brief			Denotes Maximum number of SPI channels
+
+@note			This needs to be edited if number of SPI channels
+				change.
+
+@see
+				- ioh_spi_get_resources
+				- ioh_spi_free_resources
+				- ioh_spi_handler
+				- ioh_spi_check_request_pending
+				- ioh_spi_probe
+				- ioh_spi_suspend
+				- ioh_spi_resume
+				- ioh_spi_remove
+
+<hr>
+*/
+#ifdef IOH_DEVICE_GE
+#define IOH_SPI_MAX_DEV           (1)
+#else
+#define IOH_SPI_MAX_DEV           (1)
+#endif
+
+/*! @ingroup	SPI_Global
+
+@def		    IOH_SPI_ADDRESS_SIZE
+
+@brief			Denotes the address range used by one SPI channel.
+
+@note		The base address of a subsequent SPI channel will be
+	(base address of the previous SPI channel) + (IOH_SPI_ADDRESS_SIZE)
+	This needs to be recalculated if any new register is added to a SPI
+				channel.
+
+@see
+				- ioh_spi_get_resources
+
+<hr>
+*/
+#define IOH_SPI_ADDRESS_SIZE      (0x20)
+
+/*structures*/
+
+/*! @ingroup	SPI_Global
+@struct			ioh_spi_data
+@brief			Holds the SPI channel specific details
+
+	This structure holds all the details related to a SPI channel
+
+	The status of SPI data transfer,the base address are all
+	stored in this structure.The reference to the work queue handler,
+	the SPI message and transmit and receive indices are also stored
+	in this structure.
+
+@see
+				- ioh_spi_board_data
+				- ioh_spi_select_chip
+				- ioh_spi_deselect_chip
+				- ioh_spi_transfer
+				- ioh_spi_process_messages
+<hr>
+*/
+
+struct ioh_spi_data {
+
+	u32 IORemapAddress; /**< The remapped PCI base address.*/
+
+	/**< The SPI master structure that has been registered
+							 with the Kernel.*/
+	struct spi_master *pMaster;
+
+	struct work_struct Work; /**< Reference to work queue handler*/
+
+	/**< Workqueue for carrying out execution of the requests*/
+	struct workqueue_struct *pWorkQueue;
+
+	/**< Wait queue for waking up upon receiving an interrupt.*/
+	wait_queue_head_t Wait;
+
+	u8 bTransferComplete;			/**< Status of SPI Transfer*/
+	u8 bCurrent_msg_processing; /**< Status flag for message processing*/
+
+	spinlock_t Lock;	/**< Lock for protecting this structure*/
+
+	struct list_head Queue;			/**< SPI Message queue*/
+	u8 Status;			/**< Status of the SPI driver.*/
+
+	u32 lengthInBpw;/**< Length of data to be transferred in bits per word*/
+	s8 bTransferActive;		/**< Flag showing active transfer*/
+	u32 TxIndex;/**< Transmit data count; for bookkeeping during transfer*/
+	u32 RxIndex;/**< Receive data count; for bookkeeping during transfer*/
+	u16 *pU16TxBuffer;		/**< Data to be transmitted*/
+	u16 *pU16RxBuffer;		/**< Received data*/
+
+/**< The chip number that this SPI driver currently operates on*/
+	u8 nCurrentChip;
+
+	/**< Reference to the current chip that this SPI driver currently
+								 operates on*/
+	struct spi_device *pCurrentChip;
+
+	/**< The current message that this SPI driver is handling*/
+	struct spi_message *pCurMsg;
+
+		/**< The current transfer that this SPI driver is handling*/
+	struct spi_transfer *pCurTransfer;
+
+		/**< Reference to the SPI device data structure*/
+	struct ioh_spi_board_data *pBoardData;
+};
+
+/*! @ingroup	SPI_Global
+@struct			ioh_spi_board_data
+@brief			Holds the SPI device specific details
+
+	This structure holds all the details related to a SPI device.
+
+	The reference to the pci_dev structure,status of request_irq,
+	pci_request_regions and device suspend are all stored in this structure.
+
+	This structure also has an array of pointers to ioh_spi_data structures,
+    with each pointer holding the details of one spi channel.
+
+@see
+				- ioh_spi_data
+				- ioh_spi_check_request_pending
+				- ioh_spi_get_resources
+				- ioh_spi_free_resources
+				- ioh_spi_remove
+				- ioh_spi_suspend
+				- ioh_spi_resume
+				- ioh_spi_probe
+				- ioh_spi_handler
+<hr>
+*/
+
+struct ioh_spi_board_data {
+
+	struct pci_dev *pDev;		/**< Reference to the PCI device*/
+	u8 bIrqRegistered;		/**< Status of IRQ registration*/
+	u8 bRegionRequested;		/**< Status of pci_request_regions*/
+	u8 bSuspended;			/**< Status of suspend*/
+
+	/**< Reference to SPI channel data structure*/
+	struct ioh_spi_data *pCtrlData[IOH_SPI_MAX_DEV];
+};
+
+/*function prototypes*/
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn			ioh_spi_callback( struct ioh_spi_data* pCtrlData)
+@brief			Callback function
+*/
+void ioh_spi_callback(struct ioh_spi_data *pCtrlData);
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn		ioh_spi_free_resources(struct ioh_spi_board_data* pBoardData)
+@brief			Frees the resources acquired by IOH SPI driver
+*/
+void ioh_spi_free_resources(struct ioh_spi_board_data *pBoardData);
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn	ioh_spi_check_request_pending(struct ioh_spi_board_data* pBoardData)
+@brief	Checks for any pending SPI transfer request in the queue of pending
+								 transfers
+*/
+int ioh_spi_check_request_pending(struct ioh_spi_board_data *pBoardData);
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn		ioh_spi_get_resources(struct ioh_spi_board_data* pBoardData)
+@brief		Acquires the resources for IOH SPI driver
+*/
+int ioh_spi_get_resources(struct ioh_spi_board_data *pBoardData);
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+@fn				ioh_spi_setup(struct spi_device* pSpi)
+@brief			Implements the setup routine for IOH SPI driver
+*/
+int ioh_spi_setup(struct spi_device *pSpi);
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+@fn	ioh_spi_transfer(struct spi_device* pSpi,struct spi_message* pMsg)
+@brief		Implements the transfer routine for IOH SPI driver
+*/
+int ioh_spi_transfer(struct spi_device *pSpi, struct spi_message *pMsg);
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+@fn				ioh_spi_cleanup(struct spi_device* pSpi)
+@brief          Implements the cleanup routine for IOH SPI driver
+*/
+void ioh_spi_cleanup(struct spi_device *pSpi);
+
+#endif
diff -urN linux-2.6.33-rc3/drivers/spi/pch_spi_hal.c topcliff-2.6.33-rc3/drivers/spi/pch_spi_hal.c
--- linux-2.6.33-rc3/drivers/spi/pch_spi_hal.c	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_spi_hal.c	2010-03-09 00:41:44.000000000 +0900
@@ -0,0 +1,1208 @@
+/**
+ * @file 	ioh_spi_hal.c
+ *
+ * @brief	This file defines the HAL methods .
+ *
+ * @version 0.94
+ *
+ * @par
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * @par
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include "pch_common.h"
+#include "pch_debug.h"
+#include "pch_spi.h"
+#include "pch_spi_hal.h"
+
+/*bit positions in SPCR*/
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_SPE_BIT
+@brief			SPE bit position in SPCR
+@see
+				- ioh_spi_set_enable
+*/
+#define SPCR_SPE_BIT            	(1 << 0)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_MSTR_BIT
+@brief			MSTR bit position in SPCR
+@see
+				- ioh_spi_set_master_mode
+*/
+#define SPCR_MSTR_BIT           	(1 << 1)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_LSBF_BIT
+@brief			LSBF bit position in SPCR
+@see
+				- ioh_spi_setup_transfer
+*/
+#define SPCR_LSBF_BIT           	(1 << 4)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_CPHA_BIT
+@brief			CPHA bit position in SPCR
+@see
+				- ioh_spi_setup_transfer
+*/
+#define SPCR_CPHA_BIT           	(1 << 5)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_CPOL_BIT
+@brief			CPOL bit position in SPCR
+@see
+				- ioh_spi_setup_transfer
+*/
+#define SPCR_CPOL_BIT           	(1 << 6)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_TFIE_BIT
+@brief			TFIE bit position in SPCR
+@see
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+*/
+#define SPCR_TFIE_BIT           	(1 << 8)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_RFIE_BIT
+@brief			RFIE bit position in SPCR
+@see
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+*/
+#define SPCR_RFIE_BIT           	(1 << 9)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_FIE_BIT
+@brief			FIE bit position in SPCR
+@see
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+*/
+#define SPCR_FIE_BIT            	(1 << 10)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_ORIE_BIT
+@brief			ORIE bit position in SPCR
+@see
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+*/
+#define SPCR_ORIE_BIT           	(1 << 11)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_MDFIE_BIT
+@brief			MDFIE bit position in SPCR
+@see
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+*/
+#define SPCR_MDFIE_BIT          	(1 << 12)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_FICLR_BIT
+@brief			FICLR bit position in SPCR
+@see
+				- ioh_spi_clear_fifo
+*/
+#define SPCR_FICLR_BIT          	(1 << 24)
+
+/*bit positions in SPSR*/
+
+/*! @ingroup	SPI_HALLayer
+@def			SPSR_TFI_BIT
+@brief			TFI bit position in SPCR
+*/
+#define SPSR_TFI_BIT            	(1 << 0)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPSR_RFI_BIT
+@brief			RFI bit position in SPCR
+@see
+				- ioh_spi_handler
+*/
+#define SPSR_RFI_BIT            	(1 << 1)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPSR_FI_BIT
+@brief			FI bit position in SPCR
+@see
+				- ioh_spi_handler
+*/
+#define SPSR_FI_BIT            	 	(1 << 2)
+
+/*bit positions in SPBRR*/
+
+/*! @ingroup	SPI_HALLayer
+@def			SPBRR_SIZE_BIT
+@brief			SIZE  bit position in SPCR
+@see
+				- ioh_spi_set_bits_per_word
+*/
+#define SPBRR_SIZE_BIT         		(1 << 10)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_RFIC_FIELD
+@brief			RFIC field in SPCR
+@see
+				- ioh_spi_set_threshold
+*/
+#define SPCR_RFIC_FIELD         	(20)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPCR_TFIC_FIELD
+@brief			TFIC field in SPCR
+@see
+				- ioh_spi_set_threshold
+*/
+#define SPCR_TFIC_FIELD        		(16)
+
+/*! @ingroup	SPI_HALLayer
+@def			SPSR_INT_BITS
+@brief			Mask for all interrupt bits in SPSR
+@see
+				- ioh_spi_reset
+*/
+#define SPSR_INT_BITS           	(0x1F)
+
+/*! @ingroup	SPI_HALLayer
+@def			MASK_SPBRR_SPBR_BITS
+@brief			Mask for clearing SPBR in SPBRR
+@see
+				- ioh_spi_set_baud_rate
+*/
+#define MASK_SPBRR_SPBR_BITS      	(0xFFFFFC00)
+
+/*! @ingroup	SPI_HALLayer
+@def			MASK_RFIC_SPCR_BITS
+@brief			Mask for Rx threshold in SPCR
+@see
+				- ioh_spi_set_threshold
+*/
+#define MASK_RFIC_SPCR_BITS    		(0xFF0FFFFF)
+
+/*! @ingroup	SPI_HALLayer
+@def			MASK_TFIC_SPCR_BITS
+@brief			Mask for Tx threshold in SPCR
+@see
+				- ioh_spi_set_threshold
+*/
+#define MASK_TFIC_SPCR_BITS       	(0xFFF0FFF)
+
+/*! @ingroup	SPI_HALLayer
+@def			IOH_CLOCK_HZ
+@brief			Pclock Freqeuncy
+@see
+				- ioh_spi_set_baud_rate
+*/
+#ifndef FPGA
+ /*LSI*/
+#define IOH_CLOCK_HZ            	(50000000)
+#else
+ /*FPGA*/
+#define IOH_CLOCK_HZ            	(62500000)
+#endif
+/*! @ingroup	SPI_HALLayer
+@def			IOH_SPI_MAX_SPBR
+@brief			Maximum value possible for SPBR in SPBRR
+@see
+				- ioh_spi_set_baud_rate
+*/
+#define IOH_SPI_MAX_SPBR        	(1023)
+/*global*/
+/*! @ingroup	SPI_HALLayer
+
+@var 			ioh_spi_gcbptr
+
+@brief			SPI_Global function pointer to store reference of
+						 callback function @ref
+				ioh_spi_callback
+
+@note			The reference of callback function is assigend to this
+								 pointer
+				from @ref ioh_spi_probe function by invoking
+					 the function @ref ioh_spi_entcb.
+				This global variable is used by the function
+						 @ref ioh_spi_hanlder
+				to invoke the callback function.
+
+@see
+				- ioh_spi_entcb
+				- ioh_spi_handler
+
+<hr>
+
+*/
+static void (*ioh_spi_gcbptr) (struct ioh_spi_data *);
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn			ioh_spi_set_master_mode( struct spi_master *master)
+
+@remarks		Sets the MSTR bit in SPCR
+
+				The main task performed by this method:
+				- Read the content of SPCR register
+				- Set the MSTR bit
+				- Write back the value to SPCR
+
+@note	This function is invoked from @ref ioh_spi_probe to put the IOH SPI
+				device into master mode.
+
+@param		master	[@ref IN]	Contains reference to struct spi_master
+
+@retval			None
+
+@see
+				- ioh_spi_probe
+
+<hr>
+
+*/
+void ioh_spi_set_master_mode(struct spi_master *master)
+{
+	u32 reg_spcr_val;
+	reg_spcr_val = ioh_spi_readreg(master, IOH_SPI_SPCR);
+	IOH_DEBUG("ioh_spi_set_master_mode SPCR content=%x\n", reg_spcr_val);
+
+	/*sets the second bit of SPCR to 1:master mode */
+	IOH_SET_BITMSK(reg_spcr_val, SPCR_MSTR_BIT);
+
+	/*write the value to SPCR register */
+	ioh_spi_writereg(master, IOH_SPI_SPCR, reg_spcr_val);
+	IOH_DEBUG("ioh_spi_set_master_mode SPCR after setting MSTR bit=%x\n",
+		  reg_spcr_val);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn		ioh_spi_set_enable(const struct spi_device *spi, u8 enable)
+
+@remarks		Sets/Resets the SPE bit in SPCR
+
+			The main tasks performed by this method are:
+			- Read the content of SPCR.
+			- If the enable parameter is true , set the SPE bit.
+			- If the enable paramter is false , clear the SPE bit.
+			- Write back the value to SPCR.
+
+@note 	This function is invoked by @ref ioh_spi_process_messages to enable SPI
+	transfer before start of SPI data transfer and to disable SPI data
+								 transfer
+					after completion of SPI data transfer.
+
+@param	spi		[@ref IN]	Contains reference to struct spi_device
+
+@param			enable	[@ref IN]
+				To enable SPI transfer enable = true
+				To disable SPI transfer enable = false
+
+@retval			None
+
+@see
+				- ioh_spi_process_messages
+
+<hr>
+
+*/
+void ioh_spi_set_enable(const struct spi_device *spi, u8 enable)
+{
+	u32 reg_spcr_val;
+
+	reg_spcr_val = ioh_spi_readreg(spi->master, IOH_SPI_SPCR);
+	IOH_DEBUG("ioh_spi_set_enable SPCR content=%x\n", reg_spcr_val);
+
+	if (enable == true) {
+		IOH_DEBUG("ioh_spi_set_enable enable==true\n");
+		IOH_SET_BITMSK(reg_spcr_val, SPCR_SPE_BIT);
+	} else {
+		IOH_DEBUG("ioh_spi_set_enable enable==false\n");
+		IOH_CLR_BITMSK(reg_spcr_val, SPCR_SPE_BIT);
+	}
+
+	ioh_spi_writereg(spi->master, IOH_SPI_SPCR, reg_spcr_val);
+
+	IOH_DEBUG("ioh_spi_set_enable SPCR content after modifying SPE=%x\n",
+		  reg_spcr_val);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn				ioh_spi_handler(int irq, void* dev_id)
+
+@remarks		Interrupt handler
+
+The main tasks performed by this method are:
+- Check if Corresponding interrupt bits are set in SPSR register.
+- If no, return IRQ_NONE.
+- If yes, read the number of bytes received and write required number of bytes
+according to space available.
+- Update all bookkeeping variables.
+- If bytes/words to be received is less than 16bytes/words,then disable RFI
+and set Rx threshold to 16 bytes/words.
+- If SPI data transfer is completed, invoke the callback function
+@ref ioh_spi_callback to inform the status to @ref ioh_spi_process_messages.
+- Repeat for all SPI channels.
+
+@note
+This is the interrupt handler for IOH SPI controller driver.This function is
+invoked by the kernel when any interrupt occurs on the interrupt line shared by
+IOH SPI device.	The SPI data transfer is initiated by @ref ioh_spi_process_
+messages,but is carried on by this function.For optimised operation,the HAL
+functions to read and write registers are not used in this function.
+Also register
+address calculation is done once at the beginning to avoid the calculation each
+time while accessing registers.
+
+@param			irq		[@ref IN]	The interrupt number
+
+@param	dev_id	[@ref IN]	Contains reference to struct ioh_spi_board_data
+
+@retval			irqreturn_t
+			- IRQ_NONE		The interrupt is not ours
+			- IRQ_HANDLED	The interrupt has been serviced
+
+@see
+				- ioh_spi_get_resources
+				- ioh_spi_free_resources
+				- ioh_spi_suspend
+				- ioh_spi_resume
+
+<hr>
+
+*/
+irqreturn_t ioh_spi_handler(int irq, void *dev_id)
+{
+	/*channel & read/write indices */
+	int dev, readcnt;
+
+	/*SPSR content */
+	u32 reg_spsr_val, reg_spcr_val;
+
+	/*book keeping variables */
+	u32 nReadable, TxIndex, RxIndex, lengthInBpw;
+
+	/*to hold channel data */
+
+	struct ioh_spi_data *pCtrlData;
+
+	/*buffer to store rx/tx data */
+	u16 *pU16RxBuffer, *pU16TxBuffer;
+
+	/*register addresses */
+	u32 SPSR, SPDRR, SPDWR;
+
+	/*remapped pci base address */
+	u32 IORemapAddress;
+
+	irqreturn_t tRetVal = IRQ_NONE;
+
+	struct ioh_spi_board_data *pBoardData =
+	    (struct ioh_spi_board_data *)dev_id;
+
+	if (pBoardData->bSuspended == true) {
+		IOH_DEBUG("ioh_spi_handler returning due to suspend\n");
+	} else {
+		for (dev = 0; dev < IOH_SPI_MAX_DEV; dev++) {
+			pCtrlData = pBoardData->pCtrlData[dev];
+			IORemapAddress = pCtrlData->IORemapAddress;
+			SPSR = IORemapAddress + IOH_SPI_SPSR;
+
+			reg_spsr_val = IOH_READ_LONG(SPSR);
+
+			/*Check if the interrupt is for SPI device */
+
+			if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
+				IOH_DEBUG("SPSR in ioh_spi_handler=%x\n",
+					  reg_spsr_val);
+				/*clear interrupt */
+				IOH_WRITE_LONG(reg_spsr_val, SPSR);
+
+				if (pCtrlData->bTransferActive == true) {
+					RxIndex = pCtrlData->RxIndex;
+					TxIndex = pCtrlData->TxIndex;
+					lengthInBpw = pCtrlData->lengthInBpw;
+					pU16RxBuffer = pCtrlData->pU16RxBuffer;
+					pU16TxBuffer = pCtrlData->pU16TxBuffer;
+
+					SPDRR = IORemapAddress + IOH_SPI_SPDRR;
+					SPDWR = IORemapAddress + IOH_SPI_SPDWR;
+
+					nReadable =
+					    IOH_SPI_READABLE(reg_spsr_val);
+
+					for (readcnt = 0; (readcnt < nReadable);
+					     readcnt++) {
+						/*read data */
+						pU16RxBuffer[RxIndex++] =
+						    IOH_READ_LONG(SPDRR);
+						/*write data */
+
+						if (TxIndex < lengthInBpw) {
+							IOH_WRITE_LONG
+							    (pU16TxBuffer
+							     [TxIndex++],
+							     SPDWR);
+						}
+					}
+
+					/*disable RFI if not needed */
+					if ((lengthInBpw - RxIndex) <=
+					    IOH_SPI_MAX_FIFO_DEPTH) {
+						IOH_DEBUG
+						    ("ioh_spi_handler disabling\
+						 RFI as data remaining=%d\n",
+						     (lengthInBpw - RxIndex));
+
+						reg_spcr_val =
+						    IOH_READ_LONG(IORemapAddress
+								  +
+								  IOH_SPI_SPCR);
+
+						/*disable RFI */
+						IOH_CLR_BITMSK(reg_spcr_val,
+							       SPCR_RFIE_BIT);
+
+						/*reset rx threshold */
+						reg_spcr_val &=
+						    MASK_RFIC_SPCR_BITS;
+						reg_spcr_val |=
+						    (IOH_SPI_RX_THOLD_MAX <<
+						     SPCR_RFIC_FIELD);
+
+						IOH_WRITE_LONG(IOH_CLR_BITMSK
+							       (reg_spcr_val,
+								SPCR_RFIE_BIT),
+							       (IORemapAddress +
+								IOH_SPI_SPCR));
+					}
+
+					/*update counts */
+					pCtrlData->TxIndex = TxIndex;
+
+					pCtrlData->RxIndex = RxIndex;
+
+					IOH_DEBUG
+					    ("ioh_spi_handler RxIndex=%d\n",
+					     RxIndex);
+
+					IOH_DEBUG
+					    ("ioh_spi_handler TxIndex=%d\n",
+					     TxIndex);
+
+					IOH_DEBUG
+					    ("ioh_spi_handler nWritable=%d\n",
+					     (16 -
+					      (IOH_SPI_WRITABLE
+					       (reg_spsr_val))));
+
+					IOH_DEBUG
+					    ("ioh_spi_handler nReadable=%d\n",
+					     nReadable);
+				}
+
+				/*if transfer complete interrupt */
+				if (reg_spsr_val & SPSR_FI_BIT) {
+					IOH_DEBUG
+					    ("ioh_spi_handler FI bit in SPSR\
+								 set\n");
+
+					/*disable FI & RFI interrupts */
+					ioh_spi_disable_interrupts(pCtrlData->
+								   pMaster,
+								   IOH_SPI_FI |
+								   IOH_SPI_RFI);
+
+					/*transfer is completed;inform
+						 ioh_spi_process_messages */
+
+					if (ioh_spi_gcbptr != NULL) {
+						IOH_DEBUG
+						    ("ioh_spi_handler invoking\
+								 callback\n");
+						(*ioh_spi_gcbptr) (pCtrlData);
+					}
+				}
+
+				tRetVal = IRQ_HANDLED;
+			}
+		}
+	}
+
+	IOH_DEBUG("ioh_spi_handler EXIT return value=%d\n", tRetVal);
+
+	return tRetVal;
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn		ioh_spi_entcb (void (*ioh_spi_cb)( struct ioh_spi_data* ))
+
+@remarks		Registers the callback function
+
+			The major tasks performed by this method are:
+			- Validate ioh_spi_cb
+			- Assign it to global pointer @ref ioh_spi_gcbptr
+
+@note		This function is invoked from @ref ioh_spi_probe function
+		This function should always be invoked before the interrupt
+		handler is registered.
+
+@param		ioh_spi_cb	[@ref IN]
+				Contains reference to callback function pointer
+
+@retval			None
+
+@see
+				- ioh_spi_probe
+
+<hr>
+
+*/
+void ioh_spi_entcb(void (*ioh_spi_cb) (struct ioh_spi_data *))
+{
+	if (ioh_spi_cb != NULL) {
+		/*Assign the above value to a global pointer */
+		ioh_spi_gcbptr = ioh_spi_cb;
+		IOH_DEBUG("ioh_spi_entcb ioh_spi_cb ptr not NULL\n");
+		IOH_DEBUG
+		    ("ioh_spi_entcb ioh_spi_cb ptr saved in ioh_spi_gcbptr\n");
+	} else {
+		IOH_LOG(KERN_ERR, "ioh_spi_entcb ioh_spi_cb ptr NULL\n");
+	}
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn				ioh_spi_setup_transfer(struct spi_device *spi)
+
+@remarks		Configures the IOH SPI hardware for transfer
+
+	The major tasks performed by this method are:
+	- Invoke @ref ioh_spi_set_baud_rate to set the baud rate.
+	- Invoke @ref ioh_spi_set_bits_per_word to set the bits per word.
+	- Set the bit justfication in SPCR.
+	- Set the Clock Polarity and Clock Phase in SPCR.
+	- Clear the Rx and Tx FIFO by toggling FICLR bit in SPCR.
+
+@note		This function configures the IOH SPI hardware according to the
+			configurations specified by the user.
+
+@param	spi	[@ref IN]	Contains reference to struct spi_device
+
+@retval			int
+	@ref IOH_SPI_SUCCESS	All hardware configurations have been done
+
+@see
+			- ioh_spi_select_chip
+
+<hr>
+
+*/
+s8 ioh_spi_setup_transfer(struct spi_device *spi)
+{
+	u32 reg_spcr_val;
+
+	IOH_DEBUG("ioh_spi_setup_transfer SPBRR content =%x\n",
+		  ioh_spi_readreg(spi->master, IOH_SPI_SPBRR));
+
+	/*set baud rate */
+	IOH_DEBUG("ioh_spi_setup_transfer :setting baud rate=%d\n",
+		  spi->max_speed_hz);
+	ioh_spi_set_baud_rate(spi->master, spi->max_speed_hz);
+
+	/*set bits per word */
+	IOH_DEBUG("ioh_spi_setup_transfer :setting bits_per_word=%d\n",
+		  spi->bits_per_word);
+	ioh_spi_set_bits_per_word(spi->master, spi->bits_per_word);
+
+	IOH_DEBUG
+	    ("ioh_spi_setup_transfer SPBRR content after setting baud\
+						 rate & bits per word=%x\n",
+	     ioh_spi_readreg(spi->master, IOH_SPI_SPBRR));
+
+	reg_spcr_val = ioh_spi_readreg(spi->master, IOH_SPI_SPCR);
+	IOH_DEBUG("ioh_spi_setup_transfer SPCR content = %x\n", reg_spcr_val);
+
+	/*set bit justification */
+
+	if ((spi->mode & SPI_LSB_FIRST) != 0) {
+		/*LSB first */
+		IOH_CLR_BITMSK(reg_spcr_val, SPCR_LSBF_BIT);
+		IOH_DEBUG("ioh_spi_setup_transfer :setting LSBF bit to 0\n");
+	} else {
+		/*MSB first */
+		IOH_SET_BITMSK(reg_spcr_val, SPCR_LSBF_BIT);
+		IOH_DEBUG("ioh_spi_setup_transfer :setting LSBF bit to 1\n");
+	}
+
+	/*set clock polarity */
+	if ((spi->mode & SPI_CPOL) != 0) {
+		IOH_SET_BITMSK(reg_spcr_val, SPCR_CPOL_BIT);
+		IOH_DEBUG("ioh_spi_setup_transfer clock polarity = 1\n");
+	} else {
+		IOH_CLR_BITMSK(reg_spcr_val, SPCR_CPOL_BIT);
+		IOH_DEBUG("ioh_spi_setup_transfer clock polarity = 0\n");
+	}
+
+	/*set the clock phase */
+	if ((spi->mode & SPI_CPHA) != 0) {
+		IOH_SET_BITMSK(reg_spcr_val, SPCR_CPHA_BIT);
+		IOH_DEBUG("ioh_spi_setup_transfer clock phase = 1\n");
+	} else {
+		IOH_CLR_BITMSK(reg_spcr_val, SPCR_CPHA_BIT);
+		IOH_DEBUG("ioh_spi_setup_transfer clock phase = 0\n");
+	}
+
+	/*write SPCR SPCR register */
+	ioh_spi_writereg(spi->master, IOH_SPI_SPCR, reg_spcr_val);
+
+	IOH_DEBUG
+	    ("ioh_spi_setup_transfer SPCR content after setting LSB/MSB\
+							 and MODE= %x\n",
+							     reg_spcr_val);
+
+	/*Clear the FIFO by toggling  FICLR to 1 and back to 0 */
+	ioh_spi_clear_fifo(spi->master);
+
+	IOH_DEBUG("ioh_spi_setup_transfer Return=%d\n", IOH_SPI_SUCCESS);
+
+	return IOH_SPI_SUCCESS;
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn		ioh_spi_writereg(struct spi_master *master,int idx, u32 val)
+
+@remarks		Performs  register writes
+
+	The major tasks performed by this method are:
+	- Obtain the SPI channel data structure from master.
+	- Calculate the register address as offset + base address
+	  from SPI channel data structure.
+	- Write the value specified by val to register the address calculated.
+
+@note			This function is inline.
+
+@param		master	[@ref IN]	Contains reference to struct spi_master
+
+@param		idx	[@ref IN] Contains register offset
+
+@param		val	[@ref IN] Contains value to be written to register
+
+@retval			None
+
+@see
+				- ioh_spi_setup_transfer
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+				- ioh_spi_set_enable
+				- ioh_spi_set_master_mode
+				- ioh_spi_set_baud_rate
+				- ioh_spi_set_bits_per_word
+				- ioh_spi_reset
+				- ioh_spi_set_threshold
+				- ioh_spi_clear_fifo
+				- ioh_spi_process_messages
+
+<hr>
+
+*/
+inline void ioh_spi_writereg(struct spi_master *master, int idx, u32 val)
+{
+
+	struct ioh_spi_data *pCtrlData = spi_master_get_devdata(master);
+
+	IOH_WRITE_LONG(val, (pCtrlData->IORemapAddress + idx));
+
+	IOH_DEBUG("ioh_spi_writereg Offset=%x\n", idx);
+	IOH_DEBUG("ioh_spi_writereg Value=%x\n", val);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn			ioh_spi_readreg(struct spi_master *master,int idx)
+
+@remarks		Performs  register reads
+
+		The major tasks performed by this method are:
+		- Obtain the SPI channel data structure from master.
+		- Calculate the register address as offset + base address
+		  from SPI channel data structure.
+		- Read the content of the register at the address calculated.
+
+@note			This function is inline
+
+@param		master	[@ref IN]	Contains reference to struct spi_master
+
+@param			idx		[@ref IN]	Contains register offset
+
+@retval			u32
+				The content of the register at offset idx
+
+@see
+				- ioh_spi_setup_transfer
+				- ioh_spi_enable_interrupts
+				- ioh_spi_disable_interrupts
+				- ioh_spi_set_enable
+				- ioh_spi_set_master_mode
+				- ioh_spi_set_baud_rate
+				- ioh_spi_set_bits_per_word
+				- ioh_spi_set_threshold
+				- ioh_spi_clear_fifo
+
+<hr>
+*/
+inline u32 ioh_spi_readreg(struct spi_master *master, int idx)
+{
+	u32 reg_data;
+
+	struct ioh_spi_data *pCtrlData = spi_master_get_devdata(master);
+
+	IOH_DEBUG("ioh_spi_readreg Offset=%x\n", idx);
+	reg_data = IOH_READ_LONG((pCtrlData->IORemapAddress + idx));
+
+	IOH_DEBUG("ioh_spi_readreg Content=%x\n", reg_data);
+	return reg_data;
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn	ioh_spi_enable_interrupts (struct spi_master *master, u8 interrupt)
+
+@remarks		Enables specified interrupts
+
+		The major tasks performed by this method are:
+		- Read the content of SPCR.
+		- Based on interrupt ,set corresponding bits in SPCR content.
+		- Write the value back to SPCR.
+
+@note	This function is invoked from @ref ioh_spi_process_messages before
+	starting SPI data transfer.As of now only FI and RFI interrupts are
+			used.
+
+@param	master		[@ref IN]	Contains reference to struct spi_master
+
+@param	interrupt	[@ref IN]	Interrups to be enabled.This parameter
+		is a u8 value with five least significant bits representing
+		each of the interrupts FI,RFI,TFI,ORI and MDFI.
+
+@retval			None
+
+@see
+				- ioh_spi_process_messages
+
+<hr>
+
+*/
+void ioh_spi_enable_interrupts(struct spi_master *master, u8 interrupt)
+{
+	u32 reg_val_spcr;
+
+	reg_val_spcr = ioh_spi_readreg(master, IOH_SPI_SPCR);
+
+	IOH_DEBUG("ioh_spi_enable_interrupts SPCR content=%x\n", reg_val_spcr);
+
+	if ((interrupt & IOH_SPI_RFI) != 0) {
+		/*set RFIE bit in SPCR */
+		IOH_DEBUG("setting RFI in ioh_spi_enable_interrupts\n");
+		IOH_SET_BITMSK(reg_val_spcr, SPCR_RFIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_TFI) != 0) {
+		/*set TFIE bit in SPCR */
+		IOH_DEBUG("setting TFI in ioh_spi_enable_interrupts\n");
+		IOH_SET_BITMSK(reg_val_spcr, SPCR_TFIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_FI) != 0) {
+		/*set FIE bit in SPCR */
+		IOH_DEBUG("setting FI in ioh_spi_enable_interrupts\n");
+		IOH_SET_BITMSK(reg_val_spcr, SPCR_FIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_ORI) != 0) {
+		/*set ORIE bit in SPCR */
+		IOH_DEBUG("setting ORI in ioh_spi_enable_interrupts\n");
+		IOH_SET_BITMSK(reg_val_spcr, SPCR_ORIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_MDFI) != 0) {
+		/*set MODFIE bit in SPCR */
+		IOH_DEBUG("setting MDFI in ioh_spi_enable_interrupts\n");
+		IOH_SET_BITMSK(reg_val_spcr, SPCR_MDFIE_BIT);
+	}
+
+	ioh_spi_writereg(master, IOH_SPI_SPCR, reg_val_spcr);
+
+	IOH_DEBUG
+	    ("ioh_spi_enable_interrupts SPCR content after enabling interrupt\
+								 =%x\n",
+							     reg_val_spcr);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn	ioh_spi_disable_interrupts (struct spi_master *master, u8 interrupt)
+
+@remarks		Disables specified interrupts
+
+		The major tasks performed by this method are:
+		- Read the content of SPCR.
+		- Based on interrupt ,clear corresponding bits in SPCR content.
+		- Write the value back to SPCR.
+
+@param	master		[@ref IN]	Contains reference to struct spi_master
+
+@param	interrupt	[@ref IN]	Interrups to be disabled.This parameter
+		is a u8 value with five least significant bits representing
+				each of the interrupts FI,RFI,TFI,ORI and MDFI.
+
+@retval			None
+
+@see
+				- ioh_spi_process_messages
+				- ioh_spi_handler
+				- ioh_spi_suspend
+				- ioh_spi_free_resources
+
+<hr>
+
+*/
+void ioh_spi_disable_interrupts(struct spi_master *master, u8 interrupt)
+{
+	u32 reg_val_spcr;
+
+	reg_val_spcr = ioh_spi_readreg(master, IOH_SPI_SPCR);
+
+	IOH_DEBUG("ioh_spi_disable_interrupts SPCR content =%x\n",
+		  reg_val_spcr);
+
+	if ((interrupt & IOH_SPI_RFI) != 0) {
+		/*clear RFIE bit in SPCR */
+		IOH_DEBUG("clearing RFI in ioh_spi_disable_interrupts\n");
+		IOH_CLR_BITMSK(reg_val_spcr, SPCR_RFIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_TFI) != 0) {
+		/*clear TFIE bit in SPCR */
+		IOH_DEBUG("clearing TFI in ioh_spi_disable_interrupts\n");
+		IOH_CLR_BITMSK(reg_val_spcr, SPCR_TFIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_FI) != 0) {
+		/*clear FIE bit in SPCR */
+		IOH_DEBUG("clearing FI in ioh_spi_disable_interrupts\n");
+		IOH_CLR_BITMSK(reg_val_spcr, SPCR_FIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_ORI) != 0) {
+		/*clear ORIE bit in SPCR */
+		IOH_DEBUG("clearing ORI in ioh_spi_disable_interrupts\n");
+		IOH_CLR_BITMSK(reg_val_spcr, SPCR_ORIE_BIT);
+	}
+
+	if ((interrupt & IOH_SPI_MDFI) != 0) {
+		/*clear MODFIE bit in SPCR */
+		IOH_DEBUG("clearing MDFI in ioh_spi_disable_interrupts\n");
+		IOH_CLR_BITMSK(reg_val_spcr, SPCR_MDFIE_BIT);
+	}
+
+	ioh_spi_writereg(master, IOH_SPI_SPCR, reg_val_spcr);
+
+	IOH_DEBUG
+	    ("ioh_spi_disable_interrupts SPCR after disabling interrupts =%x\n",
+	     reg_val_spcr);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn	ioh_spi_set_threshold(struct spi_device *spi, u32 threshold, u8 dir)
+
+@remarks		Sets Tx/Rx FIFO thresholds
+
+The major tasks performed by this function are:
+- Read the content of SPCR.
+- If the dir is @ref IOH_SPI_RX ,set the Rx threshold bits in SPCR content.
+- If the dir is @ref IOH_SPI_TX ,set the Tx threshold bits in SPCR content.
+- Write back the value to SPCR.
+
+@note This function is invoked from ioh_spi_process_messages to set the Receive
+threshold level.As of now, when the length of data to be transferred is greater
+than FIFO depth of 16 bytes/words ,the Receive FIFO threshold is set at
+								 8 bytes/words.
+If the length of data to be transferred is less than FIFO depth,the Receive FIFO
+threshold is set at 16 bytes/words.
+
+@param	spi		[@ref IN]	Contains reference to struct spi_device
+
+@param		threshold	[@ref IN]	Threshold value to be set
+
+@param	dir			[@ref IN]	Rx or Tx threshold to be set
+	- dir = @ref IOH_SPI_RX implies Receive FIFO threshold needs to be set.
+	- dir = @ref IOH_SPI_TX implies Transmit FIFO threshold needs to be set.
+
+@retval			None
+
+@see
+				- ioh_spi_process_messages
+
+<hr>
+*/
+void ioh_spi_set_threshold(struct spi_device *spi, u32 threshold, u8 dir)
+{
+	u32 reg_val_spcr;
+
+	reg_val_spcr = ioh_spi_readreg(spi->master, IOH_SPI_SPCR);
+	IOH_DEBUG("ioh_spi_set_threshold SPCR before modifying =%x\n",
+		  reg_val_spcr);
+	IOH_DEBUG("ioh_spi_set_threshold threshold=%d\n", (threshold + 1));
+
+	if (dir == IOH_SPI_RX) {
+		IOH_DEBUG("ioh_spi_set_threshold setting Rx threshold\n");
+		reg_val_spcr &= MASK_RFIC_SPCR_BITS;
+		reg_val_spcr |= (threshold << SPCR_RFIC_FIELD);
+	} else if (dir == IOH_SPI_TX) {
+		IOH_DEBUG("ioh_spi_set_threshold setting Tx threshold\n");
+		reg_val_spcr &= MASK_TFIC_SPCR_BITS;
+		reg_val_spcr |= (threshold << SPCR_TFIC_FIELD);
+	}
+
+	ioh_spi_writereg(spi->master, IOH_SPI_SPCR, reg_val_spcr);
+
+	IOH_DEBUG("ioh_spi_set_threshold SPCR after modifying =%x\n",
+		  reg_val_spcr);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn				ioh_spi_reset(struct spi_master* master)
+
+@remarks		Clears SPI registers
+
+	The major tasks performed by this method are:
+	- Clear all R/W bits of SPCR.
+	- Clear Receive and Transmit FIFOs by invoking @ref ioh_spi_clear_fifo
+	- Clear all R/W bits of SPBRR.
+	- Clear all interrupts in SPSR.
+	- If the device has SRST [reset register],then instead of the
+	  above steps,first 1 is written to SRST to reset SPI and then
+	  0 is written to SRST to clear reset.
+
+@note		This function is invoked to bring the IOH SPI device to an
+		initialized state.After this function is invoked all the SPI
+		registers need to be configured again.
+
+@param	master	[@ref IN]	Contains reference to struct spi_master
+
+@retval			None
+
+@see
+				- ioh_spi_get_resources
+				- ioh_spi_suspend
+				- ioh_spi_resume
+
+<hr>
+
+*/
+void ioh_spi_reset(struct spi_master *master)
+{
+#ifndef FPGA
+	 /*LSI*/
+	    /*write 1 to reset SPI */
+	    ioh_spi_writereg(master, IOH_SPI_SRST, 0x1);
+	/*clear reset */
+	ioh_spi_writereg(master, IOH_SPI_SRST, 0x0);
+#else
+	 /*FPGA*/
+	    /*write 0 to SPCR */
+	    ioh_spi_writereg(master, IOH_SPI_SPCR, 0x0);
+	IOH_DEBUG("ioh_spi_reset SPCR content after reset=%x\n",
+		  ioh_spi_readreg(master, IOH_SPI_SPCR));
+	/*Clear the FIFO */
+	ioh_spi_clear_fifo(master);
+
+	/*write 0 to SPBRR */
+	ioh_spi_writereg(master, IOH_SPI_SPBRR, 0x0);
+	IOH_DEBUG("ioh_spi_reset SPBRR content after reset=%x\n",
+		  ioh_spi_readreg(master, IOH_SPI_SPBRR));
+
+	/*clear interrupts in SPSR */
+	ioh_spi_writereg(master, IOH_SPI_SPSR, SPSR_INT_BITS);
+	IOH_DEBUG("ioh_spi_reset SPSR content after reset=%x\n",
+		  ioh_spi_readreg(master, IOH_SPI_SPSR));
+#endif
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn		ioh_spi_set_baud_rate(struct spi_master* master,u32 speed_hz)
+
+@remarks		Sets SPBR field in SPBRR
+
+		The major tasks performed by this method are:
+		- Read the content of SPBRR register.
+		- Calculate the value for SPBR field according to the baud rate.
+		- Set the SPBR field using the calculated value.
+		- Write the conetnt back to SPBRR.
+
+@note	The SPBR value is calculated from the baud rate using the formula
+				SPBR = clock frequency / baud rate.
+
+@param	master		[@ref IN]	Contains reference to struct spi_master
+
+@param			speed_hz	[@ref IN]	Baud rate to be set
+
+@retval			None
+
+@see
+				- ioh_spi_setup_transfer
+				- ioh_spi_process_messages
+
+<hr>
+
+*/
+void ioh_spi_set_baud_rate(struct spi_master *master, u32 speed_hz)
+{
+	u32 nSpbr, reg_spbrr_val;
+
+	nSpbr = IOH_CLOCK_HZ / (speed_hz * 2);
+
+	/*if baud rate is less than we can support
+	   limit it */
+
+	if (nSpbr > IOH_SPI_MAX_SPBR)
+		nSpbr = IOH_SPI_MAX_SPBR;
+
+
+	reg_spbrr_val = ioh_spi_readreg(master, IOH_SPI_SPBRR);
+
+	IOH_DEBUG("ioh_spi_set_baud_rate SPBRR content=%x\n", reg_spbrr_val);
+
+	IOH_DEBUG("ioh_spi_set_baud_rate SPBR in SPBRR=%d\n", nSpbr);
+
+	/*clear SPBRR */
+	reg_spbrr_val &= MASK_SPBRR_SPBR_BITS;
+
+	/*set the new value */
+	reg_spbrr_val |= nSpbr;
+
+	/*write the new value */
+	ioh_spi_writereg(master, IOH_SPI_SPBRR, reg_spbrr_val);
+	IOH_DEBUG("ioh_spi_set_baud_rate SPBRR content after setting SPBR=%x\n",
+		  reg_spbrr_val);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn	ioh_spi_set_bits_per_word(struct spi_master* master,u8 bits_per_word)
+
+@remarks		Sets SIZE field in SPBRR
+
+		The major tasks performed by this method are:
+		- Read the content of SPBRR register.
+		- Set the SIZE field in SPBRR according to bits per word.
+		- Write back the value to SPBRR.
+
+@note	The allowed bits per word settings are 8 and 16.The SIZE bit in SPBRR is
+	0 denotes bits per word of 8 and SIZE bit 1 denotes bits per word of 16.
+
+@param	master		[@ref IN]	Contains reference to struct spi_master
+
+@param		bits_per_word	[@ref IN]	Bits per word for SPI transfer
+
+@retval			None
+
+@see
+				- ioh_spi_setup_transfer
+				- ioh_spi_process_messages
+
+<hr>
+
+*/
+void ioh_spi_set_bits_per_word(struct spi_master *master, u8 bits_per_word)
+{
+	u32 reg_spbrr_val = ioh_spi_readreg(master, IOH_SPI_SPBRR);
+	IOH_DEBUG("ioh_spi_set_bits_per_word SPBRR content=%x\n",
+		  reg_spbrr_val);
+
+	if (bits_per_word == IOH_SPI_8_BPW) {
+		IOH_CLR_BITMSK(reg_spbrr_val, SPBRR_SIZE_BIT);
+		IOH_DEBUG("ioh_spi_set_bits_per_word 8\n");
+	} else {
+		IOH_SET_BITMSK(reg_spbrr_val, SPBRR_SIZE_BIT);
+		IOH_DEBUG("ioh_spi_set_bits_per_word 16\n");
+	}
+
+	ioh_spi_writereg(master, IOH_SPI_SPBRR, reg_spbrr_val);
+
+	IOH_DEBUG
+	    ("ioh_spi_set_bits_per_word SPBRR after setting bits per word=%x\n",
+	     reg_spbrr_val);
+}
+
+/*! @ingroup	SPI_HALLayerAPI
+
+@fn				ioh_spi_clear_fifo(struct spi_master *master)
+
+@remarks		Clears the Transmit and Receive FIFOs
+
+				The major tasks performed by this method are:
+				- Read the content of SPCR.
+				- Set FICLR bit to 1.
+				- Write back the content to SPCR.
+				- Set the FICLR bit to 0.
+				- Write back the content to SPCR.
+
+@param	master		[@ref IN]	Contains reference to struct spi_master
+
+@retval			None
+
+@see
+				- ioh_spi_setup_transfer
+				- ioh_spi_process_messages
+
+<hr>
+
+*/
+void ioh_spi_clear_fifo(struct spi_master *master)
+{
+	u32 reg_spcr_val = ioh_spi_readreg(master, IOH_SPI_SPCR);
+
+	IOH_SET_BITMSK(reg_spcr_val, SPCR_FICLR_BIT);
+	ioh_spi_writereg(master, IOH_SPI_SPCR, reg_spcr_val);
+	IOH_DEBUG("ioh_spi_clear_fifo SPCR content after setting FICLR  = %x\n",
+		  reg_spcr_val);
+
+	IOH_CLR_BITMSK(reg_spcr_val, SPCR_FICLR_BIT);
+	ioh_spi_writereg(master, IOH_SPI_SPCR, reg_spcr_val);
+
+	IOH_DEBUG
+	    ("ioh_spi_clear_fifo SPCR content after resetting FICLR  = %x\n",
+	     reg_spcr_val);
+}
diff -urN linux-2.6.33-rc3/drivers/spi/pch_spi_hal.h topcliff-2.6.33-rc3/drivers/spi/pch_spi_hal.h
--- linux-2.6.33-rc3/drivers/spi/pch_spi_hal.h	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_spi_hal.h	2010-03-06 09:02:20.000000000 +0900
@@ -0,0 +1,298 @@
+/**
+ * @file	ioh_spi_hal.h
+ *
+ * @brief This header file contains macro definitions and function declarations
+ * 			for HAL layer APIs.
+ * @version	0.94
+ *
+ * @par
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * @par
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+#ifndef __IOH_SPI_HAL__
+#define __IOH_SPI_HAL__
+
+/*Register offsets*/
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPCR
+@brief			SPCR register offset
+*/
+#define IOH_SPI_SPCR                   	(0x00)	/*SPI control register */
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPBRR
+@brief			SPBRR register offset
+*/
+#define IOH_SPI_SPBRR                  	(0x04)	/*SPI baud rate register */
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPSR
+@brief			SPSR register offset
+*/
+#define IOH_SPI_SPSR                   	(0x08)	/*SPI status register */
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPDWR
+@brief			SPDWR register offset
+*/
+#define IOH_SPI_SPDWR                  	(0x0C)	/*SPI write data register */
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPDRR
+@brief			SPDRR register offset
+*/
+#define IOH_SPI_SPDRR                  	(0x10)	/*SPI read data register */
+
+/*! @ingroup    SPI_HALLayer
+@def            IOH_SPI_SSNXCR
+@brief          SSNXCR register offset
+*/
+#define IOH_SPI_SSNXCR                  (0x18)/* SSN Expand Control Register */
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SRST
+@brief			SRST register offset
+*/
+#define IOH_SPI_SRST                  	(0x1C)	/*SPI reset register */
+
+/* valid bits per word settings*/
+
+/*! @ingroup	SPI_HALLayer
+@def    	IOH_SPI_8_BPW
+@brief		Macro to denote 8 Bits per word transfer
+*/
+#define IOH_SPI_8_BPW                 	(8)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_16_BPW
+@brief			Macro to denote 16 Bits per word transfer
+*/
+#define IOH_SPI_16_BPW                 	(16)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPSR_TFD
+@brief			Mask to obtaining TFD bits from SPSR
+*/
+#define IOH_SPI_SPSR_TFD                (0x000007C0)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_SPSR_RFD
+@brief			Mask to obtaining RFD bits from SPSR
+*/
+#define IOH_SPI_SPSR_RFD              	(0x0000F800)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_READABLE(x)
+@brief			Macro to obtain number of bytes received in Rx FIFO
+@note 			x is the content of SPSR register
+*/
+#define IOH_SPI_READABLE(x)           	(((x) & IOH_SPI_SPSR_RFD)>>11)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_WRITABLE(x)
+@brief		Macro to obtain number of bytes te be transmitted in Tx FIFO
+@note 		x is the content of SPSR register
+*/
+#define IOH_SPI_WRITABLE(x)           	(((x) & IOH_SPI_SPSR_TFD)>>6)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_RX_THOLD
+@brief			Macro to denote Rx interrupt threshold
+@note 			Currently set to interrupt when 8 bytes are received
+*/
+/*set to interrupt when 8 bytes have been received */
+#define IOH_SPI_RX_THOLD	(7)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_RX_THOLD_MAX
+@brief		Macro to denote Rx interrupt threshold when Rx FIFO is full
+*/
+/*set to interrupt when 16 bytes have been received */
+#define IOH_SPI_RX_THOLD_MAX            (15)
+
+/*direction for interrupts*/
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_RX
+@brief			Macro to indicate Receive
+*/
+#define IOH_SPI_RX                   	(1)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_TX
+@brief			Macro to indicate Transmit
+*/
+#define IOH_SPI_TX                   	(2)
+
+/*various interrupts*/
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_TFI
+@brief			Transmit interrupt
+*/
+#define IOH_SPI_TFI                  	(0x1)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_RFI
+@brief			Receive interrupt
+*/
+#define IOH_SPI_RFI                  	(0x2)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_FI
+@brief			Transfer complete interrupt
+*/
+#define IOH_SPI_FI                   	(0x4)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_ORI
+@brief			Overflow interrupt
+*/
+#define IOH_SPI_ORI                  	(0x8)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_MDFI
+@brief			Modefault interrupt
+*/
+#define IOH_SPI_MDFI                 	(0x10)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_ALL
+@brief			Macro to denote all interrupts
+*/
+#define IOH_SPI_ALL \
+		(IOH_SPI_TFI|IOH_SPI_RFI|IOH_SPI_FI|IOH_SPI_ORI|IOH_SPI_MDFI)
+
+/*! @ingroup	SPI_HALLayer
+@def    	IOH_SPI_MAX_BAUDRATE
+@brief		Macro to denote maximum possible baud rate in bits per second
+*/
+#define IOH_SPI_MAX_BAUDRATE   			(5000000)
+
+/*! @ingroup	SPI_HALLayer
+@def    		IOH_SPI_MAX_FIFO_DEPTH
+@brief			Macro to denote maximum FIFO depth(16)
+*/
+#define IOH_SPI_MAX_FIFO_DEPTH      	(16)
+
+/*status codes*/
+
+/*! @ingroup	SPI_Global
+@def			IOH_SPI_SUCCESS
+@brief			Success status code
+*/
+#define IOH_SPI_SUCCESS                	(0)
+
+/*! @ingroup	SPI_Global
+@def			IOH_SPI_FAIL
+@brief			Failure status code
+*/
+#define IOH_SPI_FAIL                   	(-1)
+
+/* hal function prototypes */
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn				ioh_spi_setup_transfer(struct spi_device *spi)
+@brief			Configures the IOH SPI hardware for SPI transfer
+*/
+s8 ioh_spi_setup_transfer(struct spi_device *spi);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn		ioh_spi_set_enable(const struct spi_device *spi, u8 enable)
+@brief		Sets/Resets SPE bit in SPCR based on enable parameter
+*/
+void ioh_spi_set_enable(const struct spi_device *spi, u8 enable);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn		ioh_spi_set_master_mode( struct spi_master *master)
+@brief		Sets MSTR bit in SPCR
+*/
+void ioh_spi_set_master_mode(struct spi_master *master);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn		ioh_spi_writereg(struct spi_master *master,int idx, u32 val)
+@brief		Performs register writes
+*/
+inline void ioh_spi_writereg(struct spi_master *master, int idx, u32 val);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn		ioh_spi_readreg(struct spi_master *master,int idx)
+@brief		Performs register reads
+*/
+inline u32 ioh_spi_readreg(struct spi_master *master, int idx);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn				ioh_spi_handler  (int irq, void* dev_id)
+@brief			The interrupt handler
+*/
+irqreturn_t ioh_spi_handler(int irq, void *dev_id);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn		ioh_spi_entcb (void (*ioh_spi_cb)( struct ioh_spi_data* ))
+@brief		Registers the Callback function
+*/
+void ioh_spi_entcb(void (*ioh_spi_cb) (struct ioh_spi_data *));
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn	ioh_spi_enable_interrupts (struct spi_master *master ,u8 interrupt)
+@brief		Enables specified interrupts in SPCR
+*/
+void ioh_spi_enable_interrupts(struct spi_master *master, u8 interrupt);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn	ioh_spi_disable_interrupts (struct spi_master *master ,u8 interrupt)
+@brief			Disables specified interrupts in SPCR
+*/
+void ioh_spi_disable_interrupts(struct spi_master *master, u8 interrupt);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn	ioh_spi_set_threshold(struct spi_device *spi,u32 threshold, u8 dir)
+@brief			Sets RFIC/TFIC fields in SPCR based on threshold and dir
+*/
+void ioh_spi_set_threshold(struct spi_device *spi, u32 threshold, u8 dir);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn				ioh_spi_reset(struct spi_master *master)
+@brief			Resets IOH SPI register settings
+*/
+void ioh_spi_reset(struct spi_master *master);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn		ioh_spi_set_baud_rate(struct spi_master *master,u32 speed_hz)
+@brief			Sets SPBR field in SPBRR
+*/
+void ioh_spi_set_baud_rate(struct spi_master *master, u32 speed_hz);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn	ioh_spi_set_bits_per_word(struct spi_master *master,u8 bits_per_word)
+@brief			Sets SIZE field in SPBRR
+*/
+void ioh_spi_set_bits_per_word(struct spi_master *master, u8 bits_per_word);
+
+/*! @ingroup	SPI_HALLayerAPI
+@fn				ioh_spi_clear_fifo(struct spi_master *master)
+@brief			Clears Tx/Rx FIFOs by toggling FICLR bit in SPCR
+*/
+void ioh_spi_clear_fifo(struct spi_master *master);
+#endif
diff -urN linux-2.6.33-rc3/drivers/spi/pch_spi_main.c topcliff-2.6.33-rc3/drivers/spi/pch_spi_main.c
--- linux-2.6.33-rc3/drivers/spi/pch_spi_main.c	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_spi_main.c	2010-03-09 00:40:52.000000000 +0900
@@ -0,0 +1,1323 @@
+/**
+ * @file 	ioh_spi_main.c
+ *
+ * @brief This file defines the SPI_InterfaceLayer APIs of the IOH SPI
+ * controller
+ * driver.
+ *
+ * @version 0.94
+ *
+ * @par
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * @par
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "pch_debug.h"
+#include "pch_spi.h"
+#include "pch_spi_hal.h"
+
+/*! @ingroup    SPI_HALLayer
+@def            SSN_LOW
+@brief          SSNXCR register value to pull down SSN
+*/
+#define SSN_LOW 			(0x02U)
+
+/*! @ingroup    SPI_HALLayer
+@def            SSN_NO_CONTROL
+@brief          SSNXCR register value to relinquish control over SSN
+*/
+#define SSN_NO_CONTROL		(0x00U)
+
+/*function prototypes*/
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn			ioh_spi_deselect_chip(struct ioh_spi_data* pCtrlData)
+@brief	Clears the details of the current slave from the SPI channel
+								data structure
+*/
+static inline void ioh_spi_deselect_chip(struct ioh_spi_data *pCtrlData);
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn ioh_spi_select_chip(struct ioh_spi_data* pCtrlData,struct spi_device* pSpi)
+@brief	Update the slave device details in the SPI channel data structure
+*/
+static inline void ioh_spi_select_chip(struct ioh_spi_data *pCtrlData,
+				       struct spi_device *pSpi);
+
+/*! @ingroup	SPI_UtilitiesAPI
+@fn			ioh_spi_process_messages(struct work_struct* pWork)
+@brief			Work Queue handler to handle SPI data transfers
+*/
+static void ioh_spi_process_messages(struct work_struct *pWork);
+
+/*! @ingroup	SPI_UtilitiesAPI
+
+@fn		ioh_spi_get_resources(struct ioh_spi_board_data* pBoardData)
+
+@remarks		Acquires the resources needed by IOH SPI driver
+
+	The major tasks performed by this method are:
+	- Initialize the spin lock of all SPI channels.
+	- Initialize queue to hold pending SPI messages of all SPI channels.
+	- Initialize wait queue head of all SPI channels.
+	- Create the work structure for all SPI channels.
+	- Create the work queues for all SPI channels.
+	- Allocate PCI regions.
+	- Get PCI memory mapped address and base addresses for all SPI channels.
+	- Reset the IOH SPI hardware for all SPI channels.
+	- Register the interrupt handler.
+
+@note	This function is invoked by ioh_spi_probe to acquire
+	the various resources needed by IOH SPI driver.If any of the actions
+	performed by ioh_spi_get_resources fails,@ref ioh_spi_free_resources
+	is invoked to perform the necessary cleanups.
+
+@param	pBoardData [@ref INOUT]
+			Contains the reference to struct ioh_spi_board_data
+
+@retval			int
+- @ref IOH_SPI_SUCCESS	The function terminates normally after all
+						required resources are acquired.
+- -EBUSY				create_singlethread_workqueue fails.
+						pci_request_regions fails.
+						request_irq fails.
+- -EINVAL				request_irq fails.
+- -ENOSYS				request_irq_fails.
+- -ENOMEM				pci_iomap_fails.
+						request_irq fails.
+
+@see
+				- ioh_spi_probe
+
+<hr>
+*/
+int ioh_spi_get_resources(struct ioh_spi_board_data *pBoardData)
+{
+	int i;
+	long IORemapAddress;
+	s32 iRetVal = IOH_SPI_SUCCESS;
+	IOH_DEBUG("ioh_spi_get_resources ENTRY\n");
+
+	/*initialize resources */
+
+	for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+		/*iniatize queue of pending messages */
+		INIT_LIST_HEAD(&(pBoardData->pCtrlData[i]->Queue));
+		IOH_DEBUG
+		  ("ioh_spi_get_resources pCtrlData[i]->Queue initialized using"
+		   "INIT_LIST_HEAD\n");
+
+		/*initialize spin locks */
+		spin_lock_init(&(pBoardData->pCtrlData[i]->Lock));
+		IOH_DEBUG
+		  ("ioh_spi_get_resources pCtrlData[i]->Lock initialized using"
+		   "spin_lock_init\n");
+
+		/*set channel status */
+		pBoardData->pCtrlData[i]->Status = STATUS_RUNNING;
+		IOH_DEBUG
+		  ("ioh_spi_get_resources pCtrlData[i]->Status\
+					 = STATUS_RUNNING\n");
+
+		/*initialize work structure */
+		INIT_WORK(&(pBoardData->pCtrlData[i]->Work),
+			  ioh_spi_process_messages);
+		IOH_DEBUG
+		    ("ioh_spi_get_resources pCtrlData[i]->Work initialized\
+							 using INIT_WORK\n");
+
+		/*initialize wait queues */
+		init_waitqueue_head(&(pBoardData->pCtrlData[i]->Wait));
+		IOH_DEBUG
+		    ("ioh_spi_get_resources pCtrlData[i]->Wait initialized\
+						 using init_waitqueue_head\n");
+	}
+
+	do {
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			/*create workqueue */
+			pBoardData->pCtrlData[i]->pWorkQueue =
+			    create_singlethread_workqueue(DRIVER_NAME);
+
+			if ((pBoardData->pCtrlData[i]->pWorkQueue) == NULL) {
+				IOH_LOG(KERN_ERR,
+					"ioh_spi_get_resources create_singlet\
+						hread_workqueue failed\n");
+				iRetVal = -EBUSY;
+				break;
+			}
+		}
+
+		if (iRetVal != 0)
+			break;
+
+
+		IOH_DEBUG
+		    ("ioh_spi_get_resources create_singlethread_workqueue\
+								 success\n");
+		iRetVal = pci_request_regions(pBoardData->pDev, DRIVER_NAME);
+		if (iRetVal != 0) {
+			IOH_LOG(KERN_ERR,
+			  "ioh_spi_get_resources request_region failed\n");
+			break;
+		}
+
+		IOH_DEBUG("ioh_spi_get_resources request_region returned=%d\n",
+			  iRetVal);
+
+		pBoardData->bRegionRequested = true;
+		IOH_DEBUG
+		 ("ioh_spi_get_resources pCtrlData->bRegionRequested = true\n");
+
+		/* Wipro 1/13/2010 Use Mem BAR */
+		IORemapAddress =
+		    (unsigned long)pci_iomap(pBoardData->pDev, 1, 0);
+
+		if (IORemapAddress == 0) {
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_get_resources pci_iomap failed\n");
+			iRetVal = -ENOMEM;
+			break;
+		}
+
+		IOH_DEBUG
+		    ("ioh_spi_get_resources pci_iomap success PCI Base\
+							 address=%x\n",
+						     (IORemapAddress));
+
+		/*calculate base address for all channels */
+
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			pBoardData->pCtrlData[i]->IORemapAddress =
+			    IORemapAddress + (IOH_SPI_ADDRESS_SIZE * i);
+			IOH_DEBUG
+			    ("ioh_spi_get_resources Base address for\
+						 channel %d= %x\n",
+			     i, (pBoardData->pCtrlData[i]->IORemapAddress));
+		}
+
+		/*reset IOH SPI h/w */
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			ioh_spi_reset(pBoardData->pCtrlData[i]->pMaster);
+			IOH_DEBUG
+			    ("ioh_spi_get_resources ioh_spi_reset invoked\
+							 successfully \n");
+		}
+
+		/*register IRQ */
+		iRetVal = request_irq(pBoardData->pDev->irq, ioh_spi_handler,
+						 IRQF_SHARED, DRIVER_NAME,
+						 (void *)pBoardData);
+		if (iRetVal != 0) {
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_get_resources request_irq failed\n");
+			break;
+		}
+
+		IOH_DEBUG("ioh_spi_get_resources request_irq returned=%d\n",
+			  iRetVal);
+
+		pBoardData->bIrqRegistered = true;
+		IOH_DEBUG
+		    ("ioh_spi_get_resources pCtrlData->bIrqRegistered=true\n");
+	} while (0);
+
+	if (iRetVal != IOH_SPI_SUCCESS) {
+		IOH_LOG(KERN_ERR,
+			"ioh_spi_get_resources FAIL:invoking\
+				 ioh_spi_free_resources\n");
+		ioh_spi_free_resources(pBoardData);
+	}
+
+	IOH_DEBUG("ioh_spi_get_resources Return=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+/*! @ingroup	SPI_UtilitiesAPI
+
+@fn             ioh_spi_free_resources(struct ioh_spi_board_data* pBoardData)
+
+@remarks        Frees the resources acquired by IOH SPI driver
+
+		The main tasks performed by this method are:
+		- Destroy the workqueus created for all SPI channels.
+		- Disables interrupts and unregisters  the interrupt handler.
+		- Unmaps the PCI base address.
+		- Releases PCI regions.
+
+@note        This function is invoked from ioh_spi_remove when the SPI device is
+	being removed from the system or when the IOH SPI driver is being
+				unloaded from the system using "rmmod" command.
+
+@param  pBoardData  [@ref INOUT]   Contains the reference to struct
+							 ioh_spi_board_data
+
+@retval         None
+
+@see
+				- ioh_spi_remove
+
+<hr>
+*/
+void ioh_spi_free_resources(struct ioh_spi_board_data *pBoardData)
+{
+	int i;
+
+	IOH_DEBUG("ioh_spi_free_resources ENTRY\n");
+
+	/*free workqueue */
+
+	for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+		if (pBoardData->pCtrlData[i]->pWorkQueue != NULL) {
+			destroy_workqueue(pBoardData->pCtrlData[i]->pWorkQueue);
+			pBoardData->pCtrlData[i]->pWorkQueue = NULL;
+			IOH_DEBUG
+			    ("ioh_spi_free_resources destroy_workqueue invoked\
+							 successfully\n");
+		}
+	}
+
+	/*disable interrupts & free IRQ */
+	if (pBoardData->bIrqRegistered == true) {
+		/* disable interrupts */
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			ioh_spi_disable_interrupts(pBoardData->pCtrlData[i]->
+						   pMaster, IOH_SPI_ALL);
+			IOH_DEBUG
+			    ("ioh_spi_free_resources ioh_spi_disable_interrupts\
+						 invoked successfully\n");
+		}
+
+		/*free IRQ */
+		free_irq(pBoardData->pDev->irq, (void *)pBoardData);
+
+		IOH_DEBUG
+		    ("ioh_spi_free_resources free_irq invoked successfully\n");
+
+		pBoardData->bIrqRegistered = false;
+	}
+
+	/*unmap PCI base address */
+	if ((pBoardData->pCtrlData[0]->IORemapAddress) != 0) {
+		pci_iounmap(pBoardData->pDev,
+			    (void *)(pBoardData->pCtrlData[0]->IORemapAddress));
+
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++)
+			pBoardData->pCtrlData[i]->IORemapAddress = 0;
+
+
+		IOH_DEBUG
+		    ("ioh_spi_free_resources pci_iounmap invoked\
+							 successfully\n");
+	}
+
+	/*release PCI region */
+	if (pBoardData->bRegionRequested == true) {
+		pci_release_regions(pBoardData->pDev);
+		IOH_DEBUG
+		    ("ioh_spi_free_resources pci_release_regions invoked\
+							 successfully\n");
+		pBoardData->bRegionRequested = false;
+	}
+}
+
+/*! @ingroup	SPI_UtilitiesAPI
+
+@fn			ioh_spi_process_messages(struct work_struct* pWork)
+
+@remarks		Work Queue handler to handle SPI data transfers
+
+The main tasks performed by this method are:
+- If system is suspended,then flush the queue of pending transfers and return.
+- Retrieve the SPI message to be processed from the queue of pending messages.
+- Invoke @ref ioh_spi_select_chip to configure the SPI channel.
+- Retrieve the 1st or the subsequent transfer structure from SPI message
+								 structure.
+- Update baud rate and bits per word,if user has specified new values.
+- Allocate memory for Transmit and Receive buffers.
+- Copy transmit data from transfer structure to Transmit buffer.
+- Pull down SSN by writing 0x2 to SSNXCR register.
+- Write transmit data to Transmit FIFO.
+- Enable required interrupts.
+- Enable SPI transfer by invoking @ref ioh_spi_set_enable.
+- Wait till SPI data transfer is completed.
+- Relinquish control over SSN by writing 0x0 to SSNXCR register.
+- Disable SPI transfer by invoking @ref ioh_spi_set_enable.
+- Clear Transmit & Receive FIFOs by invoking @ref ioh_spi_clear_fifo.
+- Copy received data from Receive buffer to transfer structure.
+- Free memory allocated for Transmit and Receive buffers.
+- Update data count in transfer structure.
+- If the SPI message has any more transfers , process them same as above.
+- If system is suspended,then flush the queue of pending transfers and return.
+- Again schedule the work queue haandler to run if there are pending messages in
+queue of pending messages.
+
+@note           Work Queue handler is scheduled by @ref ioh_spi_transfer after
+the SPI message to be processed is pushed into the queue of pending
+transfers.This function will write the first set of data to Tx FIFO and sleeps
+till all SPI data transfer is over.The data transfer is handled by
+the interrupt handler ioh_spi_handler function.
+
+@param		pWork	[@ref IN]	contains reference to struct work_struct
+
+@retval			None
+
+@see
+				- ioh_spi_transfer
+
+<hr>
+*/
+static void ioh_spi_process_messages(struct work_struct *pWork)
+{
+	int j;
+	u32 nWrites;
+
+	struct spi_message *pMsg;
+	int bMemFail, size;
+	int bpw;
+
+	struct ioh_spi_data *pCtrlData =
+	    container_of(pWork, struct ioh_spi_data, Work);
+	IOH_DEBUG("ioh_spi_process_messages pCtrlData initialized\n");
+
+	spin_lock(&pCtrlData->Lock);
+
+	/*check if suspend has been initiated;if yes flush queue */
+
+	if ((pCtrlData->pBoardData->bSuspended == true)
+	    || (pCtrlData->Status == STATUS_EXITING)) {
+		IOH_DEBUG
+		    ("ioh_spi_process_messages suspend/remove initiated,\
+							flushing queue\n");
+		list_for_each_entry(pMsg, pCtrlData->Queue.next, queue) {
+			pMsg->status = -EIO;
+
+			if (pMsg->complete != 0)
+				pMsg->complete(pMsg->context);
+
+
+			/*delete from queue */
+			list_del_init(&pMsg->queue);
+		}
+
+		spin_unlock(&pCtrlData->Lock);
+	} else {
+		pCtrlData->bCurrent_msg_processing = true;
+		IOH_DEBUG
+		    ("ioh_spi_process_messages set pCtrlData->\
+						bCurrent_msg_processing"
+								"= true\n");
+
+		/*Get the message from the queue and delete it from there. */
+		pCtrlData->pCurMsg =
+		    list_entry(pCtrlData->Queue.next, struct spi_message,
+			       queue);
+		IOH_DEBUG
+		    ("ioh_spi_process_messages :Got new message from queue \n");
+		list_del_init(&pCtrlData->pCurMsg->queue);
+
+		pCtrlData->pCurMsg->status = 0;
+
+		IOH_DEBUG
+		   ("ioh_spi_process_messages :Invoking ioh_spi_select_chip\n");
+		ioh_spi_select_chip(pCtrlData, pCtrlData->pCurMsg->spi);
+
+		spin_unlock(&pCtrlData->Lock);
+
+		do {
+			/*If we are already processing a message get the next
+								 transfer
+			   structure from the message otherwise retrieve the
+								 1st transfer
+			   request from the message. */
+			spin_lock(&pCtrlData->Lock);
+
+			if (pCtrlData->pCurTransfer == NULL) {
+				pCtrlData->pCurTransfer =
+				    list_entry(pCtrlData->pCurMsg->transfers.
+					       next, struct spi_transfer,
+					       transfer_list);
+				IOH_DEBUG
+				    ("ioh_spi_process_messages :Getting 1st\
+							 transfer structure"
+						     "for this message\n");
+			} else {
+				pCtrlData->pCurTransfer =
+				    list_entry(pCtrlData->pCurTransfer->
+					       transfer_list.next,
+					       struct spi_transfer,
+					       transfer_list);
+				IOH_DEBUG
+				    ("ioh_spi_process_messages :Getting next\
+							 transfer structure"
+						     "for this message\n");
+			}
+
+			spin_unlock(&pCtrlData->Lock);
+
+			/*set baud rate if needed */
+
+			if (pCtrlData->pCurTransfer->speed_hz) {
+				IOH_DEBUG
+				    ("ioh_spi_process_messages:setting\
+								 baud rate\n");
+				ioh_spi_set_baud_rate(pCtrlData->pMaster,
+						      (pCtrlData->pCurTransfer->
+						       speed_hz));
+			}
+
+			/*set bits per word if needed */
+			if ((pCtrlData->pCurTransfer->bits_per_word) &&
+			    ((pCtrlData->pCurMsg->spi->bits_per_word) !=
+			     (pCtrlData->pCurTransfer->bits_per_word))) {
+				IOH_DEBUG
+				    ("ioh_spi_process_messages:setting bits\
+								 per word\n");
+				ioh_spi_set_bits_per_word(pCtrlData->pMaster,
+							  (pCtrlData->
+							   pCurTransfer->
+							   bits_per_word));
+				bpw = pCtrlData->pCurTransfer->bits_per_word;
+			} else {
+				bpw = pCtrlData->pCurMsg->spi->bits_per_word;
+			}
+
+			/*reset Tx/Rx index */
+			pCtrlData->TxIndex = 0;
+
+			pCtrlData->RxIndex = 0;
+
+			if (IOH_SPI_8_BPW == bpw) {
+				/*8 bits per word */
+				pCtrlData->lengthInBpw =
+				    pCtrlData->pCurTransfer->len;
+			} else {
+				/*16 bits per word */
+				pCtrlData->lengthInBpw =
+				    (pCtrlData->pCurTransfer->len) / 2;
+			}
+
+			bMemFail = false;
+
+			/*find alloc size */
+			size =
+			    (pCtrlData->pCurTransfer->len) *
+			    (sizeof(*(pCtrlData->pU16TxBuffer)));
+			/*allocate memory for pU16TxBuffer & pU16RxBuffer */
+			pCtrlData->pU16TxBuffer =
+/*			    (u16 *) kzalloc(size, GFP_KERNEL);*/
+			    kzalloc(size, GFP_KERNEL);
+			if (pCtrlData->pU16TxBuffer != NULL) {
+				pCtrlData->pU16RxBuffer =
+/*				    (u16 *) kzalloc(size, GFP_KERNEL);*/
+				 kzalloc(size, GFP_KERNEL);
+				if (pCtrlData->pU16RxBuffer == NULL) {
+					bMemFail = true;
+					kfree(pCtrlData->pU16TxBuffer);
+				}
+			} else {
+				bMemFail = true;
+			}
+
+			if (bMemFail) {
+				/*flush queue and set status of all transfers
+								 to -ENOMEM */
+				IOH_LOG(KERN_ERR,
+					"Kzalloc fail in\
+						 ioh_spi_process_messages\n");
+				list_for_each_entry(pMsg, pCtrlData->Queue.next,
+						    queue) {
+					pMsg->status = -ENOMEM;
+
+					if (pMsg->complete != 0)
+						pMsg->complete(pMsg->context);
+
+
+					/*delete from queue */
+					list_del_init(&pMsg->queue);
+				}
+
+				return;
+			}
+
+			/*copy Tx Data */
+			if ((pCtrlData->pCurTransfer->tx_buf) != NULL) {
+				for (j = 0; j < (pCtrlData->lengthInBpw); j++) {
+					if (IOH_SPI_8_BPW == bpw) {
+						pCtrlData->pU16TxBuffer[j] =
+						    (((u8 *) (pCtrlData->
+							      pCurTransfer->
+							      tx_buf))[j]);
+						IOH_DEBUG
+						    ("xmt data in\
+						 ioh_spi_process_messages=%x\n",
+						     (pCtrlData->
+						      pU16TxBuffer[j]));
+					} else {
+						pCtrlData->pU16TxBuffer[j] =
+						    ((u16 *) (pCtrlData->
+							      pCurTransfer->
+							      tx_buf))[j];
+						IOH_DEBUG
+						    ("xmt data ioh_spi_pro\
+							cess_messages%x\n",
+						     (pCtrlData->
+						      pU16TxBuffer[j]));
+					}
+				}
+			}
+
+			/*if len greater than IOH_SPI_MAX_FIFO_DEPTH,
+						write 16,else len bytes */
+			if ((pCtrlData->lengthInBpw) > IOH_SPI_MAX_FIFO_DEPTH)
+				nWrites = IOH_SPI_MAX_FIFO_DEPTH;
+			else
+				nWrites = (pCtrlData->lengthInBpw);
+
+
+#ifndef FPGA
+			 /*LSI*/
+			    IOH_DEBUG
+			    ("\nioh_spi_process_messages:Pulling down SSN low\
+						 - writing 0x2 to SSNXCR\n");
+			ioh_spi_writereg(pCtrlData->pMaster, IOH_SPI_SSNXCR,
+					 SSN_LOW);
+#endif
+			IOH_DEBUG
+			    ("\nioh_spi_process_messages:Writing %u items\n",
+			     nWrites);
+
+			for (j = 0; j < nWrites; j++) {
+				ioh_spi_writereg(pCtrlData->pMaster,
+						 IOH_SPI_SPDWR,
+						 pCtrlData->pU16TxBuffer[j]);
+			}
+
+			/*update TxIndex */
+			pCtrlData->TxIndex = j;
+
+			IOH_DEBUG
+			    ("ioh_spi_process_messages:enabling interrupts\n");
+
+			/*reset transfer complete flag */
+			pCtrlData->bTransferComplete = false;
+
+			pCtrlData->bTransferActive = true;
+
+			IOH_DEBUG
+			    ("ioh_spi_process_messages set pCtrlData->\
+						bTransferActive = true\n");
+
+			/*enable interrupts */
+			if ((pCtrlData->lengthInBpw) > IOH_SPI_MAX_FIFO_DEPTH) {
+				/*set receive threhold to IOH_SPI_RX_THOLD */
+				ioh_spi_set_threshold(pCtrlData->pCurrentChip,
+						      IOH_SPI_RX_THOLD,
+						      IOH_SPI_RX);
+				/*enable FI and RFI interrupts */
+				ioh_spi_enable_interrupts(pCtrlData->pMaster,
+							  IOH_SPI_RFI |
+							  IOH_SPI_FI);
+			} else {
+				/*set receive threhold to maximum */
+				ioh_spi_set_threshold(pCtrlData->pCurrentChip,
+						      IOH_SPI_RX_THOLD_MAX,
+						      IOH_SPI_RX);
+				/*enable FI interrupt */
+				ioh_spi_enable_interrupts(pCtrlData->pMaster,
+							  IOH_SPI_FI);
+			}
+
+			IOH_DEBUG
+			    ("ioh_spi_process_messages:invoking\
+					 ioh_spi_set_enable to enable SPI\n");
+
+			ioh_spi_set_enable((pCtrlData->pCurrentChip), true);
+
+			/*Wait until the transfer completes; go to sleep
+					 after initiating the transfer. */
+			IOH_DEBUG
+			    ("ioh_spi_process_messages:waiting for transfer\
+							 to get over\n");
+
+			wait_event_interruptible(pCtrlData->Wait,
+						 false !=
+						 pCtrlData->bTransferComplete);
+#ifndef FPGA
+			 /*LSI*/
+			    ioh_spi_writereg(pCtrlData->pMaster, IOH_SPI_SSNXCR,
+					     SSN_NO_CONTROL);
+			IOH_DEBUG
+			    ("\n ioh_spi_process_messages:no more control over\
+						 SSN-writing 0x0 to SSNXCR");
+#endif
+			IOH_DEBUG("ioh_spi_process_messages:transmit over\n");
+
+			pCtrlData->bTransferActive = false;
+			IOH_DEBUG
+			    ("ioh_spi_process_messages set pCtrlData->\
+						bTransferActive = false\n");
+
+			/*clear all interrupts */
+			ioh_spi_writereg(pCtrlData->pMaster, IOH_SPI_SPSR,
+					 (ioh_spi_readreg
+					  (pCtrlData->pMaster, IOH_SPI_SPSR)));
+			/*disable interrupts */
+			ioh_spi_disable_interrupts(pCtrlData->pMaster,
+						   IOH_SPI_ALL);
+
+			/*Disable SPI transfer */
+			IOH_DEBUG
+			    ("ioh_spi_process_messages:invoking\
+						 ioh_spi_set_enable to disable"
+			     "spi transfer\n");
+			ioh_spi_set_enable((pCtrlData->pCurrentChip), false);
+
+			/*clear FIFO */
+			IOH_DEBUG
+			    ("ioh_spi_process_messages:invoking\
+						 ioh_spi_clear_fifo to "
+							"clear fifo\n");
+			ioh_spi_clear_fifo(pCtrlData->pMaster);
+
+			/*copy Rx Data */
+
+			if ((pCtrlData->pCurTransfer->rx_buf) != NULL) {
+				for (j = 0; j < (pCtrlData->lengthInBpw); j++) {
+					if (IOH_SPI_8_BPW == bpw) {
+						((u8 *) (pCtrlData->
+							 pCurTransfer->
+							 rx_buf))[j] =
+						    (u8) ((pCtrlData->
+							   pU16RxBuffer[j]) &
+							  0xFF);
+
+						IOH_DEBUG
+						    ("rcv data in ioh_spi_proc\
+							ess_messages=%x\n",
+						     (pCtrlData->
+						      pU16RxBuffer[j]));
+
+					} else {
+						((u16 *) (pCtrlData->
+							  pCurTransfer->
+							  rx_buf))[j] =
+						    (u16) (pCtrlData->
+							   pU16RxBuffer[j]);
+						IOH_DEBUG
+						    ("rcv data in ioh_spi_proce\
+							ss_messages=%x\n",
+						     (pCtrlData->
+						      pU16RxBuffer[j]));
+					}
+				}
+			}
+
+			/*free memory */
+			kfree(pCtrlData->pU16RxBuffer);
+			pCtrlData->pU16RxBuffer = NULL;
+
+
+			kfree(pCtrlData->pU16TxBuffer);
+			pCtrlData->pU16TxBuffer = NULL;
+
+
+			/*increment message count */
+			pCtrlData->pCurMsg->actual_length +=
+			    pCtrlData->pCurTransfer->len;
+
+			IOH_DEBUG
+			    ("ioh_spi_process_messages:pCtrlData->pCurMsg->\
+							actual_length=%d\n",
+					pCtrlData->pCurMsg->actual_length);
+
+			/*check for delay */
+			if (pCtrlData->pCurTransfer->delay_usecs) {
+				IOH_DEBUG
+				 ("ioh_spi_process_messages:delay in usec=%d\n",
+				     pCtrlData->pCurTransfer->delay_usecs);
+				udelay(pCtrlData->pCurTransfer->delay_usecs);
+			}
+
+			spin_lock(&pCtrlData->Lock);
+
+			/*No more transfer in this message. */
+
+			if ((pCtrlData->pCurTransfer->transfer_list.next) ==
+			    &(pCtrlData->pCurMsg->transfers)) {
+				IOH_DEBUG
+				    ("ioh_spi_process_messages:no more\
+						 transfers in this message\n");
+				/*Invoke complete callback
+				   [To the spi core..indicating
+							 end of transfer] */
+				pCtrlData->pCurMsg->status = 0;
+
+				if ((pCtrlData->pCurMsg->complete) != 0) {
+					IOH_DEBUG
+					    ("ioh_spi_process_messages:Invoking\
+						 callback of SPI core\n");
+					pCtrlData->pCurMsg->complete(pCtrlData->
+								     pCurMsg->
+								     context);
+				}
+
+				/*update status in global variable */
+				pCtrlData->bCurrent_msg_processing = false;
+
+				IOH_DEBUG
+				    ("ioh_spi_process_messages:pCtrlData->\
+						bCurrent_msg_processing"
+							"set to false\n");
+
+				pCtrlData->pCurMsg = NULL;
+
+				pCtrlData->pCurTransfer = NULL;
+
+				/*check if we have items in list and not
+								 suspending */
+				/*return 1 if list empty */
+				if ((list_empty(&pCtrlData->Queue) == 0) &&
+				    (pCtrlData->pBoardData->bSuspended == false)
+				    && (pCtrlData->Status != STATUS_EXITING)) {
+					/*We have some more work to do
+						 (either there is more transfer
+					   requests in the current message or
+						 there are more messages) */
+					IOH_DEBUG
+					    ("ioh_spi_process_messages:we\
+							 have pending messages"
+					     "-Invoking queue_work\n");
+					queue_work(pCtrlData->pWorkQueue,
+						   &pCtrlData->Work);
+				}
+
+				/*check if suspend has been initiated;if yes
+							 flush queue */
+				else if ((pCtrlData->pBoardData->bSuspended ==
+					  true)
+					 || (pCtrlData->Status ==
+					     STATUS_EXITING)) {
+					IOH_DEBUG
+					    ("ioh_spi_process_messages\
+						 suspend/remove initiated,"
+					     "flushing queue\n");
+					list_for_each_entry(pMsg,
+							    pCtrlData->Queue.
+							    next, queue) {
+						pMsg->status = -EIO;
+
+						if (pMsg->complete != 0) {
+							pMsg->complete(pMsg->
+								       context);
+						}
+
+						/*delete from queue */
+						list_del_init(&pMsg->queue);
+					}
+				}
+			}
+
+			spin_unlock(&pCtrlData->Lock);
+
+		} while ((pCtrlData->pCurTransfer) != NULL);
+	}
+}
+
+/*! @ingroup	SPI_UtilitiesAPI
+
+@fn ioh_spi_select_chip(struct ioh_spi_data* pCtrlData,struct spi_device* pSpi)
+
+@remarks	Update the SPI device details in the SPI channel data structure
+
+The main tasks performed by this method are:
+- Check whether the active SPI device is different from the device to
+  which the previous data transfer occured.
+- If yes invoke @ref ioh_spi_deselect_chip to clear details of old device
+  from pCtrlData.
+- Update the details of the new device in pCtrlData
+- Invoke @ref ioh_spi_setup_transfer to configure the SPI channel.
+
+@note	This function is invoked by @ref ioh_spi_process_messages before
+								 processing
+				each SPI message.
+
+@param pCtrlData	[@ref INOUT] contains reference to struct ioh_spi_data
+
+@param	pSpi		[@ref IN]	contains reference to struct spi_device
+
+@retval			None
+
+@see
+				- ioh_spi_process_messages
+
+<hr>
+*/
+static inline void ioh_spi_select_chip(struct ioh_spi_data *pCtrlData,
+				       struct spi_device *pSpi)
+{
+	if ((pCtrlData->pCurrentChip) != NULL) {
+		if ((pSpi->chip_select) != (pCtrlData->nCurrentChip)) {
+			IOH_DEBUG
+			    ("ioh_spi_select_chip : different slave-Invoking"
+			     "ioh_spi_deselect_chip\n");
+			ioh_spi_deselect_chip(pCtrlData);
+		}
+	}
+
+	pCtrlData->pCurrentChip = pSpi;
+
+	pCtrlData->nCurrentChip = pCtrlData->pCurrentChip->chip_select;
+
+	IOH_DEBUG("ioh_spi_select_chip :Invoking ioh_spi_setup_transfer\n");
+	ioh_spi_setup_transfer(pSpi);
+}
+
+/*! @ingroup	SPI_UtilitiesAPI
+
+@fn			ioh_spi_deselect_chip(struct ioh_spi_data* pCtrlData)
+
+@remarks	Clear the SPI device details from the SPI channel data structure
+
+	The main tasks performed by this method are:
+	- Clear the details of SPI device from SPI channel data structure.
+
+@note           This function is invoked from @ref ioh_spi_select_chip
+
+@param	pCtrlData	[@ref INOUT] Contains reference to struct ioh_spi_data
+
+@retval			None
+
+@see
+				- ioh_spi_select_chip
+
+<hr>
+*/
+static inline void ioh_spi_deselect_chip(struct ioh_spi_data *pCtrlData)
+{
+	if (pCtrlData->pCurrentChip != NULL) {
+		IOH_DEBUG
+		    ("ioh_spi_deselect_chip :clearing pCurrentChip data\n");
+		pCtrlData->pCurrentChip = NULL;
+	}
+}
+
+/*! @ingroup	SPI_UtilitiesAPI
+
+@fn	ioh_spi_check_request_pending(struct ioh_spi_board_data* pBoardData)
+
+@remarks	Checks for any pending SPI transfer request in the queue of
+							 pending transfers
+
+	The main tasks performed by this method are:
+	- If the message queue is empty return IOH_SPI_SUCCESS.
+	- Sleep for 100ms and again check if message queue is empty,if yes
+	  return IOH_SPI_SUCCESS.
+	- Repeat 500 times.
+	- If queue is still not empty return -EBUSY.
+
+@note			This function is invoked by @ref ioh_spi_remove
+
+@param	pBoardData	[@ref INOUT]	Contains reference to struct
+							 ioh_spi_board_data
+
+@retval			int
+	- @ref IOH_SPI_SUCCESS	Message queue is empty
+		- -EBUSY				Queue is not empty
+
+@see
+				- ioh_spi_remove
+
+<hr>
+*/
+int ioh_spi_check_request_pending(struct ioh_spi_board_data *pBoardData)
+{
+	int i;
+	int iStatus = IOH_SPI_SUCCESS;
+	u16 count;
+
+	for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+		count = 500;
+		spin_lock(&(pBoardData->pCtrlData[i]->Lock));
+		pBoardData->pCtrlData[i]->Status = STATUS_EXITING;
+
+		while ((list_empty(&(pBoardData->pCtrlData[i]->Queue)) == 0) &&
+		       (--count)) {
+			IOH_DEBUG
+			   ("ioh_spi_check_request_pending :Queue not empty\n");
+			spin_unlock(&(pBoardData->pCtrlData[i]->Lock));
+			msleep(IOH_SPI_SLEEP_TIME);
+			spin_lock(&(pBoardData->pCtrlData[i]->Lock));
+		}
+
+		spin_unlock(&(pBoardData->pCtrlData[i]->Lock));
+
+		if (count) {
+			IOH_DEBUG
+			    ("ioh_spi_check_request_pending :Queue empty\n");
+		} else {
+			iStatus = -EBUSY;
+		}
+	}
+
+	IOH_DEBUG("ioh_spi_check_request_pending : EXIT=%d\n", iStatus);
+
+	return iStatus;
+}
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+
+@fn				int ioh_spi_setup(struct spi_device* pSpi)
+
+@remarks Validates the SPI device configuration  paramters specified by user
+
+The main tasks performed by this method are:
+- Validate the bits per word paramter (should be either 8 or 16).
+- Validate the maximum baud rate parameter (should not be greater than 5Mbps).
+
+@note	This function is registered with the SPI core as the setup routine of
+IOH SPI controller driver.This function is invoked by the kernel SPI
+component when user invokes any of spidev's IOCTLs to configure the
+SPI device setting.In this function no hardware settings are modified
+as this can affect any ongoing SPI data transfers.So the setting passed
+by the user is validated and the function returns.Hardware settings are
+updated in the function	@ref ioh_spi_setup_transfer, which is invoked from
+@ref ioh_spi_process_messages before initiating a SPI data transfer.
+
+@param		pSpi	[@ref IN] Contains reference to structure spi_device
+
+@retval		int
+				- IOH_SPI_SUCCESS All paramters are valid
+				- -EINVAL Any of the paramter is invalid
+
+@see
+				- ioh_spi_probe
+
+<hr>
+*/
+int ioh_spi_setup(struct spi_device *pSpi)
+{
+	int iRetVal = IOH_SPI_SUCCESS;
+
+	/*check bits per word */
+
+	if ((pSpi->bits_per_word) == 0) {
+		pSpi->bits_per_word = IOH_SPI_8_BPW;
+		IOH_DEBUG("ioh_spi_setup 8 bits per word \n");
+	}
+
+	if (((pSpi->bits_per_word) != IOH_SPI_8_BPW) &&
+	    ((pSpi->bits_per_word != IOH_SPI_16_BPW))) {
+		IOH_LOG(KERN_ERR, "ioh_spi_setup Invalid bits per word\n");
+		iRetVal = -EINVAL;
+	}
+
+	/*Check baud rate setting */
+	/*if baud rate of chip is greater than
+	   max we can support,return error */
+	if ((pSpi->max_speed_hz) > IOH_SPI_MAX_BAUDRATE) {
+		iRetVal = -EINVAL;
+		IOH_LOG(KERN_ERR, "ioh_spi_setup Invalid Baud rate\n");
+	}
+
+	IOH_DEBUG(KERN_ERR, "ioh_spi_setup MODE = %x\n",
+		  ((pSpi->mode) & (SPI_CPOL | SPI_CPHA)));
+
+	if (((pSpi->mode) & SPI_LSB_FIRST) != 0)
+		IOH_DEBUG("ioh_spi_setup LSB_FIRST\n");
+	else
+		IOH_DEBUG("ioh_spi_setup MSB_FIRST\n");
+
+
+	IOH_DEBUG("ioh_spi_setup Return=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+
+@fn	ioh_spi_transfer(struct spi_device* pSpi,struct spi_message* pMsg)
+
+@remarks	Validates the SPI message and pushes it onto queue of pending
+								 transfers
+
+	The main tasks performed by this method are:
+	- If the list of transfers is empty return -EINVAL.
+	- If the maximum baud rate is zero return -EINVAL.
+	- If Tranmit buffer and Receive buffer both are invalid for
+	  any transfer return -EINVAL.
+	- If the length of transfer is zero for any transfer return -EINVAL.
+	- If maximum baud rate and bits per word are invalid return -EINVAL.
+	- If status of SPI channel is STATUS_EXITING return -ESHUTDOWN.
+	- If device is suspended return -EINVAL.
+	- Add the SPI message to queue of pending SPI messages.
+	- Schedule work queue handler to run.
+
+@note	ioh_spi_transfer is registered by IOH SPI controller driver
+								with SPI core as
+		its transfer routine from the function @ref ioh_spi_probe.It
+		is invoked by the kernel's SPI component when user invokes
+		read,write or SPI_IOC_MESSAGE ioctl.
+
+@param	pSpi		[@ref IN]	Contains reference to struct spi_device
+
+@param	pMsg		[@ref IN]	Contains reference to struct spi_message
+
+@retval		int
+- @ref IOH_SPI_SUCCESS The function exists normally after adding the SPI message
+		to queue of pending SPI messages and schedules work queue
+			handler to run.
+- -EINVAL	Any of the paramters are found to be invalid or the system is
+			suspended.
+- -ESHUTDOWN		When the status of the SPI channel is STATUS_EXITING
+			The status STATUS_EXITING is set when ioh_spi_remove
+			is invoked.
+
+@see
+				- ioh_spi_probe
+
+<hr>
+*/
+int ioh_spi_transfer(struct spi_device *pSpi, struct spi_message *pMsg)
+{
+
+	struct spi_transfer *pTransfer;
+
+	struct ioh_spi_data *pCtrlData = spi_master_get_devdata(pSpi->master);
+	int iRetVal = IOH_SPI_SUCCESS;
+
+	do {
+		/*validate spi message and baud rate */
+		if (unlikely((list_empty(&pMsg->transfers) == 1) ||
+			     ((pSpi->max_speed_hz) == 0))) {
+			if (list_empty(&pMsg->transfers) == 1) {
+				IOH_LOG(KERN_ERR,
+					"ioh_spi_transfer list empty\n");
+			}
+
+			if ((pSpi->max_speed_hz) == 0) {
+				IOH_LOG(KERN_ERR,
+					"ioh_spi_tranfer maxspeed=%d\n",
+					(pSpi->max_speed_hz));
+			}
+
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_transfer returning EINVAL\n");
+
+			iRetVal = -EINVAL;
+			break;
+		}
+
+		IOH_DEBUG("ioh_spi_transfer Transfer List not empty\n");
+
+		IOH_DEBUG("ioh_spi_transfer Transfer Speed is set\n");
+
+		/*validate Tx/Rx buffers and Transfer length */
+		list_for_each_entry(pTransfer, &pMsg->transfers,
+							 transfer_list) {
+			if ((((pTransfer->tx_buf) == NULL)
+			     && ((pTransfer->rx_buf) == NULL))
+			    || (pTransfer->len == 0)) {
+				if (((pTransfer->tx_buf) == NULL)
+				    && ((pTransfer->rx_buf) == NULL)) {
+					IOH_LOG(KERN_ERR,
+						"ioh_spi_transfer Tx and Rx\
+							 buffer NULL\n");
+				}
+
+				if (pTransfer->len == 0) {
+					IOH_LOG(KERN_ERR,
+						"ioh_spi_transfer Transfer\
+							 length invalid\n");
+				}
+
+				IOH_LOG(KERN_ERR,
+					"ioh_spi_transfer returning EINVAL\n");
+
+				iRetVal = -EINVAL;
+				break;
+			}
+
+			IOH_DEBUG("ioh_spi_transfer Tx/Rx buffer valid\n");
+
+			IOH_DEBUG("ioh_spi_transfer Transfer length valid\n");
+
+			/*if baud rate hs been specified validate the same */
+
+			if (pTransfer->speed_hz) {
+				if ((pTransfer->speed_hz) >
+				    IOH_SPI_MAX_BAUDRATE) {
+					iRetVal = -EINVAL;
+					IOH_LOG(KERN_ERR,
+						"ioh_spi_transfer Invalid\
+								 Baud rate\n");
+				}
+			}
+
+			/*if bits per word has been specified validate
+								 the same */
+			if (pTransfer->bits_per_word) {
+				if ((pTransfer->bits_per_word != IOH_SPI_8_BPW)
+				    && (pTransfer->bits_per_word !=
+					IOH_SPI_16_BPW)) {
+					iRetVal = -EINVAL;
+					IOH_LOG(KERN_ERR,
+						"ioh_spi_transfer Invalid bits\
+								 per word\n");
+					break;
+				}
+			}
+		}
+
+		if (iRetVal == -EINVAL)
+			break;
+
+
+		spin_lock(&pCtrlData->Lock);
+
+		/*We won't process any messages if we have been asked
+								 to terminate */
+
+		if (STATUS_EXITING == (pCtrlData->Status)) {
+			spin_unlock(&pCtrlData->Lock);
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_transfer -pCtrlData->Status\
+							 = STATUS_EXITING"
+						"returning ESHUTDOWN\n");
+			iRetVal = -ESHUTDOWN;
+			break;
+		}
+
+		/*If suspended ,return -EINVAL */
+		if (pCtrlData->pBoardData->bSuspended == true) {
+			IOH_LOG(KERN_ERR,
+					"ioh_spi_transfer pCtrlData->\
+					pBoardData->bSuspending"
+					"= true returning EINVAL\n");
+			spin_unlock(&pCtrlData->Lock);
+			iRetVal = -EINVAL;
+			break;
+		}
+
+		/*set status of message */
+		pMsg->actual_length = 0;
+
+		IOH_DEBUG
+		  ("ioh_spi_transfer  - setting pMsg->status = -EINPROGRESS\n");
+
+		pMsg->status = -EINPROGRESS;
+
+		/*add message to queue */
+		list_add_tail(&pMsg->queue, &pCtrlData->Queue);
+
+		IOH_DEBUG("ioh_spi_transfer - Invoked list_add_tail\n");
+
+		/*schedule work queue to run */
+		queue_work(pCtrlData->pWorkQueue, &pCtrlData->Work);
+
+		IOH_DEBUG("ioh_spi_transfer  - Invoked Queue Work\n");
+
+		spin_unlock(&pCtrlData->Lock);
+
+	} while (0);
+
+	IOH_DEBUG("ioh_spi_transfer RETURN=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+
+@fn				ioh_spi_cleanup(struct spi_device* pSpi)
+
+@remarks		Provides the Cleanup routine for IOH SPI driver
+
+@note			This is a dummy function.
+	It is not mandatory to have a cleanup function.
+	If SPI master provides a cleanup function while they register
+	with the SPI core, then SPI core invokes the cleanup function
+	when SPI master calls spi_unregister_master function.This
+	driver invokes spi_unregister_master from ioh_spi_remove
+	function. Before invoking spi_unregister_master all the resources
+	used is freed i.e. cleanup activities are handled in the
+	@ref ioh_spi_remove function itself.This function is registered
+	as the cleanup routine for this SPI controller driver from
+	the @ref ioh_spi_probe function.
+
+@param	pSpi		[@ref IN]	Contains reference to struct spi_device
+
+@retval			None
+
+@see
+				- ioh_spi_probe
+
+<hr>
+
+*/
+void ioh_spi_cleanup(struct spi_device *pSpi)
+{
+	IOH_DEBUG("spi_cleanup\n");
+}
+
+/*! @ingroup		SPI_UtilitiesAPI
+
+@fn			ioh_spi_callback( struct ioh_spi_data* pCtrlData)
+
+@remarks Informs ioh_spi_process_messages that SPI data transfer is complete
+
+	The main tasks performed by this method are:
+	- Set transfer status of the SPI channel to completed.
+	- Inform this to @ref ioh_spi_process_messages.
+
+@note	The reference to this callback function is saved in a global pointer
+by the function @ref ioh_spi_entcb invoked from @ref ioh_spi_probe function.
+This function is invoked by the interrupt handler ioh_spi_handler
+after transfer complete interrupt is received indicating the end of
+SPI data transfer.ioh_spi_callback wakes up ioh_spi_process_messages
+which blocks till SPI data transfer is completed.
+
+@param	pCtrldata   	[@ref IN]   Contains reference to struct ioh_spi_data
+
+@retval				None
+
+@see
+					- ioh_spi_handler
+					- ioh_spi_probe
+
+<hr>
+*/
+void ioh_spi_callback(struct ioh_spi_data *pCtrlData)
+{
+	IOH_DEBUG("ioh_ spi _callback waking up process\n");
+	spin_lock(&pCtrlData->Lock);
+	pCtrlData->bTransferComplete = true;
+	wake_up(&pCtrlData->Wait);
+	IOH_DEBUG("ioh_ spi _callback invoked wake_up\n");
+	spin_unlock(&pCtrlData->Lock);
+}
diff -urN linux-2.6.33-rc3/drivers/spi/pch_spi_pci.c topcliff-2.6.33-rc3/drivers/spi/pch_spi_pci.c
--- linux-2.6.33-rc3/drivers/spi/pch_spi_pci.c	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_spi_pci.c	2010-03-17 20:05:19.000000000 +0900
@@ -0,0 +1,811 @@
+/**
+ * @file	ioh_spi_pci.c
+ *
+ * @brief This file contains the function definition for the PCI Layer APIs
+ *
+ * @version 0.94
+ *
+ * @par
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * @section
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+
+/*includes*/
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+/*#include <asm/io.h>  modify by checkpatch.pl*/
+#include <linux/io.h>
+#include "pch_spi.h"
+#include "pch_spi_hal.h"
+#include "pch_debug.h"
+
+/*! @ingroup    SPI_PCILayer
+
+@def            IOH_SPI_MAX_CS
+
+@brief          Denotes the maximum chip select number possible.
+
+@note          	Currently this is just used to set the number of chip selects in
+			spi_master structure in @ref ioh_spi_probe function.
+
+@see 			ioh_spi_probe
+
+<hr>
+
+*/
+#define IOH_SPI_MAX_CS         	   (0xFF)
+
+/*pci device ids*/
+
+/*! @ingroup    SPI_PCILayer
+
+@brief			Denotes the PCI device ID of the supported device.
+
+@see			ioh_spi_pcidev_id
+
+<hr>
+
+*/
+#ifndef FPGA
+#define PCI_DEVICE_ID_IOH_SPI          (0x8816) /*LSI*/
+#else
+#define PCI_DEVICE_ID_IOH_SPI          (0x8005) /*FPGA*/
+#endif
+/*! @ingroup	SPI_PCILayerAPI
+
+@fn	ioh_spi_probe(struct pci_dev *pDev, const struct pci_device_id *id)
+
+@brief			Implements the Probe functionality for IOH SPI driver
+
+@remarks		Implements the Probe functionality for IOH SPI driver
+
+		The major tasks performed by this method are:
+		- Register the callback function.
+		- Enable the PCI device.
+		- Allocate memory for SPI master.
+		- Initialize members of SPI master structure.
+		- Register the SPI master.
+		- Invoke @ref ioh_spi_get_resources to acquire and initialize
+		  other resources needed by the driver.
+
+@note		This function is invoked by the kernel when it detects
+		a SPI device matching the vendor ID and device ID specified
+				by this driver.
+
+@param		pDev	[@ref INOUT]	contains reference to struct pci_dev
+
+@param	id	[@ref IN]	contains reference to struct pci_device_id
+
+@retval			int
+- @ref IOH_SPI_SUCCESS	The function exists successfully
+- -ENOMEM		spi_alloc_master API fails/kmalloc fails
+- -EINVAL		pci_enable_device fails/spi_register_master fails
+				/ioh_spi_get_resources fails
+- -EIO			pci_enable_device fails
+- -ENODEV		spi_register_master API fails
+- -ENOSYS		ioh_spi_get_resources fails
+- -ENOMEM		ioh_spi_get_resources fails
+
+@see			ioh_spi_pcidev
+
+<hr>
+
+*/
+static int ioh_spi_probe(struct pci_dev *pDev, const struct pci_device_id *id)
+{
+
+	struct spi_master *pMaster[IOH_SPI_MAX_DEV];
+
+	struct ioh_spi_board_data *pBoardData;
+	int iRetVal, i, j;
+
+	IOH_DEBUG("ioh_spi_probe ENTRY\n");
+	/*initialize the call back function */
+	ioh_spi_entcb(ioh_spi_callback);
+	IOH_DEBUG("ioh_spi_probe invoked ioh_spi_entcb\n");
+
+	do {
+		/*allocate memory for private data */
+		pBoardData =
+		    kmalloc(sizeof(struct ioh_spi_board_data), GFP_KERNEL);
+
+		if (pBoardData == NULL) {
+			IOH_LOG(KERN_ERR,
+				" ioh_spi_probe memory allocation for private\
+							 data failed\n");
+			iRetVal = -ENOMEM;
+			break;
+		}
+
+		IOH_DEBUG
+		    (" ioh_spi_probe memory allocation for private data\
+								 success\n");
+
+		/*enable PCI device */
+		iRetVal = pci_enable_device(pDev);
+		if (iRetVal != 0) {
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe pci_enable_device FAILED\n");
+
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe invoked kfree to free memory\
+						 allocated for pBoardData\n");
+			kfree(pBoardData);
+			break;
+		}
+
+		IOH_DEBUG("ioh_spi_probe pci_enable_device returned=%d\n",
+			  iRetVal);
+
+		pBoardData->pDev = pDev;
+
+		/*alllocate memory for SPI master */
+		i = 0;
+
+		do {
+			pMaster[i] =
+			    spi_alloc_master(&pDev->dev,
+					     sizeof(struct ioh_spi_data));
+
+			if (pMaster[i] == NULL) {
+				iRetVal = -ENOMEM;
+
+				if (i > 0) {
+					j = 0;
+
+					do {
+						spi_master_put(pMaster[j]);
+						j++;
+						IOH_DEBUG
+						    ("ioh_spi_probe invoked\
+							 spi_master_put\n");
+					} while (j < i);
+				}
+
+				IOH_LOG(KERN_ERR,
+					"ioh_spi_probe spi_alloc_master\
+								 failed\n");
+
+				break;
+			}
+
+			i++;
+		} while (i < IOH_SPI_MAX_DEV);
+
+		IOH_DEBUG("ioh_spi_probe spi_alloc_master returned non NULL\n");
+
+		if (iRetVal != 0) {
+			kfree(pBoardData);
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe invoked kfree to free memory\
+						 allocated for pBoardData\n");
+			pci_disable_device(pDev);
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe Invoked pci_disable_device\n");
+			break;
+		}
+
+		/*initialize members of SPI master */
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			pMaster[i]->bus_num = i;
+			pMaster[i]->num_chipselect = IOH_SPI_MAX_CS;
+			pMaster[i]->setup = ioh_spi_setup;
+			IOH_DEBUG
+			    ("ioh_spi_probe setup member of SPI master\
+							 initialized\n");
+			pMaster[i]->transfer = ioh_spi_transfer;
+			IOH_DEBUG
+			    ("ioh_spi_probe transfer member of SPI master\
+							 initialized\n");
+			pMaster[i]->cleanup = ioh_spi_cleanup;
+			IOH_DEBUG
+			    ("ioh_spi_probe cleanup member of SPI master\
+							 initialized\n");
+
+			pBoardData->pCtrlData[i] =
+			    spi_master_get_devdata(pMaster[i]);
+
+			pBoardData->pCtrlData[i]->pMaster = pMaster[i];
+			pBoardData->pCtrlData[i]->nCurrentChip = 255;
+			pBoardData->pCtrlData[i]->pCurrentChip = NULL;
+			pBoardData->pCtrlData[i]->bTransferComplete = false;
+			pBoardData->pCtrlData[i]->pU16TxBuffer = NULL;
+			pBoardData->pCtrlData[i]->pU16RxBuffer = NULL;
+			pBoardData->pCtrlData[i]->TxIndex = 0;
+			pBoardData->pCtrlData[i]->RxIndex = 0;
+			pBoardData->pCtrlData[i]->bTransferActive = false;
+			pBoardData->pCtrlData[i]->pBoardData = pBoardData;
+
+			/*Register the controller with the SPI core. */
+			iRetVal = spi_register_master(pMaster[i]);
+			if (iRetVal != 0) {
+				spi_master_put(pMaster[i]);
+				IOH_DEBUG
+				    ("ioh_spi_probe invoked spi_master_put\n");
+				/*unregister master for any channel that has
+							 registered master */
+
+				if (i > 0) {
+#if 0
+					for (j = 0; j < i; j++) {
+						spi_unregister_master(pMaster
+								      [j]);
+						IOH_DEBUG
+						    ("ioh_spi_probe invoked\
+						 spi_unregister_master\n");
+					}
+#else
+					spi_unregister_master(pMaster[0]);
+					IOH_DEBUG
+					    ("ioh_spi_probe invoked\
+						 spi_unregister_master\n");
+#endif
+				}
+
+				IOH_LOG(KERN_ERR,
+					"ioh_spi_probe spi_register_\
+							master FAILED\n");
+
+				break;
+			}
+
+			IOH_DEBUG
+			    ("ioh_spi_probe spi_register_master\
+							 returned=%d\n",
+							iRetVal);
+		}
+
+		if (iRetVal != 0) {
+			kfree(pBoardData);
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe invoked kfree to free memory\
+					 allocated for pBoardData\n");
+			pci_disable_device(pDev);
+			IOH_DEBUG("ioh_spi_probe invoked pci_disable\n");
+			break;
+		}
+
+		/*allocate resources for IOH SPI */
+		iRetVal = ioh_spi_get_resources(pBoardData);
+		if (iRetVal != IOH_SPI_SUCCESS) {
+			/*
+			for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+				spi_unregister_master(pMaster[i]);
+				IOH_DEBUG
+				    ("ioh_spi_probe invoked\
+					 spi_unregister_master\n");
+			}
+			*/
+			spi_unregister_master(pMaster[0]);
+			IOH_DEBUG
+			    ("ioh_spi_probe invoked spi_unregister_master\n");
+
+
+			kfree(pBoardData);
+
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe invoked kfree to free memory\
+					 allocated for pBoardData\n");
+			pci_disable_device(pDev);
+			IOH_DEBUG("ioh_spi_probe invoked pci_disable\n");
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_probe get_resources FAILED\n");
+			break;
+		}
+
+		IOH_DEBUG("ioh_spi_probe ioh_spi_get_resources returned=%d\n",
+			  iRetVal);
+
+		/*save private data in dev */
+		pci_set_drvdata(pDev, (void *)pBoardData);
+		IOH_DEBUG("ioh_spi_probe invoked pci_set_drvdata\n");
+
+		/*set master mode */
+
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			ioh_spi_set_master_mode(pMaster[i]);
+			IOH_DEBUG
+			    ("ioh_spi_probe invoked ioh_spi_set_master_mode\n");
+		}
+
+		iRetVal = IOH_SPI_SUCCESS;
+
+	} while (false);
+
+	IOH_DEBUG("ioh_spi_probe Return=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+/*! @ingroup	SPI_PCILayerAPI
+
+@fn				ioh_spi_remove(struct pci_dev *pDev)
+
+@brief			Implements the remove routine for IOH SPI driver
+
+@remarks		Implements the remove routine for IOH SPI driver
+
+	The major tasks performed by this method are:
+	- Invoke @ref ioh_spi_check_request_pending function to find
+	  out if there are any pending requests.
+	- Free the allocated resources by invoking @ref ioh_spi_free_resources.
+	- Unregister SPI master.
+	- Disable PCI device.
+
+@note	This function is invoked when the IOH SPI controller driver module
+		is removed from the system using "rmmod" command OR when the SPI
+				device is removed from the system.
+
+@param		pDev	[@ref INOUT]	contains reference to struct pci_dev
+
+@retval			None
+
+@see			ioh_spi_pcidev
+
+<hr>
+
+*/
+static void ioh_spi_remove(struct pci_dev *pDev)
+{
+	struct ioh_spi_board_data *pBoardData = pci_get_drvdata(pDev);
+
+	IOH_DEBUG("ioh_spi_remove ENTRY\n");
+
+	if (pBoardData != NULL) {
+		IOH_DEBUG("ioh_spi_remove invoked pci_get_drvdata\n");
+
+		/*check for any pending messages */
+
+		if ((-EBUSY) == ioh_spi_check_request_pending(pBoardData)) {
+			IOH_DEBUG
+			    ("ioh_spi_remove ioh_spi_check_request_pending\
+							 returned EBUSY\n");
+			/*no need to take any particular action;proceed with
+			 remove even
+			   though queue is not empty */
+		}
+
+		IOH_DEBUG
+		    ("ioh_spi_remove ioh_spi_check_request_pending invoked\n");
+
+		/*Free resources allocated for IOH SPI */
+		ioh_spi_free_resources(pBoardData);
+		IOH_DEBUG("ioh_spi_remove invoked ioh_spi_free_resources\n");
+
+		/*Unregister SPI master */
+
+#if 0
+		int i;
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			spi_unregister_master(pBoardData->pCtrlData[i]->
+					      pMaster);
+			IOH_DEBUG
+			    ("ioh_spi_remove invoked spi_unregister_master\n");
+		}
+#else
+		spi_unregister_master(pBoardData->pCtrlData[0]->pMaster);
+		IOH_DEBUG("ioh_spi_remove invoked spi_unregister_master\n");
+
+#endif
+
+		/*free memory for private data */
+		kfree(pBoardData);
+
+		pci_set_drvdata(pDev, NULL);
+
+		IOH_DEBUG("ioh_spi_remove memory for private data freed\n");
+
+		/*disable PCI device */
+		pci_disable_device(pDev);
+
+		IOH_DEBUG("ioh_spi_remove invoked pci_disable_device\n");
+
+	} else {
+		IOH_LOG(KERN_ERR,
+			"ioh_spi_remove pci_get_drvdata returned NULL\n");
+	}
+}
+
+/*! @ingroup	SPI_PCILayerAPI
+
+@fn			ioh_spi_suspend(struct pci_dev *pDev,pm_message_t state)
+
+@brief			Implements the suspend routine for IOH SPI driver
+
+@remarks		Implements the suspend routine for IOH SPI driver
+
+	The major tasks performed by this method are:
+	- Wait till current message is processed.
+	- Disable interrupts by invoking @ref ioh_spi_disable_interrupts.
+	- Unregister the interrupt handler.
+	- Save current state.
+	- Disable PM notifications.
+	- Disable PCI device.
+	- Move the device to D3Hot power state.
+
+@note 	This function is invoked by the kernel when the system transitions
+				to low power state.
+
+@param		pDev	[@ref INOUT]	contains reference to struct pci_dev
+
+@param	state	[@ref IN]	contains new PM state to which to transition to.
+
+@retval			int
+		- @ref IOH_SPI_SUCCESS	The function returns successfully
+		- -ENOMEM				pci_save_state fails
+
+@see			ioh_spi_pcidev
+
+<hr>
+
+*/
+#ifdef CONFIG_PM
+static int ioh_spi_suspend(struct pci_dev *pDev, pm_message_t state)
+{
+	int i;
+	u8 count;
+	s32 iRetVal = IOH_SPI_SUCCESS;
+
+	struct ioh_spi_board_data *pBoardData = pci_get_drvdata(pDev);
+
+	IOH_DEBUG("ioh_spi_suspend ENTRY\n");
+
+	if (pBoardData == NULL) {
+		IOH_LOG(KERN_ERR,
+			"ioh_spi_suspend pci_get_drvdata returned NULL\n");
+		iRetVal = -EFAULT;
+	} else {
+		IOH_DEBUG
+		    ("ioh_spi_suspend pci_get_drvdata invoked successfully\n");
+		pBoardData->bSuspended = true;
+		IOH_DEBUG
+		    ("ioh_spi_suspend pBoardData->bSuspending set to true\n");
+
+		/*check if the current message is processed:
+		   Only after thats done the transfer will be suspended */
+
+		for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+			count = 255;
+
+			while ((--count) > 0) {
+				if (pBoardData->pCtrlData[i]->
+				    bCurrent_msg_processing == false) {
+					IOH_DEBUG
+					    ("ioh_spi_suspend pBoardData\
+						->pCtrlData->"
+					     "bCurrent_msg_processing\
+							 = false\n");
+					break;
+				} else {
+					IOH_DEBUG
+					    ("ioh_spi_suspend pBoardData\
+							->pCtrlData->"
+					    "bCurrent_msg_processing = true\n");
+				}
+
+				msleep(IOH_SPI_SLEEP_TIME);
+			}
+		}
+
+		/*Free IRQ */
+		if (pBoardData->bIrqRegistered == true) {
+			/*disable all interrupts */
+			for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+				ioh_spi_disable_interrupts(pBoardData->
+							   pCtrlData[i]->
+							   pMaster,
+							   IOH_SPI_ALL);
+				ioh_spi_reset(pBoardData->pCtrlData[i]->
+					      pMaster);
+				IOH_DEBUG
+				    ("ioh_spi_suspend ioh_spi_\
+					disable_interrupts invoked"
+				     "successfully\n");
+			}
+
+			free_irq(pBoardData->pDev->irq, (void *)pBoardData);
+
+			pBoardData->bIrqRegistered = false;
+			IOH_DEBUG
+			    ("ioh_spi_suspend free_irq invoked successfully\n");
+			IOH_DEBUG
+			    ("ioh_spi_suspend pCtrlData->bIrqRegistered\
+								 = false\n");
+		}
+
+		/*save config space */
+		iRetVal = pci_save_state(pDev);
+
+		if (iRetVal == 0) {
+			IOH_DEBUG
+			    ("ioh_spi_suspend pci_save_state returned=%d\n",
+			     iRetVal);
+			/*disable PM notifications */
+			pci_enable_wake(pDev, PCI_D3hot, 0);
+			IOH_DEBUG
+			    ("ioh_spi_suspend pci_enable_wake invoked\
+							 successfully\n");
+			/*disable PCI device */
+			pci_disable_device(pDev);
+			IOH_DEBUG
+			    ("ioh_spi_suspend pci_disable_device invoked\
+							 successfully\n");
+			/*move device to D3hot  state */
+			pci_set_power_state(pDev, PCI_D3hot);
+			IOH_DEBUG
+			    ("ioh_spi_suspend pci_set_power_state invoked\
+							 successfully\n");
+		} else {
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_suspend pci_save_state failed\n");
+		}
+	}
+
+	IOH_DEBUG("ioh_spi_suspend return=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+#endif
+/*! @ingroup	SPI_PCILayerAPI
+
+@fn				ioh_spi_resume(struct pci_dev *pDev)
+
+@brief			Implements the resume routine for IOH SPI driver
+
+@remarks		Implements the resume routine for IOH SPI driver
+
+				The major tasks performed by this method are:
+				- Move the device to D0 power state.
+				- Restore the saved state.
+				- Enable the PCI device.
+				- Disable PM notifications.
+				- Register interrupt handler.
+				- Reset IOH SPI hardware.
+				- Set IOH SPI hardware in master mode.
+
+@note		This function is invoked by the kernel when the system is being
+				resumed from suspend.
+
+@param		pDev	[@ref INOUT]	contains reference to struct pci_dev
+
+@retval			int
+		- @ref IOH_SPI_SUCCESS	The function returns successfully
+		- -EINVAL				request_irq fails
+		- -ENOMEM				request_irq fails
+		- -ENOSYS				request_irq fails
+		- -EBUSY				request_irq fails
+		- -EIO 					pci_enable_device fails
+
+@see			ioh_spi_pcidev
+
+<hr>
+
+*/
+#ifdef CONFIG_PM
+static int ioh_spi_resume(struct pci_dev *pDev)
+{
+	int i;
+	s32 iRetVal = IOH_SPI_SUCCESS;
+
+	struct ioh_spi_board_data *pBoardData = pci_get_drvdata(pDev);
+	IOH_DEBUG("ioh_spi_resume ENTRY\n");
+
+	if (pBoardData == NULL) {
+		IOH_LOG(KERN_ERR,
+			"ioh_spi_resume pci_get_drvdata returned NULL\n");
+		iRetVal = -EFAULT;
+	} else {
+		/*move device to DO power state */
+		pci_set_power_state(pDev, PCI_D0);
+		IOH_DEBUG
+		  ("ioh_spi_resume pci_set_power_state invoked successfully\n");
+
+		/*restore state */
+		pci_restore_state(pDev);
+		IOH_DEBUG
+		    ("ioh_spi_resume pci_restore_state invoked successfully\n");
+		iRetVal = pci_enable_device(pDev);
+		if (iRetVal < 0) {
+			IOH_LOG(KERN_ERR,
+				"ioh_spi_resume pci_enable_device failed\n");
+		} else {
+			IOH_DEBUG
+			    ("ioh_spi_resume pci_enable_device returned=%d\n",
+			     iRetVal);
+
+			/*disable PM notifications */
+			pci_enable_wake(pDev, PCI_D3hot, 0);
+			IOH_DEBUG
+			    ("ioh_spi_resume pci_enable_wake invoked\
+							 successfully\n");
+
+			/*register IRQ handler */
+
+			if ((pBoardData->bIrqRegistered) != true) {
+				/*register IRQ */
+				iRetVal = request_irq(pBoardData->pDev->irq,
+						 ioh_spi_handler, IRQF_SHARED,
+						 DRIVER_NAME,
+						 pBoardData);
+				if (iRetVal < 0) {
+					IOH_LOG(KERN_ERR,
+						"ioh_spi_resume\
+						 request_irq failed\n");
+				} else {
+					IOH_DEBUG
+					    ("ioh_spi_resume request_irq\
+							 returned=%d\n",
+					     iRetVal);
+					pBoardData->bIrqRegistered = true;
+
+					/*reset IOH SPI h/w */
+
+					for (i = 0; i < IOH_SPI_MAX_DEV; i++) {
+						ioh_spi_reset(pBoardData->
+							      pCtrlData[i]->
+							      pMaster);
+						IOH_DEBUG
+						    ("ioh_spi_resume\
+						 ioh_spi_reset invoked "
+						     "successfully \n");
+						ioh_spi_set_master_mode
+						    (pBoardData->pCtrlData[i]->
+						     pMaster);
+						IOH_DEBUG
+						    ("ioh_spi_resume\
+					 ioh_spi_set_master_mode invoked"
+						     "successfully \n");
+					}
+
+					/*set suspend status to false */
+					pBoardData->bSuspended = false;
+
+					IOH_DEBUG
+					    ("ioh_spi_resume set pBoardData->\
+						bSuspending = false\n");
+				}
+			}
+		}
+	}
+
+	IOH_DEBUG("ioh_spi_resume returning=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+#endif
+/*! @ingroup	SPI_PCILayerFacilitators
+
+@struct			ioh_spi_pcidev_id
+
+@brief			Store information of supported PCI devices
+
+@see			ioh_spi_pcidev
+
+<hr>
+
+*/
+
+static struct pci_device_id ioh_spi_pcidev_id[] = {
+	 /*LSI*/ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_IOH_SPI)},
+	{0,}
+
+};
+
+/*! @ingroup	SPI_PCILayerFacilitators
+
+@struct			ioh_spi_pcidev
+
+@brief			Store the references of PCI driver interfaces to kernel
+
+@note 			This structure is registerd with the kernel via the call
+				pci_register_driver	from @ref ioh_spi_init
+
+@see
+				- ioh_spi_init
+				- ioh_spi_exit
+
+<hr>
+
+*/
+
+static struct pci_driver ioh_spi_pcidev = {
+	.name = "ioh_spi",
+	.id_table = ioh_spi_pcidev_id,
+	.probe = ioh_spi_probe,
+	.remove = ioh_spi_remove,
+#ifdef CONFIG_PM
+	.suspend = ioh_spi_suspend,
+	.resume = ioh_spi_resume,
+#endif
+
+};
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+
+@fn				ioh_spi_init(void)
+
+@brief			Entry point function for this module.
+
+@remarks		Init function for IOH SPI driver module
+
+@param			None
+
+@retval		    int
+				- 0		Function exits successfully
+				- -EEXIST 	pci_register_driver fails
+				- -EINVAL	pci_register_driver fails
+				- -ENOMEM	pci_register_driver fails
+
+<hr>
+
+*/
+static int __init ioh_spi_init(void)
+{
+	s32 iRetVal;
+
+	iRetVal = pci_register_driver(&ioh_spi_pcidev);
+	if (iRetVal == 0) {
+		IOH_DEBUG
+		    ("ioh_spi_init pci_register_driver invoked successfully\n");
+	} else {
+		IOH_LOG(KERN_ERR, "ioh_spi_init pci_register_driver failed\n");
+	}
+
+	IOH_DEBUG("ioh_spi_init returning=%d\n", iRetVal);
+
+	return iRetVal;
+}
+
+/*! @ingroup	SPI_InterfaceLayerAPI
+
+@fn				ioh_spi_exit(void)
+
+@brief			Exit point function for this module.
+
+@remarks		Function invoked when module is removed
+
+@param			None
+
+@retval			None
+
+<hr>
+
+*/
+static void __exit ioh_spi_exit(void)
+{
+	IOH_DEBUG("ioh_spi_exit Invoking pci_unregister_driver\n");
+	pci_unregister_driver(&ioh_spi_pcidev);
+}
+
+MODULE_DESCRIPTION("IOH SPI PCI Driver");
+MODULE_LICENSE("GPL");
+module_init(ioh_spi_init);
+module_exit(ioh_spi_exit);
diff -urN linux-2.6.33-rc3/drivers/spi/pch_spi_platform_devices.c topcliff-2.6.33-rc3/drivers/spi/pch_spi_platform_devices.c
--- linux-2.6.33-rc3/drivers/spi/pch_spi_platform_devices.c	1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33-rc3/drivers/spi/pch_spi_platform_devices.c	2010-03-06 07:44:02.000000000 +0900
@@ -0,0 +1,50 @@
+#include <linux/module.h>
+#include <linux/spi/spidev.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+static struct spi_board_info ioh_spi_slaves[] = {
+	{
+	 .modalias = "spidev",	/* Name of spi_driver for this device*/
+	 .max_speed_hz = 1000000,	/* max spi clock (SCK) speed in HZ*/
+	 .bus_num = 0,		/* Framework bus number*/
+	 .chip_select = 0,	/* Framework chip select.*/
+	 .platform_data = NULL,
+	 .mode = SPI_MODE_0,
+	 },
+#if (CONFIG_PCH_SPI_PLATFORM_DEVICE_COUNT - 1)
+	{
+	 .modalias = "spidev",	/* Name of spi_driver for this device*/
+	 .max_speed_hz = 1000000,	/* max spi clock (SCK) speed in HZ*/
+	 .bus_num = 1,		/* Framework bus number*/
+	 .chip_select = 0,	/* Framework chip select.*/
+	 .platform_data = NULL,
+	 .mode = SPI_MODE_0,
+	 },
+#endif
+};
+
+static __init int Load(void)
+{
+	int iRetVal = -1;
+
+	printk(KERN_INFO "Registering IOH SPI devices... \n");
+
+	if (!spi_register_board_info
+	    (ioh_spi_slaves, ARRAY_SIZE(ioh_spi_slaves)))
+		iRetVal = 0;
+	else
+		printk(KERN_ERR "Registering IOH SPI devices failed\n");
+
+	return iRetVal;
+}
+
+/*
+ * static __exit void Unload()
+ * {
+ *
+ * }
+ * */
+
+module_init(Load);
+MODULE_LICENSE("GPL");
