summaryrefslogtreecommitdiff
path: root/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-spi.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-spi.patch')
-rw-r--r--meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-spi.patch4377
1 files changed, 4377 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-spi.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-spi.patch
new file mode 100644
index 000000000..43129c728
--- /dev/null
+++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-spi.patch
@@ -0,0 +1,4377 @@
+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");