浏览代码

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
Grant Likely 14 年之前
父节点
当前提交
94a544a4e8

+ 2 - 2
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
 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
 "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 {
 struct pxa2xx_spi_master {
 	enum pxa_ssp_type ssp_type;
 	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
 Each slave device attached to the PXA must provide slave specific configuration
 information via the structure "pxa2xx_spi_chip" found in
 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
 will uses the configuration whenever the driver communicates with the slave
 device. All fields are optional.
 device. All fields are optional.
 
 

+ 1 - 1
arch/arm/mach-pxa/cm-x255.c

@@ -17,13 +17,13 @@
 #include <linux/mtd/nand-gpio.h>
 #include <linux/mtd/nand-gpio.h>
 
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 
 
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 #include <asm/mach/map.h>
 
 
 #include <mach/pxa25x.h>
 #include <mach/pxa25x.h>
-#include <mach/pxa2xx_spi.h>
 
 
 #include "generic.h"
 #include "generic.h"
 
 

+ 1 - 1
arch/arm/mach-pxa/cm-x270.c

@@ -19,12 +19,12 @@
 #include <video/mbxfb.h>
 #include <video/mbxfb.h>
 
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/libertas_spi.h>
 #include <linux/spi/libertas_spi.h>
 
 
 #include <mach/pxa27x.h>
 #include <mach/pxa27x.h>
 #include <mach/ohci.h>
 #include <mach/ohci.h>
 #include <mach/mmc.h>
 #include <mach/mmc.h>
-#include <mach/pxa2xx_spi.h>
 
 
 #include "generic.h"
 #include "generic.h"
 
 

+ 1 - 1
arch/arm/mach-pxa/corgi.c

@@ -28,6 +28,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/corgi_lcd.h>
 #include <linux/spi/corgi_lcd.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/input/matrix_keypad.h>
 #include <video/w100fb.h>
 #include <video/w100fb.h>
@@ -48,7 +49,6 @@
 #include <mach/irda.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/udc.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/corgi.h>
 #include <mach/corgi.h>
 #include <mach/sharpsl_pm.h>
 #include <mach/sharpsl_pm.h>
 
 

+ 1 - 1
arch/arm/mach-pxa/devices.c

@@ -3,6 +3,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
+#include <linux/spi/pxa2xx_spi.h>
 
 
 #include <asm/pmu.h>
 #include <asm/pmu.h>
 #include <mach/udc.h>
 #include <mach/udc.h>
@@ -12,7 +13,6 @@
 #include <mach/irda.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
 #include <mach/ohci.h>
 #include <plat/pxa27x_keypad.h>
 #include <plat/pxa27x_keypad.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/camera.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
 #include <mach/audio.h>
 #include <mach/hardware.h>
 #include <mach/hardware.h>

+ 1 - 1
arch/arm/mach-pxa/em-x270.c

@@ -26,6 +26,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/tdo24m.h>
 #include <linux/spi/tdo24m.h>
 #include <linux/spi/libertas_spi.h>
 #include <linux/spi/libertas_spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/power_supply.h>
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 #include <linux/apm-emulation.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
@@ -46,7 +47,6 @@
 #include <plat/pxa27x_keypad.h>
 #include <plat/pxa27x_keypad.h>
 #include <plat/i2c.h>
 #include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/camera.h>
-#include <mach/pxa2xx_spi.h>
 
 
 #include "generic.h"
 #include "generic.h"
 #include "devices.h"
 #include "devices.h"

+ 1 - 1
arch/arm/mach-pxa/hx4700.c

@@ -33,6 +33,7 @@
 #include <linux/regulator/max1586.h>
 #include <linux/regulator/max1586.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/usb/gpio_vbus.h>
 
 
 #include <mach/hardware.h>
 #include <mach/hardware.h>
@@ -43,7 +44,6 @@
 #include <mach/hx4700.h>
 #include <mach/hx4700.h>
 #include <plat/i2c.h>
 #include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/irda.h>
-#include <mach/pxa2xx_spi.h>
 
 
 #include <video/platform_lcd.h>
 #include <video/platform_lcd.h>
 #include <video/w100fb.h>
 #include <video/w100fb.h>

+ 1 - 1
arch/arm/mach-pxa/icontrol.c

@@ -24,7 +24,7 @@
 #include <mach/mxm8x10.h>
 #include <mach/mxm8x10.h>
 
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
-#include <mach/pxa2xx_spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/can/platform/mcp251x.h>
 #include <linux/can/platform/mcp251x.h>
 
 
 #include "generic.h"
 #include "generic.h"

+ 0 - 47
arch/arm/mach-pxa/include/mach/pxa2xx_spi.h

@@ -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_*/

+ 1 - 1
arch/arm/mach-pxa/littleton.c

@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/smc91x.h>
 #include <linux/smc91x.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/leds.h>
 #include <linux/leds.h>
@@ -42,7 +43,6 @@
 #include <mach/pxa300.h>
 #include <mach/pxa300.h>
 #include <mach/pxafb.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/mmc.h>
-#include <mach/pxa2xx_spi.h>
 #include <plat/pxa27x_keypad.h>
 #include <plat/pxa27x_keypad.h>
 #include <mach/littleton.h>
 #include <mach/littleton.h>
 #include <plat/i2c.h>
 #include <plat/i2c.h>

+ 1 - 1
arch/arm/mach-pxa/lubbock.c

@@ -25,7 +25,7 @@
 
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/ads7846.h>
-#include <mach/pxa2xx_spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 
 
 #include <asm/setup.h>
 #include <asm/setup.h>
 #include <asm/memory.h>
 #include <asm/memory.h>

+ 1 - 1
arch/arm/mach-pxa/pcm027.c

@@ -25,12 +25,12 @@
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/max7301.h>
 #include <linux/spi/max7301.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/leds.h>
 #include <linux/leds.h>
 
 
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
 #include <mach/pxa27x.h>
 #include <mach/pxa27x.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/pcm027.h>
 #include <mach/pcm027.h>
 #include "generic.h"
 #include "generic.h"
 
 

+ 1 - 1
arch/arm/mach-pxa/poodle.c

@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/ads7846.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/mtd/sharpsl.h>
 
 
 #include <mach/hardware.h>
 #include <mach/hardware.h>
@@ -43,7 +44,6 @@
 #include <mach/irda.h>
 #include <mach/irda.h>
 #include <mach/poodle.h>
 #include <mach/poodle.h>
 #include <mach/pxafb.h>
 #include <mach/pxafb.h>
-#include <mach/pxa2xx_spi.h>
 #include <plat/i2c.h>
 #include <plat/i2c.h>
 
 
 #include <asm/hardware/scoop.h>
 #include <asm/hardware/scoop.h>

+ 1 - 2
arch/arm/mach-pxa/spitz.c

@@ -23,7 +23,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/corgi_lcd.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/mtd/sharpsl.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/machine.h>
@@ -41,7 +41,6 @@
 #include <mach/mmc.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <mach/ohci.h>
 #include <mach/pxafb.h>
 #include <mach/pxafb.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/spitz.h>
 #include <mach/spitz.h>
 #include <mach/sharpsl_pm.h>
 #include <mach/sharpsl_pm.h>
 
 

+ 1 - 1
arch/arm/mach-pxa/stargate2.c

@@ -46,10 +46,10 @@
 #include <plat/i2c.h>
 #include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/udc.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/pxa27x-udc.h>
 
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mfd/da903x.h>
 #include <linux/mfd/da903x.h>
 #include <linux/sht15.h>
 #include <linux/sht15.h>
 
 

+ 1 - 1
arch/arm/mach-pxa/tosa.c

@@ -32,6 +32,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
 #include <linux/pda_power.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/input/matrix_keypad.h>
 
 
 #include <asm/setup.h>
 #include <asm/setup.h>
@@ -44,7 +45,6 @@
 #include <mach/mmc.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/udc.h>
 #include <mach/tosa_bt.h>
 #include <mach/tosa_bt.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/audio.h>
 #include <mach/audio.h>
 
 
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>

+ 0 - 1
arch/arm/mach-pxa/trizeps4.c

@@ -40,7 +40,6 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/flash.h>
 
 
 #include <mach/pxa27x.h>
 #include <mach/pxa27x.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/trizeps4.h>
 #include <mach/trizeps4.h>
 #include <mach/audio.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
 #include <mach/pxafb.h>

+ 1 - 1
arch/arm/mach-pxa/z2.c

@@ -20,6 +20,7 @@
 #include <linux/z2_battery.h>
 #include <linux/z2_battery.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/libertas_spi.h>
 #include <linux/spi/libertas_spi.h>
 #include <linux/spi/lms283gf05.h>
 #include <linux/spi/lms283gf05.h>
 #include <linux/power_supply.h>
 #include <linux/power_supply.h>
@@ -38,7 +39,6 @@
 #include <mach/pxafb.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/mmc.h>
 #include <plat/pxa27x_keypad.h>
 #include <plat/pxa27x_keypad.h>
-#include <mach/pxa2xx_spi.h>
 
 
 #include <plat/i2c.h>
 #include <plat/i2c.h>
 
 

+ 1 - 1
arch/arm/mach-pxa/zeus.c

@@ -20,6 +20,7 @@
 #include <linux/dm9000.h>
 #include <linux/dm9000.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/physmap.h>
@@ -41,7 +42,6 @@
 #include <mach/pxa27x-udc.h>
 #include <mach/pxa27x-udc.h>
 #include <mach/udc.h>
 #include <mach/udc.h>
 #include <mach/pxafb.h>
 #include <mach/pxafb.h>
-#include <mach/pxa2xx_spi.h>
 #include <mach/mfp-pxa27x.h>
 #include <mach/mfp-pxa27x.h>
 #include <mach/pm.h>
 #include <mach/pm.h>
 #include <mach/audio.h>
 #include <mach/audio.h>

+ 1 - 1
arch/arm/plat-pxa/ssp.c

@@ -28,11 +28,11 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/io.h>
 #include <linux/io.h>
 
 
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <mach/hardware.h>
-#include <plat/ssp.h>
 
 
 static DEFINE_MUTEX(ssp_lock);
 static DEFINE_MUTEX(ssp_lock);
 static LIST_HEAD(ssp_list);
 static LIST_HEAD(ssp_list);

+ 8 - 5
drivers/spi/Kconfig

@@ -270,12 +270,15 @@ config SPI_PPC4xx
 
 
 config SPI_PXA2XX
 config SPI_PXA2XX
 	tristate "PXA2xx SSP SPI master"
 	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
 	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
 config SPI_S3C24XX
 	tristate "Samsung S3C24XX series SPI"
 	tristate "Samsung S3C24XX series SPI"

+ 1 - 0
drivers/spi/Makefile

@@ -25,6 +25,7 @@ obj-$(CONFIG_SPI_GPIO)			+= spi_gpio.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
 obj-$(CONFIG_SPI_PXA2XX)		+= pxa2xx_spi.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_OMAP_UWIRE)		+= omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= omap2_mcspi.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= omap2_mcspi.o
 obj-$(CONFIG_SPI_OMAP_100K)		+= omap_spi_100k.o
 obj-$(CONFIG_SPI_OMAP_100K)		+= omap_spi_100k.o

+ 134 - 56
drivers/spi/pxa2xx_spi.c

@@ -23,11 +23,11 @@
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/spi/pxa2xx_spi.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
-#include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
@@ -35,9 +35,6 @@
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 #include <asm/delay.h>
 
 
-#include <mach/dma.h>
-#include <plat/ssp.h>
-#include <mach/pxa2xx_spi.h>
 
 
 MODULE_AUTHOR("Stephen Street");
 MODULE_AUTHOR("Stephen Street");
 MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
 MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
@@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 
 
 #define MAX_BUSES 3
 #define MAX_BUSES 3
 
 
-#define RX_THRESH_DFLT 	8
-#define TX_THRESH_DFLT 	8
 #define TIMOUT_DFLT		1000
 #define TIMOUT_DFLT		1000
 
 
 #define DMA_INT_MASK		(DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
 #define DMA_INT_MASK		(DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
@@ -168,7 +163,10 @@ struct chip_data {
 	u8 enable_dma;
 	u8 enable_dma;
 	u8 bits_per_word;
 	u8 bits_per_word;
 	u32 speed_hz;
 	u32 speed_hz;
-	int gpio_cs;
+	union {
+		int gpio_cs;
+		unsigned int frm;
+	};
 	int gpio_cs_inverted;
 	int gpio_cs_inverted;
 	int (*write)(struct driver_data *drv_data);
 	int (*write)(struct driver_data *drv_data);
 	int (*read)(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;
 	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) {
 	if (chip->cs_control) {
 		chip->cs_control(PXA2XX_CS_ASSERT);
 		chip->cs_control(PXA2XX_CS_ASSERT);
 		return;
 		return;
@@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data)
 {
 {
 	struct chip_data *chip = drv_data->cur_chip;
 	struct chip_data *chip = drv_data->cur_chip;
 
 
+	if (drv_data->ssp_type == CE4100_SSP)
+		return;
+
 	if (chip->cs_control) {
 	if (chip->cs_control) {
 		chip->cs_control(PXA2XX_CS_DEASSERT);
 		chip->cs_control(PXA2XX_CS_DEASSERT);
 		return;
 		return;
@@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data)
 		gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
 		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)
 static int flush(struct driver_data *drv_data)
 {
 {
 	unsigned long limit = loops_per_jiffy << 1;
 	unsigned long limit = loops_per_jiffy << 1;
@@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data)
 			read_SSDR(reg);
 			read_SSDR(reg);
 		}
 		}
 	} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
 	} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
-	write_SSSR(SSSR_ROR, reg);
+	write_SSSR_CS(drv_data, SSSR_ROR);
 
 
 	return limit;
 	return limit;
 }
 }
@@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data)
 	void __iomem *reg = drv_data->ioaddr;
 	void __iomem *reg = drv_data->ioaddr;
 	u8 n_bytes = drv_data->n_bytes;
 	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))
 		|| (drv_data->tx == drv_data->tx_end))
 		return 0;
 		return 0;
 
 
@@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data)
 {
 {
 	void __iomem *reg = drv_data->ioaddr;
 	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))
 		|| (drv_data->tx == drv_data->tx_end))
 		return 0;
 		return 0;
 
 
@@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data)
 {
 {
 	void __iomem *reg = drv_data->ioaddr;
 	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))
 		|| (drv_data->tx == drv_data->tx_end))
 		return 0;
 		return 0;
 
 
@@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data)
 {
 {
 	void __iomem *reg = drv_data->ioaddr;
 	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))
 		|| (drv_data->tx == drv_data->tx_end))
 		return 0;
 		return 0;
 
 
@@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
 	/* Stop and reset */
 	/* Stop and reset */
 	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
 	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
 	DCSR(drv_data->tx_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);
 	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);
 		write_SSTO(0, reg);
 	flush(drv_data);
 	flush(drv_data);
 	write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 	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*/
 	/* Clear and disable interrupts on SSP and DMA channels*/
 	write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
 	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->tx_channel) = RESET_DMA_CHANNEL;
 	DCSR(drv_data->rx_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
 		/* Clear and disable timeout interrupt, do the rest in
 		 * dma_transfer_complete */
 		 * dma_transfer_complete */
-		if (drv_data->ssp_type != PXA25x_SSP)
+		if (!pxa25x_ssp_comp(drv_data))
 			write_SSTO(0, reg);
 			write_SSTO(0, reg);
 
 
 		/* finish this transfer, start the next */
 		/* finish this transfer, start the next */
@@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 	return IRQ_NONE;
 	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)
 static void int_error_stop(struct driver_data *drv_data, const char* msg)
 {
 {
 	void __iomem *reg = drv_data->ioaddr;
 	void __iomem *reg = drv_data->ioaddr;
 
 
 	/* Stop and reset SSP */
 	/* 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);
 		write_SSTO(0, reg);
 	flush(drv_data);
 	flush(drv_data);
 	write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 	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;
 	void __iomem *reg = drv_data->ioaddr;
 
 
 	/* Stop SSP */
 	/* 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);
 		write_SSTO(0, reg);
 
 
 	/* Update total byte transfered return count actual bytes read */
 	/* 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) {
 	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 */
 	/* We did something */
@@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
 {
 {
 	struct driver_data *drv_data = dev_id;
 	struct driver_data *drv_data = dev_id;
 	void __iomem *reg = drv_data->ioaddr;
 	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) {
 	if (!drv_data->cur_msg) {
 
 
 		write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 		write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
 		write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, 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_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 "
 		dev_err(&drv_data->pdev->dev, "bad message state "
 			"in interrupt handler\n");
 			"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);
 	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;
 		return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
 	else
 	else
 		return ((ssp_clk / rate - 1) & 0xfff) << 8;
 		return ((ssp_clk / rate - 1) & 0xfff) << 8;
@@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data)
 
 
 		/* Clear status  */
 		/* Clear status  */
 		cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
 		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 */
 	/* 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 */
 		/* stop the SSP, and update the other bits */
 		write_SSCR0(cr0 & ~SSCR0_SSE, reg);
 		write_SSCR0(cr0 & ~SSCR0_SSE, reg);
-		if (drv_data->ssp_type != PXA25x_SSP)
+		if (!pxa25x_ssp_comp(drv_data))
 			write_SSTO(chip->timeout, reg);
 			write_SSTO(chip->timeout, reg);
 		/* first set CR1 without interrupt and service enables */
 		/* first set CR1 without interrupt and service enables */
 		write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
 		write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
@@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data)
 		write_SSCR0(cr0, reg);
 		write_SSCR0(cr0, reg);
 
 
 	} else {
 	} else {
-		if (drv_data->ssp_type != PXA25x_SSP)
+		if (!pxa25x_ssp_comp(drv_data))
 			write_SSTO(chip->timeout, reg);
 			write_SSTO(chip->timeout, reg);
 	}
 	}
 
 
@@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi)
 	uint tx_thres = TX_THRESH_DFLT;
 	uint tx_thres = TX_THRESH_DFLT;
 	uint rx_thres = RX_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)) {
 		&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
 		dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
 		dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
 				"b/w not 4-32 for type non-PXA25x_SSP\n",
 				"b/w not 4-32 for type non-PXA25x_SSP\n",
 				drv_data->ssp_type, spi->bits_per_word);
 				drv_data->ssp_type, spi->bits_per_word);
 		return -EINVAL;
 		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 < 4
 				|| spi->bits_per_word > 16)) {
 				|| spi->bits_per_word > 16)) {
 		dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
 		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;
 			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->enable_dma = 0;
 		chip->timeout = TIMOUT_DFLT;
 		chip->timeout = TIMOUT_DFLT;
 		chip->dma_burst_size = drv_data->master_info->enable_dma ?
 		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);
 			| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
 
 
 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
-	if (drv_data->ssp_type != PXA25x_SSP)
+	if (!pxa25x_ssp_comp(drv_data))
 		dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
 		dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
 			clk_get_rate(ssp->clk)
 			clk_get_rate(ssp->clk)
 				/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
 				/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
@@ -1350,23 +1418,27 @@ static int setup(struct spi_device *spi)
 
 
 	spi_set_ctldata(spi, chip);
 	spi_set_ctldata(spi, chip);
 
 
+	if (drv_data->ssp_type == CE4100_SSP)
+		return 0;
+
 	return setup_cs(spi, chip, chip_info);
 	return setup_cs(spi, chip, chip_info);
 }
 }
 
 
 static void cleanup(struct spi_device *spi)
 static void cleanup(struct spi_device *spi)
 {
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
 	struct chip_data *chip = spi_get_ctldata(spi);
+	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
 
 
 	if (!chip)
 	if (!chip)
 		return;
 		return;
 
 
-	if (gpio_is_valid(chip->gpio_cs))
+	if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
 		gpio_free(chip->gpio_cs);
 		gpio_free(chip->gpio_cs);
 
 
 	kfree(chip);
 	kfree(chip);
 }
 }
 
 
-static int __init init_queue(struct driver_data *drv_data)
+static int __devinit init_queue(struct driver_data *drv_data)
 {
 {
 	INIT_LIST_HEAD(&drv_data->queue);
 	INIT_LIST_HEAD(&drv_data->queue);
 	spin_lock_init(&drv_data->lock);
 	spin_lock_init(&drv_data->lock);
@@ -1454,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)
 	return 0;
 	return 0;
 }
 }
 
 
-static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
 {
 {
 	struct device *dev = &pdev->dev;
 	struct device *dev = &pdev->dev;
 	struct pxa2xx_spi_master *platform_info;
 	struct pxa2xx_spi_master *platform_info;
@@ -1484,6 +1556,10 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 	drv_data->pdev = pdev;
 	drv_data->pdev = pdev;
 	drv_data->ssp = ssp;
 	drv_data->ssp = ssp;
 
 
+	master->dev.parent = &pdev->dev;
+#ifdef CONFIG_OF
+	master->dev.of_node = pdev->dev.of_node;
+#endif
 	/* the spi->mode bits understood by this driver: */
 	/* the spi->mode bits understood by this driver: */
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
 
@@ -1500,7 +1576,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 
 
 	drv_data->ioaddr = ssp->mmio_base;
 	drv_data->ioaddr = ssp->mmio_base;
 	drv_data->ssdr_physical = ssp->phys_base + SSDR;
 	drv_data->ssdr_physical = ssp->phys_base + SSDR;
-	if (ssp->type == PXA25x_SSP) {
+	if (pxa25x_ssp_comp(drv_data)) {
 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
 		drv_data->dma_cr1 = 0;
 		drv_data->dma_cr1 = 0;
 		drv_data->clear_sr = SSSR_ROR;
 		drv_data->clear_sr = SSSR_ROR;
@@ -1512,7 +1588,8 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
 	}
 	}
 
 
-	status = request_irq(ssp->irq, ssp_int, 0, dev_name(dev), drv_data);
+	status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
+			drv_data);
 	if (status < 0) {
 	if (status < 0) {
 		dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
 		dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
 		goto out_error_master_alloc;
 		goto out_error_master_alloc;
@@ -1561,7 +1638,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 			| SSCR0_Motorola
 			| SSCR0_Motorola
 			| SSCR0_DataSize(8),
 			| SSCR0_DataSize(8),
 			drv_data->ioaddr);
 			drv_data->ioaddr);
-	if (drv_data->ssp_type != PXA25x_SSP)
+	if (!pxa25x_ssp_comp(drv_data))
 		write_SSTO(0, drv_data->ioaddr);
 		write_SSTO(0, drv_data->ioaddr);
 	write_SSPSP(0, drv_data->ioaddr);
 	write_SSPSP(0, drv_data->ioaddr);
 
 
@@ -1723,13 +1800,14 @@ static struct platform_driver driver = {
 		.pm	= &pxa2xx_spi_pm_ops,
 		.pm	= &pxa2xx_spi_pm_ops,
 #endif
 #endif
 	},
 	},
+	.probe = pxa2xx_spi_probe,
 	.remove = pxa2xx_spi_remove,
 	.remove = pxa2xx_spi_remove,
 	.shutdown = pxa2xx_spi_shutdown,
 	.shutdown = pxa2xx_spi_shutdown,
 };
 };
 
 
 static int __init pxa2xx_spi_init(void)
 static int __init pxa2xx_spi_init(void)
 {
 {
-	return platform_driver_probe(&driver, pxa2xx_spi_probe);
+	return platform_driver_register(&driver);
 }
 }
 subsys_initcall(pxa2xx_spi_init);
 subsys_initcall(pxa2xx_spi_init);
 
 

+ 201 - 0
drivers/spi/pxa2xx_spi_pci.c

@@ -0,0 +1,201 @@
+/*
+ * CE4100's SPI device is more or less the same one as found on PXA
+ *
+ */
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/spi/pxa2xx_spi.h>
+
+struct awesome_struct {
+	struct ssp_device ssp;
+	struct platform_device spi_pdev;
+	struct pxa2xx_spi_master spi_pdata;
+};
+
+static DEFINE_MUTEX(ssp_lock);
+static LIST_HEAD(ssp_list);
+
+struct ssp_device *pxa_ssp_request(int port, const char *label)
+{
+	struct ssp_device *ssp = NULL;
+
+	mutex_lock(&ssp_lock);
+
+	list_for_each_entry(ssp, &ssp_list, node) {
+		if (ssp->port_id == port && ssp->use_count == 0) {
+			ssp->use_count++;
+			ssp->label = label;
+			break;
+		}
+	}
+
+	mutex_unlock(&ssp_lock);
+
+	if (&ssp->node == &ssp_list)
+		return NULL;
+
+	return ssp;
+}
+EXPORT_SYMBOL_GPL(pxa_ssp_request);
+
+void pxa_ssp_free(struct ssp_device *ssp)
+{
+	mutex_lock(&ssp_lock);
+	if (ssp->use_count) {
+		ssp->use_count--;
+		ssp->label = NULL;
+	} else
+		dev_err(&ssp->pdev->dev, "device already free\n");
+	mutex_unlock(&ssp_lock);
+}
+EXPORT_SYMBOL_GPL(pxa_ssp_free);
+
+static void plat_dev_release(struct device *dev)
+{
+	struct awesome_struct *as = container_of(dev,
+			struct awesome_struct, spi_pdev.dev);
+
+	of_device_node_put(&as->spi_pdev.dev);
+}
+
+static int __devinit ce4100_spi_probe(struct pci_dev *dev,
+		const struct pci_device_id *ent)
+{
+	int ret;
+	resource_size_t phys_beg;
+	resource_size_t phys_len;
+	struct awesome_struct *spi_info;
+	struct platform_device *pdev;
+	struct pxa2xx_spi_master *spi_pdata;
+	struct ssp_device *ssp;
+
+	ret = pci_enable_device(dev);
+	if (ret)
+		return ret;
+
+	phys_beg = pci_resource_start(dev, 0);
+	phys_len = pci_resource_len(dev, 0);
+
+	if (!request_mem_region(phys_beg, phys_len,
+				"CE4100 SPI")) {
+		dev_err(&dev->dev, "Can't request register space.\n");
+		ret = -EBUSY;
+		return ret;
+	}
+
+	spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
+	if (!spi_info) {
+		ret = -ENOMEM;
+		goto err_kz;
+	}
+	ssp = &spi_info->ssp;
+	pdev = &spi_info->spi_pdev;
+	spi_pdata =  &spi_info->spi_pdata;
+
+	pdev->name = "pxa2xx-spi";
+	pdev->id = dev->devfn;
+	pdev->dev.parent = &dev->dev;
+	pdev->dev.platform_data = &spi_info->spi_pdata;
+
+#ifdef CONFIG_OF
+	pdev->dev.of_node = dev->dev.of_node;
+#endif
+	pdev->dev.release = plat_dev_release;
+
+	spi_pdata->num_chipselect = dev->devfn;
+
+	ssp->phys_base = pci_resource_start(dev, 0);
+	ssp->mmio_base = ioremap(phys_beg, phys_len);
+	if (!ssp->mmio_base) {
+		dev_err(&pdev->dev, "failed to ioremap() registers\n");
+		ret = -EIO;
+		goto err_remap;
+	}
+	ssp->irq = dev->irq;
+	ssp->port_id = pdev->id;
+	ssp->type = PXA25x_SSP;
+
+	mutex_lock(&ssp_lock);
+	list_add(&ssp->node, &ssp_list);
+	mutex_unlock(&ssp_lock);
+
+	pci_set_drvdata(dev, spi_info);
+
+	ret = platform_device_register(pdev);
+	if (ret)
+		goto err_dev_add;
+
+	return ret;
+
+err_dev_add:
+	pci_set_drvdata(dev, NULL);
+	mutex_lock(&ssp_lock);
+	list_del(&ssp->node);
+	mutex_unlock(&ssp_lock);
+	iounmap(ssp->mmio_base);
+
+err_remap:
+	kfree(spi_info);
+
+err_kz:
+	release_mem_region(phys_beg, phys_len);
+
+	return ret;
+}
+
+static void __devexit ce4100_spi_remove(struct pci_dev *dev)
+{
+	struct awesome_struct *spi_info;
+	struct platform_device *pdev;
+	struct ssp_device *ssp;
+
+	spi_info = pci_get_drvdata(dev);
+
+	ssp = &spi_info->ssp;
+	pdev = &spi_info->spi_pdev;
+
+	platform_device_unregister(pdev);
+
+	iounmap(ssp->mmio_base);
+	release_mem_region(pci_resource_start(dev, 0),
+			pci_resource_len(dev, 0));
+
+	mutex_lock(&ssp_lock);
+	list_del(&ssp->node);
+	mutex_unlock(&ssp_lock);
+
+	pci_set_drvdata(dev, NULL);
+	pci_disable_device(dev);
+	kfree(spi_info);
+}
+
+static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
+
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
+
+static struct pci_driver ce4100_spi_driver = {
+	.name           = "ce4100_spi",
+	.id_table       = ce4100_spi_devices,
+	.probe          = ce4100_spi_probe,
+	.remove         = __devexit_p(ce4100_spi_remove),
+};
+
+static int __init ce4100_spi_init(void)
+{
+	return pci_register_driver(&ce4100_spi_driver);
+}
+module_init(ce4100_spi_init);
+
+static void __exit ce4100_spi_exit(void)
+{
+	pci_unregister_driver(&ce4100_spi_driver);
+}
+module_exit(ce4100_spi_exit);
+
+MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");

+ 31 - 8
arch/arm/plat-pxa/include/plat/ssp.h → include/linux/pxa2xx_ssp.h

@@ -1,5 +1,5 @@
 /*
 /*
- *  ssp.h
+ *  pxa2xx_ssp.h
  *
  *
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *
  *
@@ -16,8 +16,8 @@
  *       PXA3xx     SSP1, SSP2, SSP3, SSP4
  *       PXA3xx     SSP1, SSP2, SSP3, SSP4
  */
  */
 
 
-#ifndef __ASM_ARCH_SSP_H
-#define __ASM_ARCH_SSP_H
+#ifndef __LINUX_SSP_H
+#define __LINUX_SSP_H
 
 
 #include <linux/list.h>
 #include <linux/list.h>
 #include <linux/io.h>
 #include <linux/io.h>
@@ -71,11 +71,8 @@
 #define SSCR1_SPO	(1 << 3)	/* Motorola SPI SSPSCLK polarity setting */
 #define SSCR1_SPO	(1 << 3)	/* Motorola SPI SSPSCLK polarity setting */
 #define SSCR1_SPH	(1 << 4)	/* Motorola SPI SSPSCLK phase setting */
 #define SSCR1_SPH	(1 << 4)	/* Motorola SPI SSPSCLK phase setting */
 #define SSCR1_MWDS	(1 << 5)	/* Microwire Transmit Data Size */
 #define SSCR1_MWDS	(1 << 5)	/* Microwire Transmit Data Size */
-#define SSCR1_TFT	(0x000003c0)	/* Transmit FIFO Threshold (mask) */
-#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
-#define SSCR1_RFT	(0x00003c00)	/* Receive FIFO Threshold (mask) */
-#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
 
 
+#define SSSR_ALT_FRM_MASK	3	/* Masks the SFRM signal number */
 #define SSSR_TNF	(1 << 2)	/* Transmit FIFO Not Full */
 #define SSSR_TNF	(1 << 2)	/* Transmit FIFO Not Full */
 #define SSSR_RNE	(1 << 3)	/* Receive FIFO Not Empty */
 #define SSSR_RNE	(1 << 3)	/* Receive FIFO Not Empty */
 #define SSSR_BSY	(1 << 4)	/* SSP Busy */
 #define SSSR_BSY	(1 << 4)	/* SSP Busy */
@@ -83,6 +80,31 @@
 #define SSSR_RFS	(1 << 6)	/* Receive FIFO Service Request */
 #define SSSR_RFS	(1 << 6)	/* Receive FIFO Service Request */
 #define SSSR_ROR	(1 << 7)	/* Receive FIFO Overrun */
 #define SSSR_ROR	(1 << 7)	/* Receive FIFO Overrun */
 
 
+#ifdef CONFIG_ARCH_PXA
+#define RX_THRESH_DFLT	8
+#define TX_THRESH_DFLT	8
+
+#define SSSR_TFL_MASK	(0xf << 8)	/* Transmit FIFO Level mask */
+#define SSSR_RFL_MASK	(0xf << 12)	/* Receive FIFO Level mask */
+
+#define SSCR1_TFT	(0x000003c0)	/* Transmit FIFO Threshold (mask) */
+#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
+#define SSCR1_RFT	(0x00003c00)	/* Receive FIFO Threshold (mask) */
+#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
+
+#else
+
+#define RX_THRESH_DFLT	2
+#define TX_THRESH_DFLT	2
+
+#define SSSR_TFL_MASK	(0x3 << 8)	/* Transmit FIFO Level mask */
+#define SSSR_RFL_MASK	(0x3 << 12)	/* Receive FIFO Level mask */
+
+#define SSCR1_TFT	(0x000000c0)	/* Transmit FIFO Threshold (mask) */
+#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
+#define SSCR1_RFT	(0x00000c00)	/* Receive FIFO Threshold (mask) */
+#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
+#endif
 
 
 /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
 /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
 #define SSCR0_TISSP		(1 << 4)	/* TI Sync Serial Protocol */
 #define SSCR0_TISSP		(1 << 4)	/* TI Sync Serial Protocol */
@@ -139,6 +161,7 @@ enum pxa_ssp_type {
 	PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
 	PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
 	PXA27x_SSP,
 	PXA27x_SSP,
 	PXA168_SSP,
 	PXA168_SSP,
+	CE4100_SSP,
 };
 };
 
 
 struct ssp_device {
 struct ssp_device {
@@ -183,4 +206,4 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
 
 
 struct ssp_device *pxa_ssp_request(int port, const char *label);
 struct ssp_device *pxa_ssp_request(int port, const char *label);
 void pxa_ssp_free(struct ssp_device *);
 void pxa_ssp_free(struct ssp_device *);
-#endif /* __ASM_ARCH_SSP_H */
+#endif

+ 152 - 0
include/linux/spi/pxa2xx_spi.h

@@ -0,0 +1,152 @@
+/*
+ * 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 __linux_pxa2xx_spi_h
+#define __linux_pxa2xx_spi_h
+
+#include <linux/pxa2xx_ssp.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);
+};
+
+#ifdef CONFIG_ARCH_PXA
+
+#include <linux/clk.h>
+#include <mach/dma.h>
+
+extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
+
+#else
+/*
+ * This is the implemtation for CE4100 on x86. ARM defines them in mach/ or
+ * plat/ include path.
+ * The CE4100 does not provide DMA support. This bits are here to let the driver
+ * compile and will never be used. Maybe we get DMA support at a later point in
+ * time.
+ */
+
+#define DCSR(n)         (n)
+#define DSADR(n)        (n)
+#define DTADR(n)        (n)
+#define DCMD(n)         (n)
+#define DRCMR(n)        (n)
+
+#define DCSR_RUN	(1 << 31)	/* Run Bit */
+#define DCSR_NODESC	(1 << 30)	/* No-Descriptor Fetch */
+#define DCSR_STOPIRQEN	(1 << 29)	/* Stop Interrupt Enable */
+#define DCSR_REQPEND	(1 << 8)	/* Request Pending (read-only) */
+#define DCSR_STOPSTATE	(1 << 3)	/* Stop State (read-only) */
+#define DCSR_ENDINTR	(1 << 2)	/* End Interrupt */
+#define DCSR_STARTINTR	(1 << 1)	/* Start Interrupt */
+#define DCSR_BUSERR	(1 << 0)	/* Bus Error Interrupt */
+
+#define DCSR_EORIRQEN	(1 << 28)	/* End of Receive Interrupt Enable */
+#define DCSR_EORJMPEN	(1 << 27)	/* Jump to next descriptor on EOR */
+#define DCSR_EORSTOPEN	(1 << 26)	/* STOP on an EOR */
+#define DCSR_SETCMPST	(1 << 25)	/* Set Descriptor Compare Status */
+#define DCSR_CLRCMPST	(1 << 24)	/* Clear Descriptor Compare Status */
+#define DCSR_CMPST	(1 << 10)	/* The Descriptor Compare Status */
+#define DCSR_EORINTR	(1 << 9)	/* The end of Receive */
+
+#define DRCMR_MAPVLD	(1 << 7)	/* Map Valid */
+#define DRCMR_CHLNUM	0x1f		/* mask for Channel Number */
+
+#define DDADR_DESCADDR	0xfffffff0	/* Address of next descriptor */
+#define DDADR_STOP	(1 << 0)	/* Stop */
+
+#define DCMD_INCSRCADDR	(1 << 31)	/* Source Address Increment Setting. */
+#define DCMD_INCTRGADDR	(1 << 30)	/* Target Address Increment Setting. */
+#define DCMD_FLOWSRC	(1 << 29)	/* Flow Control by the source. */
+#define DCMD_FLOWTRG	(1 << 28)	/* Flow Control by the target. */
+#define DCMD_STARTIRQEN	(1 << 22)	/* Start Interrupt Enable */
+#define DCMD_ENDIRQEN	(1 << 21)	/* End Interrupt Enable */
+#define DCMD_ENDIAN	(1 << 18)	/* Device Endian-ness. */
+#define DCMD_BURST8	(1 << 16)	/* 8 byte burst */
+#define DCMD_BURST16	(2 << 16)	/* 16 byte burst */
+#define DCMD_BURST32	(3 << 16)	/* 32 byte burst */
+#define DCMD_WIDTH1	(1 << 14)	/* 1 byte width */
+#define DCMD_WIDTH2	(2 << 14)	/* 2 byte width (HalfWord) */
+#define DCMD_WIDTH4	(3 << 14)	/* 4 byte width (Word) */
+#define DCMD_LENGTH	0x01fff		/* length mask (max = 8K - 1) */
+
+/*
+ * Descriptor structure for PXA's DMA engine
+ * Note: this structure must always be aligned to a 16-byte boundary.
+ */
+
+typedef enum {
+	DMA_PRIO_HIGH = 0,
+	DMA_PRIO_MEDIUM = 1,
+	DMA_PRIO_LOW = 2
+} pxa_dma_prio;
+
+/*
+ * DMA registration
+ */
+
+static inline int pxa_request_dma(char *name,
+		pxa_dma_prio prio,
+		void (*irq_handler)(int, void *),
+		void *data)
+{
+	return -ENODEV;
+}
+
+static inline void pxa_free_dma(int dma_ch)
+{
+}
+
+/*
+ * The CE4100 does not have the clk framework implemented and SPI clock can
+ * not be switched on/off or the divider changed.
+ */
+static inline void clk_disable(struct clk *clk)
+{
+}
+
+static inline int clk_enable(struct clk *clk)
+{
+	return 0;
+}
+
+static inline unsigned long clk_get_rate(struct clk *clk)
+{
+	return 3686400;
+}
+
+#endif
+#endif

+ 1 - 1
sound/soc/pxa/pxa-ssp.c

@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/io.h>
+#include <linux/pxa2xx_ssp.h>
 
 
 #include <asm/irq.h>
 #include <asm/irq.h>
 
 
@@ -33,7 +34,6 @@
 #include <mach/hardware.h>
 #include <mach/hardware.h>
 #include <mach/dma.h>
 #include <mach/dma.h>
 #include <mach/audio.h>
 #include <mach/audio.h>
-#include <plat/ssp.h>
 
 
 #include "../../arm/pxa2xx-pcm.h"
 #include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
 #include "pxa-ssp.h"