diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-12-29 01:05:14 -0700 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-12-29 01:05:50 -0700 |
commit | 94a544a4e8d05a027613443c529c399c39cc3371 (patch) | |
tree | edada38e93a958a918b5826eaef173b1b92079d1 | |
parent | 496a2e360a34e1f41c336d23947f800216cb9bdf (diff) | |
parent | 21486af0f34d03b813b023d7a2b887b329f60486 (diff) |
Merge branch 'spi' of git://git.linutronix.de/users/bigeasy/soda into spi/next
* 'spi' of git://git.linutronix.de/users/bigeasy/soda into spi/next
spi/pxa2xx: register driver properly
spi/pxa2xx: add support for shared IRQ handler
spi/pxa2xx: Use define for SSSR_TFL_MASK instead of plain numbers
arm/pxa2xx: reorgazine SSP and SPI header files
spi/pxa2xx: Add CE4100 support
spi/pxa2xx: Consider CE4100's FIFO depth
spi/pxa2xx: Add chipselect support for Sodaville
spi/pxa2xx: Modify RX-Tresh instead of busy-loop for the remaining RX bytes.
spi/pxa2xx: pass of_node to spi device and set a parent device
27 files changed, 547 insertions, 138 deletions
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx index 6bb916d57c9..68a4fe3818a 100644 --- a/Documentation/spi/pxa2xx +++ b/Documentation/spi/pxa2xx @@ -19,7 +19,7 @@ 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 arch/arm/mach-pxa/include/mach/pxa2xx_spi.h: +found in include/linux/spi/pxa2xx_spi.h: struct pxa2xx_spi_master { enum pxa_ssp_type ssp_type; @@ -94,7 +94,7 @@ using the "spi_board_info" structure found in "linux/spi/spi.h". See Each slave device attached to the PXA must provide slave specific configuration information via the structure "pxa2xx_spi_chip" found in -"arch/arm/mach-pxa/include/mach/pxa2xx_spi.h". The pxa2xx_spi master controller driver +"include/linux/spi/pxa2xx_spi.h". The pxa2xx_spi master controller driver will uses the configuration whenever the driver communicates with the slave device. All fields are optional. diff --git a/arch/arm/mach-pxa/cm-x255.c b/arch/arm/mach-pxa/cm-x255.c index f1a7703d771..93f59f877fc 100644 --- a/arch/arm/mach-pxa/cm-x255.c +++ b/arch/arm/mach-pxa/cm-x255.c @@ -17,13 +17,13 @@ #include <linux/mtd/nand-gpio.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <asm/mach/arch.h> #include <asm/mach-types.h> #include <asm/mach/map.h> #include <mach/pxa25x.h> -#include <mach/pxa2xx_spi.h> #include "generic.h" diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index a9926bb7592..b88d601a809 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -19,12 +19,12 @@ #include <video/mbxfb.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/libertas_spi.h> #include <mach/pxa27x.h> #include <mach/ohci.h> #include <mach/mmc.h> -#include <mach/pxa2xx_spi.h> #include "generic.h" diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 821229acabe..3b8dcac2b8f 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -28,6 +28,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/spi/corgi_lcd.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/mtd/sharpsl.h> #include <linux/input/matrix_keypad.h> #include <video/w100fb.h> @@ -48,7 +49,6 @@ #include <mach/irda.h> #include <mach/mmc.h> #include <mach/udc.h> -#include <mach/pxa2xx_spi.h> #include <mach/corgi.h> #include <mach/sharpsl_pm.h> diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index aaa1166df96..c4f9c715be7 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -3,6 +3,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/spi/pxa2xx_spi.h> #include <asm/pmu.h> #include <mach/udc.h> @@ -12,7 +13,6 @@ #include <mach/irda.h> #include <mach/ohci.h> #include <plat/pxa27x_keypad.h> -#include <mach/pxa2xx_spi.h> #include <mach/camera.h> #include <mach/audio.h> #include <mach/hardware.h> diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index ed0dbfdb22e..b20b944c337 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -26,6 +26,7 @@ #include <linux/spi/spi.h> #include <linux/spi/tdo24m.h> #include <linux/spi/libertas_spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/power_supply.h> #include <linux/apm-emulation.h> #include <linux/i2c.h> @@ -46,7 +47,6 @@ #include <plat/pxa27x_keypad.h> #include <plat/i2c.h> #include <mach/camera.h> -#include <mach/pxa2xx_spi.h> #include "generic.h" #include "devices.h" diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 76d93a25bab..f09526f5215 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -33,6 +33,7 @@ #include <linux/regulator/max1586.h> #include <linux/spi/ads7846.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/usb/gpio_vbus.h> #include <mach/hardware.h> @@ -43,7 +44,6 @@ #include <mach/hx4700.h> #include <plat/i2c.h> #include <mach/irda.h> -#include <mach/pxa2xx_spi.h> #include <video/platform_lcd.h> #include <video/w100fb.h> diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c index d51ee3d25e7..3ab6fd36958 100644 --- a/arch/arm/mach-pxa/icontrol.c +++ b/arch/arm/mach-pxa/icontrol.c @@ -24,7 +24,7 @@ #include <mach/mxm8x10.h> #include <linux/spi/spi.h> -#include <mach/pxa2xx_spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/can/platform/mcp251x.h> #include "generic.h" diff --git a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h b/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h deleted file mode 100644 index b87cecd9bbd..00000000000 --- a/arch/arm/mach-pxa/include/mach/pxa2xx_spi.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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) - -/* device.platform_data for SSP controller devices */ -struct pxa2xx_spi_master { - 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; - u8 enable_loopback; - int gpio_cs; - void (*cs_control)(u32 command); -}; - -extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info); - -#endif /*PXA2XX_SPI_H_*/ diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index 41aa89e3577..8051925d457 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/gpio.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/smc91x.h> #include <linux/i2c.h> #include <linux/leds.h> @@ -42,7 +43,6 @@ #include <mach/pxa300.h> #include <mach/pxafb.h> #include <mach/mmc.h> -#include <mach/pxa2xx_spi.h> #include <plat/pxa27x_keypad.h> #include <mach/littleton.h> #include <plat/i2c.h> diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 1499493cd07..4a3fe450c20 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -25,7 +25,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> -#include <mach/pxa2xx_spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <asm/setup.h> #include <asm/memory.h> diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c index c77e8f30a43..a5596f9b17b 100644 --- a/arch/arm/mach-pxa/pcm027.c +++ b/arch/arm/mach-pxa/pcm027.c @@ -25,12 +25,12 @@ #include <linux/mtd/physmap.h> #include <linux/spi/spi.h> #include <linux/spi/max7301.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/leds.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/pxa27x.h> -#include <mach/pxa2xx_spi.h> #include <mach/pcm027.h> #include "generic.h" diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 93a191c889d..c05eee32623 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -25,6 +25,7 @@ #include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/mtd/sharpsl.h> #include <mach/hardware.h> @@ -43,7 +44,6 @@ #include <mach/irda.h> #include <mach/poodle.h> #include <mach/pxafb.h> -#include <mach/pxa2xx_spi.h> #include <plat/i2c.h> #include <asm/hardware/scoop.h> diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index f736119f1eb..4fd5572f699 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -23,7 +23,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/spi/corgi_lcd.h> -#include <linux/mtd/physmap.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/mtd/sharpsl.h> #include <linux/input/matrix_keypad.h> #include <linux/regulator/machine.h> @@ -41,7 +41,6 @@ #include <mach/mmc.h> #include <mach/ohci.h> #include <mach/pxafb.h> -#include <mach/pxa2xx_spi.h> #include <mach/spitz.h> #include <mach/sharpsl_pm.h> diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index 738adc1773f..325f6ac6b59 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -46,10 +46,10 @@ #include <plat/i2c.h> #include <mach/mmc.h> #include <mach/udc.h> -#include <mach/pxa2xx_spi.h> #include <mach/pxa27x-udc.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/mfd/da903x.h> #include <linux/sht15.h> diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 0ee1df49606..7b5765dacbd 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -32,6 +32,7 @@ #include <linux/gpio.h> #include <linux/pda_power.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/input/matrix_keypad.h> #include <asm/setup.h> @@ -44,7 +45,6 @@ #include <mach/mmc.h> #include <mach/udc.h> #include <mach/tosa_bt.h> -#include <mach/pxa2xx_spi.h> #include <mach/audio.h> #include <asm/mach/arch.h> diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index 565d062f51d..bdb02a0ae1b 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -40,7 +40,6 @@ #include <asm/mach/flash.h> #include <mach/pxa27x.h> -#include <mach/pxa2xx_spi.h> #include <mach/trizeps4.h> #include <mach/audio.h> #include <mach/pxafb.h> diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c index fefde9848d8..1b8b71b3c71 100644 --- a/arch/arm/mach-pxa/z2.c +++ b/arch/arm/mach-pxa/z2.c @@ -20,6 +20,7 @@ #include <linux/z2_battery.h> #include <linux/dma-mapping.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/libertas_spi.h> #include <linux/spi/lms283gf05.h> #include <linux/power_supply.h> @@ -38,7 +39,6 @@ #include <mach/pxafb.h> #include <mach/mmc.h> #include <plat/pxa27x_keypad.h> -#include <mach/pxa2xx_spi.h> #include <plat/i2c.h> diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index dea46a2d089..f5c9f3032c3 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -20,6 +20,7 @@ #include <linux/dm9000.h> #include <linux/mmc/host.h> #include <linux/spi/spi.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> @@ -41,7 +42,6 @@ #include <mach/pxa27x-udc.h> #include <mach/udc.h> #include <mach/pxafb.h> -#include <mach/pxa2xx_spi.h> #include <mach/mfp-pxa27x.h> #include <mach/pm.h> #include <mach/audio.h> diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c index c6357e554ab..58b79809d20 100644 --- a/arch/arm/plat-pxa/ssp.c +++ b/arch/arm/plat-pxa/ssp.c @@ -28,11 +28,11 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/platform_device.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/io.h> #include <asm/irq.h> #include <mach/hardware.h> -#include <plat/ssp.h> static DEFINE_MUTEX(ssp_lock); static LIST_HEAD(ssp_list); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6efac5fd439..1906840c111 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -270,12 +270,15 @@ config SPI_PPC4xx config SPI_PXA2XX tristate "PXA2xx SSP SPI master" - depends on ARCH_PXA && EXPERIMENTAL - select PXA_SSP + depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL + select PXA_SSP if ARCH_PXA 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. + This enables using a PXA2xx or Sodaville 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. + +config SPI_PXA2XX_PCI + def_bool SPI_PXA2XX && X86_32 && PCI config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7ec375b6c0c..3a42463c92a 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o +obj-$(CONFIG_SPI_PXA2XX_PCI) += pxa2xx_spi_pci.o obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index e76b1afafe0..95928833855 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -23,11 +23,11 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/spi/pxa2xx_spi.h> #include <linux/dma-mapping.h> #include <linux/spi/spi.h> #include <linux/workqueue.h> #include <linux/delay.h> -#include <linux/clk.h> #include <linux/gpio.h> #include <linux/slab.h> @@ -35,9 +35,6 @@ #include <asm/irq.h> #include <asm/delay.h> -#include <mach/dma.h> -#include <plat/ssp.h> -#include <mach/pxa2xx_spi.h> MODULE_AUTHOR("Stephen Street"); MODULE_DESCRIPTION("PXA2xx SSP SPI Controller"); @@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi"); #define MAX_BUSES 3 -#define RX_THRESH_DFLT 8 -#define TX_THRESH_DFLT 8 #define TIMOUT_DFLT 1000 #define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR) @@ -168,7 +163,10 @@ struct chip_data { u8 enable_dma; u8 bits_per_word; u32 speed_hz; - int gpio_cs; + union { + int gpio_cs; + unsigned int frm; + }; int gpio_cs_inverted; int (*write)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data); @@ -181,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + if (drv_data->ssp_type == CE4100_SSP) { + write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr); + return; + } + if (chip->cs_control) { chip->cs_control(PXA2XX_CS_ASSERT); return; @@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; + if (drv_data->ssp_type == CE4100_SSP) + return; + if (chip->cs_control) { chip->cs_control(PXA2XX_CS_DEASSERT); return; @@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data) gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); } +static void write_SSSR_CS(struct driver_data *drv_data, u32 val) +{ + void __iomem *reg = drv_data->ioaddr; + + if (drv_data->ssp_type == CE4100_SSP) + val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; + + write_SSSR(val, reg); +} + +static int pxa25x_ssp_comp(struct driver_data *drv_data) +{ + if (drv_data->ssp_type == PXA25x_SSP) + return 1; + if (drv_data->ssp_type == CE4100_SSP) + return 1; + return 0; +} + static int flush(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; @@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data) read_SSDR(reg); } } while ((read_SSSR(reg) & SSSR_BSY) && --limit); - write_SSSR(SSSR_ROR, reg); + write_SSSR_CS(drv_data, SSSR_ROR); return limit; } @@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data) void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; - if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) + if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; @@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg) /* Stop and reset */ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; - write_SSSR(drv_data->clear_sr, reg); + write_SSSR_CS(drv_data, drv_data->clear_sr); write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); - if (drv_data->ssp_type != PXA25x_SSP) + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); flush(drv_data); write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); @@ -529,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data) /* Clear and disable interrupts on SSP and DMA channels*/ write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); - write_SSSR(drv_data->clear_sr, reg); + write_SSSR_CS(drv_data, drv_data->clear_sr); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; @@ -622,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) /* Clear and disable timeout interrupt, do the rest in * dma_transfer_complete */ - if (drv_data->ssp_type != PXA25x_SSP) + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); /* finish this transfer, start the next */ @@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) return IRQ_NONE; } +static void reset_sccr1(struct driver_data *drv_data) +{ + void __iomem *reg = drv_data->ioaddr; + struct chip_data *chip = drv_data->cur_chip; + u32 sccr1_reg; + + sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1; + sccr1_reg &= ~SSCR1_RFT; + sccr1_reg |= chip->threshold; + write_SSCR1(sccr1_reg, reg); +} + static void int_error_stop(struct driver_data *drv_data, const char* msg) { void __iomem *reg = drv_data->ioaddr; /* Stop and reset SSP */ - write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); - if (drv_data->ssp_type != PXA25x_SSP) + write_SSSR_CS(drv_data, drv_data->clear_sr); + reset_sccr1(drv_data); + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); flush(drv_data); write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); @@ -658,9 +695,9 @@ static void int_transfer_complete(struct driver_data *drv_data) void __iomem *reg = drv_data->ioaddr; /* Stop SSP */ - write_SSSR(drv_data->clear_sr, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); - if (drv_data->ssp_type != PXA25x_SSP) + write_SSSR_CS(drv_data, drv_data->clear_sr); + reset_sccr1(drv_data); + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); /* Update total byte transfered return count actual bytes read */ @@ -714,24 +751,34 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) } if (drv_data->tx == drv_data->tx_end) { - write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); - /* PXA25x_SSP has no timeout, read trailing bytes */ - if (drv_data->ssp_type == PXA25x_SSP) { - if (!wait_ssp_rx_stall(reg)) - { - int_error_stop(drv_data, "interrupt_transfer: " - "rx stall failed"); - return IRQ_HANDLED; - } - if (!drv_data->read(drv_data)) - { - int_error_stop(drv_data, - "interrupt_transfer: " - "trailing byte read failed"); - return IRQ_HANDLED; + u32 bytes_left; + u32 sccr1_reg; + + sccr1_reg = read_SSCR1(reg); + sccr1_reg &= ~SSCR1_TIE; + + /* + * PXA25x_SSP has no timeout, set up rx threshould for the + * remaing RX bytes. + */ + if (pxa25x_ssp_comp(drv_data)) { + + sccr1_reg &= ~SSCR1_RFT; + + bytes_left = drv_data->rx_end - drv_data->rx; + switch (drv_data->n_bytes) { + case 4: + bytes_left >>= 1; + case 2: + bytes_left >>= 1; } - int_transfer_complete(drv_data); + + if (bytes_left > RX_THRESH_DFLT) + bytes_left = RX_THRESH_DFLT; + + sccr1_reg |= SSCR1_RxTresh(bytes_left); } + write_SSCR1(sccr1_reg, reg); } /* We did something */ @@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; void __iomem *reg = drv_data->ioaddr; + u32 sccr1_reg = read_SSCR1(reg); + u32 mask = drv_data->mask_sr; + u32 status; + + status = read_SSSR(reg); + + /* Ignore possible writes if we don't need to write */ + if (!(sccr1_reg & SSCR1_TIE)) + mask &= ~SSSR_TFS; + + if (!(status & mask)) + return IRQ_NONE; if (!drv_data->cur_msg) { write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); - if (drv_data->ssp_type != PXA25x_SSP) + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); - write_SSSR(drv_data->clear_sr, reg); + write_SSSR_CS(drv_data, drv_data->clear_sr); dev_err(&drv_data->pdev->dev, "bad message state " "in interrupt handler\n"); @@ -862,7 +921,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate) { unsigned long ssp_clk = clk_get_rate(ssp->clk); - if (ssp->type == PXA25x_SSP) + if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; else return ((ssp_clk / rate - 1) & 0xfff) << 8; @@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data) /* Clear status */ cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1; - write_SSSR(drv_data->clear_sr, reg); + write_SSSR_CS(drv_data, drv_data->clear_sr); } /* see if we need to reload the config registers */ @@ -1098,7 +1157,7 @@ static void pump_transfers(unsigned long data) /* stop the SSP, and update the other bits */ write_SSCR0(cr0 & ~SSCR0_SSE, reg); - if (drv_data->ssp_type != PXA25x_SSP) + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(chip->timeout, reg); /* first set CR1 without interrupt and service enables */ write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg); @@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data) write_SSCR0(cr0, reg); } else { - if (drv_data->ssp_type != PXA25x_SSP) + if (!pxa25x_ssp_comp(drv_data)) write_SSTO(chip->timeout, reg); } @@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi) uint tx_thres = TX_THRESH_DFLT; uint rx_thres = RX_THRESH_DFLT; - if (drv_data->ssp_type != PXA25x_SSP + if (!pxa25x_ssp_comp(drv_data) && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) { dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " "b/w not 4-32 for type non-PXA25x_SSP\n", drv_data->ssp_type, spi->bits_per_word); return -EINVAL; - } - else if (drv_data->ssp_type == PXA25x_SSP + } else if (pxa25x_ssp_comp(drv_data) && (spi->bits_per_word < 4 || spi->bits_per_word > 16)) { dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " @@ -1259,7 +1317,17 @@ static int setup(struct spi_device *spi) return -ENOMEM; } - chip->gpio_cs = -1; + if (drv_data->ssp_type == CE4100_SSP) { + if (spi->chip_select > 4) { + dev_err(&spi->dev, "failed setup: " + "cs number must not be > 4.\n"); + kfree(chip); + return -EINVAL; + } + + chip->frm = spi->chip_select; + } else + chip->gpio_cs = -1; chip->enable_dma = 0; chip->timeout = TIMOUT_DFLT; chip->dma_burst_size = drv_data->master_info->enable_dma ? @@ -1315,7 +1383,7 @@ static int setup(struct spi_device *spi) | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); /* NOTE: PXA25x_SSP _could_ use e |