diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-05-17 09:15:06 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-05-17 09:15:06 -0700 |
commit | 0dc51fce3ada84fe5d191d48489b50f5b927e687 (patch) | |
tree | 21d0697136a47460fa57a1fe0098a4020b58b1e4 /driver | |
parent | f0e3ae84732e61fe198a11197b7d0bef9952a6c5 (diff) | |
download | patches-0dc51fce3ada84fe5d191d48489b50f5b927e687.tar.gz |
refresh to 2.6.17-rc4-git4
Also move base file to version
Diffstat (limited to 'driver')
-rw-r--r-- | driver/spi-add-david-as-the-spi-subsystem-maintainer.patch | 33 | ||||
-rw-r--r-- | driver/spi-add-pxa2xx-ssp-spi-driver.patch | 1773 | ||||
-rw-r--r-- | driver/spi-busnum-0-needs-to-work.patch | 121 | ||||
-rw-r--r-- | driver/spi-devices-can-require-lsb-first-encodings.patch | 79 | ||||
-rw-r--r-- | driver/spi-per-transfer-overrides-for-wordsize-and-clocking.patch | 223 | ||||
-rw-r--r-- | driver/spi-renamed-bitbang_transfer_setup-to-spi_bitbang_setup_transfer-and-export-it.patch | 72 | ||||
-rw-r--r-- | driver/spi-spi-bounce-buffer-has-a-minimum-length.patch | 30 | ||||
-rw-r--r-- | driver/spi-spi-whitespace-fixes.patch | 86 | ||||
-rw-r--r-- | driver/spi-spi_bitbang-clocking-fixes.patch | 90 | ||||
-rw-r--r-- | driver/spi-update-to-pxa2xx-spi-driver.patch | 202 | ||||
-rw-r--r-- | driver/sysfs-crash-debugging.patch | 2 |
11 files changed, 1 insertions, 2710 deletions
diff --git a/driver/spi-add-david-as-the-spi-subsystem-maintainer.patch b/driver/spi-add-david-as-the-spi-subsystem-maintainer.patch deleted file mode 100644 index 16cf37ca28728..0000000000000 --- a/driver/spi-add-david-as-the-spi-subsystem-maintainer.patch +++ /dev/null @@ -1,33 +0,0 @@ -From galak@kernel.crashing.org Sun Apr 2 14:07:08 2006 -Date: Sun, 2 Apr 2006 16:05:54 -0500 (CDT) -From: Kumar Gala <galak@kernel.crashing.org> -To: david-b@pacbell.net -cc: <spi-devel-general@lists.sourceforge.net>, Greg KH <greg@kroah.com>, Andrew Morton <akpm@osdl.org> -Subject: SPI: Add David as the SPI subsystem maintainer -Message-ID: <Pine.LNX.4.44.0604021605160.9478-100000@gate.crashing.org> - -Add David as the SPI subsystem maintainer - -Signed-off-by: Kumar Gala <galak@kernel.crashing.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - - ---- - MAINTAINERS | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- gregkh-2.6.orig/MAINTAINERS -+++ gregkh-2.6/MAINTAINERS -@@ -2518,6 +2518,12 @@ M: perex@suse.cz - L: alsa-devel@alsa-project.org - S: Maintained - -+SPI SUBSYSTEM -+P: David Brownell -+M: dbrownell@users.sourceforge.net -+L: spi-devel-general@lists.sourceforge.net -+S: Maintained -+ - TPM DEVICE DRIVER - P: Kylene Hall - M: kjhall@us.ibm.com diff --git a/driver/spi-add-pxa2xx-ssp-spi-driver.patch b/driver/spi-add-pxa2xx-ssp-spi-driver.patch deleted file mode 100644 index d8ebcc7d25c07..0000000000000 --- a/driver/spi-add-pxa2xx-ssp-spi-driver.patch +++ /dev/null @@ -1,1773 +0,0 @@ -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/spi-busnum-0-needs-to-work.patch b/driver/spi-busnum-0-needs-to-work.patch deleted file mode 100644 index 27e6c1d775336..0000000000000 --- a/driver/spi-busnum-0-needs-to-work.patch +++ /dev/null @@ -1,121 +0,0 @@ -From david-b@pacbell.net Mon Apr 3 15:55:59 2006 -From: David Brownell <david-b@pacbell.net> -To: Greg KH <greg@kroah.com> -Subject: SPI: busnum == 0 needs to work -Date: Mon, 3 Apr 2006 15:49:04 -0700 -Message-Id: <200604031549.04064.david-b@pacbell.net> - -We need to be able to have a "SPI bus 0" matching chip numbering; but -that number was wrongly used to flag dynamic allocation of a bus number. - -This patch resolves that issue; now negative numbers trigger dynamic alloc. - -It also updates the how-to-write-a-controller-driver overview to mention -this stuff. - -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - - ---- - Documentation/spi/spi-summary | 34 +++++++++++++++++++++++++++++++++- - drivers/spi/spi.c | 4 ++-- - include/linux/spi/spi.h | 6 +++--- - 3 files changed, 38 insertions(+), 6 deletions(-) - ---- gregkh-2.6.orig/Documentation/spi/spi-summary -+++ gregkh-2.6/Documentation/spi/spi-summary -@@ -414,7 +414,33 @@ to get the driver-private data allocated - The driver will initialize the fields of that spi_master, including the - bus number (maybe the same as the platform device ID) and three methods - used to interact with the SPI core and SPI protocol drivers. It will --also initialize its own internal state. -+also initialize its own internal state. (See below about bus numbering -+and those methods.) -+ -+After you initialize the spi_master, then use spi_register_master() to -+publish it to the rest of the system. At that time, device nodes for -+the controller and any predeclared spi devices will be made available, -+and the driver model core will take care of binding them to drivers. -+ -+If you need to remove your SPI controller driver, spi_unregister_master() -+will reverse the effect of spi_register_master(). -+ -+ -+BUS NUMBERING -+ -+Bus numbering is important, since that's how Linux identifies a given -+SPI bus (shared SCK, MOSI, MISO). Valid bus numbers start at zero. On -+SOC systems, the bus numbers should match the numbers defined by the chip -+manufacturer. For example, hardware controller SPI2 would be bus number 2, -+and spi_board_info for devices connected to it would use that number. -+ -+If you don't have such hardware-assigned bus number, and for some reason -+you can't just assign them, then provide a negative bus number. That will -+then be replaced by a dynamically assigned number. You'd then need to treat -+this as a non-static configuration (see above). -+ -+ -+SPI MASTER METHODS - - master->setup(struct spi_device *spi) - This sets up the device clock rate, SPI mode, and word sizes. -@@ -431,6 +457,9 @@ also initialize its own internal state. - state it dynamically associates with that device. If you do that, - be sure to provide the cleanup() method to free that state. - -+ -+SPI MESSAGE QUEUE -+ - The bulk of the driver will be managing the I/O queue fed by transfer(). - - That queue could be purely conceptual. For example, a driver used only -@@ -440,6 +469,9 @@ But the queue will probably be very real - often DMA (especially if the root filesystem is in SPI flash), and - execution contexts like IRQ handlers, tasklets, or workqueues (such - as keventd). Your driver can be as fancy, or as simple, as you need. -+Such a transfer() method would normally just add the message to a -+queue, and then start some asynchronous transfer engine (unless it's -+already running). - - - THANKS TO ---- gregkh-2.6.orig/drivers/spi/spi.c -+++ gregkh-2.6/drivers/spi/spi.c -@@ -395,7 +395,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master); - int __init_or_module - spi_register_master(struct spi_master *master) - { -- static atomic_t dyn_bus_id = ATOMIC_INIT(0); -+ static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1); - struct device *dev = master->cdev.dev; - int status = -ENODEV; - int dynamic = 0; -@@ -404,7 +404,7 @@ spi_register_master(struct spi_master *m - return -ENODEV; - - /* convention: dynamically assigned bus IDs count down from the max */ -- if (master->bus_num == 0) { -+ if (master->bus_num < 0) { - master->bus_num = atomic_dec_return(&dyn_bus_id); - dynamic = 1; - } ---- gregkh-2.6.orig/include/linux/spi/spi.h -+++ gregkh-2.6/include/linux/spi/spi.h -@@ -172,13 +172,13 @@ static inline void spi_unregister_driver - struct spi_master { - struct class_device cdev; - -- /* other than zero (== assign one dynamically), bus_num is fully -+ /* other than negative (== assign one dynamically), bus_num is fully - * board-specific. usually that simplifies to being SOC-specific. -- * example: one SOC has three SPI controllers, numbered 1..3, -+ * example: one SOC has three SPI controllers, numbered 0..2, - * and one board's schematics might show it using SPI-2. software - * would normally use bus_num=2 for that controller. - */ -- u16 bus_num; -+ s16 bus_num; - - /* chipselects will be integral to many controllers; some others - * might use board-specific GPIOs. diff --git a/driver/spi-devices-can-require-lsb-first-encodings.patch b/driver/spi-devices-can-require-lsb-first-encodings.patch deleted file mode 100644 index 55554af2869eb..0000000000000 --- a/driver/spi-devices-can-require-lsb-first-encodings.patch +++ /dev/null @@ -1,79 +0,0 @@ -From david-b@pacbell.net Mon Apr 3 15:55:59 2006 -From: David Brownell <david-b@pacbell.net> -To: Greg KH <greg@kroah.com> -Subject: SPI: devices can require LSB-first encodings -Date: Mon, 3 Apr 2006 15:46:22 -0700 -Message-Id: <200604031546.22777.david-b@pacbell.net> - -Add spi_device hook for LSB-first word encoding, and update all the -(in-tree) controller drivers to reject such devices. Eventually, -some controller drivers will be updated to support lsb-first encodings -on the wire; no current drivers need this. - -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - drivers/spi/spi_bitbang.c | 11 ++++++++++- - include/linux/spi/spi.h | 7 +++++-- - 2 files changed, 15 insertions(+), 3 deletions(-) - ---- gregkh-2.6.orig/drivers/spi/spi_bitbang.c -+++ gregkh-2.6/drivers/spi/spi_bitbang.c -@@ -187,13 +187,22 @@ int spi_bitbang_setup(struct spi_device - if (!spi->max_speed_hz) - return -EINVAL; - -+ bitbang = spi_master_get_devdata(spi->master); -+ -+ /* REVISIT: some systems will want to support devices using lsb-first -+ * bit encodings on the wire. In pure software that would be trivial, -+ * just bitbang_txrx_le_cphaX() routines shifting the other way, and -+ * some hardware controllers also have this support. -+ */ -+ if ((spi->mode & SPI_LSB_FIRST) != 0) -+ return -EINVAL; -+ - if (!cs) { - cs = kzalloc(sizeof *cs, SLAB_KERNEL); - if (!cs) - return -ENOMEM; - spi->controller_state = cs; - } -- bitbang = spi_master_get_devdata(spi->master); - - if (!spi->bits_per_word) - spi->bits_per_word = 8; ---- gregkh-2.6.orig/include/linux/spi/spi.h -+++ gregkh-2.6/include/linux/spi/spi.h -@@ -35,10 +35,13 @@ extern struct bus_type spi_bus_type; - * @chip-select: Chipselect, distinguishing chips handled by "master". - * @mode: The spi mode defines how data is clocked out and in. - * This may be changed by the device's driver. -+ * The "active low" default for chipselect mode can be overridden, -+ * as can the "MSB first" default for each word in a transfer. - * @bits_per_word: Data transfers involve one or more words; word sizes - * like eight or 12 bits are common. In-memory wordsizes are - * powers of two bytes (e.g. 20 bit samples use 32 bits). -- * This may be changed by the device's driver. -+ * This may be changed by the device's driver, or left at the -+ * default (0) indicating protocol words are eight bit bytes. - * The spi_transfer.bits_per_word can override this for each transfer. - * @irq: Negative, or the number passed to request_irq() to receive - * interrupts from this device. -@@ -67,6 +70,7 @@ struct spi_device { - #define SPI_MODE_2 (SPI_CPOL|0) - #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) - #define SPI_CS_HIGH 0x04 /* chipselect active high? */ -+#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ - u8 bits_per_word; - int irq; - void *controller_state; -@@ -75,7 +79,6 @@ struct spi_device { - - // likely need more hooks for more protocol options affecting how - // the controller talks to each chip, like: -- // - bit order (default is wordwise msb-first) - // - memory packing (12 bit samples into low bits, others zeroed) - // - priority - // - drop chipselect after each word diff --git a/driver/spi-per-transfer-overrides-for-wordsize-and-clocking.patch b/driver/spi-per-transfer-overrides-for-wordsize-and-clocking.patch deleted file mode 100644 index cda64caab046f..0000000000000 --- a/driver/spi-per-transfer-overrides-for-wordsize-and-clocking.patch +++ /dev/null @@ -1,223 +0,0 @@ -From david-b@pacbell.net Fri Feb 17 10:02:22 2006 -From: Imre Deak <imre.deak@nokia.com> -To: Andrew Morton <akpm@osdl.org>, Greg KH <greg@kroah.com> -Subject: SPI: per-transfer overrides for wordsize and clocking -Date: Fri, 17 Feb 2006 10:02:18 -0800 -Cc: imre.deak@nokia.com -Message-Id: <200602171002.18568.david-b@pacbell.net> - -From: Imre Deak <imre.deak@nokia.com> - -Some protocols (like one for some bitmap displays) require different clock -speed or word size settings for each transfer in an SPI message. This adds -those parameters to struct spi_transfer. They are to be used when they are -nonzero; otherwise the defaults from spi_device are to be used. - -The patch also adds a setup_transfer callback to spi_bitbang, uses it for -messages that use those overrides, and implements it so that the pure -bitbanging code can help resolve any questions about how it should work. - -Signed-off-by: Imre Deak <imre.deak@nokia.com> -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - drivers/spi/spi_bitbang.c | 77 ++++++++++++++++++++++++++++++++-------- - include/linux/spi/spi.h | 8 ++++ - include/linux/spi/spi_bitbang.h | 6 +++ - 3 files changed, 77 insertions(+), 14 deletions(-) - ---- gregkh-2.6.orig/drivers/spi/spi_bitbang.c -+++ gregkh-2.6/drivers/spi/spi_bitbang.c -@@ -138,6 +138,43 @@ static unsigned bitbang_txrx_32( - return t->len - count; - } - -+static int -+bitbang_transfer_setup(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct spi_bitbang_cs *cs = spi->controller_state; -+ u8 bits_per_word; -+ u32 hz; -+ -+ if (t) { -+ bits_per_word = t->bits_per_word; -+ hz = t->speed_hz; -+ } else { -+ bits_per_word = 0; -+ hz = 0; -+ } -+ -+ /* spi_transfer level calls that work per-word */ -+ if (!bits_per_word) -+ bits_per_word = spi->bits_per_word; -+ if (bits_per_word <= 8) -+ cs->txrx_bufs = bitbang_txrx_8; -+ else if (bits_per_word <= 16) -+ cs->txrx_bufs = bitbang_txrx_16; -+ else if (bits_per_word <= 32) -+ cs->txrx_bufs = bitbang_txrx_32; -+ else -+ return -EINVAL; -+ -+ /* nsecs = (clock period)/2 */ -+ if (!hz) -+ hz = spi->max_speed_hz; -+ cs->nsecs = (1000000000/2) / hz; -+ if (cs->nsecs > MAX_UDELAY_MS * 1000) -+ return -EINVAL; -+ -+ return 0; -+} -+ - /** - * spi_bitbang_setup - default setup for per-word I/O loops - */ -@@ -145,6 +182,7 @@ int spi_bitbang_setup(struct spi_device - { - struct spi_bitbang_cs *cs = spi->controller_state; - struct spi_bitbang *bitbang; -+ int retval; - - if (!spi->max_speed_hz) - return -EINVAL; -@@ -160,25 +198,14 @@ int spi_bitbang_setup(struct spi_device - if (!spi->bits_per_word) - spi->bits_per_word = 8; - -- /* spi_transfer level calls that work per-word */ -- if (spi->bits_per_word <= 8) -- cs->txrx_bufs = bitbang_txrx_8; -- else if (spi->bits_per_word <= 16) -- cs->txrx_bufs = bitbang_txrx_16; -- else if (spi->bits_per_word <= 32) -- cs->txrx_bufs = bitbang_txrx_32; -- else -- return -EINVAL; -- - /* per-word shift register access, in hardware or bitbanging */ - cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)]; - if (!cs->txrx_word) - return -EINVAL; - -- /* nsecs = (clock period)/2 */ -- cs->nsecs = (1000000000/2) / (spi->max_speed_hz); -- if (cs->nsecs > MAX_UDELAY_MS * 1000) -- return -EINVAL; -+ retval = bitbang_transfer_setup(spi, NULL); -+ if (retval < 0) -+ return retval; - - dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", - __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), -@@ -246,6 +273,8 @@ static void bitbang_work(void *_bitbang) - unsigned tmp; - unsigned cs_change; - int status; -+ int (*setup_transfer)(struct spi_device *, -+ struct spi_transfer *); - - m = container_of(bitbang->queue.next, struct spi_message, - queue); -@@ -262,6 +291,7 @@ static void bitbang_work(void *_bitbang) - tmp = 0; - cs_change = 1; - status = 0; -+ setup_transfer = NULL; - - list_for_each_entry (t, &m->transfers, transfer_list) { - if (bitbang->shutdown) { -@@ -269,6 +299,20 @@ static void bitbang_work(void *_bitbang) - break; - } - -+ /* override or restore speed and wordsize */ -+ if (t->speed_hz || t->bits_per_word) { -+ setup_transfer = bitbang->setup_transfer; -+ if (!setup_transfer) { -+ status = -ENOPROTOOPT; -+ break; -+ } -+ } -+ if (setup_transfer) { -+ status = setup_transfer(spi, t); -+ if (status < 0) -+ break; -+ } -+ - /* set up default clock polarity, and activate chip; - * this implicitly updates clock and spi modes as - * previously recorded for this device via setup(). -@@ -325,6 +369,10 @@ static void bitbang_work(void *_bitbang) - m->status = status; - m->complete(m->context); - -+ /* restore speed and wordsize */ -+ if (setup_transfer) -+ setup_transfer(spi, NULL); -+ - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. -@@ -406,6 +454,7 @@ int spi_bitbang_start(struct spi_bitbang - bitbang->use_dma = 0; - bitbang->txrx_bufs = spi_bitbang_bufs; - if (!bitbang->master->setup) { -+ bitbang->setup_transfer = bitbang_transfer_setup; - bitbang->master->setup = spi_bitbang_setup; - bitbang->master->cleanup = spi_bitbang_cleanup; - } ---- gregkh-2.6.orig/include/linux/spi/spi.h -+++ gregkh-2.6/include/linux/spi/spi.h -@@ -31,6 +31,7 @@ extern struct bus_type spi_bus_type; - * @master: SPI controller used with the device. - * @max_speed_hz: Maximum clock rate to be used with this chip - * (on this board); may be changed by the device's driver. -+ * The spi_transfer.speed_hz can override this for each transfer. - * @chip-select: Chipselect, distinguishing chips handled by "master". - * @mode: The spi mode defines how data is clocked out and in. - * This may be changed by the device's driver. -@@ -38,6 +39,7 @@ extern struct bus_type spi_bus_type; - * like eight or 12 bits are common. In-memory wordsizes are - * powers of two bytes (e.g. 20 bit samples use 32 bits). - * This may be changed by the device's driver. -+ * The spi_transfer.bits_per_word can override this for each transfer. - * @irq: Negative, or the number passed to request_irq() to receive - * interrupts from this device. - * @controller_state: Controller's runtime state -@@ -268,6 +270,10 @@ extern struct spi_master *spi_busnum_to_ - * @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped - * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped - * @len: size of rx and tx buffers (in bytes) -+ * @speed_hz: Select a speed other then the device default for this -+ * transfer. If 0 the default (from spi_device) is used. -+ * @bits_per_word: select a bits_per_word other then the device default -+ * for this transfer. If 0 the default (from spi_device) is used. - * @cs_change: affects chipselect after this transfer completes - * @delay_usecs: microseconds to delay after this transfer before - * (optionally) changing the chipselect status, then starting -@@ -322,7 +328,9 @@ struct spi_transfer { - dma_addr_t rx_dma; - - unsigned cs_change:1; -+ u8 bits_per_word; - u16 delay_usecs; -+ u32 speed_hz; - - struct list_head transfer_list; - }; ---- gregkh-2.6.orig/include/linux/spi/spi_bitbang.h -+++ gregkh-2.6/include/linux/spi/spi_bitbang.h -@@ -30,6 +30,12 @@ struct spi_bitbang { - - struct spi_master *master; - -+ /* setup_transfer() changes clock and/or wordsize to match settings -+ * for this transfer; zeroes restore defaults from spi_device. -+ */ -+ int (*setup_transfer)(struct spi_device *spi, -+ struct spi_transfer *t); -+ - void (*chipselect)(struct spi_device *spi, int is_on); - #define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ - #define BITBANG_CS_INACTIVE 0 diff --git a/driver/spi-renamed-bitbang_transfer_setup-to-spi_bitbang_setup_transfer-and-export-it.patch b/driver/spi-renamed-bitbang_transfer_setup-to-spi_bitbang_setup_transfer-and-export-it.patch deleted file mode 100644 index b81b0adda8e48..0000000000000 --- a/driver/spi-renamed-bitbang_transfer_setup-to-spi_bitbang_setup_transfer-and-export-it.patch +++ /dev/null @@ -1,72 +0,0 @@ -From galak@kernel.crashing.org Sun Apr 2 14:07:51 2006 -Date: Sun, 2 Apr 2006 16:06:35 -0500 (CDT) -From: Kumar Gala <galak@kernel.crashing.org> -To: david-b@pacbell.net -cc: <spi-devel-general@lists.sourceforge.net>, Greg KH <greg@kroah.com>, Andrew Morton <akpm@osdl.org> -Subject: SPI: Renamed bitbang_transfer_setup to spi_bitbang_setup_transfer and export it -Message-ID: <Pine.LNX.4.44.0604021605560.9478-100000@gate.crashing.org> - -Renamed bitbang_transfer_setup to follow convention of other exported symbols -from spi-bitbang. Exported spi_bitbang_setup_transfer to allow users of -spi-bitbang to use the function in their own setup_transfer. - -Signed-off-by: Kumar Gala <galak@kernel.crashing.org> -Cc: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - drivers/spi/spi_bitbang.c | 10 ++++++---- - include/linux/spi/spi_bitbang.h | 2 ++ - 2 files changed, 8 insertions(+), 4 deletions(-) - ---- gregkh-2.6.orig/drivers/spi/spi_bitbang.c -+++ gregkh-2.6/drivers/spi/spi_bitbang.c -@@ -138,8 +138,7 @@ static unsigned bitbang_txrx_32( - return t->len - count; - } - --static int --bitbang_transfer_setup(struct spi_device *spi, struct spi_transfer *t) -+int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t) - { - struct spi_bitbang_cs *cs = spi->controller_state; - u8 bits_per_word; -@@ -174,6 +173,7 @@ bitbang_transfer_setup(struct spi_device - - return 0; - } -+EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer); - - /** - * spi_bitbang_setup - default setup for per-word I/O loops -@@ -203,7 +203,7 @@ int spi_bitbang_setup(struct spi_device - if (!cs->txrx_word) - return -EINVAL; - -- retval = bitbang_transfer_setup(spi, NULL); -+ retval = spi_bitbang_setup_transfer(spi, NULL); - if (retval < 0) - return retval; - -@@ -454,7 +454,9 @@ int spi_bitbang_start(struct spi_bitbang - bitbang->use_dma = 0; - bitbang->txrx_bufs = spi_bitbang_bufs; - if (!bitbang->master->setup) { -- bitbang->setup_transfer = bitbang_transfer_setup; -+ if (!bitbang->setup_transfer) -+ bitbang->setup_transfer = -+ spi_bitbang_setup_transfer; - bitbang->master->setup = spi_bitbang_setup; - bitbang->master->cleanup = spi_bitbang_cleanup; - } ---- gregkh-2.6.orig/include/linux/spi/spi_bitbang.h -+++ gregkh-2.6/include/linux/spi/spi_bitbang.h -@@ -57,6 +57,8 @@ struct spi_bitbang { - extern int spi_bitbang_setup(struct spi_device *spi); - extern void spi_bitbang_cleanup(const struct spi_device *spi); - extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); -+extern int spi_bitbang_setup_transfer(struct spi_device *spi, -+ struct spi_transfer *t); - - /* start or stop queue processing */ - extern int spi_bitbang_start(struct spi_bitbang *spi); diff --git a/driver/spi-spi-bounce-buffer-has-a-minimum-length.patch b/driver/spi-spi-bounce-buffer-has-a-minimum-length.patch deleted file mode 100644 index c7acd0c539756..0000000000000 --- a/driver/spi-spi-bounce-buffer-has-a-minimum-length.patch +++ /dev/null @@ -1,30 +0,0 @@ -From david-b@pacbell.net Sun Apr 2 11:38:22 2006 -From: David Brownell <david-b@pacbell.net> -To: Greg KH <greg@kroah.com> -Subject: SPI: spi bounce buffer has a minimum length -Date: Sun, 2 Apr 2006 10:37:40 -0800 -Cc: Andrew Morton <akpm@osdl.org> -Message-Id: <200604021137.40719.david-b@pacbell.net> - -Make sure that spi_write_then_read() can always handle at least 32 bytes -of transfer (total, both directions), minimizing one portability issue. - -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - drivers/spi/spi.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- gregkh-2.6.orig/drivers/spi/spi.c -+++ gregkh-2.6/drivers/spi/spi.c -@@ -522,7 +522,8 @@ int spi_sync(struct spi_device *spi, str - } - EXPORT_SYMBOL_GPL(spi_sync); - --#define SPI_BUFSIZ (SMP_CACHE_BYTES) -+/* portable code must never pass more than 32 bytes */ -+#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES) - - static u8 *buf; - diff --git a/driver/spi-spi-whitespace-fixes.patch b/driver/spi-spi-whitespace-fixes.patch deleted file mode 100644 index f39df4354da85..0000000000000 --- a/driver/spi-spi-whitespace-fixes.patch +++ /dev/null @@ -1,86 +0,0 @@ -From david-b@pacbell.net Sun Apr 2 11:38:22 2006 -From: David Brownell <david-b@pacbell.net> -To: Greg KH <greg@kroah.com> -Subject: SPI: spi whitespace fixes -Date: Sun, 2 Apr 2006 10:33:37 -0800 -Cc: Andrew Morton <akpm@osdl.org> -Message-Id: <200604021133.38140.david-b@pacbell.net> - -This removes superfluous whitespace in the <linux/spi/spi.h> header. - -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - include/linux/spi/spi.h | 24 ++++++++++++------------ - 1 file changed, 12 insertions(+), 12 deletions(-) - ---- gregkh-2.6.orig/include/linux/spi/spi.h -+++ gregkh-2.6/include/linux/spi/spi.h -@@ -36,15 +36,15 @@ extern struct bus_type spi_bus_type; - * @mode: The spi mode defines how data is clocked out and in. - * This may be changed by the device's driver. - * @bits_per_word: Data transfers involve one or more words; word sizes -- * like eight or 12 bits are common. In-memory wordsizes are -+ * like eight or 12 bits are common. In-memory wordsizes are - * powers of two bytes (e.g. 20 bit samples use 32 bits). - * This may be changed by the device's driver. - * The spi_transfer.bits_per_word can override this for each transfer. - * @irq: Negative, or the number passed to request_irq() to receive -- * interrupts from this device. -+ * interrupts from this device. - * @controller_state: Controller's runtime state - * @controller_data: Board-specific definitions for controller, such as -- * FIFO initialization parameters; from board_info.controller_data -+ * FIFO initialization parameters; from board_info.controller_data - * - * An spi_device is used to interchange data between an SPI slave - * (usually a discrete chip) and CPU memory. -@@ -145,13 +145,13 @@ static inline void spi_unregister_driver - * struct spi_master - interface to SPI master controller - * @cdev: class interface to this driver - * @bus_num: board-specific (and often SOC-specific) identifier for a -- * given SPI controller. -+ * given SPI controller. - * @num_chipselect: chipselects are used to distinguish individual -- * SPI slaves, and are numbered from zero to num_chipselects. -- * each slave has a chipselect signal, but it's common that not -- * every chipselect is connected to a slave. -+ * SPI slaves, and are numbered from zero to num_chipselects. -+ * each slave has a chipselect signal, but it's common that not -+ * every chipselect is connected to a slave. - * @setup: updates the device mode and clocking records used by a -- * device's SPI controller; protocol code may call this. -+ * device's SPI controller; protocol code may call this. - * @transfer: adds a message to the controller's transfer queue. - * @cleanup: frees controller-specific state - * -@@ -276,8 +276,8 @@ extern struct spi_master *spi_busnum_to_ - * for this transfer. If 0 the default (from spi_device) is used. - * @cs_change: affects chipselect after this transfer completes - * @delay_usecs: microseconds to delay after this transfer before -- * (optionally) changing the chipselect status, then starting -- * the next transfer or completing this spi_message. -+ * (optionally) changing the chipselect status, then starting -+ * the next transfer or completing this spi_message. - * @transfer_list: transfers are sequenced through spi_message.transfers - * - * SPI transfers always write the same number of bytes as they read. -@@ -364,7 +364,7 @@ struct spi_transfer { - * and its transfers, ignore them until its completion callback. - */ - struct spi_message { -- struct list_head transfers; -+ struct list_head transfers; - - struct spi_device *spi; - -@@ -382,7 +382,7 @@ struct spi_message { - */ - - /* completion is reported through a callback */ -- void (*complete)(void *context); -+ void (*complete)(void *context); - void *context; - unsigned actual_length; - int status; diff --git a/driver/spi-spi_bitbang-clocking-fixes.patch b/driver/spi-spi_bitbang-clocking-fixes.patch deleted file mode 100644 index 082ed054111f5..0000000000000 --- a/driver/spi-spi_bitbang-clocking-fixes.patch +++ /dev/null @@ -1,90 +0,0 @@ -From david-b@pacbell.net Thu Apr 6 23:03:36 2006 -From: David Brownell <david-b@pacbell.net> -To: Greg KH <greg@kroah.com> -Subject: SPI: spi_bitbang: clocking fixes -Date: Thu, 6 Apr 2006 22:25:56 -0700 -Message-Id: <200604062225.56448.david-b@pacbell.net> - -This fixes two problems triggered by the MMC stack updating clocks: - - - SPI masters driver should accept a max clock speed of zero; that's one - convention for marking idle devices. (Presumably that helps controllers - that don't autogate clocks to "off" when not in use.) - - - There are more than 1000 nanoseconds per millisecond; setting the clock - down to 125 KHz now works properly. - -Showing once again that Zero (http://en.wikipedia.org/wiki/Zero) is still -an inexhaustible number of bugs. - -Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - - ---- - drivers/spi/spi_bitbang.c | 24 ++++++++++++++---------- - 1 file changed, 14 insertions(+), 10 deletions(-) - ---- gregkh-2.6.orig/drivers/spi/spi_bitbang.c -+++ gregkh-2.6/drivers/spi/spi_bitbang.c -@@ -167,9 +167,11 @@ int spi_bitbang_setup_transfer(struct sp - /* nsecs = (clock period)/2 */ - if (!hz) - hz = spi->max_speed_hz; -- cs->nsecs = (1000000000/2) / hz; -- if (cs->nsecs > MAX_UDELAY_MS * 1000) -- return -EINVAL; -+ if (hz) { -+ cs->nsecs = (1000000000/2) / hz; -+ if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000)) -+ return -EINVAL; -+ } - - return 0; - } -@@ -184,9 +186,6 @@ int spi_bitbang_setup(struct spi_device - struct spi_bitbang *bitbang; - int retval; - -- if (!spi->max_speed_hz) -- return -EINVAL; -- - bitbang = spi_master_get_devdata(spi->master); - - /* REVISIT: some systems will want to support devices using lsb-first -@@ -216,7 +215,7 @@ int spi_bitbang_setup(struct spi_device - if (retval < 0) - return retval; - -- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", -+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), - spi->bits_per_word, 2 * cs->nsecs); - -@@ -405,6 +404,7 @@ int spi_bitbang_transfer(struct spi_devi - { - struct spi_bitbang *bitbang; - unsigned long flags; -+ int status = 0; - - m->actual_length = 0; - m->status = -EINPROGRESS; -@@ -414,11 +414,15 @@ int spi_bitbang_transfer(struct spi_devi - return -ESHUTDOWN; - - spin_lock_irqsave(&bitbang->lock, flags); -- list_add_tail(&m->queue, &bitbang->queue); -- queue_work(bitbang->workqueue, &bitbang->work); -+ if (!spi->max_speed_hz) -+ status = -ENETDOWN; -+ else { -+ list_add_tail(&m->queue, &bitbang->queue); -+ queue_work(bitbang->workqueue, &bitbang->work); -+ } - spin_unlock_irqrestore(&bitbang->lock, flags); - -- return 0; -+ return status; - } - EXPORT_SYMBOL_GPL(spi_bitbang_transfer); - diff --git a/driver/spi-update-to-pxa2xx-spi-driver.patch b/driver/spi-update-to-pxa2xx-spi-driver.patch deleted file mode 100644 index 5603325cd8b2b..0000000000000 --- a/driver/spi-update-to-pxa2xx-spi-driver.patch +++ /dev/null @@ -1,202 +0,0 @@ -From akpm@osdl.org Tue Mar 28 14:05:35 2006 -Message-Id: <200603282205.k2SM5UpW027797@shell0.pdx.osdl.net> -Subject: spi: Update to PXA2xx SPI Driver -To: greg@kroah.com -Cc: akpm@osdl.org, stephen@streetfiresound.com -From: Stephen Street <stephen@streetfiresound.com> -Date: Tue, 28 Mar 2006 14:05:23 -0800 - -From: Stephen Street <stephen@streetfiresound.com> - -Fix two outstanding issues with the pxa2xx_spi driver: - -1) Bad cast in the function u32_writer. Thanks to Henrik Bechmann -2) Adds support for per transfer changes to speed and bits per word - -Signed-off-by: Stephen Street <stephen@streetfiresound.com> -Cc: David Brownell <dbrownell@users.sourceforge.net> -Signed-off-by: Andrew Morton <akpm@osdl.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - drivers/spi/pxa2xx_spi.c | 82 ++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 75 insertions(+), 7 deletions(-) - ---- gregkh-2.6.orig/drivers/spi/pxa2xx_spi.c -+++ gregkh-2.6/drivers/spi/pxa2xx_spi.c -@@ -120,6 +120,8 @@ struct driver_data { - dma_addr_t tx_dma; - size_t rx_map_len; - size_t tx_map_len; -+ u8 n_bytes; -+ u32 dma_width; - int cs_change; - void (*write)(struct driver_data *drv_data); - void (*read)(struct driver_data *drv_data); -@@ -139,6 +141,8 @@ struct chip_data { - u32 threshold; - u32 dma_threshold; - u8 enable_dma; -+ u8 bits_per_word; -+ u32 speed_hz; - void (*write)(struct driver_data *drv_data); - void (*read)(struct driver_data *drv_data); - void (*cs_control)(u32 command); -@@ -186,7 +190,7 @@ 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; -+ u8 n_bytes = drv_data->n_bytes; - - while ((read_SSSR(reg) & SSSR_TNF) - && (drv_data->tx < drv_data->tx_end)) { -@@ -198,7 +202,7 @@ static void null_writer(struct driver_da - static void null_reader(struct driver_data *drv_data) - { - void *reg = drv_data->ioaddr; -- u8 n_bytes = drv_data->cur_chip->n_bytes; -+ u8 n_bytes = drv_data->n_bytes; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { -@@ -256,7 +260,7 @@ static void u32_writer(struct driver_dat - - while ((read_SSSR(reg) & SSSR_TNF) - && (drv_data->tx < drv_data->tx_end)) { -- write_SSDR(*(u16 *)(drv_data->tx), reg); -+ write_SSDR(*(u32 *)(drv_data->tx), reg); - drv_data->tx += 4; - } - } -@@ -677,6 +681,10 @@ static void pump_transfers(unsigned long - struct spi_transfer *previous = NULL; - struct chip_data *chip = NULL; - void *reg = drv_data->ioaddr; -+ u32 clk_div = 0; -+ u8 bits = 0; -+ u32 speed = 0; -+ u32 cr0; - - /* Get current state information */ - message = drv_data->cur_msg; -@@ -713,6 +721,8 @@ static void pump_transfers(unsigned long - giveback(message, drv_data); - return; - } -+ drv_data->n_bytes = chip->n_bytes; -+ drv_data->dma_width = chip->dma_width; - drv_data->cs_control = chip->cs_control; - drv_data->tx = (void *)transfer->tx_buf; - drv_data->tx_end = drv_data->tx + transfer->len; -@@ -724,6 +734,62 @@ static void pump_transfers(unsigned long - 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; -+ -+ /* Change speed and bit per word on a per transfer */ -+ if (transfer->speed_hz || transfer->bits_per_word) { -+ -+ /* Disable clock */ -+ write_SSCR0(chip->cr0 & ~SSCR0_SSE, reg); -+ cr0 = chip->cr0; -+ bits = chip->bits_per_word; -+ speed = chip->speed_hz; -+ -+ if (transfer->speed_hz) -+ speed = transfer->speed_hz; -+ -+ if (transfer->bits_per_word) -+ bits = transfer->bits_per_word; -+ -+ if (reg == SSP1_VIRT) -+ clk_div = SSP1_SerClkDiv(speed); -+ else if (reg == SSP2_VIRT) -+ clk_div = SSP2_SerClkDiv(speed); -+ else if (reg == SSP3_VIRT) -+ clk_div = SSP3_SerClkDiv(speed); -+ -+ if (bits <= 8) { -+ drv_data->n_bytes = 1; -+ drv_data->dma_width = DCMD_WIDTH1; -+ drv_data->read = drv_data->read != null_reader ? -+ u8_reader : null_reader; -+ drv_data->write = drv_data->write != null_writer ? -+ u8_writer : null_writer; -+ } else if (bits <= 16) { -+ drv_data->n_bytes = 2; -+ drv_data->dma_width = DCMD_WIDTH2; -+ drv_data->read = drv_data->read != null_reader ? -+ u16_reader : null_reader; -+ drv_data->write = drv_data->write != null_writer ? -+ u16_writer : null_writer; -+ } else if (bits <= 32) { -+ drv_data->n_bytes = 4; -+ drv_data->dma_width = DCMD_WIDTH4; -+ drv_data->read = drv_data->read != null_reader ? -+ u32_reader : null_reader; -+ drv_data->write = drv_data->write != null_writer ? -+ u32_writer : null_writer; -+ } -+ -+ cr0 = clk_div -+ | SSCR0_Motorola -+ | SSCR0_DataSize(bits & 0x0f) -+ | SSCR0_SSE -+ | (bits > 16 ? SSCR0_EDSS : 0); -+ -+ /* Start it back up */ -+ write_SSCR0(cr0, reg); -+ } -+ - message->state = RUNNING_STATE; - - /* Try to map dma buffer and do a dma transfer if successful */ -@@ -739,13 +805,13 @@ static void pump_transfers(unsigned long - if (drv_data->rx == drv_data->null_dma_buf) - /* No target address increment */ - DCMD(drv_data->rx_channel) = DCMD_FLOWSRC -- | chip->dma_width -+ | drv_data->dma_width - | chip->dma_burst_size - | drv_data->len; - else - DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR - | DCMD_FLOWSRC -- | chip->dma_width -+ | drv_data->dma_width - | chip->dma_burst_size - | drv_data->len; - -@@ -756,13 +822,13 @@ static void pump_transfers(unsigned long - if (drv_data->tx == drv_data->null_dma_buf) - /* No source address increment */ - DCMD(drv_data->tx_channel) = DCMD_FLOWTRG -- | chip->dma_width -+ | drv_data->dma_width - | chip->dma_burst_size - | drv_data->len; - else - DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR - | DCMD_FLOWTRG -- | chip->dma_width -+ | drv_data->dma_width - | chip->dma_burst_size - | drv_data->len; - -@@ -943,6 +1009,7 @@ static int setup(struct spi_device *spi) - clk_div = SSP3_SerClkDiv(spi->max_speed_hz); - else - return -ENODEV; -+ chip->speed_hz = spi->max_speed_hz; - - chip->cr0 = clk_div - | SSCR0_Motorola -@@ -987,6 +1054,7 @@ static int setup(struct spi_device *spi) - kfree(chip); - return -ENODEV; - } -+ chip->bits_per_word = spi->bits_per_word; - - spi_set_ctldata(spi, chip); - diff --git a/driver/sysfs-crash-debugging.patch b/driver/sysfs-crash-debugging.patch index 7cb020e65747c..2ab142db9c54c 100644 --- a/driver/sysfs-crash-debugging.patch +++ b/driver/sysfs-crash-debugging.patch @@ -35,7 +35,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> NOTIFY_STOP) { --- gregkh-2.6.orig/arch/x86_64/kernel/traps.c +++ gregkh-2.6/arch/x86_64/kernel/traps.c -@@ -436,6 +436,7 @@ void __kprobes __die(const char * str, s +@@ -438,6 +438,7 @@ void __kprobes __die(const char * str, s printk("DEBUG_PAGEALLOC"); #endif printk("\n"); |