diff -Naur linux-2.6.30.4-orig/drivers/spi/comcerto_spi.c linux-2.6.30.4-new/drivers/spi/comcerto_spi.c
--- linux-2.6.30.4-orig/drivers/spi/comcerto_spi.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.30.4-new/drivers/spi/comcerto_spi.c	2010-02-05 10:42:30.846513000 -0800
@@ -0,0 +1,285 @@
+/*
+ *  drivers/spi2/busses/comcerto_spi.c
+ *
+ *  Copyright (C) 2004,2005 Mindspeed Technologies, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/delay.h>
+
+#define COMCERTO_SPI_DRIVER_NAME	"Comcerto SPI"
+
+#define COMCERTO_SPI_CTRLR0               0x00
+#define COMCERTO_SPI_CTRLR1               0x04
+#define COMCERTO_SPI_SSIENR               0x08
+#define COMCERTO_SPI_MWCR                 0x0C
+#define COMCERTO_SPI_SER                  0x10
+#define COMCERTO_SPI_BAUDR                0x14
+#define COMCERTO_SPI_TXFTLR               0x18
+#define COMCERTO_SPI_RXFTLR               0x1C
+#define COMCERTO_SPI_TXFLR                0x20
+#define COMCERTO_SPI_RXFLR                0x24
+#define COMCERTO_SPI_SR                   0x28
+#define COMCERTO_SPI_IMR                  0x2C
+#define COMCERTO_SPI_ISR                  0x30
+#define COMCERTO_SPI_RISR                 0x34
+#define COMCERTO_SPI_TXOICR               0x38
+#define COMCERTO_SPI_RXOICR               0x3C
+#define COMCERTO_SPI_RXUICR               0x40
+#define COMCERTO_SPI_MSTICR               0x44
+#define COMCERTO_SPI_ICR                  0x48
+#define COMCERTO_SPI_IDR                  0x58
+#define COMCERTO_SPI_DR                   0x60
+
+/* SR - status register bits */
+#define BUSY		(1<<0)	/* serial transfer in progress */
+#define RFNE            (1<<3)  /* receive FIFO not empty */
+
+struct comcerto_spi
+{
+	unsigned long membase;
+	int irq;
+	unsigned long clock_rate;
+};
+
+static void transfer(struct spi_device *spi, struct spi_transfer *xfer)
+{
+	struct comcerto_spi *cs = spi_master_get_devdata(spi->master);
+	unsigned int t, len, bits;
+	const u8 *w8 = xfer->tx_buf;
+	const u16 *w16 = xfer->tx_buf;
+	u8 *r8 = xfer->rx_buf;
+	u16 *r16 = xfer->rx_buf;
+	u32 mb = cs->membase;
+	u32 dr = mb + COMCERTO_SPI_DR;
+	u32 ctrlr0, baudr;
+
+	/* make sure last transaction is finished */
+	while (__raw_readl(mb + COMCERTO_SPI_SR) & BUSY)
+		;
+
+	bits = xfer->bits_per_word;
+	if (bits == 0)
+		bits = 8;
+
+	ctrlr0 = (((spi->mode & SPI_CPOL) == SPI_CPOL) << 7) |
+		(((spi->mode & SPI_CPHA) == SPI_CPHA) << 6) |
+		(((bits - 1) & 0xf) << 0);
+	if (spi->max_speed_hz)
+		baudr = DIV_ROUND_UP(cs->clock_rate, spi->max_speed_hz) & 0xfffe;
+	else
+		baudr = 0xfffe;
+
+	__raw_writel(0, mb + COMCERTO_SPI_SSIENR);
+	__raw_writel(ctrlr0, mb + COMCERTO_SPI_CTRLR0);
+	__raw_writel(baudr, mb + COMCERTO_SPI_BAUDR);
+	__raw_writel(spi->chip_select, mb + COMCERTO_SPI_SER);
+	__raw_writel(0, mb + COMCERTO_SPI_RXFTLR);
+	__raw_writel(0, mb + COMCERTO_SPI_TXFTLR);
+	__raw_writel(0, mb + COMCERTO_SPI_IMR);
+	__raw_writel(1, mb + COMCERTO_SPI_SSIENR);
+
+	len = xfer->len;
+#if 0
+	printk("[%d/%d%s%s%d", spi->chip_select,
+	       (unsigned int)spi->controller_data,
+	       r8?"r":"", w8?"w":"", len);
+
+	if (w8 && len < 6) {
+		int i;
+		printk(">");
+		for (i = 0; i < len; i++)
+			printk("%02x", w8[i]);
+	}
+#endif
+	while (len--) {
+		/* write outgoing piece */
+		if (xfer->tx_buf)
+			t = bits > 8 ? *w16++ : *w8++;
+		else
+			t = 0;
+		__raw_writel(cpu_to_le32(t), dr);
+
+		/* wait for read/write cycle to clock */
+		while (!(__raw_readl(mb + COMCERTO_SPI_SR) & RFNE))
+			;
+
+		/* read incoming piece */
+		t = le32_to_cpu(__raw_readl(dr));
+		if (xfer->rx_buf) {
+			if (bits > 8)
+				*r16++ = t;
+			else
+				*r8++ = t;
+		}
+	}
+
+#if 0
+	if (r8 && xfer->len < 6) {
+		int i;
+		r8 = xfer->rx_buf;
+		printk(">");
+		for (i = 0; i < xfer->len; i++)
+			printk("%02x", r8[i]);
+	}
+
+	if (r8 && xfer->len >= 6) {
+		int i;
+		r8 = xfer->rx_buf;
+		printk(">");
+		for (i = 0; i < 6; i++)
+			printk("%02x", r8[i]);
+		printk("...");
+	}
+	printk("]");
+#endif
+	if (xfer->delay_usecs)
+		udelay(xfer->delay_usecs);
+}
+
+static int comcerto_spi_transfer(struct spi_device *spi,
+				 struct spi_message *msg)
+{
+	struct spi_transfer *xfer;
+	int gpio_pin = (unsigned int)spi->controller_data;
+	int gpio_dir = spi->mode & SPI_CS_HIGH;
+
+	if (list_empty(&msg->transfers))
+		return -EINVAL;
+
+	/* drive stable GPIO chip select */
+	if (gpio_pin) {
+		comcerto_gpio_enable_output(gpio_pin);
+		if (gpio_dir)
+			comcerto_gpio_set_1(gpio_pin);
+		else
+			comcerto_gpio_set_0(gpio_pin);
+	}
+
+	msg->actual_length = 0;
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		transfer(spi, xfer);
+		msg->actual_length += xfer->len;
+	}
+
+	if (gpio_pin) {
+		if (gpio_dir)
+			comcerto_gpio_set_0(gpio_pin);
+		else
+			comcerto_gpio_set_1(gpio_pin);
+	}
+
+	msg->complete(msg->context);
+	return 0;
+}
+
+static int comcerto_spi_setup(struct spi_device *spi)
+{
+	return 0;
+}
+
+static int __init comcerto_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct comcerto_spi *c;
+	unsigned long base, len;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*c));
+	if (!master)
+		return -ENODEV;
+
+	master->transfer = comcerto_spi_transfer;
+	master->num_chipselect = 8;
+	master->bus_num = pdev->id;
+	master->setup = comcerto_spi_setup;
+	platform_set_drvdata(pdev, master);
+
+	base = pdev->resource[0].start;
+	len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(base, len, COMCERTO_SPI_DRIVER_NAME)) {
+		printk(KERN_INFO "comcerto_spi: error requesting memory region %#lx - %#lx", base, base + len);
+		goto err;
+	}
+
+	c = spi_master_get_devdata(master);
+	/* io-remaped in arch/arm/mm.c */
+	c->membase = APB_VADDR(pdev->resource[0].start);
+	c->irq = pdev->resource[1].start;
+	c->clock_rate = (COMCERTO_AHBCLK * 1000000);
+
+	/* enable SPI bus */
+	comcerto_gpio_ctrl(0x3 << 4, 0x3 << 4);
+	writel(0, c->membase + COMCERTO_SPI_SSIENR);
+	writel(0, c->membase + COMCERTO_SPI_IMR);
+
+	return spi_register_master(master);
+
+      err:
+	release_mem_region(base, len);
+	return -1;
+}
+
+static int comcerto_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct comcerto_spi *c = spi_master_get_devdata(master);
+	unsigned long base, len;
+
+	writel(0, c->membase + COMCERTO_SPI_SSIENR);
+	writel(0, c->membase + COMCERTO_SPI_IMR);
+	comcerto_gpio_ctrl(0x0 << 4, 0x3 << 4);
+	base = pdev->resource[0].start;
+	len = pdev->resource[0].end - pdev->resource[0].start + 1;
+	release_mem_region(base, len);
+	spi_unregister_master(master);
+
+	return 0;
+}
+
+static struct platform_driver comcerto_spi_driver = {
+	.driver = {
+		.name	= "comcerto-spi",
+		.owner	= THIS_MODULE,
+	},
+	.probe = comcerto_spi_probe,
+	.remove = comcerto_spi_remove,
+};
+
+static int __init comcerto_spi_init(void)
+{
+	int r;
+	r = platform_driver_register(&comcerto_spi_driver);
+	return r;
+}
+
+static void __exit comcerto_spi_exit(void)
+{
+	platform_driver_unregister(&comcerto_spi_driver);
+}
+
+MODULE_AUTHOR("Mindspeed Technologies, Inc.");
+MODULE_DESCRIPTION("Comcerto SPI bus driver");
+MODULE_LICENSE("GPL");
+
+module_init(comcerto_spi_init);
+module_exit(comcerto_spi_exit);
diff -Naur linux-2.6.30.4-orig/drivers/spi/Kconfig linux-2.6.30.4-new/drivers/spi/Kconfig
--- linux-2.6.30.4-orig/drivers/spi/Kconfig	2009-07-30 15:34:47.000000000 -0700
+++ linux-2.6.30.4-new/drivers/spi/Kconfig	2010-02-05 10:42:30.840514000 -0800
@@ -220,6 +220,9 @@
 	  See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
 	  Product Specification document (DS464) for hardware details.
 
+config SPI_COMCERTO
+	tristate "Comcerto SPI controller"
+
 #
 # Add new SPI master controllers in alphabetical order above this line
 #
diff -Naur linux-2.6.30.4-orig/drivers/spi/Makefile linux-2.6.30.4-new/drivers/spi/Makefile
--- linux-2.6.30.4-orig/drivers/spi/Makefile	2009-07-30 15:34:47.000000000 -0700
+++ linux-2.6.30.4-new/drivers/spi/Makefile	2010-02-05 10:42:30.843513000 -0800
@@ -30,6 +30,7 @@
 obj-$(CONFIG_SPI_TXX9)			+= spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)		+= xilinx_spi.o
 obj-$(CONFIG_SPI_SH_SCI)		+= spi_sh_sci.o
+obj-$(CONFIG_SPI_COMCERTO)	        += comcerto_spi.o
 # 	... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
