From 239a368d5715d8f5b7733f9400339c2350c49369 Mon Sep 17 00:00:00 2001 From: Saul Wold Date: Fri, 24 Sep 2010 15:36:24 -0700 Subject: netbook: Correct netbook build by moving netbook configuration from moblin to meta Signed-off-by: Saul Wold --- .../linux-2.6.34-pch-spi.patch | 4377 ++++++++++++++++++++ 1 file changed, 4377 insertions(+) create mode 100644 meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-pch-spi.patch (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-pch-spi.patch') diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-pch-spi.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-pch-spi.patch new file mode 100644 index 000000000..43129c728 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-pch-spi.patch @@ -0,0 +1,4377 @@ +From: Masayuki Ohtake +Subject: OKI Semiconductor PCH SPI driver + +This driver implements SPI controls for PCH. + +Signed-off-by: Masayuki Ohtake +Acked-by: Wang Qi + +--- + 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. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @defgroup SPI_PCILayerFacilitators ++@ingroup SPI_PCILayer ++@brief This group contains the data structures used by the PCI ++ Layer APIs for their functionalities. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @defgroup SPI_InterfaceLayerFacilitators ++@ingroup SPI_InterfaceLayer ++@brief This group contains the data structures used by the Driver ++ interface APIs for their functionalities. ++
++*/ ++ ++/*! @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. ++
++*/ ++ ++/*! @defgroup SPI_UtilitiesAPI ++@ingroup SPI_Utilities ++@brief This group contains the APIs(functions) used by other functions ++ in their operations. ++
++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/*! @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 ++ ++
++*/ ++#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 ++ ++
++*/ ++#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 ++ ++
++*/ ++#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 ++ ++
++*/ ++#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 ++ ++
++*/ ++#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 ++ ++
++*/ ++#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 ++
++*/ ++ ++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 ++
++*/ ++ ++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 ++#include ++#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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++#include ++#include ++#include ++#include ++#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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++*/ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/*#include modify by checkpatch.pl*/ ++#include ++#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 ++ ++
++ ++*/ ++#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 ++ ++
++ ++*/ ++#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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++#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 ++ ++
++ ++*/ ++#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 ++ ++
++ ++*/ ++ ++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 ++ ++
++ ++*/ ++ ++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 ++ ++
++ ++*/ ++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 ++ ++
++ ++*/ ++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 ++#include ++#include ++#include ++ ++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"); -- cgit v1.2.3