aboutsummaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-03-14 14:44:45 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-03-14 14:44:45 -0800
commite5d80d56cbb9674181c3625fc3c9bcdbaa3fd5ec (patch)
treefd90bc50929eb457f93efb18a52cd9ecfa685ba0 /driver
parent180abda08ab8e841b0dfbad3afcffb656d75c220 (diff)
downloadpatches-e5d80d56cbb9674181c3625fc3c9bcdbaa3fd5ec.tar.gz
more patches and updates
Diffstat (limited to 'driver')
-rw-r--r--driver/get_cpu_sysdev-signedness-fix.patch43
-rw-r--r--driver/spi-add-pxa2xx-ssp-spi-driver.patch1773
-rw-r--r--driver/sysfs-crash-debugging.patch4
-rw-r--r--driver/sysfs-fix-problem-with-duplicate-sysfs-directories-and-files.patch2
4 files changed, 1819 insertions, 3 deletions
diff --git a/driver/get_cpu_sysdev-signedness-fix.patch b/driver/get_cpu_sysdev-signedness-fix.patch
new file mode 100644
index 0000000000000..f997163e016e8
--- /dev/null
+++ b/driver/get_cpu_sysdev-signedness-fix.patch
@@ -0,0 +1,43 @@
+From akpm@osdl.org Tue Mar 7 23:55:21 2006
+Message-Id: <200603080755.k287tEKn001163@shell0.pdx.osdl.net>
+From: Andrew Morton <akpm@osdl.org>
+Subject: get_cpu_sysdev() signedness fix
+To: greg@kroah.com
+Cc: akpm@osdl.org
+Date: Tue, 07 Mar 2006 23:53:25 -0800
+
+
+From: Andrew Morton <akpm@osdl.org>
+
+Doing (int < NR_CPUS) doesn't dtrt if it's negative..
+
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ drivers/base/cpu.c | 2 +-
+ include/linux/cpu.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/base/cpu.c
++++ gregkh-2.6/drivers/base/cpu.c
+@@ -141,7 +141,7 @@ int __devinit register_cpu(struct cpu *c
+ return error;
+ }
+
+-struct sys_device *get_cpu_sysdev(int cpu)
++struct sys_device *get_cpu_sysdev(unsigned cpu)
+ {
+ if (cpu < NR_CPUS)
+ return cpu_sys_devices[cpu];
+--- gregkh-2.6.orig/include/linux/cpu.h
++++ gregkh-2.6/include/linux/cpu.h
+@@ -32,7 +32,7 @@ struct cpu {
+ };
+
+ extern int register_cpu(struct cpu *, int, struct node *);
+-extern struct sys_device *get_cpu_sysdev(int cpu);
++extern struct sys_device *get_cpu_sysdev(unsigned cpu);
+ #ifdef CONFIG_HOTPLUG_CPU
+ extern void unregister_cpu(struct cpu *, struct node *);
+ #endif
diff --git a/driver/spi-add-pxa2xx-ssp-spi-driver.patch b/driver/spi-add-pxa2xx-ssp-spi-driver.patch
new file mode 100644
index 0000000000000..d8ebcc7d25c07
--- /dev/null
+++ b/driver/spi-add-pxa2xx-ssp-spi-driver.patch
@@ -0,0 +1,1773 @@
+From akpm@osdl.org Tue Mar 7 23:55:21 2006
+From: Stephen Street <stephen@streetfiresound.com>
+Message-Id: <200603080755.k287tDU7001158@shell0.pdx.osdl.net>
+Subject: SPI: add PXA2xx SSP SPI Driver
+To: greg@kroah.com
+Cc: akpm@osdl.org, stephen@streetfiresound.com
+Date: Tue, 07 Mar 2006 23:53:24 -0800
+
+
+From: Stephen Street <stephen@streetfiresound.com>
+
+This driver turns a PXA2xx synchronous serial port (SSP) into a SPI master
+controller (see Documentation/spi/spi_summary). The driver has the following
+features:
+
+- Support for any PXA2xx SSP
+- SSP PIO and SSP DMA data transfers.
+- External and Internal (SSPFRM) chip selects.
+- Per slave device (chip) configuration.
+- Full suspend, freeze, resume support.
+
+Signed-off-by: Stephen Street <stephen@streetfiresound.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Cc: David Brownell <david-b@pacbell.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+
+---
+ Documentation/spi/pxa2xx | 234 +++++
+ drivers/spi/Kconfig | 8
+ drivers/spi/Makefile | 1
+ drivers/spi/pxa2xx_spi.c | 1399 ++++++++++++++++++++++++++++++++++
+ include/asm-arm/arch-pxa/pxa2xx_spi.h | 68 +
+ 5 files changed, 1710 insertions(+)
+
+--- /dev/null
++++ gregkh-2.6/Documentation/spi/pxa2xx
+@@ -0,0 +1,234 @@
++PXA2xx SPI on SSP driver HOWTO
++===================================================
++This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx
++synchronous serial port into a SPI master controller
++(see Documentation/spi/spi_summary). The driver has the following features
++
++- Support for any PXA2xx SSP
++- SSP PIO and SSP DMA data transfers.
++- External and Internal (SSPFRM) chip selects.
++- Per slave device (chip) configuration.
++- Full suspend, freeze, resume support.
++
++The driver is built around a "spi_message" fifo serviced by workqueue and a
++tasklet. The workqueue, "pump_messages", drives message fifo and the tasklet
++(pump_transfer) is responsible for queuing SPI transactions and setting up and
++launching the dma/interrupt driven transfers.
++
++Declaring PXA2xx Master Controllers
++-----------------------------------
++Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
++"platform device". The master configuration is passed to the driver via a table
++found in include/asm-arm/arch-pxa/pxa2xx_spi.h:
++
++struct pxa2xx_spi_master {
++ enum pxa_ssp_type ssp_type;
++ u32 clock_enable;
++ u16 num_chipselect;
++ u8 enable_dma;
++};
++
++The "pxa2xx_spi_master.ssp_type" field must have a value between 1 and 3 and
++informs the driver which features a particular SSP supports.
++
++The "pxa2xx_spi_master.clock_enable" field is used to enable/disable the
++corresponding SSP peripheral block in the "Clock Enable Register (CKEN"). See
++the "PXA2xx Developer Manual" section "Clocks and Power Management".
++
++The "pxa2xx_spi_master.num_chipselect" field is used to determine the number of
++slave device (chips) attached to this SPI master.
++
++The "pxa2xx_spi_master.enable_dma" field informs the driver that SSP DMA should
++be used. This caused the driver to acquire two DMA channels: rx_channel and
++tx_channel. The rx_channel has a higher DMA service priority the tx_channel.
++See the "PXA2xx Developer Manual" section "DMA Controller".
++
++NSSP MASTER SAMPLE
++------------------
++Below is a sample configuration using the PXA255 NSSP.
++
++static struct resource pxa_spi_nssp_resources[] = {
++ [0] = {
++ .start = __PREG(SSCR0_P(2)), /* Start address of NSSP */
++ .end = __PREG(SSCR0_P(2)) + 0x2c, /* Range of registers */
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_NSSP, /* NSSP IRQ */
++ .end = IRQ_NSSP,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct pxa2xx_spi_master pxa_nssp_master_info = {
++ .ssp_type = PXA25x_NSSP, /* Type of SSP */
++ .clock_enable = CKEN9_NSSP, /* NSSP Peripheral clock */
++ .num_chipselect = 1, /* Matches the number of chips attached to NSSP */
++ .enable_dma = 1, /* Enables NSSP DMA */
++};
++
++static struct platform_device pxa_spi_nssp = {
++ .name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */
++ .id = 2, /* Bus number, MUST MATCH SSP number 1..n */
++ .resource = pxa_spi_nssp_resources,
++ .num_resources = ARRAY_SIZE(pxa_spi_nssp_resources),
++ .dev = {
++ .platform_data = &pxa_nssp_master_info, /* Passed to driver */
++ },
++};
++
++static struct platform_device *devices[] __initdata = {
++ &pxa_spi_nssp,
++};
++
++static void __init board_init(void)
++{
++ (void)platform_add_device(devices, ARRAY_SIZE(devices));
++}
++
++Declaring Slave Devices
++-----------------------
++Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c
++using the "spi_board_info" structure found in "linux/spi/spi.h". See
++"Documentation/spi/spi_summary" for additional information.
++
++Each slave device attached to the PXA must provide slave specific configuration
++information via the structure "pxa2xx_spi_chip" found in
++"include/asm-arm/arch-pxa/pxa2xx_spi.h". The pxa2xx_spi master controller driver
++will uses the configuration whenever the driver communicates with the slave
++device.
++
++struct pxa2xx_spi_chip {
++ u8 tx_threshold;
++ u8 rx_threshold;
++ u8 dma_burst_size;
++ u32 timeout_microsecs;
++ u8 enable_loopback;
++ void (*cs_control)(u32 command);
++};
++
++The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
++used to configure the SSP hardware fifo. These fields are critical to the
++performance of pxa2xx_spi driver and misconfiguration will result in rx
++fifo overruns (especially in PIO mode transfers). Good default values are
++
++ .tx_threshold = 12,
++ .rx_threshold = 4,
++
++The "pxa2xx_spi_chip.dma_burst_size" field is used to configure PXA2xx DMA
++engine and is related the "spi_device.bits_per_word" field. Read and understand
++the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
++to determine the correct value. An SSP configured for byte-wide transfers would
++use a value of 8.
++
++The "pxa2xx_spi_chip.timeout_microsecs" fields is used to efficiently handle
++trailing bytes in the SSP receiver fifo. The correct value for this field is
++dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
++slave device. Please note the the PXA2xx SSP 1 does not support trailing byte
++timeouts and must busy-wait any trailing bytes.
++
++The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting
++into internal loopback mode. In this mode the SSP controller internally
++connects the SSPTX pin the the SSPRX pin. This is useful for initial setup
++testing.
++
++The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
++function for asserting/deasserting a slave device chip select. If the field is
++NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
++configured to use SSPFRM instead.
++
++NSSP SALVE SAMPLE
++-----------------
++The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the
++"spi_board_info.controller_data" field. Below is a sample configuration using
++the PXA255 NSSP.
++
++/* Chip Select control for the CS8415A SPI slave device */
++static void cs8415a_cs_control(u32 command)
++{
++ if (command & PXA2XX_CS_ASSERT)
++ GPCR(2) = GPIO_bit(2);
++ else
++ GPSR(2) = GPIO_bit(2);
++}
++
++/* Chip Select control for the CS8405A SPI slave device */
++static void cs8405a_cs_control(u32 command)
++{
++ if (command & PXA2XX_CS_ASSERT)
++ GPCR(3) = GPIO_bit(3);
++ else
++ GPSR(3) = GPIO_bit(3);
++}
++
++static struct pxa2xx_spi_chip cs8415a_chip_info = {
++ .tx_threshold = 12, /* SSP hardward FIFO threshold */
++ .rx_threshold = 4, /* SSP hardward FIFO threshold */
++ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
++ .timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
++ .cs_control = cs8415a_cs_control, /* Use external chip select */
++};
++
++static struct pxa2xx_spi_chip cs8405a_chip_info = {
++ .tx_threshold = 12, /* SSP hardward FIFO threshold */
++ .rx_threshold = 4, /* SSP hardward FIFO threshold */
++ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
++ .timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
++ .cs_control = cs8405a_cs_control, /* Use external chip select */
++};
++
++static struct spi_board_info streetracer_spi_board_info[] __initdata = {
++ {
++ .modalias = "cs8415a", /* Name of spi_driver for this device */
++ .max_speed_hz = 3686400, /* Run SSP as fast a possbile */
++ .bus_num = 2, /* Framework bus number */
++ .chip_select = 0, /* Framework chip select */
++ .platform_data = NULL; /* No spi_driver specific config */
++ .controller_data = &cs8415a_chip_info, /* Master chip config */
++ .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */
++ },
++ {
++ .modalias = "cs8405a", /* Name of spi_driver for this device */
++ .max_speed_hz = 3686400, /* Run SSP as fast a possbile */
++ .bus_num = 2, /* Framework bus number */
++ .chip_select = 1, /* Framework chip select */
++ .controller_data = &cs8405a_chip_info, /* Master chip config */
++ .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */
++ },
++};
++
++static void __init streetracer_init(void)
++{
++ spi_register_board_info(streetracer_spi_board_info,
++ ARRAY_SIZE(streetracer_spi_board_info));
++}
++
++
++DMA and PIO I/O Support
++-----------------------
++The pxa2xx_spi driver support both DMA and interrupt driven PIO message
++transfers. The driver defaults to PIO mode and DMA transfers must enabled by
++setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and and
++ensuring that the "pxa2xx_spi_chip.dma_burst_size" field is non-zero. The DMA
++mode support both coherent and stream based DMA mappings.
++
++The following logic is used to determine the type of I/O to be used on
++a per "spi_transfer" basis:
++
++if !enable_dma or dma_burst_size == 0 then
++ always use PIO transfers
++
++if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then
++ use coherent DMA mode
++
++if rx_buf and tx_buf are aligned on 8 byte boundary then
++ use streaming DMA mode
++
++otherwise
++ use PIO transfer
++
++THANKS TO
++---------
++
++David Brownell and others for mentoring the development of this driver.
++
+--- gregkh-2.6.orig/drivers/spi/Kconfig
++++ gregkh-2.6/drivers/spi/Kconfig
+@@ -75,6 +75,14 @@ config SPI_BUTTERFLY
+ inexpensive battery powered microcontroller evaluation board.
+ This same cable can be used to flash new firmware.
+
++config SPI_PXA2XX
++ tristate "PXA2xx SSP SPI master"
++ depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
++ help
++ This enables using a PXA2xx SSP port as a SPI master controller.
++ The driver can be configured to use any SSP port and additional
++ documentation can be found a Documentation/spi/pxa2xx.
++
+ #
+ # Add new SPI master controllers in alphabetical order above this line
+ #
+--- gregkh-2.6.orig/drivers/spi/Makefile
++++ gregkh-2.6/drivers/spi/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o
+ # SPI master controller drivers (bus)
+ obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
+ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
++obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
+ # ... add above this line ...
+
+ # SPI protocol drivers (device/link on bus)
+--- /dev/null
++++ gregkh-2.6/drivers/spi/pxa2xx_spi.c
+@@ -0,0 +1,1399 @@
++/*
++ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
++ *
++ * 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; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/ioport.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/spi/spi.h>
++#include <linux/workqueue.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/delay.h>
++#include <asm/dma.h>
++
++#include <asm/arch/hardware.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/pxa2xx_spi.h>
++
++MODULE_AUTHOR("Stephen Street");
++MODULE_DESCRIPTION("PXA2xx SSP SPI Contoller");
++MODULE_LICENSE("GPL");
++
++#define MAX_BUSES 3
++
++#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
++#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
++#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
++
++#define DEFINE_SSP_REG(reg, off) \
++static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
++static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
++
++DEFINE_SSP_REG(SSCR0, 0x00)
++DEFINE_SSP_REG(SSCR1, 0x04)
++DEFINE_SSP_REG(SSSR, 0x08)
++DEFINE_SSP_REG(SSITR, 0x0c)
++DEFINE_SSP_REG(SSDR, 0x10)
++DEFINE_SSP_REG(SSTO, 0x28)
++DEFINE_SSP_REG(SSPSP, 0x2c)
++
++#define START_STATE ((void*)0)
++#define RUNNING_STATE ((void*)1)
++#define DONE_STATE ((void*)2)
++#define ERROR_STATE ((void*)-1)
++
++#define QUEUE_RUNNING 0
++#define QUEUE_STOPPED 1
++
++struct driver_data {
++ /* Driver model hookup */
++ struct platform_device *pdev;
++
++ /* SPI framework hookup */
++ enum pxa_ssp_type ssp_type;
++ struct spi_master *master;
++
++ /* PXA hookup */
++ struct pxa2xx_spi_master *master_info;
++
++ /* DMA setup stuff */
++ int rx_channel;
++ int tx_channel;
++ u32 *null_dma_buf;
++
++ /* SSP register addresses */
++ void *ioaddr;
++ u32 ssdr_physical;
++
++ /* SSP masks*/
++ u32 dma_cr1;
++ u32 int_cr1;
++ u32 clear_sr;
++ u32 mask_sr;
++
++ /* Driver message queue */
++ struct workqueue_struct *workqueue;
++ struct work_struct pump_messages;
++ spinlock_t lock;
++ struct list_head queue;
++ int busy;
++ int run;
++
++ /* Message Transfer pump */
++ struct tasklet_struct pump_transfers;
++
++ /* Current message transfer state info */
++ struct spi_message* cur_msg;
++ struct spi_transfer* cur_transfer;
++ struct chip_data *cur_chip;
++ size_t len;
++ void *tx;
++ void *tx_end;
++ void *rx;
++ void *rx_end;
++ int dma_mapped;
++ dma_addr_t rx_dma;
++ dma_addr_t tx_dma;
++ size_t rx_map_len;
++ size_t tx_map_len;
++ int cs_change;
++ void (*write)(struct driver_data *drv_data);
++ void (*read)(struct driver_data *drv_data);
++ irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
++ void (*cs_control)(u32 command);
++};
++
++struct chip_data {
++ u32 cr0;
++ u32 cr1;
++ u32 to;
++ u32 psp;
++ u32 timeout;
++ u8 n_bytes;
++ u32 dma_width;
++ u32 dma_burst_size;
++ u32 threshold;
++ u32 dma_threshold;
++ u8 enable_dma;
++ void (*write)(struct driver_data *drv_data);
++ void (*read)(struct driver_data *drv_data);
++ void (*cs_control)(u32 command);
++};
++
++static void pump_messages(void *data);
++
++static int flush(struct driver_data *drv_data)
++{
++ unsigned long limit = loops_per_jiffy << 1;
++
++ void *reg = drv_data->ioaddr;
++
++ do {
++ while (read_SSSR(reg) & SSSR_RNE) {
++ read_SSDR(reg);
++ }
++ } while ((read_SSSR(reg) & SSSR_BSY) && limit--);
++ write_SSSR(SSSR_ROR, reg);
++
++ return limit;
++}
++
++static void restore_state(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ /* Clear status and disable clock */
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR0(drv_data->cur_chip->cr0 & ~SSCR0_SSE, reg);
++
++ /* Load the registers */
++ write_SSCR1(drv_data->cur_chip->cr1, reg);
++ write_SSCR0(drv_data->cur_chip->cr0, reg);
++ if (drv_data->ssp_type != PXA25x_SSP) {
++ write_SSTO(0, reg);
++ write_SSPSP(drv_data->cur_chip->psp, reg);
++ }
++}
++
++static void null_cs_control(u32 command)
++{
++}
++
++static void null_writer(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++ u8 n_bytes = drv_data->cur_chip->n_bytes;
++
++ while ((read_SSSR(reg) & SSSR_TNF)
++ && (drv_data->tx < drv_data->tx_end)) {
++ write_SSDR(0, reg);
++ drv_data->tx += n_bytes;
++ }
++}
++
++static void null_reader(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++ u8 n_bytes = drv_data->cur_chip->n_bytes;
++
++ while ((read_SSSR(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ read_SSDR(reg);
++ drv_data->rx += n_bytes;
++ }
++}
++
++static void u8_writer(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ while ((read_SSSR(reg) & SSSR_TNF)
++ && (drv_data->tx < drv_data->tx_end)) {
++ write_SSDR(*(u8 *)(drv_data->tx), reg);
++ ++drv_data->tx;
++ }
++}
++
++static void u8_reader(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ while ((read_SSSR(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ *(u8 *)(drv_data->rx) = read_SSDR(reg);
++ ++drv_data->rx;
++ }
++}
++
++static void u16_writer(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ while ((read_SSSR(reg) & SSSR_TNF)
++ && (drv_data->tx < drv_data->tx_end)) {
++ write_SSDR(*(u16 *)(drv_data->tx), reg);
++ drv_data->tx += 2;
++ }
++}
++
++static void u16_reader(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ while ((read_SSSR(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ *(u16 *)(drv_data->rx) = read_SSDR(reg);
++ drv_data->rx += 2;
++ }
++}
++static void u32_writer(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ while ((read_SSSR(reg) & SSSR_TNF)
++ && (drv_data->tx < drv_data->tx_end)) {
++ write_SSDR(*(u16 *)(drv_data->tx), reg);
++ drv_data->tx += 4;
++ }
++}
++
++static void u32_reader(struct driver_data *drv_data)
++{
++ void *reg = drv_data->ioaddr;
++
++ while ((read_SSSR(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ *(u32 *)(drv_data->rx) = read_SSDR(reg);
++ drv_data->rx += 4;
++ }
++}
++
++static void *next_transfer(struct driver_data *drv_data)
++{
++ struct spi_message *msg = drv_data->cur_msg;
++ struct spi_transfer *trans = drv_data->cur_transfer;
++
++ /* Move to next transfer */
++ if (trans->transfer_list.next != &msg->transfers) {
++ drv_data->cur_transfer =
++ list_entry(trans->transfer_list.next,
++ struct spi_transfer,
++ transfer_list);
++ return RUNNING_STATE;
++ } else
++ return DONE_STATE;
++}
++
++static int map_dma_buffers(struct driver_data *drv_data)
++{
++ struct spi_message *msg = drv_data->cur_msg;
++ struct device *dev = &msg->spi->dev;
++
++ if (!drv_data->cur_chip->enable_dma)
++ return 0;
++
++ if (msg->is_dma_mapped)
++ return drv_data->rx_dma && drv_data->tx_dma;
++
++ if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
++ return 0;
++
++ /* Modify setup if rx buffer is null */
++ if (drv_data->rx == NULL) {
++ *drv_data->null_dma_buf = 0;
++ drv_data->rx = drv_data->null_dma_buf;
++ drv_data->rx_map_len = 4;
++ } else
++ drv_data->rx_map_len = drv_data->len;
++
++
++ /* Modify setup if tx buffer is null */
++ if (drv_data->tx == NULL) {
++ *drv_data->null_dma_buf = 0;
++ drv_data->tx = drv_data->null_dma_buf;
++ drv_data->tx_map_len = 4;
++ } else
++ drv_data->tx_map_len = drv_data->len;
++
++ /* Stream map the rx buffer */
++ drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
++ drv_data->rx_map_len,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(drv_data->rx_dma))
++ return 0;
++
++ /* Stream map the tx buffer */
++ drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
++ drv_data->tx_map_len,
++ DMA_TO_DEVICE);
++
++ if (dma_mapping_error(drv_data->tx_dma)) {
++ dma_unmap_single(dev, drv_data->rx_dma,
++ drv_data->rx_map_len, DMA_FROM_DEVICE);
++ return 0;
++ }
++
++ return 1;
++}
++
++static void unmap_dma_buffers(struct driver_data *drv_data)
++{
++ struct device *dev;
++
++ if (!drv_data->dma_mapped)
++ return;
++
++ if (!drv_data->cur_msg->is_dma_mapped) {
++ dev = &drv_data->cur_msg->spi->dev;
++ dma_unmap_single(dev, drv_data->rx_dma,
++ drv_data->rx_map_len, DMA_FROM_DEVICE);
++ dma_unmap_single(dev, drv_data->tx_dma,
++ drv_data->tx_map_len, DMA_TO_DEVICE);
++ }
++
++ drv_data->dma_mapped = 0;
++}
++
++/* caller already set message->status; dma and pio irqs are blocked */
++static void giveback(struct spi_message *message, struct driver_data *drv_data)
++{
++ struct spi_transfer* last_transfer;
++
++ last_transfer = list_entry(message->transfers.prev,
++ struct spi_transfer,
++ transfer_list);
++
++ if (!last_transfer->cs_change)
++ drv_data->cs_control(PXA2XX_CS_DEASSERT);
++
++ message->state = NULL;
++ if (message->complete)
++ message->complete(message->context);
++
++ drv_data->cur_msg = NULL;
++ drv_data->cur_transfer = NULL;
++ drv_data->cur_chip = NULL;
++ queue_work(drv_data->workqueue, &drv_data->pump_messages);
++}
++
++static int wait_ssp_rx_stall(void *ioaddr)
++{
++ unsigned long limit = loops_per_jiffy << 1;
++
++ while ((read_SSSR(ioaddr) & SSSR_BSY) && limit--)
++ cpu_relax();
++
++ return limit;
++}
++
++static int wait_dma_channel_stop(int channel)
++{
++ unsigned long limit = loops_per_jiffy << 1;
++
++ while (!(DCSR(channel) & DCSR_STOPSTATE) && limit--)
++ cpu_relax();
++
++ return limit;
++}
++
++static void dma_handler(int channel, void *data, struct pt_regs *regs)
++{
++ struct driver_data *drv_data = data;
++ struct spi_message *msg = drv_data->cur_msg;
++ void *reg = drv_data->ioaddr;
++ u32 irq_status = DCSR(channel) & DMA_INT_MASK;
++ u32 trailing_sssr = 0;
++
++ if (irq_status & DCSR_BUSERR) {
++
++ /* Disable interrupts, clear status and reset DMA */
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(0, reg);
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
++ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
++ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
++
++ if (flush(drv_data) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "dma_handler: flush fail\n");
++
++ unmap_dma_buffers(drv_data);
++
++ if (channel == drv_data->tx_channel)
++ dev_err(&drv_data->pdev->dev,
++ "dma_handler: bad bus address on "
++ "tx channel %d, source %x target = %x\n",
++ channel, DSADR(channel), DTADR(channel));
++ else
++ dev_err(&drv_data->pdev->dev,
++ "dma_handler: bad bus address on "
++ "rx channel %d, source %x target = %x\n",
++ channel, DSADR(channel), DTADR(channel));
++
++ msg->state = ERROR_STATE;
++ tasklet_schedule(&drv_data->pump_transfers);
++ }
++
++ /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
++ if ((drv_data->ssp_type == PXA25x_SSP)
++ && (channel == drv_data->tx_channel)
++ && (irq_status & DCSR_ENDINTR)) {
++
++ /* Wait for rx to stall */
++ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "dma_handler: ssp rx stall failed\n");
++
++ /* Clear and disable interrupts on SSP and DMA channels*/
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
++ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
++ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
++ if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "dma_handler: dma rx channel stop failed\n");
++
++ unmap_dma_buffers(drv_data);
++
++ /* Read trailing bytes */
++ /* Calculate number of trailing bytes, read them */
++ trailing_sssr = read_SSSR(reg);
++ if ((trailing_sssr & 0xf008) != 0xf000) {
++ drv_data->rx = drv_data->rx_end -
++ (((trailing_sssr >> 12) & 0x0f) + 1);
++ drv_data->read(drv_data);
++ }
++ msg->actual_length += drv_data->len;
++
++ /* Release chip select if requested, transfer delays are
++ * handled in pump_transfers */
++ if (drv_data->cs_change)
++ drv_data->cs_control(PXA2XX_CS_DEASSERT);
++
++ /* Move to next transfer */
++ msg->state = next_transfer(drv_data);
++
++ /* Schedule transfer tasklet */
++ tasklet_schedule(&drv_data->pump_transfers);
++ }
++}
++
++static irqreturn_t dma_transfer(struct driver_data *drv_data)
++{
++ u32 irq_status;
++ u32 trailing_sssr = 0;
++ struct spi_message *msg = drv_data->cur_msg;
++ void *reg = drv_data->ioaddr;
++
++ irq_status = read_SSSR(reg) & drv_data->mask_sr;
++ if (irq_status & SSSR_ROR) {
++ /* Clear and disable interrupts on SSP and DMA channels*/
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(0, reg);
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
++ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
++ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
++ unmap_dma_buffers(drv_data);
++
++ if (flush(drv_data) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "dma_transfer: flush fail\n");
++
++ dev_warn(&drv_data->pdev->dev, "dma_transfer: fifo overun\n");
++
++ drv_data->cur_msg->state = ERROR_STATE;
++ tasklet_schedule(&drv_data->pump_transfers);
++
++ return IRQ_HANDLED;
++ }
++
++ /* Check for false positive timeout */
++ if ((irq_status & SSSR_TINT) && DCSR(drv_data->tx_channel) & DCSR_RUN) {
++ write_SSSR(SSSR_TINT, reg);
++ return IRQ_HANDLED;
++ }
++
++ if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
++
++ /* Clear and disable interrupts on SSP and DMA channels*/
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(0, reg);
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
++ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
++ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
++
++ if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "dma_transfer: dma rx channel stop failed\n");
++
++ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "dma_transfer: ssp rx stall failed\n");
++
++ unmap_dma_buffers(drv_data);
++
++ /* Calculate number of trailing bytes, read them */
++ trailing_sssr = read_SSSR(reg);
++ if ((trailing_sssr & 0xf008) != 0xf000) {
++ drv_data->rx = drv_data->rx_end -
++ (((trailing_sssr >> 12) & 0x0f) + 1);
++ drv_data->read(drv_data);
++ }
++ msg->actual_length += drv_data->len;
++
++ /* Release chip select if requested, transfer delays are
++ * handled in pump_transfers */
++ if (drv_data->cs_change)
++ drv_data->cs_control(PXA2XX_CS_DEASSERT);
++
++ /* Move to next transfer */
++ msg->state = next_transfer(drv_data);
++
++ /* Schedule transfer tasklet */
++ tasklet_schedule(&drv_data->pump_transfers);
++
++ return IRQ_HANDLED;
++ }
++
++ /* Opps problem detected */
++ return IRQ_NONE;
++}
++
++static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
++{
++ u32 irq_status;
++ struct spi_message *msg = drv_data->cur_msg;
++ void *reg = drv_data->ioaddr;
++ irqreturn_t handled = IRQ_NONE;
++ unsigned long limit = loops_per_jiffy << 1;
++
++ while ((irq_status = (read_SSSR(reg) & drv_data->mask_sr))) {
++
++ if (irq_status & SSSR_ROR) {
++
++ /* Clear and disable interrupts */
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(0, reg);
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
++
++ if (flush(drv_data) == 0)
++ dev_err(&drv_data->pdev->dev,
++ "interrupt_transfer: flush fail\n");
++
++ dev_warn(&drv_data->pdev->dev,
++ "interrupt_transfer: fifo overun\n");
++
++ msg->state = ERROR_STATE;
++ tasklet_schedule(&drv_data->pump_transfers);
++
++ return IRQ_HANDLED;
++ }
++
++ /* Look for false positive timeout */
++ if ((irq_status & SSSR_TINT)
++ && (drv_data->rx < drv_data->rx_end))
++ write_SSSR(SSSR_TINT, reg);
++
++ /* Pump data */
++ drv_data->read(drv_data);
++ drv_data->write(drv_data);
++
++ if (drv_data->tx == drv_data->tx_end) {
++ /* Disable tx interrupt */
++ write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
++
++ /* PXA25x_SSP has no timeout, read trailing bytes */
++ if (drv_data->ssp_type == PXA25x_SSP) {
++ while ((read_SSSR(reg) & SSSR_BSY) && limit--)
++ drv_data->read(drv_data);
++
++ if (limit == 0)
++ dev_err(&drv_data->pdev->dev,
++ "interrupt_transfer: "
++ "trailing byte read failed\n");
++ }
++ }
++
++ if ((irq_status & SSSR_TINT)
++ || (drv_data->rx == drv_data->rx_end)) {
++
++ /* Clear timeout */
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(0, reg);
++ write_SSSR(drv_data->clear_sr, reg);
++ write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
++
++ /* Update total byte transfered */
++ msg->actual_length += drv_data->len;
++
++ /* Release chip select if requested, transfer delays are
++ * handled in pump_transfers */
++ if (drv_data->cs_change)
++ drv_data->cs_control(PXA2XX_CS_DEASSERT);
++
++ /* Move to next transfer */
++ msg->state = next_transfer(drv_data);
++
++ /* Schedule transfer tasklet */
++ tasklet_schedule(&drv_data->pump_transfers);
++
++ return IRQ_HANDLED;
++ }
++
++ /* We did something */
++ handled = IRQ_HANDLED;
++ }
++
++ return handled;
++}
++
++static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct driver_data *drv_data = (struct driver_data *)dev_id;
++
++ if (!drv_data->cur_msg) {
++ dev_err(&drv_data->pdev->dev, "bad message state "
++ "in interrupt handler\n");
++ /* Never fail */
++ return IRQ_HANDLED;
++ }
++
++ return drv_data->transfer_handler(drv_data);
++}
++
++static void pump_transfers(unsigned long data)
++{
++ struct driver_data *drv_data = (struct driver_data *)data;
++ struct spi_message *message = NULL;
++ struct spi_transfer *transfer = NULL;
++ struct spi_transfer *previous = NULL;
++ struct chip_data *chip = NULL;
++ void *reg = drv_data->ioaddr;
++
++ /* Get current state information */
++ message = drv_data->cur_msg;
++ transfer = drv_data->cur_transfer;
++ chip = drv_data->cur_chip;
++
++ /* Handle for abort */
++ if (message->state == ERROR_STATE) {
++ message->status = -EIO;
++ giveback(message, drv_data);
++ return;
++ }
++
++ /* Handle end of message */
++ if (message->state == DONE_STATE) {
++ message->status = 0;
++ giveback(message, drv_data);
++ return;
++ }
++
++ /* Delay if requested at end of transfer*/
++ if (message->state == RUNNING_STATE) {
++ previous = list_entry(transfer->transfer_list.prev,
++ struct spi_transfer,
++ transfer_list);
++ if (previous->delay_usecs)
++ udelay(previous->delay_usecs);
++ }
++
++ /* Setup the transfer state based on the type of transfer */
++ if (flush(drv_data) == 0) {
++ dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
++ message->status = -EIO;
++ giveback(message, drv_data);
++ return;
++ }
++ drv_data->cs_control = chip->cs_control;
++ drv_data->tx = (void *)transfer->tx_buf;
++ drv_data->tx_end = drv_data->tx + transfer->len;
++ drv_data->rx = transfer->rx_buf;
++ drv_data->rx_end = drv_data->rx + transfer->len;
++ drv_data->rx_dma = transfer->rx_dma;
++ drv_data->tx_dma = transfer->tx_dma;
++ drv_data->len = transfer->len;
++ drv_data->write = drv_data->tx ? chip->write : null_writer;
++ drv_data->read = drv_data->rx ? chip->read : null_reader;
++ drv_data->cs_change = transfer->cs_change;
++ message->state = RUNNING_STATE;
++
++ /* Try to map dma buffer and do a dma transfer if successful */
++ if ((drv_data->dma_mapped = map_dma_buffers(drv_data))) {
++
++ /* Ensure we have the correct interrupt handler */
++ drv_data->transfer_handler = dma_transfer;
++
++ /* Setup rx DMA Channel */
++ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
++ DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
++ DTADR(drv_data->rx_channel) = drv_data->rx_dma;
++ if (drv_data->rx == drv_data->null_dma_buf)
++ /* No target address increment */
++ DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
++ | chip->dma_width
++ | chip->dma_burst_size
++ | drv_data->len;
++ else
++ DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
++ | DCMD_FLOWSRC
++ | chip->dma_width
++ | chip->dma_burst_size
++ | drv_data->len;
++
++ /* Setup tx DMA Channel */
++ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
++ DSADR(drv_data->tx_channel) = drv_data->tx_dma;
++ DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
++ if (drv_data->tx == drv_data->null_dma_buf)
++ /* No source address increment */
++ DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
++ | chip->dma_width
++ | chip->dma_burst_size
++ | drv_data->len;
++ else
++ DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
++ | DCMD_FLOWTRG
++ | chip->dma_width
++ | chip->dma_burst_size
++ | drv_data->len;
++
++ /* Enable dma end irqs on SSP to detect end of transfer */
++ if (drv_data->ssp_type == PXA25x_SSP)
++ DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
++
++ /* Fix me, need to handle cs polarity */
++ drv_data->cs_control(PXA2XX_CS_ASSERT);
++
++ /* Go baby, go */
++ write_SSSR(drv_data->clear_sr, reg);
++ DCSR(drv_data->rx_channel) |= DCSR_RUN;
++ DCSR(drv_data->tx_channel) |= DCSR_RUN;
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(chip->timeout, reg);
++ write_SSCR1(chip->cr1
++ | chip->dma_threshold
++ | drv_data->dma_cr1,
++ reg);
++ } else {
++ /* Ensure we have the correct interrupt handler */
++ drv_data->transfer_handler = interrupt_transfer;
++
++ /* Fix me, need to handle cs polarity */
++ drv_data->cs_control(PXA2XX_CS_ASSERT);
++
++ /* Go baby, go */
++ write_SSSR(drv_data->clear_sr, reg);
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(chip->timeout, reg);
++ write_SSCR1(chip->cr1
++ | chip->threshold
++ | drv_data->int_cr1,
++ reg);
++ }
++}
++
++static void pump_messages(void *data)
++{
++ struct driver_data *drv_data = data;
++ unsigned long flags;
++
++ /* Lock queue and check for queue work */
++ spin_lock_irqsave(&drv_data->lock, flags);
++ if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
++ drv_data->busy = 0;
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++ return;
++ }
++
++ /* Make sure we are not already running a message */
++ if (drv_data->cur_msg) {
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++ return;
++ }
++
++ /* Extract head of queue */
++ drv_data->cur_msg = list_entry(drv_data->queue.next,
++ struct spi_message, queue);
++ list_del_init(&drv_data->cur_msg->queue);
++ drv_data->busy = 1;
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++
++ /* Initial message state*/
++ drv_data->cur_msg->state = START_STATE;
++ drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
++ struct spi_transfer,
++ transfer_list);
++
++ /* Setup the SSP using the per chip configuration */
++ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
++ restore_state(drv_data);
++
++ /* Mark as busy and launch transfers */
++ tasklet_schedule(&drv_data->pump_transfers);
++}
++
++static int transfer(struct spi_device *spi, struct spi_message *msg)
++{
++ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
++ unsigned long flags;
++
++ spin_lock_irqsave(&drv_data->lock, flags);
++
++ if (drv_data->run == QUEUE_STOPPED) {
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++ return -ESHUTDOWN;
++ }
++
++ msg->actual_length = 0;
++ msg->status = -EINPROGRESS;
++ msg->state = START_STATE;
++
++ list_add_tail(&msg->queue, &drv_data->queue);
++
++ if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
++ queue_work(drv_data->workqueue, &drv_data->pump_messages);
++
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++
++ return 0;
++}
++
++static int setup(struct spi_device *spi)
++{
++ struct pxa2xx_spi_chip *chip_info = NULL;
++ struct chip_data *chip;
++ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
++ unsigned int clk_div;
++
++ if (!spi->bits_per_word)
++ spi->bits_per_word = 8;
++
++ if (drv_data->ssp_type != PXA25x_SSP
++ && (spi->bits_per_word < 4 || spi->bits_per_word > 32))
++ return -EINVAL;
++ else if (spi->bits_per_word < 4 || spi->bits_per_word > 16)
++ return -EINVAL;
++
++ /* Only alloc (or use chip_info) on first setup */
++ chip = spi_get_ctldata(spi);
++ if (chip == NULL) {
++ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
++ if (!chip)
++ return -ENOMEM;
++
++ chip->cs_control = null_cs_control;
++ chip->enable_dma = 0;
++ chip->timeout = 5;
++ chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
++ chip->dma_burst_size = drv_data->master_info->enable_dma ?
++ DCMD_BURST8 : 0;
++
++ chip_info = spi->controller_data;
++ }
++
++ /* chip_info isn't always needed */
++ if (chip_info) {
++ if (chip_info->cs_control)
++ chip->cs_control = chip_info->cs_control;
++
++ chip->timeout = (chip_info->timeout_microsecs * 10000) / 2712;
++
++ chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold)
++ | SSCR1_TxTresh(chip_info->tx_threshold);
++
++ chip->enable_dma = chip_info->dma_burst_size != 0
++ && drv_data->master_info->enable_dma;
++ chip->dma_threshold = 0;
++
++ if (chip->enable_dma) {
++ if (chip_info->dma_burst_size <= 8) {
++ chip->dma_threshold = SSCR1_RxTresh(8)
++ | SSCR1_TxTresh(8);
++ chip->dma_burst_size = DCMD_BURST8;
++ } else if (chip_info->dma_burst_size <= 16) {
++ chip->dma_threshold = SSCR1_RxTresh(16)
++ | SSCR1_TxTresh(16);
++ chip->dma_burst_size = DCMD_BURST16;
++ } else {
++ chip->dma_threshold = SSCR1_RxTresh(32)
++ | SSCR1_TxTresh(32);
++ chip->dma_burst_size = DCMD_BURST32;
++ }
++ }
++
++
++ if (chip_info->enable_loopback)
++ chip->cr1 = SSCR1_LBM;
++ }
++
++ if (drv_data->ioaddr == SSP1_VIRT)
++ clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
++ else if (drv_data->ioaddr == SSP2_VIRT)
++ clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
++ else if (drv_data->ioaddr == SSP3_VIRT)
++ clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
++ else
++ return -ENODEV;
++
++ chip->cr0 = clk_div
++ | SSCR0_Motorola
++ | SSCR0_DataSize(spi->bits_per_word & 0x0f)
++ | SSCR0_SSE
++ | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
++ chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4)
++ | (((spi->mode & SPI_CPOL) != 0) << 3);
++
++ /* NOTE: PXA25x_SSP _could_ use external clocking ... */
++ if (drv_data->ssp_type != PXA25x_SSP)
++ dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
++ spi->bits_per_word,
++ (CLOCK_SPEED_HZ)
++ / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
++ spi->mode & 0x3);
++ else
++ dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
++ spi->bits_per_word,
++ (CLOCK_SPEED_HZ/2)
++ / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
++ spi->mode & 0x3);
++
++ if (spi->bits_per_word <= 8) {
++ chip->n_bytes = 1;
++ chip->dma_width = DCMD_WIDTH1;
++ chip->read = u8_reader;
++ chip->write = u8_writer;
++ } else if (spi->bits_per_word <= 16) {
++ chip->n_bytes = 2;
++ chip->dma_width = DCMD_WIDTH2;
++ chip->read = u16_reader;
++ chip->write = u16_writer;
++ } else if (spi->bits_per_word <= 32) {
++ chip->cr0 |= SSCR0_EDSS;
++ chip->n_bytes = 4;
++ chip->dma_width = DCMD_WIDTH4;
++ chip->read = u32_reader;
++ chip->write = u32_writer;
++ } else {
++ dev_err(&spi->dev, "invalid wordsize\n");
++ kfree(chip);
++ return -ENODEV;
++ }
++
++ spi_set_ctldata(spi, chip);
++
++ return 0;
++}
++
++static void cleanup(const struct spi_device *spi)
++{
++ struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
++
++ kfree(chip);
++}
++
++static int init_queue(struct driver_data *drv_data)
++{
++ INIT_LIST_HEAD(&drv_data->queue);
++ spin_lock_init(&drv_data->lock);
++
++ drv_data->run = QUEUE_STOPPED;
++ drv_data->busy = 0;
++
++ tasklet_init(&drv_data->pump_transfers,
++ pump_transfers, (unsigned long)drv_data);
++
++ INIT_WORK(&drv_data->pump_messages, pump_messages, drv_data);
++ drv_data->workqueue = create_singlethread_workqueue(
++ drv_data->master->cdev.dev->bus_id);
++ if (drv_data->workqueue == NULL)
++ return -EBUSY;
++
++ return 0;
++}
++
++static int start_queue(struct driver_data *drv_data)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&drv_data->lock, flags);
++
++ if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++ return -EBUSY;
++ }
++
++ drv_data->run = QUEUE_RUNNING;
++ drv_data->cur_msg = NULL;
++ drv_data->cur_transfer = NULL;
++ drv_data->cur_chip = NULL;
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++
++ queue_work(drv_data->workqueue, &drv_data->pump_messages);
++
++ return 0;
++}
++
++static int stop_queue(struct driver_data *drv_data)
++{
++ unsigned long flags;
++ unsigned limit = 500;
++ int status = 0;
++
++ spin_lock_irqsave(&drv_data->lock, flags);
++
++ /* This is a bit lame, but is optimized for the common execution path.
++ * A wait_queue on the drv_data->busy could be used, but then the common
++ * execution path (pump_messages) would be required to call wake_up or
++ * friends on every SPI message. Do this instead */
++ drv_data->run = QUEUE_STOPPED;
++ while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++ msleep(10);
++ spin_lock_irqsave(&drv_data->lock, flags);
++ }
++
++ if (!list_empty(&drv_data->queue) || drv_data->busy)
++ status = -EBUSY;
++
++ spin_unlock_irqrestore(&drv_data->lock, flags);
++
++ return status;
++}
++
++static int destroy_queue(struct driver_data *drv_data)
++{
++ int status;
++
++ status = stop_queue(drv_data);
++ if (status != 0)
++ return status;
++
++ destroy_workqueue(drv_data->workqueue);
++
++ return 0;
++}
++
++static int pxa2xx_spi_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct pxa2xx_spi_master *platform_info;
++ struct spi_master *master;
++ struct driver_data *drv_data = 0;
++ struct resource *memory_resource;
++ int irq;
++ int status = 0;
++
++ platform_info = dev->platform_data;
++
++ if (platform_info->ssp_type == SSP_UNDEFINED) {
++ dev_err(&pdev->dev, "undefined SSP\n");
++ return -ENODEV;
++ }
++
++ /* Allocate master with space for drv_data and null dma buffer */
++ master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
++ if (!master) {
++ dev_err(&pdev->dev, "can not alloc spi_master\n");
++ return -ENOMEM;
++ }
++ drv_data = spi_master_get_devdata(master);
++ drv_data->master = master;
++ drv_data->master_info = platform_info;
++ drv_data->pdev = pdev;
++
++ master->bus_num = pdev->id;
++ master->num_chipselect = platform_info->num_chipselect;
++ master->cleanup = cleanup;
++ master->setup = setup;
++ master->transfer = transfer;
++
++ drv_data->ssp_type = platform_info->ssp_type;
++ drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
++ sizeof(struct driver_data)), 8);
++
++ /* Setup register addresses */
++ memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!memory_resource) {
++ dev_err(&pdev->dev, "memory resources not defined\n");
++ status = -ENODEV;
++ goto out_error_master_alloc;
++ }
++
++ drv_data->ioaddr = (void *)io_p2v(memory_resource->start);
++ drv_data->ssdr_physical = memory_resource->start + 0x00000010;
++ if (platform_info->ssp_type == PXA25x_SSP) {
++ drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
++ drv_data->dma_cr1 = 0;
++ drv_data->clear_sr = SSSR_ROR;
++ drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
++ } else {
++ drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
++ drv_data->dma_cr1 = SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE;
++ drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
++ drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
++ }
++
++ /* Attach to IRQ */
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "irq resource not defined\n");
++ status = -ENODEV;
++ goto out_error_master_alloc;
++ }
++
++ status = request_irq(irq, ssp_int, SA_INTERRUPT, dev->bus_id, drv_data);
++ if (status < 0) {
++ dev_err(&pdev->dev, "can not get IRQ\n");
++ goto out_error_master_alloc;
++ }
++
++ /* Setup DMA if requested */
++ drv_data->tx_channel = -1;
++ drv_data->rx_channel = -1;
++ if (platform_info->enable_dma) {
++
++ /* Get two DMA channels (rx and tx) */
++ drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
++ DMA_PRIO_HIGH,
++ dma_handler,
++ drv_data);
++ if (drv_data->rx_channel < 0) {
++ dev_err(dev, "problem (%d) requesting rx channel\n",
++ drv_data->rx_channel);
++ status = -ENODEV;
++ goto out_error_irq_alloc;
++ }
++ drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
++ DMA_PRIO_MEDIUM,
++ dma_handler,
++ drv_data);
++ if (drv_data->tx_channel < 0) {
++ dev_err(dev, "problem (%d) requesting tx channel\n",
++ drv_data->tx_channel);
++ status = -ENODEV;
++ goto out_error_dma_alloc;
++ }
++
++ if (drv_data->ioaddr == SSP1_VIRT) {
++ DRCMRRXSSDR = DRCMR_MAPVLD
++ | drv_data->rx_channel;
++ DRCMRTXSSDR = DRCMR_MAPVLD
++ | drv_data->tx_channel;
++ } else if (drv_data->ioaddr == SSP2_VIRT) {
++ DRCMRRXSS2DR = DRCMR_MAPVLD
++ | drv_data->rx_channel;
++ DRCMRTXSS2DR = DRCMR_MAPVLD
++ | drv_data->tx_channel;
++ } else if (drv_data->ioaddr == SSP3_VIRT) {
++ DRCMRRXSS3DR = DRCMR_MAPVLD
++ | drv_data->rx_channel;
++ DRCMRTXSS3DR = DRCMR_MAPVLD
++ | drv_data->tx_channel;
++ } else {
++ dev_err(dev, "bad SSP type\n");
++ goto out_error_dma_alloc;
++ }
++ }
++
++ /* Enable SOC clock */
++ pxa_set_cken(platform_info->clock_enable, 1);
++
++ /* Load default SSP configuration */
++ write_SSCR0(0, drv_data->ioaddr);
++ write_SSCR1(SSCR1_RxTresh(4) | SSCR1_TxTresh(12), drv_data->ioaddr);
++ write_SSCR0(SSCR0_SerClkDiv(2)
++ | SSCR0_Motorola
++ | SSCR0_DataSize(8),
++ drv_data->ioaddr);
++ if (drv_data->ssp_type != PXA25x_SSP)
++ write_SSTO(0, drv_data->ioaddr);
++ write_SSPSP(0, drv_data->ioaddr);
++
++ /* Initial and start queue */
++ status = init_queue(drv_data);
++ if (status != 0) {
++ dev_err(&pdev->dev, "problem initializing queue\n");
++ goto out_error_clock_enabled;
++ }
++ status = start_queue(drv_data);
++ if (status != 0) {
++ dev_err(&pdev->dev, "problem starting queue\n");
++ goto out_error_clock_enabled;
++ }
++
++ /* Register with the SPI framework */
++ platform_set_drvdata(pdev, drv_data);
++ status = spi_register_master(master);
++ if (status != 0) {
++ dev_err(&pdev->dev, "problem registering spi master\n");
++ goto out_error_queue_alloc;
++ }
++
++ return status;
++
++out_error_queue_alloc:
++ destroy_queue(drv_data);
++
++out_error_clock_enabled:
++ pxa_set_cken(platform_info->clock_enable, 0);
++
++out_error_dma_alloc:
++ if (drv_data->tx_channel != -1)
++ pxa_free_dma(drv_data->tx_channel);
++ if (drv_data->rx_channel != -1)
++ pxa_free_dma(drv_data->rx_channel);
++
++out_error_irq_alloc:
++ free_irq(irq, drv_data);
++
++out_error_master_alloc:
++ spi_master_put(master);
++ return status;
++}
++
++static int pxa2xx_spi_remove(struct platform_device *pdev)
++{
++ struct driver_data *drv_data = platform_get_drvdata(pdev);
++ int irq;
++ int status = 0;
++
++ if (!drv_data)
++ return 0;
++
++ /* Remove the queue */
++ status = destroy_queue(drv_data);
++ if (status != 0)
++ return status;
++
++ /* Disable the SSP at the peripheral and SOC level */
++ write_SSCR0(0, drv_data->ioaddr);
++ pxa_set_cken(drv_data->master_info->clock_enable, 0);
++
++ /* Release DMA */
++ if (drv_data->master_info->enable_dma) {
++ if (drv_data->ioaddr == SSP1_VIRT) {
++ DRCMRRXSSDR = 0;
++ DRCMRTXSSDR = 0;
++ } else if (drv_data->ioaddr == SSP2_VIRT) {
++ DRCMRRXSS2DR = 0;
++ DRCMRTXSS2DR = 0;
++ } else if (drv_data->ioaddr == SSP3_VIRT) {
++ DRCMRRXSS3DR = 0;
++ DRCMRTXSS3DR = 0;
++ }
++ pxa_free_dma(drv_data->tx_channel);
++ pxa_free_dma(drv_data->rx_channel);
++ }
++
++ /* Release IRQ */
++ irq = platform_get_irq(pdev, 0);
++ if (irq >= 0)
++ free_irq(irq, drv_data);
++
++ /* Disconnect from the SPI framework */
++ spi_unregister_master(drv_data->master);
++
++ /* Prevent double remove */
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++static void pxa2xx_spi_shutdown(struct platform_device *pdev)
++{
++ int status = 0;
++
++ if ((status = pxa2xx_spi_remove(pdev)) != 0)
++ dev_err(&pdev->dev, "shutdown failed with %d\n", status);
++}
++
++#ifdef CONFIG_PM
++static int suspend_devices(struct device *dev, void *pm_message)
++{
++ pm_message_t *state = pm_message;
++
++ if (dev->power.power_state.event != state->event) {
++ dev_warn(dev, "pm state does not match request\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct driver_data *drv_data = platform_get_drvdata(pdev);
++ int status = 0;
++
++ /* Check all childern for current power state */
++ if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
++ dev_warn(&pdev->dev, "suspend aborted\n");
++ return -1;
++ }
++
++ status = stop_queue(drv_data);
++ if (status != 0)
++ return status;
++ write_SSCR0(0, drv_data->ioaddr);
++ pxa_set_cken(drv_data->master_info->clock_enable, 0);
++
++ return 0;
++}
++
++static int pxa2xx_spi_resume(struct platform_device *pdev)
++{
++ struct driver_data *drv_data = platform_get_drvdata(pdev);
++ int status = 0;
++
++ /* Enable the SSP clock */
++ pxa_set_cken(drv_data->master_info->clock_enable, 1);
++
++ /* Start the queue running */
++ status = start_queue(drv_data);
++ if (status != 0) {
++ dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
++ return status;
++ }
++
++ return 0;
++}
++#else
++#define pxa2xx_spi_suspend NULL
++#define pxa2xx_spi_resume NULL
++#endif /* CONFIG_PM */
++
++static struct platform_driver driver = {
++ .driver = {
++ .name = "pxa2xx-spi",
++ .bus = &platform_bus_type,
++ .owner = THIS_MODULE,
++ },
++ .probe = pxa2xx_spi_probe,
++ .remove = __devexit_p(pxa2xx_spi_remove),
++ .shutdown = pxa2xx_spi_shutdown,
++ .suspend = pxa2xx_spi_suspend,
++ .resume = pxa2xx_spi_resume,
++};
++
++static int __init pxa2xx_spi_init(void)
++{
++ platform_driver_register(&driver);
++
++ return 0;
++}
++module_init(pxa2xx_spi_init);
++
++static void __exit pxa2xx_spi_exit(void)
++{
++ platform_driver_unregister(&driver);
++}
++module_exit(pxa2xx_spi_exit);
+--- /dev/null
++++ gregkh-2.6/include/asm-arm/arch-pxa/pxa2xx_spi.h
+@@ -0,0 +1,68 @@
++/*
++ * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
++ *
++ * 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; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef PXA2XX_SPI_H_
++#define PXA2XX_SPI_H_
++
++#define PXA2XX_CS_ASSERT (0x01)
++#define PXA2XX_CS_DEASSERT (0x02)
++
++#if defined(CONFIG_PXA25x)
++#define CLOCK_SPEED_HZ 3686400
++#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/2/(x+1))<<8)&0x0000ff00)
++#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
++#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
++#elif defined(CONFIG_PXA27x)
++#define CLOCK_SPEED_HZ 13000000
++#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
++#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
++#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
++#endif
++
++#define SSP1_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(1)))))
++#define SSP2_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(2)))))
++#define SSP3_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(3)))))
++
++enum pxa_ssp_type {
++ SSP_UNDEFINED = 0,
++ PXA25x_SSP, /* pxa 210, 250, 255, 26x */
++ PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
++ PXA27x_SSP,
++};
++
++/* device.platform_data for SSP controller devices */
++struct pxa2xx_spi_master {
++ enum pxa_ssp_type ssp_type;
++ u32 clock_enable;
++ u16 num_chipselect;
++ u8 enable_dma;
++};
++
++/* spi_board_info.controller_data for SPI slave devices,
++ * copied to spi_device.platform_data ... mostly for dma tuning
++ */
++struct pxa2xx_spi_chip {
++ u8 tx_threshold;
++ u8 rx_threshold;
++ u8 dma_burst_size;
++ u32 timeout_microsecs;
++ u8 enable_loopback;
++ void (*cs_control)(u32 command);
++};
++
++#endif /*PXA2XX_SPI_H_*/
diff --git a/driver/sysfs-crash-debugging.patch b/driver/sysfs-crash-debugging.patch
index 320226bc2d848..c659becb51413 100644
--- a/driver/sysfs-crash-debugging.patch
+++ b/driver/sysfs-crash-debugging.patch
@@ -87,7 +87,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
--- gregkh-2.6.orig/include/linux/sysfs.h
+++ gregkh-2.6/include/linux/sysfs.h
-@@ -155,6 +155,8 @@ int sysfs_create_group(struct kobject *,
+@@ -120,6 +120,8 @@ int sysfs_create_group(struct kobject *,
void sysfs_remove_group(struct kobject *, const struct attribute_group *);
void sysfs_notify(struct kobject * k, char *dir, char *attr);
@@ -96,7 +96,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#else /* CONFIG_SYSFS */
static inline int sysfs_create_dir(struct kobject * k)
-@@ -227,6 +229,11 @@ static inline void sysfs_notify(struct k
+@@ -192,6 +194,11 @@ static inline void sysfs_notify(struct k
;
}
diff --git a/driver/sysfs-fix-problem-with-duplicate-sysfs-directories-and-files.patch b/driver/sysfs-fix-problem-with-duplicate-sysfs-directories-and-files.patch
index 1da39edc88515..9e341b44267d5 100644
--- a/driver/sysfs-fix-problem-with-duplicate-sysfs-directories-and-files.patch
+++ b/driver/sysfs-fix-problem-with-duplicate-sysfs-directories-and-files.patch
@@ -55,7 +55,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
void * element, umode_t mode, int type)
{
-@@ -117,7 +143,11 @@ static int create_dir(struct kobject * k
+@@ -103,7 +129,11 @@ static int create_dir(struct kobject * k
mutex_lock(&p->d_inode->i_mutex);
*d = lookup_one_len(n, p, strlen(n));
if (!IS_ERR(*d)) {