aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/patches/019-m5445x_spi.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/coldfire/patches/019-m5445x_spi.patch')
-rw-r--r--target/linux/coldfire/patches/019-m5445x_spi.patch3345
1 files changed, 0 insertions, 3345 deletions
diff --git a/target/linux/coldfire/patches/019-m5445x_spi.patch b/target/linux/coldfire/patches/019-m5445x_spi.patch
deleted file mode 100644
index 49b83e0b18..0000000000
--- a/target/linux/coldfire/patches/019-m5445x_spi.patch
+++ /dev/null
@@ -1,3345 +0,0 @@
-From bc755a3b8859e7307a8b10f39ca4cb6401c51987 Mon Sep 17 00:00:00 2001
-From: Kurt Mahan <kmahan@freescale.com>
-Date: Tue, 27 Nov 2007 14:39:37 -0700
-Subject: [PATCH] Add M5445x SPI support.
-
-LTIBName: m5445x-spi
-Signed-off-by: Kurt Mahan <kmahan@freescale.com>
----
- arch/m68k/configs/m54455evb_defconfig | 24 +-
- drivers/spi/Kconfig | 36 +
- drivers/spi/Makefile | 4 +
- drivers/spi/coldfire_edma.c | 358 ++++++++
- drivers/spi/spi-m5445x.c | 156 ++++
- drivers/spi/spi_coldfire.c | 1552 +++++++++++++++++++++++++++++++++
- drivers/spi/ssi_audio.c | 906 +++++++++++++++++++
- include/asm-m68k/coldfire_edma.h | 101 ++-
- include/linux/spi/mcfqspi.h | 80 ++
- 9 files changed, 3196 insertions(+), 21 deletions(-)
- create mode 100644 drivers/spi/coldfire_edma.c
- create mode 100644 drivers/spi/spi-m5445x.c
- create mode 100644 drivers/spi/spi_coldfire.c
- create mode 100644 drivers/spi/ssi_audio.c
- create mode 100644 include/linux/spi/mcfqspi.h
-
---- a/arch/m68k/configs/m54455evb_defconfig
-+++ b/arch/m68k/configs/m54455evb_defconfig
-@@ -321,6 +321,8 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
- #
- # Self-contained MTD device drivers
- #
-+# CONFIG_MTD_DATAFLASH is not set
-+# CONFIG_MTD_M25P80 is not set
- # CONFIG_MTD_SLRAM is not set
- # CONFIG_MTD_PHRAM is not set
- # CONFIG_MTD_MTDRAM is not set
-@@ -497,8 +499,26 @@ CONFIG_UNIX98_PTYS=y
- #
- # SPI support
- #
--# CONFIG_SPI is not set
--# CONFIG_SPI_MASTER is not set
-+CONFIG_SPI=y
-+# CONFIG_SPI_DEBUG is not set
-+CONFIG_COLDFIRE_EDMA=y
-+CONFIG_SPI_MASTER=y
-+
-+#
-+# SPI Master Controller Drivers
-+#
-+# CONFIG_SPI_BITBANG is not set
-+CONFIG_SPI_COLDFIRE=y
-+CONFIG_SPI_COLDFIRE_DSPI_EDMA=y
-+
-+#
-+# SPI Protocol Masters
-+#
-+# CONFIG_SPI_AT25 is not set
-+# CONFIG_SPI_SPIDEV is not set
-+# CONFIG_SPI_TLE62X0 is not set
-+CONFIG_SPI_COLDFIRE_SSI_AUDIO=y
-+# CONFIG_SSIAUDIO_USE_EDMA is not set
- # CONFIG_W1 is not set
- # CONFIG_POWER_SUPPLY is not set
- # CONFIG_HWMON is not set
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -35,6 +35,15 @@ config SPI_DEBUG
- Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
- sysfs, and debugfs support in SPI controller and protocol drivers.
-
-+config COLDFIRE_EDMA
-+ tristate "Coldfire eDMA"
-+ depends on COLDFIRE && EXPERIMENTAL
-+ help
-+ Support for Coldfire eDMA controller. Required for example
-+ by SSI audio device driver.
-+
-+
-+
- #
- # MASTER side ... talking to discrete SPI slave chips including microcontrollers
- #
-@@ -113,6 +122,21 @@ config SPI_GPIO
-
- If unsure, say N.
-
-+config SPI_COLDFIRE
-+ tristate "Coldfire QSPI/DSPI SPI Master"
-+ depends on SPI_MASTER && COLDFIRE && EXPERIMENTAL
-+ help
-+ SPI driver for Freescale Coldfire QSPI module in master mode.
-+ Tested with the 5282 processor, but should also work with other
-+ Coldfire variants.
-+
-+config SPI_COLDFIRE_DSPI_EDMA
-+ boolean "Coldfire DSPI master driver uses eDMA"
-+ depends on SPI_MASTER && COLDFIRE && SPI_COLDFIRE && EXPERIMENTAL && COLDFIRE_EDMA
-+ default n
-+ help
-+ Say "yes" if you want DSPI master driver to use eDMA for transfers.
-+
- config SPI_IMX
- tristate "Freescale iMX SPI controller"
- depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL
-@@ -255,6 +279,18 @@ config SPI_TLE62X0
- #
- # Add new SPI protocol masters in alphabetical order above this line
- #
-+config SPI_COLDFIRE_SSI_AUDIO
-+ tristate "Coldfire SSI AUDIO"
-+ depends on SPI_MASTER && SPI_COLDFIRE && EXPERIMENTAL
-+ help
-+ SSI audio device driver
-+
-+config SSIAUDIO_USE_EDMA
-+ boolean "Coldfire DSPI master driver uses eDMA"
-+ default y
-+ depends on EXPERIMENTAL && COLDFIRE_EDMA && SPI_COLDFIRE_SSI_AUDIO
-+ help
-+ Say "yes" if you want SSI audio driver to use eDMA for SSI transfers.
-
- # (slave support would go here)
-
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -6,6 +6,8 @@ ifeq ($(CONFIG_SPI_DEBUG),y)
- EXTRA_CFLAGS += -DDEBUG
- endif
-
-+obj-$(CONFIG_COLDFIRE_EDMA) += coldfire_edma.o
-+
- # small core, mostly translating board-specific
- # config declarations into driver model code
- obj-$(CONFIG_SPI_MASTER) += spi.o
-@@ -16,6 +18,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.
- obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
- obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
- obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
-+obj-$(CONFIG_SPI_COLDFIRE) += spi_coldfire.o spi-m5445x.o
- obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
- obj-$(CONFIG_SPI_IMX) += spi_imx.o
- obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
-@@ -35,6 +38,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.
- obj-$(CONFIG_SPI_AT25) += at25.o
- obj-$(CONFIG_SPI_SPIDEV) += spidev.o
- obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
-+obj-$(CONFIG_SPI_COLDFIRE_SSI_AUDIO) += ssi_audio.o
- # ... add above this line ...
-
- # SPI slave controller drivers (upstream link)
---- /dev/null
-+++ b/drivers/spi/coldfire_edma.c
-@@ -0,0 +1,358 @@
-+/*
-+ *
-+ * coldfire_edma.c - eDMA driver for Coldfire MCF5445x
-+ *
-+ * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
-+ *
-+ * Copyright Freescale Semiconductor, Inc. 2007
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <asm/virtconvert.h>
-+#include <asm/coldfire.h>
-+#include <linux/fs.h>
-+#include <linux/cdev.h>
-+#include <linux/seq_file.h>
-+#include <linux/proc_fs.h>
-+#include <asm/mcf5445x_edma.h>
-+#include <asm/mcf5445x_intc.h>
-+#include <asm/coldfire_edma.h>
-+
-+
-+/* callback handler data for each TCD */
-+struct edma_isr_record {
-+ edma_irq_handler irq_handler; /* interrupt handler */
-+ edma_error_handler error_handler; /* error interrupt handler */
-+ void* dev; /* device used for the channel */
-+ int allocated; /* busy flag */
-+ spinlock_t *lock; /* spin lock (if needs to be locked in interrupt) */
-+ const char* device_id; /* device id string, used in proc file system */
-+};
-+
-+/* device structure */
-+struct coldfire_edma_dev {
-+ struct cdev cdev; /* character device */
-+ struct edma_isr_record dma_interrupt_handlers[EDMA_CHANNELS]; /* channel handlers */
-+};
-+
-+/* allocated major device number */
-+static int coldfire_dma_major;
-+/* device driver structure */
-+static struct coldfire_edma_dev* devp = NULL;
-+
-+/* device driver file operations */
-+struct file_operations coldfire_edma_fops = {
-+ .owner = THIS_MODULE,
-+};
-+
-+/* eDMA channel interrupt handler */
-+static int dmaisr(int irq, void *dev_id)
-+{
-+ int channel = irq - EDMA_INT_CONTROLLER_BASE - EDMA_INT_CHANNEL_BASE;
-+ int result = IRQ_HANDLED;
-+
-+ if (devp!=NULL && devp->dma_interrupt_handlers[channel].lock) {
-+ spin_lock(devp->dma_interrupt_handlers[channel].lock);
-+ }
-+
-+ if (devp!=NULL && devp->dma_interrupt_handlers[channel].irq_handler) {
-+ result = devp->dma_interrupt_handlers[channel].irq_handler(channel,
-+ devp->dma_interrupt_handlers[channel].dev);
-+ } else {
-+ confirm_edma_interrupt_handled(channel);
-+ printk(EDMA_DRIVER_NAME ": No handler for DMA channel %d\n", channel);
-+ }
-+
-+ if (devp!=NULL && devp->dma_interrupt_handlers[channel].lock) {
-+ spin_unlock(devp->dma_interrupt_handlers[channel].lock);
-+ }
-+
-+ return result;
-+}
-+
-+/* eDMA error interrupt handler */
-+static int dma_error_isr(int irq, void* dev_id)
-+{
-+ u16 err;
-+ int i;
-+
-+ err = MCF_EDMA_ERR;
-+ for (i=0;i<EDMA_CHANNELS;i++) {
-+ if (err & (1<<i)) {
-+ if (devp!=NULL && devp->dma_interrupt_handlers[i].error_handler) {
-+ devp->dma_interrupt_handlers[i].error_handler(i, devp->dma_interrupt_handlers[i].dev);
-+ } else {
-+ printk(KERN_WARNING EDMA_DRIVER_NAME ": DMA error on channel %d\n", i);
-+ }
-+ }
-+ }
-+
-+ MCF_EDMA_CERR = MCF_EDMA_CERR_CAER;
-+ return IRQ_HANDLED;
-+}
-+
-+/* sets channel parameters */
-+void set_edma_params(int channel, u32 source, u32 dest,
-+ u32 attr, u32 soff, u32 nbytes, u32 slast,
-+ u32 citer, u32 biter, u32 doff, u32 dlast_sga,
-+ int major_int, int disable_req)
-+{
-+
-+ if (channel<0 || channel>EDMA_CHANNELS)
-+ return;
-+
-+ MCF_EDMA_TCD_SADDR(channel) = source;
-+ MCF_EDMA_TCD_DADDR(channel) = dest;
-+ MCF_EDMA_TCD_ATTR(channel) = attr;
-+ MCF_EDMA_TCD_SOFF(channel) = MCF_EDMA_TCD_SOFF_SOFF(soff);
-+ MCF_EDMA_TCD_NBYTES(channel) = MCF_EDMA_TCD_NBYTES_NBYTES(nbytes);
-+ MCF_EDMA_TCD_SLAST(channel) = MCF_EDMA_TCD_SLAST_SLAST(slast);
-+ MCF_EDMA_TCD_CITER(channel) = MCF_EDMA_TCD_CITER_CITER(citer);
-+ MCF_EDMA_TCD_BITER(channel)=MCF_EDMA_TCD_BITER_BITER(biter);
-+ MCF_EDMA_TCD_DOFF(channel) = MCF_EDMA_TCD_DOFF_DOFF(doff);
-+ MCF_EDMA_TCD_DLAST_SGA(channel) = MCF_EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga);
-+ /* interrupt at the end of major loop */
-+ if (major_int) {
-+ MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_INT_MAJOR;
-+ } else {
-+ MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_INT_MAJOR;
-+ }
-+ /* disable request at the end of major loop of transfer or not*/
-+ if (disable_req) {
-+ MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_D_REQ;
-+ } else {
-+ MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_D_REQ;
-+ }
-+
-+}
-+EXPORT_SYMBOL(set_edma_params);
-+
-+/* init eDMA controller */
-+void init_edma(void)
-+{
-+ MCF_EDMA_CR = 0;
-+}
-+EXPORT_SYMBOL(init_edma);
-+
-+/* request eDMA channel */
-+int request_edma_channel(int channel,
-+ edma_irq_handler handler,
-+ edma_error_handler error_handler,
-+ void* dev,
-+ spinlock_t *lock,
-+ const char* device_id )
-+{
-+ if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) {
-+ if (devp->dma_interrupt_handlers[channel].allocated) {
-+ return -EBUSY;
-+ }
-+ devp->dma_interrupt_handlers[channel].allocated = 1;
-+ devp->dma_interrupt_handlers[channel].irq_handler = handler;
-+ devp->dma_interrupt_handlers[channel].error_handler = error_handler;
-+ devp->dma_interrupt_handlers[channel].dev = dev;
-+ devp->dma_interrupt_handlers[channel].lock = lock;
-+ devp->dma_interrupt_handlers[channel].device_id = device_id;
-+ return 0;
-+ }
-+ return -EINVAL;
-+}
-+EXPORT_SYMBOL(request_edma_channel);
-+
-+/* free eDMA channel */
-+int free_edma_channel(int channel, void* dev)
-+{
-+ if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) {
-+ if (devp->dma_interrupt_handlers[channel].allocated) {
-+ if (devp->dma_interrupt_handlers[channel].dev != dev) {
-+ return -EBUSY;
-+ }
-+ devp->dma_interrupt_handlers[channel].allocated = 0;
-+ devp->dma_interrupt_handlers[channel].dev = NULL;
-+ devp->dma_interrupt_handlers[channel].irq_handler = NULL;
-+ devp->dma_interrupt_handlers[channel].error_handler = NULL;
-+ devp->dma_interrupt_handlers[channel].lock = NULL;
-+ }
-+ return 0;
-+ }
-+ return -EINVAL;
-+}
-+EXPORT_SYMBOL(free_edma_channel);
-+
-+/* clean-up device driver allocated resources */
-+static void coldfire_edma_cleanup(void)
-+{
-+ dev_t devno;
-+ int i;
-+
-+ /* free interrupts/memory */
-+ if (devp) {
-+ for (i=0;i<EDMA_CHANNELS;i++)
-+ {
-+ MCF_INTC0_SIMR = EDMA_INT_CHANNEL_BASE+i;
-+ free_irq(EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+i, devp);
-+ }
-+ MCF_INTC0_SIMR = EDMA_INT_CHANNEL_BASE+EDMA_CHANNELS;
-+ free_irq(EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+EDMA_CHANNELS, devp);
-+ cdev_del(&devp->cdev);
-+ kfree(devp);
-+ }
-+
-+ /* unregister character device */
-+ devno = MKDEV(coldfire_dma_major, 0);
-+ unregister_chrdev_region(devno, 1);
-+}
-+
-+#ifdef CONFIG_PROC_FS
-+/* proc file system support */
-+
-+#define FREE_CHANNEL "free"
-+#define DEVICE_UNKNOWN "device unknown"
-+
-+static int proc_edma_show(struct seq_file *m, void *v)
-+{
-+ int i;
-+
-+ if (devp==NULL) return 0;
-+
-+ for (i = 0 ; i < EDMA_CHANNELS ; i++) {
-+ if (devp->dma_interrupt_handlers[i].allocated) {
-+ if (devp->dma_interrupt_handlers[i].device_id)
-+ seq_printf(m, "%2d: %s\n", i, devp->dma_interrupt_handlers[i].device_id);
-+ else
-+ seq_printf(m, "%2d: %s\n", i, DEVICE_UNKNOWN);
-+ } else {
-+ seq_printf(m, "%2d: %s\n", i, FREE_CHANNEL);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int proc_edma_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, proc_edma_show, NULL);
-+}
-+
-+static const struct file_operations proc_edma_operations = {
-+ .open = proc_edma_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+static int __init proc_edma_init(void)
-+{
-+ struct proc_dir_entry *e;
-+
-+ e = create_proc_entry("edma", 0, NULL);
-+ if (e)
-+ e->proc_fops = &proc_edma_operations;
-+
-+ return 0;
-+}
-+
-+#endif
-+
-+/* initializes device driver */
-+static int __init coldfire_edma_init(void)
-+{
-+ dev_t dev;
-+ int result;
-+ int i;
-+
-+ /* allocate free major number */
-+ result = alloc_chrdev_region(&dev, DMA_DEV_MINOR, 1, EDMA_DRIVER_NAME);
-+ if (result<0) {
-+ printk(KERN_WARNING EDMA_DRIVER_NAME": can't get major %d\n", result);
-+ return result;
-+ }
-+ coldfire_dma_major = MAJOR(dev);
-+
-+ /* allocate device driver structure */
-+ devp = kmalloc(sizeof(struct coldfire_edma_dev), GFP_KERNEL);
-+ if (!devp) {
-+ result = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ /* init handlers (no handlers for beggining) */
-+ for (i=0;i<EDMA_CHANNELS;i++) {
-+ devp->dma_interrupt_handlers[i].irq_handler = NULL;
-+ devp->dma_interrupt_handlers[i].error_handler = NULL;
-+ devp->dma_interrupt_handlers[i].dev = NULL;
-+ devp->dma_interrupt_handlers[i].allocated = 0;
-+ devp->dma_interrupt_handlers[i].lock = NULL;
-+ devp->dma_interrupt_handlers[i].device_id = NULL;
-+ }
-+
-+ /* register char device */
-+ cdev_init(&devp->cdev, &coldfire_edma_fops);
-+ devp->cdev.owner = THIS_MODULE;
-+ devp->cdev.ops = &coldfire_edma_fops;
-+ result = cdev_add(&devp->cdev, dev, 1);
-+ if (result) {
-+ printk(KERN_NOTICE EDMA_DRIVER_NAME": Error %d adding coldfire-dma device\n", result);
-+ result = -ENODEV;
-+ goto fail;
-+ }
-+
-+ /* request/enable irq for each eDMA channel */
-+ for (i=0;i<EDMA_CHANNELS;i++)
-+ {
-+ result = request_irq(EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+i,
-+ dmaisr, SA_INTERRUPT, EDMA_DRIVER_NAME, devp);
-+ if (result) {
-+ printk(KERN_WARNING EDMA_DRIVER_NAME": Cannot request irq %d\n",
-+ EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+i);
-+ result = -EBUSY;
-+ goto fail;
-+ }
-+
-+ MCF_INTC0_ICR(EDMA_INT_CHANNEL_BASE+i) = EDMA_IRQ_LEVEL;
-+ MCF_INTC0_CIMR = EDMA_INT_CHANNEL_BASE+i;
-+
-+ }
-+
-+ /* request error interrupt */
-+ result = request_irq(EDMA_INT_CHANNEL_BASE + EDMA_INT_CONTROLLER_BASE + EDMA_CHANNELS,
-+ dma_error_isr, SA_INTERRUPT, EDMA_DRIVER_NAME, devp);
-+ if (result) {
-+ printk(KERN_WARNING EDMA_DRIVER_NAME": Cannot request irq %d\n",
-+ EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+EDMA_CHANNELS);
-+ result = -EBUSY;
-+ goto fail;
-+ }
-+
-+ /* enable error interrupt in interrupt controller */
-+ MCF_INTC0_ICR(EDMA_INT_CHANNEL_BASE+EDMA_CHANNELS) = EDMA_IRQ_LEVEL;
-+ MCF_INTC0_CIMR = EDMA_INT_CHANNEL_BASE+EDMA_CHANNELS;
-+
-+#ifdef CONFIG_PROC_FS
-+ proc_edma_init();
-+#endif
-+
-+ printk(EDMA_DRIVER_NAME ": initialized successfully\n");
-+
-+ return 0;
-+fail:
-+ coldfire_edma_cleanup();
-+ return result;
-+
-+}
-+
-+static void __exit coldfire_edma_exit(void)
-+{
-+ coldfire_edma_cleanup();
-+}
-+
-+module_init(coldfire_edma_init);
-+module_exit(coldfire_edma_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Yaroslav Vinogradov, Freescale Inc.");
-+MODULE_DESCRIPTION("eDMA library for Coldfire 5445x");
---- /dev/null
-+++ b/drivers/spi/spi-m5445x.c
-@@ -0,0 +1,156 @@
-+/***************************************************************************/
-+/*
-+ * linux/arch/m68k/coldfire/spi-m5445x.c
-+ *
-+ * Sub-architcture dependant initialization code for the Freescale
-+ * 5445x SPI module
-+ *
-+ * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
-+ * Copyright Freescale Semiconductor, Inc 2007
-+ *
-+ * 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.
-+ */
-+/***************************************************************************/
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/param.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/spi/spi.h>
-+
-+#include <asm/dma.h>
-+#include <asm/traps.h>
-+#include <asm/machdep.h>
-+#include <asm/coldfire.h>
-+#include <asm/mcfsim.h>
-+#include <asm/mcfqspi.h>
-+#include <asm/mcf5445x_gpio.h>
-+
-+#define SPI_NUM_CHIPSELECTS 0x10
-+#define SPI_PAR_VAL (0 | MCF_GPIO_PAR_DSPI_PCS5_PCS5 | MCF_GPIO_PAR_DSPI_PCS2_PCS2 \
-+ | MCF_GPIO_PAR_DSPI_PCS1_PCS1 | MCF_GPIO_PAR_DSPI_PCS0_PCS0 | MCF_GPIO_PAR_DSPI_SIN_SIN \
-+ | MCF_GPIO_PAR_DSPI_SOUT_SOUT | MCF_GPIO_PAR_DSPI_SCK_SCK)
-+
-+#define MCF5445x_DSPI_IRQ_SOURCE (31)
-+#define MCF5445x_DSPI_IRQ_VECTOR (64 + MCF5445x_DSPI_IRQ_SOURCE)
-+
-+#define MCF5445x_DSPI_PAR (0xFC0A4063)
-+#define MCF5445x_DSPI_MCR (0xFC05C000)
-+#define MCF5445x_INTC0_ICR (0xFC048040)
-+#define MCF5445x_INTC0_IMRL (0xFC04800C)
-+
-+
-+#define M5445x_AUDIO_IRQ_SOURCE 49
-+#define M5445x_AUDIO_IRQ_VECTOR (128+M5445x_AUDIO_IRQ_SOURCE)
-+#define M5445x_AUDIO_IRQ_LEVEL 4
-+
-+void coldfire_qspi_cs_control(u8 cs, u8 command)
-+{
-+}
-+
-+#if defined(CONFIG_SPI_COLDFIRE_SSI_AUDIO)
-+static struct coldfire_spi_chip ssi_audio_chip_info = {
-+ .mode = SPI_MODE_0,
-+ .bits_per_word = 16,
-+ .del_cs_to_clk = 16,
-+ .del_after_trans = 16,
-+ .void_write_data = 0
-+};
-+
-+#endif
-+
-+static struct spi_board_info spi_board_info[] = {
-+
-+#if defined(CONFIG_SPI_COLDFIRE_SSI_AUDIO)
-+ {
-+ .modalias = "ssi_audio",
-+ .max_speed_hz = 300000,
-+ .bus_num = 1,
-+ .chip_select = 5,
-+ .irq = M5445x_AUDIO_IRQ_VECTOR,
-+ .platform_data = NULL,
-+ .controller_data = &ssi_audio_chip_info
-+ }
-+#endif
-+
-+};
-+
-+static struct coldfire_spi_master coldfire_master_info = {
-+ .bus_num = 1,
-+ .num_chipselect = SPI_NUM_CHIPSELECTS,
-+ .irq_source = MCF5445x_DSPI_IRQ_SOURCE,
-+ .irq_vector = MCF5445x_DSPI_IRQ_VECTOR,
-+ .irq_mask = (0x01 << MCF5445x_DSPI_IRQ_SOURCE),
-+ .irq_lp = 0x2, /* Level */
-+ .par_val = SPI_PAR_VAL,
-+// .par_val16 = SPI_PAR_VAL,
-+ .cs_control = coldfire_qspi_cs_control,
-+};
-+
-+static struct resource coldfire_spi_resources[] = {
-+ [0] = {
-+ .name = "qspi-par",
-+ .start = MCF5445x_DSPI_PAR,
-+ .end = MCF5445x_DSPI_PAR,
-+ .flags = IORESOURCE_MEM
-+ },
-+
-+ [1] = {
-+ .name = "qspi-module",
-+ .start = MCF5445x_DSPI_MCR,
-+ .end = MCF5445x_DSPI_MCR + 0xB8,
-+ .flags = IORESOURCE_MEM
-+ },
-+
-+ [2] = {
-+ .name = "qspi-int-level",
-+ .start = MCF5445x_INTC0_ICR + MCF5445x_DSPI_IRQ_SOURCE,
-+ .end = MCF5445x_INTC0_ICR + MCF5445x_DSPI_IRQ_SOURCE,
-+ .flags = IORESOURCE_MEM
-+ },
-+
-+ [3] = {
-+ .name = "qspi-int-mask",
-+ .start = MCF5445x_INTC0_IMRL,
-+ .end = MCF5445x_INTC0_IMRL,
-+ .flags = IORESOURCE_MEM
-+ }
-+};
-+
-+static struct platform_device coldfire_spi = {
-+ .name = "spi_coldfire", //"coldfire-qspi",
-+ .id = -1,
-+ .resource = coldfire_spi_resources,
-+ .num_resources = ARRAY_SIZE(coldfire_spi_resources),
-+ .dev = {
-+ .platform_data = &coldfire_master_info,
-+ }
-+};
-+
-+static int __init spi_dev_init(void)
-+{
-+ int retval = 0;
-+
-+ retval = platform_device_register(&coldfire_spi);
-+
-+ if (retval < 0) {
-+ printk(KERN_ERR "SPI-m5445x: platform_device_register failed with code=%d\n", retval);
-+ goto out;
-+ }
-+
-+ if (ARRAY_SIZE(spi_board_info))
-+ retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
-+
-+
-+out:
-+ return retval;
-+}
-+
-+arch_initcall(spi_dev_init);
---- /dev/null
-+++ b/drivers/spi/spi_coldfire.c
-@@ -0,0 +1,1552 @@
-+/****************************************************************************/
-+
-+/*
-+ * spi_coldfire.c - Master QSPI/DSPI controller for the ColdFire processors
-+ *
-+ * (C) Copyright 2005, Intec Automation,
-+ * Mike Lavender (mike@steroidmicros)
-+ *
-+ * (C) Copyright 2007, Freescale Inc,
-+ * Yaroslav Vinogradov (yaroslav.vinogradov@freescale.com)
-+ *
-+
-+ 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. */
-+/* ------------------------------------------------------------------------- */
-+
-+
-+/****************************************************************************/
-+
-+/*
-+ * Includes
-+ */
-+
-+#include <linux/autoconf.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/device.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/spi/spi.h>
-+#include <linux/workqueue.h>
-+#include <linux/delay.h>
-+
-+#include <asm/delay.h>
-+#include <asm/mcfsim.h>
-+#include <asm/mcfqspi.h>
-+#include <asm/coldfire.h>
-+#include <asm/virtconvert.h>
-+
-+#if defined(CONFIG_M54455)
-+ #define SPI_DSPI
-+ #if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA)
-+ #define SPI_DSPI_EDMA
-+ #ifdef CONFIG_MMU
-+ #define SPI_USE_MMU
-+ #endif
-+ #endif
-+#endif
-+
-+#ifdef SPI_DSPI
-+#include <asm/mcf5445x_dspi.h>
-+
-+
-+#endif
-+
-+#if defined(SPI_DSPI_EDMA)
-+
-+/* edma buffer size in transfer units (32bits) */
-+#define EDMA_BUFFER_SIZE (PAGE_SIZE/4)
-+#define EDMA_BUFSIZE_KMALLOC (EDMA_BUFFER_SIZE*4)
-+
-+#define DSPI_DMA_RX_TCD 12
-+#define DSPI_DMA_TX_TCD 13
-+
-+
-+#include <asm/coldfire_edma.h>
-+#include <asm/mcf5445x_edma.h>
-+#endif
-+
-+
-+MODULE_AUTHOR("Mike Lavender");
-+MODULE_DESCRIPTION("ColdFire QSPI Contoller");
-+MODULE_LICENSE("GPL");
-+
-+#define DRIVER_NAME "Coldfire QSPI/DSPI"
-+
-+/****************************************************************************/
-+
-+/*
-+ * Local constants and macros
-+ */
-+
-+#define QSPI_RAM_SIZE 0x10 /* 16 word table */
-+
-+#define QSPI_TRANSMIT_RAM 0x00
-+#define QSPI_RECEIVE_RAM 0x10
-+#define QSPI_COMMAND_RAM 0x20
-+
-+#define QSPI_COMMAND 0x7000 /* 15: X = Continuous CS
-+ * 14: 1 = Get BITSE from QMR[BITS]
-+ * 13: 1 = Get DT from QDLYR[DTL]
-+ * 12: 1 = Get DSK from QDLYR[QCD]
-+ * 8-11: XXXX = next 4 bytes for CS
-+ * 0-7: 0000 0000 Reserved
-+ */
-+
-+#define QIR_WCEF 0x0008 /* write collison */
-+#define QIR_ABRT 0x0004 /* abort */
-+#define QIR_SPIF 0x0001 /* finished */
-+
-+#define QIR_WCEFE 0x0800
-+#define QIR_ABRTE 0x0400
-+#define QIR_SPIFE 0x0100
-+
-+#define QIR_WCEFB 0x8000
-+#define QIR_ABRTB 0x4000
-+#define QIR_ABRTL 0x1000
-+
-+#define QMR_BITS 0x3C00
-+#define QMR_BITS_8 0x2000
-+
-+#define QCR_CONT 0x8000
-+
-+#define QDLYR_SPE 0x8000
-+
-+#define QWR_ENDQP_MASK 0x0F00
-+#define QWR_CSIV 0x1000 /* 1 = active low chip selects */
-+
-+
-+#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
-+
-+/****************************************************************************/
-+
-+/*
-+ * Local Data Structures
-+ */
-+
-+struct transfer_state {
-+ u32 index;
-+ u32 len;
-+ void *tx;
-+ void *tx_end;
-+ void *rx;
-+ void *rx_end;
-+ char flags;
-+#define TRAN_STATE_RX_VOID 0x01
-+#define TRAN_STATE_TX_VOID 0x02
-+#define TRAN_STATE_WORD_ODD_NUM 0x04
-+ u8 cs;
-+ u16 void_write_data;
-+ unsigned cs_change:1;
-+};
-+
-+typedef struct {
-+ unsigned master:1;
-+ unsigned dohie:1;
-+ unsigned bits:4;
-+ unsigned cpol:1;
-+ unsigned cpha:1;
-+ unsigned baud:8;
-+} QMR;
-+
-+typedef struct {
-+ unsigned spe:1;
-+ unsigned qcd:7;
-+ unsigned dtl:8;
-+} QDLYR;
-+
-+typedef struct {
-+ unsigned halt:1;
-+ unsigned wren:1;
-+ unsigned wrto:1;
-+ unsigned csiv:1;
-+ unsigned endqp:4;
-+ unsigned cptqp:4;
-+ unsigned newqp:4;
-+} QWR;
-+
-+
-+typedef struct {
-+ unsigned master:1;
-+ unsigned cont_scke:1;
-+ unsigned dconf:2;
-+ unsigned frz:1;
-+ unsigned mtfe:1;
-+ unsigned pcsse:1;
-+ unsigned rooe:1;
-+ unsigned pcsis:8;
-+ unsigned reserved15:1;
-+ unsigned mdis:1;
-+ unsigned dis_tx:1;
-+ unsigned dis_rxf:1;
-+ unsigned clr_tx:1;
-+ unsigned clr_rxf:1;
-+ unsigned smpl_pt:2;
-+ unsigned reserved71:7;
-+ unsigned halt:1;
-+} DSPI_MCR;
-+
-+typedef struct {
-+ unsigned dbr:1;
-+ unsigned fmsz:4;
-+ unsigned cpol:1;
-+ unsigned cpha:1;
-+ unsigned lsbfe:1;
-+ unsigned pcssck:2;
-+ unsigned pasc:2;
-+ unsigned pdt:2;
-+ unsigned pbr:2;
-+ unsigned cssck:4;
-+ unsigned asc:4;
-+ unsigned dt:4;
-+ unsigned br:4;
-+} DSPI_CTAR;
-+
-+struct chip_data {
-+#if defined(SPI_DSPI)
-+ /* dspi data */
-+ union {
-+ u32 mcr_val;
-+ DSPI_MCR mcr;
-+ };
-+ union {
-+ u32 ctar_val;
-+ DSPI_CTAR ctar;
-+ };
-+#else
-+ union {
-+ u16 qmr_val;
-+ QMR qmr;
-+ };
-+ union {
-+ u16 qdlyr_val;
-+ QDLYR qdlyr;
-+ };
-+ union {
-+ u16 qwr_val;
-+ QWR qwr;
-+ };
-+#endif
-+
-+ u16 void_write_data;
-+};
-+
-+
-+struct driver_data {
-+ /* Driver model hookup */
-+ struct platform_device *pdev;
-+
-+ /* SPI framework hookup */
-+ struct spi_master *master;
-+
-+ /* 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;
-+ char flags;
-+#define TRAN_STATE_RX_VOID 0x01
-+#define TRAN_STATE_TX_VOID 0x02
-+#define TRAN_STATE_WORD_ODD_NUM 0x04
-+ u8 cs;
-+ u16 void_write_data;
-+ unsigned cs_change:1;
-+
-+ u32 trans_cnt;
-+ u32 wce_cnt;
-+ u32 abrt_cnt;
-+#if defined(SPI_DSPI)
-+ u32 *mcr; /* DSPI MCR register */
-+ u32 *ctar; /* DSPI CTAR register */
-+ u32 *dspi_dtfr; /* DSPI DTFR register */
-+ u32 *dspi_drfr; /* DSPI DRFR register */
-+ u32 *dspi_rser; /* DSPI RSER register */
-+ u32 *dspi_sr; /* DSPI status register */
-+ u8 dspi_ctas; /* DSPI CTAS value*/
-+
-+#if defined(SPI_DSPI_EDMA)
-+ void* edma_tx_buf;
-+ void* edma_rx_buf;
-+#endif
-+
-+
-+#else
-+ u16 *qmr; /* QSPI mode register */
-+ u16 *qdlyr; /* QSPI delay register */
-+ u16 *qwr; /* QSPI wrap register */
-+ u16 *qir; /* QSPI interrupt register */
-+ u16 *qar; /* QSPI address register */
-+ u16 *qdr; /* QSPI data register */
-+ u16 *qcr; /* QSPI command register */
-+#endif
-+ u8 *par; /* Pin assignment register */
-+ u8 *int_icr; /* Interrupt level and priority register */
-+ u32 *int_mr; /* Interrupt mask register */
-+ void (*cs_control)(u8 cs, u8 command);
-+};
-+
-+#define DSPI_CS(cs) ((1<<(cs))<<16)
-+
-+
-+/****************************************************************************/
-+
-+/*
-+ * SPI local functions
-+ */
-+
-+//#define SPI_COLDFIRE_DEBUG
-+
-+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;
-+}
-+
-+
-+#define DSPI_BITS MCF_DSPI_DCTAR_FMSZ(15)
-+#define DSPI_BITS_16 MCF_DSPI_DCTAR_FMSZ(15)
-+#define DSPI_BITS_8 MCF_DSPI_DCTAR_FMSZ(7)
-+#define DSPI_FIFO_SIZE 16
-+
-+static inline int is_word_transfer(struct driver_data *drv_data)
-+{
-+#if defined(SPI_DSPI)
-+ return ((*drv_data->ctar & DSPI_BITS_16) == DSPI_BITS_8) ? 0 : 1;
-+#else
-+ return ((*drv_data->qmr & QMR_BITS) == QMR_BITS_8) ? 0 : 1;
-+#endif
-+}
-+
-+static void inline set_8bit_transfer_mode(struct driver_data *drv_data)
-+{
-+#if defined(SPI_DSPI)
-+ *drv_data->ctar |= (*drv_data->ctar & ~DSPI_BITS) | DSPI_BITS_8;
-+#else
-+ *drv_data->qmr |= (*drv_data->qmr & ~QMR_BITS) | QMR_BITS_8;
-+#endif
-+}
-+
-+static void inline set_16bit_transfer_mode(struct driver_data *drv_data)
-+{
-+#if defined(SPI_DSPI)
-+ *drv_data->ctar |= (*drv_data->ctar & ~DSPI_BITS) | DSPI_BITS_16;
-+#else
-+ *drv_data->qmr |= (*drv_data->qmr & ~QMR_BITS);
-+#endif
-+}
-+
-+static int write(struct driver_data *drv_data)
-+{
-+ int tx_count = 0;
-+#ifndef SPI_DSPI
-+ int cmd_count = 0;
-+#endif
-+ int tx_word;
-+
-+#if defined(SPI_DSPI)
-+
-+#if defined(SPI_DSPI_EDMA)
-+ u32* edma_wr;
-+#endif
-+
-+ u16 d16;
-+ u8 d8;
-+ u32 dspi_pushr;
-+ int first = 1;
-+#endif
-+
-+ tx_word = is_word_transfer(drv_data);
-+
-+ // If we are in word mode, but only have a single byte to transfer
-+ // then switch to byte mode temporarily. Will switch back at the
-+ // end of the transfer.
-+ if (tx_word && ((drv_data->tx_end - drv_data->tx) == 1)) {
-+ drv_data->flags |= TRAN_STATE_WORD_ODD_NUM;
-+ set_8bit_transfer_mode(drv_data);
-+ tx_word = 0;
-+ }
-+
-+
-+#if defined(SPI_DSPI)
-+
-+#if defined(SPI_DSPI_EDMA)
-+ edma_wr = (u32*)(drv_data->edma_tx_buf);
-+#endif
-+
-+
-+#if defined(SPI_DSPI_EDMA)
-+ while ((drv_data->tx < drv_data->tx_end) && (tx_count < EDMA_BUFFER_SIZE)) {
-+#else
-+ while ((drv_data->tx < drv_data->tx_end) && (tx_count < DSPI_FIFO_SIZE)) {
-+#endif
-+ if (tx_word) {
-+ if ((drv_data->tx_end - drv_data->tx) == 1)
-+ break;
-+ if (!(drv_data->flags & TRAN_STATE_TX_VOID)) {
-+ d16 = *(u16 *)drv_data->tx;
-+ } else {
-+ d16 = drv_data->void_write_data;
-+ }
-+
-+ dspi_pushr = MCF_DSPI_DTFR_TXDATA(d16)
-+ | DSPI_CS(drv_data->cs)
-+ | MCF_DSPI_DTFR_CTAS(drv_data->dspi_ctas)
-+ //| MCF_DSPI_DTFR_CONT
-+ ;
-+
-+ drv_data->tx += 2;
-+
-+#if defined(SPI_DSPI_EDMA)
-+ if (drv_data->tx == drv_data->tx_end || tx_count==EDMA_BUFFER_SIZE-1) {
-+#else
-+ if (drv_data->tx == drv_data->tx_end || tx_count==DSPI_FIFO_SIZE-1) {
-+#endif
-+ // last transfer in queue
-+ dspi_pushr |= MCF_DSPI_DTFR_EOQ;
-+ if (drv_data->cs_change) {
-+ dspi_pushr &= ~MCF_DSPI_DTFR_CONT;
-+ }
-+ }
-+
-+ if (first) {
-+ first = 0;
-+ dspi_pushr |= MCF_DSPI_DTFR_CTCNT; // clear counter
-+ }
-+#if defined(SPI_DSPI_EDMA)
-+ *edma_wr = dspi_pushr;
-+ edma_wr++;
-+#else
-+ *drv_data->dspi_dtfr = dspi_pushr;
-+ //MCF_DSPI_DTFR = dspi_pushr;
-+#endif
-+
-+
-+ } else {
-+ if (!(drv_data->flags & TRAN_STATE_TX_VOID)) {
-+ d8 = *(u8 *)drv_data->tx;
-+ } else {
-+ d8 = *(u8 *)&drv_data->void_write_data;
-+ }
-+
-+ dspi_pushr = MCF_DSPI_DTFR_TXDATA(d8)
-+ | DSPI_CS(drv_data->cs)
-+ /* | MCF_DSPI_DTFR_PCS5 | */
-+ | MCF_DSPI_DTFR_CTAS(drv_data->dspi_ctas)
-+ | MCF_DSPI_DTFR_CONT;
-+
-+ drv_data->tx++;
-+
-+ if (drv_data->tx == drv_data->tx_end || tx_count==DSPI_FIFO_SIZE-1) {
-+ // last transfer in queue
-+ dspi_pushr |= MCF_DSPI_DTFR_EOQ;
-+ if (drv_data->cs_change) {
-+ dspi_pushr &= ~MCF_DSPI_DTFR_CONT;
-+ }
-+ }
-+
-+ if (first) {
-+ first = 0;
-+ dspi_pushr |= MCF_DSPI_DTFR_CTCNT; // clear counter
-+ }
-+
-+#if defined(SPI_DSPI_EDMA)
-+ *edma_wr = dspi_pushr;
-+ edma_wr++;
-+#else
-+ *drv_data->dspi_dtfr = dspi_pushr;
-+ //MCF_DSPI_DTFR = dspi_pushr;
-+#endif
-+
-+ }
-+ tx_count++;
-+ }
-+
-+#if defined(SPI_DSPI_EDMA)
-+
-+ if (tx_count>0) {
-+
-+ // TODO: initiate eDMA transfer
-+ set_edma_params(DSPI_DMA_TX_TCD,
-+#ifdef SPI_USE_MMU
-+ virt_to_phys(drv_data->edma_tx_buf),
-+#else
-+ drv_data->edma_tx_buf,
-+#endif
-+ (u32)drv_data->dspi_dtfr,
-+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
-+ 4, // soff
-+ 4, // nbytes
-+ 0, // slast
-+ tx_count, // citer
-+ tx_count, // biter
-+ 0, // doff
-+ 0, // dlastsga
-+ 0, // major_int
-+ 1 // disable_req
-+ );
-+
-+ set_edma_params(DSPI_DMA_RX_TCD,
-+ (u32)drv_data->dspi_drfr,
-+#ifdef SPI_USE_MMU
-+ virt_to_phys(drv_data->edma_rx_buf),
-+#else
-+ drv_data->edma_rx_buf,
-+#endif
-+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
-+ 0, // soff
-+ 4, // nbytes
-+ 0, // slast
-+ tx_count, // citer
-+ tx_count, // biter
-+ 4, // doff
-+ 0, // dlastsga
-+ 0, // major_int
-+ 1 // disable_req
-+ );
-+
-+
-+ start_edma_transfer(DSPI_DMA_TX_TCD); // transmit SPI data
-+ start_edma_transfer(DSPI_DMA_RX_TCD); // receive SPI data
-+ }
-+#endif
-+
-+#else
-+
-+ *drv_data->qar = QSPI_TRANSMIT_RAM;
-+ while ((drv_data->tx < drv_data->tx_end) && (tx_count < QSPI_RAM_SIZE)) {
-+ if (tx_word) {
-+ if ((drv_data->tx_end - drv_data->tx) == 1)
-+ break;
-+
-+ if (!(drv_data->flags & TRAN_STATE_TX_VOID))
-+ *drv_data->qdr = *(u16 *)drv_data->tx;
-+ else
-+ *drv_data->qdr = drv_data->void_write_data;
-+ drv_data->tx += 2;
-+ } else {
-+ if (!(drv_data->flags & TRAN_STATE_TX_VOID))
-+ *drv_data->qdr = *(u8 *)drv_data->tx;
-+ else
-+ *drv_data->qdr = *(u8 *)&drv_data->void_write_data;
-+ drv_data->tx++;
-+ }
-+ tx_count++;
-+ }
-+
-+
-+ *drv_data->qar = QSPI_COMMAND_RAM;
-+ while (cmd_count < tx_count) {
-+ u16 qcr = QSPI_COMMAND
-+ | QCR_CONT
-+ | (~((0x01 << drv_data->cs) << 8) & 0x0F00);
-+
-+ if ( (cmd_count == tx_count - 1)
-+ && (drv_data->tx == drv_data->tx_end)
-+ && (drv_data->cs_change) ) {
-+ qcr &= ~QCR_CONT;
-+ }
-+ *drv_data->qcr = qcr;
-+ cmd_count++;
-+ }
-+
-+ *drv_data->qwr = (*drv_data->qwr & ~QWR_ENDQP_MASK) | ((cmd_count - 1) << 8);
-+
-+ /* Fire it up! */
-+ *drv_data->qdlyr |= QDLYR_SPE;
-+#endif
-+
-+ return tx_count;
-+}
-+
-+
-+static int read(struct driver_data *drv_data)
-+{
-+ int rx_count = 0;
-+ int rx_word;
-+#if defined(SPI_DSPI_EDMA)
-+ u32* rx_edma;
-+#endif
-+ u16 d;
-+ rx_word = is_word_transfer(drv_data);
-+
-+#if defined(SPI_DSPI)
-+
-+#if defined(SPI_DSPI_EDMA)
-+ rx_edma = (u32*) drv_data->edma_tx_buf;
-+ while ((drv_data->rx < drv_data->rx_end) && (rx_count < EDMA_BUFFER_SIZE)) {
-+#else
-+ while ((drv_data->rx < drv_data->rx_end) && (rx_count < DSPI_FIFO_SIZE)) {
-+#endif
-+ if (rx_word) {
-+ if ((drv_data->rx_end - drv_data->rx) == 1)
-+ break;
-+#if defined(SPI_DSPI_EDMA)
-+ d = MCF_DSPI_DRFR_RXDATA(*rx_edma);
-+ rx_edma++;
-+#else
-+ d = MCF_DSPI_DRFR_RXDATA(*drv_data->dspi_drfr);
-+#endif
-+
-+ if (!(drv_data->flags & TRAN_STATE_RX_VOID))
-+ *(u16 *)drv_data->rx = d;
-+ drv_data->rx += 2;
-+ } else {
-+#if defined(SPI_DSPI_EDMA)
-+ d = MCF_DSPI_DRFR_RXDATA(*rx_edma);
-+ rx_edma++;
-+#else
-+ d = MCF_DSPI_DRFR_RXDATA(*drv_data->dspi_drfr);
-+#endif
-+ if (!(drv_data->flags & TRAN_STATE_RX_VOID))
-+ *(u8 *)drv_data->rx = d;
-+ drv_data->rx++;
-+ }
-+ rx_count++;
-+ }
-+
-+
-+#else
-+
-+ *drv_data->qar = QSPI_RECEIVE_RAM;
-+ while ((drv_data->rx < drv_data->rx_end) && (rx_count < QSPI_RAM_SIZE)) {
-+ if (rx_word) {
-+ if ((drv_data->rx_end - drv_data->rx) == 1)
-+ break;
-+
-+ if (!(drv_data->flags & TRAN_STATE_RX_VOID))
-+ *(u16 *)drv_data->rx = *drv_data->qdr;
-+ drv_data->rx += 2;
-+ } else {
-+ if (!(drv_data->flags & TRAN_STATE_RX_VOID))
-+ *(u8 *)drv_data->rx = *drv_data->qdr;
-+ drv_data->rx++;
-+ }
-+ rx_count++;
-+ }
-+#endif
-+
-+ return rx_count;
-+}
-+
-+
-+static inline void qspi_setup_chip(struct driver_data *drv_data)
-+{
-+ struct chip_data *chip = drv_data->cur_chip;
-+
-+#if defined(SPI_DSPI)
-+
-+ *drv_data->mcr = chip->mcr_val;
-+
-+ // TODO: remove later
-+ chip->ctar_val = 0x78560118;
-+
-+ *drv_data->ctar = chip->ctar_val;
-+ *drv_data->dspi_rser = 0
-+ | MCF_DSPI_DRSER_EOQFE
-+#if defined(SPI_DSPI_EDMA)
-+ | MCF_DSPI_DRSER_TFFFE
-+ | MCF_DSPI_DRSER_TFFFS
-+#endif
-+ ;
-+
-+
-+#else
-+ *drv_data->qmr = chip->qmr_val;
-+ *drv_data->qdlyr = chip->qdlyr_val;
-+ *drv_data->qwr = chip->qwr_val;
-+
-+ /*
-+ * Enable all the interrupts and clear all the flags
-+ */
-+ *drv_data->qir = (QIR_SPIFE | QIR_ABRTE | QIR_WCEFE)
-+ | (QIR_WCEFB | QIR_ABRTB | QIR_ABRTL)
-+ | (QIR_SPIF | QIR_ABRT | QIR_WCEF);
-+#endif
-+}
-+
-+#if defined(SPI_DSPI_EDMA)
-+static int edma_tx_handler(int channel, void* dev)
-+{
-+ if (channel == DSPI_DMA_TX_TCD) {
-+ stop_edma_transfer(DSPI_DMA_TX_TCD);
-+ }
-+ return IRQ_HANDLED;
-+}
-+
-+static int edma_rx_handler(int channel, void* dev)
-+{
-+ if (channel == DSPI_DMA_RX_TCD) {
-+ stop_edma_transfer(DSPI_DMA_RX_TCD);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+#endif
-+
-+static irqreturn_t qspi_interrupt(int irq, void *dev_id)
-+{
-+ struct driver_data *drv_data = (struct driver_data *)dev_id;
-+ struct spi_message *msg = drv_data->cur_msg;
-+#if defined(SPI_DSPI)
-+#if !defined(SPI_DSPI_EDMA)
-+ u32 irq_status = *drv_data->dspi_sr;
-+#endif
-+#else
-+ u16 irq_status = *drv_data->qir;
-+#endif
-+
-+ /* Clear all flags immediately */
-+#if defined(SPI_DSPI)
-+ *drv_data->dspi_sr = MCF_DSPI_DSR_EOQF;
-+#else
-+ *drv_data->qir |= (QIR_SPIF | QIR_ABRT | QIR_WCEF);
-+#endif
-+
-+ if (!drv_data->cur_msg || !drv_data->cur_msg->state) {
-+#if !defined(SPI_DSPI_EDMA)
-+ /* if eDMA is used it happens some time (at least once)*/
-+ printk(KERN_ERR "coldfire-qspi: bad message or transfer "
-+ "state in interrupt handler. IRQ status=%x\n", irq_status);
-+#endif
-+ return IRQ_NONE;
-+ }
-+
-+#if !defined(SPI_DSPI)
-+ if (irq_status & QIR_SPIF) {
-+#endif
-+ /*
-+ * Read the data into the buffer and reload and start
-+ * queue with new data if not finished. If finished
-+ * then setup the next transfer
-+ */
-+ read(drv_data);
-+
-+ if (drv_data->rx == drv_data->rx_end) {
-+ /*
-+ * Finished now - fall through and schedule next
-+ * transfer tasklet
-+ */
-+ if (drv_data->flags & TRAN_STATE_WORD_ODD_NUM) {
-+ //*drv_data->qmr &= ~QMR_BITS;
-+ set_16bit_transfer_mode(drv_data);
-+ }
-+
-+ msg->state = next_transfer(drv_data);
-+ msg->actual_length += drv_data->len;
-+ } else {
-+ /* not finished yet - keep going */
-+ write(drv_data);
-+ return IRQ_HANDLED;
-+ }
-+#if !defined(SPI_DSPI)
-+ } else {
-+ if (irq_status & QIR_WCEF)
-+ drv_data->wce_cnt++;
-+
-+ if (irq_status & QIR_ABRT)
-+ drv_data->abrt_cnt++;
-+
-+ msg->state = ERROR_STATE;
-+ }
-+#endif
-+
-+ tasklet_schedule(&drv_data->pump_transfers);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/* caller already set message->status; dma and pio irqs are blocked */
-+static void giveback(struct driver_data *drv_data)
-+{
-+ struct spi_transfer* last_transfer;
-+ unsigned long flags;
-+ struct spi_message *msg;
-+
-+ spin_lock_irqsave(&drv_data->lock, flags);
-+ msg = drv_data->cur_msg;
-+ drv_data->cur_msg = NULL;
-+ drv_data->cur_transfer = NULL;
-+ drv_data->cur_chip = NULL;
-+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
-+ spin_unlock_irqrestore(&drv_data->lock, flags);
-+
-+ last_transfer = list_entry(msg->transfers.prev,
-+ struct spi_transfer,
-+ transfer_list);
-+
-+ if (!last_transfer->cs_change)
-+ drv_data->cs_control(drv_data->cs, QSPI_CS_DROP);
-+
-+ msg->state = NULL;
-+ if (msg->complete)
-+ msg->complete(msg->context);
-+}
-+
-+
-+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;
-+ unsigned long flags;
-+
-+ /* 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(drv_data);
-+ return;
-+ }
-+
-+ /* Handle end of message */
-+ if (message->state == DONE_STATE) {
-+ message->status = 0;
-+ giveback(drv_data);
-+ return;
-+ }
-+
-+ if (message->state == START_STATE) {
-+ qspi_setup_chip(drv_data);
-+
-+ if (drv_data->cs_control) {
-+ //printk( "m s\n" );
-+ drv_data->cs_control(message->spi->chip_select, QSPI_CS_ASSERT);
-+ }
-+ }
-+
-+ /* 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 (drv_data->cs_control && transfer->cs_change)
-+ drv_data->cs_control(message->spi->chip_select, QSPI_CS_DROP);
-+
-+ if (previous->delay_usecs)
-+ udelay(previous->delay_usecs);
-+
-+ if (drv_data->cs_control && transfer->cs_change)
-+ drv_data->cs_control(message->spi->chip_select, QSPI_CS_ASSERT);
-+ }
-+
-+ drv_data->flags = 0;
-+ 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->len = transfer->len;
-+ if (!drv_data->rx)
-+ drv_data->flags |= TRAN_STATE_RX_VOID;
-+ if (!drv_data->tx)
-+ drv_data->flags |= TRAN_STATE_TX_VOID;
-+ drv_data->cs = message->spi->chip_select;
-+ drv_data->cs_change = transfer->cs_change;
-+ drv_data->void_write_data = chip->void_write_data;
-+
-+ message->state = RUNNING_STATE;
-+
-+ /* Go baby, go */
-+ local_irq_save(flags);
-+ write(drv_data);
-+ local_irq_restore(flags);
-+}
-+
-+
-+static void pump_messages(struct work_struct * work)
-+{
-+ struct driver_data *drv_data;
-+ unsigned long flags;
-+
-+ drv_data = container_of(work, struct driver_data, pump_messages);
-+
-+ /* 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);
-+
-+ /* 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 SPI Registers using the per chip configuration */
-+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
-+
-+ /* Mark as busy and launch transfers */
-+ tasklet_schedule(&drv_data->pump_transfers);
-+
-+ drv_data->busy = 1;
-+ spin_unlock_irqrestore(&drv_data->lock, flags);
-+}
-+
-+/****************************************************************************/
-+
-+/*
-+ * SPI master implementation
-+ */
-+
-+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 coldfire_spi_chip *chip_info;
-+ struct chip_data *chip;
-+#ifndef SPI_DSPI
-+ u32 baud_divisor = 255;
-+#endif
-+
-+ chip_info = (struct coldfire_spi_chip *)spi->controller_data;
-+
-+ /* Only alloc on first setup */
-+ chip = spi_get_ctldata(spi);
-+ if (chip == NULL) {
-+ chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
-+ if (!chip)
-+ return -ENOMEM;
-+ spi->mode = chip_info->mode;
-+ spi->bits_per_word = chip_info->bits_per_word;
-+ }
-+
-+#if defined(SPI_DSPI)
-+ chip->mcr.master = 1;
-+ chip->mcr.cont_scke = 0;
-+ chip->mcr.dconf = 0;
-+ chip->mcr.frz = 0;
-+ chip->mcr.mtfe = 1;
-+ chip->mcr.pcsse = 0;
-+ chip->mcr.rooe = 0;
-+ chip->mcr.pcsis = 0xFF;
-+ chip->mcr.reserved15 = 0;
-+ chip->mcr.mdis = 0;
-+ chip->mcr.dis_tx = 0;
-+ chip->mcr.dis_rxf = 0;
-+ chip->mcr.clr_tx = 1;
-+ chip->mcr.clr_rxf = 1;
-+ chip->mcr.smpl_pt = 0;
-+ chip->mcr.reserved71 = 0;
-+ chip->mcr.halt = 0;
-+
-+ if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
-+ chip->ctar.fmsz = spi->bits_per_word-1;
-+ } else {
-+ printk(KERN_ERR "coldfire-qspi: invalid wordsize\n");
-+ kfree(chip);
-+ return -ENODEV;
-+ }
-+
-+ if (spi->mode & SPI_CPHA)
-+ chip->ctar.cpha = 1;
-+ else
-+ chip->ctar.cpha = 0;
-+
-+ if (spi->mode & SPI_CPOL)
-+ chip->ctar.cpol = 1;
-+ else
-+ chip->ctar.cpol = 0;
-+
-+ if (spi->mode & SPI_LSB_FIRST)
-+ chip->ctar.lsbfe = 1;
-+ else
-+ chip->ctar.lsbfe = 0;
-+
-+ /* This values are default for audio device */
-+ chip->ctar.dbr = 0;
-+ chip->ctar.pbr = 2;
-+ chip->ctar.br = 8;
-+
-+ /* This values are default for audio device */
-+ chip->ctar.pcssck = 1;
-+ chip->ctar.pasc = 1;
-+ chip->ctar.pdt = 1;
-+ chip->ctar.cssck = 0;
-+ chip->ctar.asc = 1;
-+ chip->ctar.dt = 1;
-+
-+ chip->void_write_data = chip_info->void_write_data;
-+
-+#else
-+
-+ chip->qwr.csiv = 1; // Chip selects are active low
-+ chip->qmr.master = 1; // Must set to master mode
-+ chip->qmr.dohie = 1; // Data output high impediance enabled
-+ chip->void_write_data = chip_info->void_write_data;
-+
-+ chip->qdlyr.qcd = chip_info->del_cs_to_clk;
-+ chip->qdlyr.dtl = chip_info->del_after_trans;
-+
-+ if (spi->max_speed_hz != 0)
-+ baud_divisor = (MCF_CLK/(2*spi->max_speed_hz));
-+
-+ if (baud_divisor < 2)
-+ baud_divisor = 2;
-+
-+ if (baud_divisor > 255)
-+ baud_divisor = 255;
-+
-+ chip->qmr.baud = baud_divisor;
-+
-+ //printk( "QSPI: spi->max_speed_hz %d\n", spi->max_speed_hz );
-+ //printk( "QSPI: Baud set to %d\n", chip->qmr.baud );
-+
-+ if (spi->mode & SPI_CPHA)
-+ chip->qmr.cpha = 1;
-+
-+ if (spi->mode & SPI_CPOL)
-+ chip->qmr.cpol = 1;
-+
-+ if (spi->bits_per_word == 16) {
-+ chip->qmr.bits = 0;
-+ } else if ((spi->bits_per_word >= 8) && (spi->bits_per_word <= 15)) {
-+ chip->qmr.bits = spi->bits_per_word;
-+ } else {
-+ printk(KERN_ERR "coldfire-qspi: invalid wordsize\n");
-+ kfree(chip);
-+ return -ENODEV;
-+ }
-+
-+#endif
-+
-+ spi_set_ctldata(spi, chip);
-+
-+ return 0;
-+}
-+
-+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 void cleanup(const struct spi_device *spi)
-+{
-+ struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
-+
-+ dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n",
-+ spi->master->bus_num, spi->chip_select);
-+
-+ kfree(chip);
-+}
-+
-+
-+/****************************************************************************/
-+
-+/*
-+ * Generic Device driver routines and interface implementation
-+ */
-+
-+static int coldfire_spi_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct coldfire_spi_master *platform_info;
-+ struct spi_master *master;
-+ struct driver_data *drv_data = 0;
-+ struct resource *memory_resource;
-+ int irq;
-+ int status = 0;
-+ int i;
-+
-+#if defined(SPI_DSPI_EDMA)
-+ init_edma();
-+#endif
-+
-+ platform_info = (struct coldfire_spi_master *)pdev->dev.platform_data;
-+
-+ master = spi_alloc_master(dev, sizeof(struct driver_data));
-+ if (!master)
-+ return -ENOMEM;
-+
-+ drv_data = class_get_devdata(&master->cdev);
-+ drv_data->master = master;
-+
-+ INIT_LIST_HEAD(&drv_data->queue);
-+ spin_lock_init(&drv_data->lock);
-+
-+ master->bus_num = platform_info->bus_num;
-+ master->num_chipselect = platform_info->num_chipselect;
-+ master->cleanup = cleanup;
-+ master->setup = setup;
-+ master->transfer = transfer;
-+
-+ drv_data->cs_control = platform_info->cs_control;
-+ if (drv_data->cs_control)
-+ for(i = 0; i < master->num_chipselect; i++)
-+ drv_data->cs_control(i, QSPI_CS_INIT | QSPI_CS_DROP);
-+
-+ /* Setup register addresses */
-+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi-module");
-+ if (!memory_resource) {
-+ dev_dbg(dev, "can not find platform module memory\n");
-+ goto out_error_master_alloc;
-+ }
-+
-+#if defined(SPI_DSPI_EDMA)
-+ drv_data->edma_tx_buf = kmalloc(EDMA_BUFSIZE_KMALLOC, GFP_DMA);
-+ if (!drv_data->edma_tx_buf) {
-+ dev_dbg(dev, "cannot allocate eDMA TX memory\n");
-+ goto out_error_master_alloc;
-+ }
-+ drv_data->edma_rx_buf = kmalloc(EDMA_BUFSIZE_KMALLOC, GFP_DMA);
-+ if (!drv_data->edma_rx_buf) {
-+ kfree(drv_data->edma_tx_buf);
-+ dev_dbg(dev, "cannot allocate eDMA RX memory\n");
-+ goto out_error_master_alloc;
-+ }
-+#endif
-+
-+#if defined(SPI_DSPI)
-+
-+ drv_data->mcr = (void *)(memory_resource->start + 0x00000000);
-+ drv_data->ctar = (void *)(memory_resource->start + 0x0000000C);
-+ drv_data->dspi_sr = (void *)(memory_resource->start + 0x0000002C);
-+ drv_data->dspi_rser = (void *)(memory_resource->start + 0x00000030);
-+ drv_data->dspi_dtfr = (void *)(memory_resource->start + 0x00000034);
-+ drv_data->dspi_drfr = (void *)(memory_resource->start + 0x00000038);
-+
-+#else
-+
-+ drv_data->qmr = (void *)(memory_resource->start + 0x00000000);
-+ drv_data->qdlyr = (void *)(memory_resource->start + 0x00000004);
-+ drv_data->qwr = (void *)(memory_resource->start + 0x00000008);
-+ drv_data->qir = (void *)(memory_resource->start + 0x0000000c);
-+ drv_data->qar = (void *)(memory_resource->start + 0x00000010);
-+ drv_data->qdr = (void *)(memory_resource->start + 0x00000014);
-+ drv_data->qcr = (void *)(memory_resource->start + 0x00000014);
-+
-+#endif
-+
-+ /* Setup register addresses */
-+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi-par");
-+ if (!memory_resource) {
-+ dev_dbg(dev, "can not find platform par memory\n");
-+ goto out_error_master_alloc;
-+ }
-+
-+ drv_data->par = (void *)memory_resource->start;
-+
-+ /* Setup register addresses */
-+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi-int-level");
-+ if (!memory_resource) {
-+ dev_dbg(dev, "can not find platform par memory\n");
-+ goto out_error_master_alloc;
-+ }
-+
-+ drv_data->int_icr = (void *)memory_resource->start;
-+
-+ /* Setup register addresses */
-+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi-int-mask");
-+ if (!memory_resource) {
-+ dev_dbg(dev, "can not find platform par memory\n");
-+ goto out_error_master_alloc;
-+ }
-+
-+ drv_data->int_mr = (void *)memory_resource->start;
-+
-+ irq = platform_info->irq_vector;
-+
-+ status = request_irq(platform_info->irq_vector, qspi_interrupt, SA_INTERRUPT, dev->bus_id, drv_data);
-+ if (status < 0) {
-+ dev_err(&pdev->dev, "unable to attach ColdFire QSPI interrupt\n");
-+ goto out_error_master_alloc;
-+ }
-+
-+ /* Now that we have all the addresses etc. Let's set it up */
-+ // TODO:
-+ //*drv_data->par = platform_info->par_val;
-+
-+ MCF_GPIO_PAR_DSPI = 0
-+ | MCF_GPIO_PAR_DSPI_PCS5_PCS5
-+ | MCF_GPIO_PAR_DSPI_PCS2_PCS2
-+ | MCF_GPIO_PAR_DSPI_PCS1_PCS1
-+ | MCF_GPIO_PAR_DSPI_PCS0_PCS0
-+ | MCF_GPIO_PAR_DSPI_SIN_SIN
-+ | MCF_GPIO_PAR_DSPI_SOUT_SOUT
-+ | MCF_GPIO_PAR_DSPI_SCK_SCK;
-+
-+ *drv_data->int_icr = platform_info->irq_lp;
-+ *drv_data->int_mr &= ~platform_info->irq_mask;
-+
-+#ifdef SPI_DSPI
-+ drv_data->dspi_ctas = 0; // TODO: change later
-+#endif
-+
-+ /* Initial and start queue */
-+ status = init_queue(drv_data);
-+ if (status != 0) {
-+ dev_err(&pdev->dev, "problem initializing queue\n");
-+ goto out_error_irq_alloc;
-+ }
-+ status = start_queue(drv_data);
-+ if (status != 0) {
-+ dev_err(&pdev->dev, "problem starting queue\n");
-+ goto out_error_irq_alloc;
-+ }
-+
-+ /* 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");
-+ status = -EINVAL;
-+ goto out_error_queue_alloc;
-+ }
-+
-+#if defined(SPI_DSPI_EDMA)
-+ if (request_edma_channel(DSPI_DMA_TX_TCD,
-+ edma_tx_handler,
-+ NULL,
-+ pdev,
-+ NULL, /* spinlock */
-+ DRIVER_NAME
-+ )!=0)
-+ {
-+ dev_err(&pdev->dev, "problem requesting edma transmit channel\n");
-+ status = -EINVAL;
-+ goto out_error_queue_alloc;
-+ }
-+
-+ if (request_edma_channel(DSPI_DMA_RX_TCD,
-+ edma_rx_handler,
-+ NULL,
-+ pdev,
-+ NULL, /* spinlock */
-+ DRIVER_NAME
-+ )!=0)
-+ {
-+ dev_err(&pdev->dev, "problem requesting edma receive channel\n");
-+ status = -EINVAL;
-+ goto out_edma_transmit;
-+ }
-+#endif
-+
-+ printk( "SPI: Coldfire master initialized\n" );
-+ //dev_info(&pdev->dev, "driver initialized\n");
-+ return status;
-+
-+#if defined(SPI_DSPI_EDMA)
-+out_edma_transmit:
-+ free_edma_channel(DSPI_DMA_TX_TCD, pdev);
-+#endif
-+
-+out_error_queue_alloc:
-+ destroy_queue(drv_data);
-+
-+out_error_irq_alloc:
-+ free_irq(irq, drv_data);
-+
-+out_error_master_alloc:
-+ spi_master_put(master);
-+ return status;
-+
-+}
-+
-+static int coldfire_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;
-+
-+#if defined(SPI_DSPI_EDMA)
-+ free_edma_channel(DSPI_DMA_TX_TCD, pdev);
-+ free_edma_channel(DSPI_DMA_RX_TCD, pdev);
-+#endif
-+
-+ /* 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 coldfire_spi_shutdown(struct platform_device *pdev)
-+{
-+ int status = 0;
-+
-+ if ((status = coldfire_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 coldfire_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 coldfire_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 coldfire_spi_suspend NULL
-+#define coldfire_spi_resume NULL
-+#endif /* CONFIG_PM */
-+
-+static struct platform_driver driver = {
-+ .driver = {
-+ .name = "spi_coldfire",
-+ .bus = &platform_bus_type,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = coldfire_spi_probe,
-+ .remove = __devexit_p(coldfire_spi_remove),
-+ .shutdown = coldfire_spi_shutdown,
-+ .suspend = coldfire_spi_suspend,
-+ .resume = coldfire_spi_resume,
-+};
-+
-+static int __init coldfire_spi_init(void)
-+{
-+ platform_driver_register(&driver);
-+
-+ return 0;
-+}
-+module_init(coldfire_spi_init);
-+
-+static void __exit coldfire_spi_exit(void)
-+{
-+ platform_driver_unregister(&driver);
-+}
-+module_exit(coldfire_spi_exit);
---- /dev/null
-+++ b/drivers/spi/ssi_audio.c
-@@ -0,0 +1,906 @@
-+/*
-+ * MCF5445x audio driver.
-+ *
-+ * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
-+ * Copyright Freescale Semiconductor, Inc. 2006
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/spi/spi.h>
-+#include <linux/fs.h>
-+#include <linux/kernel.h>
-+#include <linux/major.h>
-+#include <asm/mcfsim.h>
-+#include <linux/interrupt.h>
-+#include <linux/soundcard.h>
-+#include <asm/uaccess.h>
-+#include <asm/virtconvert.h>
-+
-+#include <asm/coldfire.h>
-+#include <asm/coldfire_edma.h>
-+#include <asm/mcf5445x_ssi.h>
-+#include <asm/mcf5445x_ccm.h>
-+#include <asm/mcf5445x_gpio.h>
-+
-+#define SOUND_DEVICE_NAME "sound"
-+#define DRIVER_NAME "ssi_audio"
-+
-+
-+/* #define AUDIO_DEBUG */
-+
-+#ifdef CONFIG_MMU
-+#define USE_MMU
-+#endif
-+
-+#define MAX_SPEED_HZ 12000000
-+
-+#define M5445x_AUDIO_IRQ_SOURCE 49
-+#define M5445x_AUDIO_IRQ_VECTOR (128+M5445x_AUDIO_IRQ_SOURCE)
-+#define M5445x_AUDIO_IRQ_LEVEL 5
-+
-+/* TLV320DAC23 audio chip registers */
-+
-+#define CODEC_LEFT_IN_REG (0x00)
-+#define CODEC_RIGHT_IN_REG (0x01)
-+#define CODEC_LEFT_HP_VOL_REG (0x02)
-+#define CODEC_RIGHT_HP_VOL_REG (0x03)
-+#define CODEC_ANALOG_APATH_REG (0x04)
-+#define CODEC_DIGITAL_APATH_REG (0x05)
-+#define CODEC_POWER_DOWN_REG (0x06)
-+#define CODEC_DIGITAL_IF_FMT_REG (0x07)
-+#define CODEC_SAMPLE_RATE_REG (0x08)
-+#define CODEC_DIGITAL_IF_ACT_REG (0x09)
-+#define CODEC_RESET_REG (0x0f)
-+
-+#define CODEC_SAMPLE_8KHZ (0x0C)
-+#define CODEC_SAMPLE_16KHZ (0x58)
-+#define CODEC_SAMPLE_22KHZ (0x62)
-+#define CODEC_SAMPLE_32KHZ (0x18)
-+#define CODEC_SAMPLE_44KHZ (0x22)
-+#define CODEC_SAMPLE_48KHZ (0x00)
-+
-+/* Audio buffer data size */
-+#define BUFSIZE (64*1024)
-+/* DMA transfer size */
-+#define DMASIZE (16*1024)
-+
-+/* transmit eDMA channel for SSI channel 0 */
-+#define DMA_TCD 10
-+/* transmit eDMA channel for SSI channel 1 */
-+#define DMA_TCD2 11
-+
-+struct ssi_audio {
-+ struct spi_device *spi;
-+ u32 speed;
-+ u32 stereo;
-+ u32 bits;
-+ u32 format;
-+ u8 isopen;
-+ u8 dmaing;
-+ u8 ssi_enabled;
-+ u8 channel;
-+ spinlock_t lock;
-+ u8* audio_buf;
-+};
-+
-+static struct ssi_audio* audio_device = NULL;
-+volatile u32 audio_start;
-+volatile u32 audio_count;
-+volatile u32 audio_append;
-+volatile u32 audio_appstart;
-+volatile u32 audio_txbusy;
-+
-+struct ssi_audio_format {
-+ unsigned int format;
-+ unsigned int bits;
-+} ssi_audio_formattable[] = {
-+ { AFMT_MU_LAW, 8 },
-+ { AFMT_A_LAW, 8 },
-+ { AFMT_IMA_ADPCM, 8 },
-+ { AFMT_U8, 8 },
-+ { AFMT_S16_LE, 16 },
-+ { AFMT_S16_BE, 16 },
-+ { AFMT_S8, 8 },
-+ { AFMT_U16_LE, 16 },
-+ { AFMT_U16_BE, 16 },
-+};
-+
-+#define FORMATSIZE (sizeof(ssi_audio_formattable) / sizeof(struct ssi_audio_format))
-+
-+static void ssi_audio_setsamplesize(int val)
-+{
-+ int i;
-+
-+ if (audio_device == NULL) return;
-+
-+ for (i = 0; (i < FORMATSIZE); i++) {
-+ if (ssi_audio_formattable[i].format == val) {
-+ audio_device->format = ssi_audio_formattable[i].format;
-+ audio_device->bits = ssi_audio_formattable[i].bits;
-+ break;
-+ }
-+ }
-+
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_setsamplesize %d %d\n", audio_device->format, audio_device->bits);
-+#endif
-+}
-+
-+static void ssi_audio_txdrain(void)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_txdrain()\n");
-+#endif
-+
-+ if (audio_device == NULL) return;
-+
-+ while (!signal_pending(current)) {
-+ if (audio_txbusy == 0)
-+ break;
-+ current->state = TASK_INTERRUPTIBLE;
-+ schedule_timeout(1);
-+ }
-+}
-+
-+#ifdef CONFIG_SSIAUDIO_USE_EDMA
-+/*
-+ * Configure and start DMA engine.
-+ */
-+void __inline__ ssi_audio_dmarun(void)
-+{
-+ set_edma_params(DMA_TCD,
-+#ifdef USE_MMU
-+ virt_to_phys(&(audio_device->audio_buf[audio_start])),
-+#else
-+ (u32)&(audio_device->audio_buf[audio_start]),
-+#endif
-+ (u32)&MCF_SSI_TX0,
-+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
-+ 8,
-+ 4,
-+ 0,
-+ audio_count/8,
-+ audio_count/8,
-+ 0,
-+ 0,
-+ 0, // major_int
-+ 0 // disable_req
-+ );
-+
-+ set_edma_params(DMA_TCD2,
-+#ifdef USE_MMU
-+ virt_to_phys(&(audio_device->audio_buf[audio_start+4])),
-+#else
-+ (u32)&(audio_device->audio_buf[audio_start+4]),
-+#endif
-+ (u32)&MCF_SSI_TX1,
-+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
-+ 8,
-+ 4,
-+ 0,
-+ audio_count/8,
-+ audio_count/8,
-+ 0,
-+ 0,
-+ 1, // major_int
-+ 0 // disable_req
-+ );
-+
-+ audio_device->dmaing = 1;
-+ audio_txbusy = 1;
-+
-+ start_edma_transfer(DMA_TCD);
-+ start_edma_transfer(DMA_TCD2);
-+#if 0
-+ MCF_EDMA_ERQ |= (1<<DMA_TCD) | (1<<DMA_TCD2);
-+ MCF_EDMA_SSRT = DMA_TCD;
-+ MCF_EDMA_SSRT = DMA_TCD2;
-+#endif
-+
-+}
-+
-+/*
-+ * Start DMA'ing a new buffer of data if any available.
-+ */
-+static void ssi_audio_dmabuf(void)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_dmabuf(): append=%x start=%x\n", audio_append, audio_appstart);
-+#endif
-+
-+ /* If already running then nothing to do... */
-+ if (audio_device->dmaing)
-+ return;
-+
-+ /* Set DMA buffer size */
-+ audio_count = (audio_append >= audio_appstart) ?
-+ (audio_append - audio_appstart) :
-+ (BUFSIZE - audio_appstart);
-+ if (audio_count > DMASIZE)
-+ audio_count = DMASIZE;
-+
-+ /* Adjust pointers and counters accordingly */
-+ audio_appstart += audio_count;
-+ if (audio_appstart >= BUFSIZE)
-+ audio_appstart = 0;
-+
-+ if (audio_count > 0)
-+ ssi_audio_dmarun();
-+ else {
-+ audio_txbusy = 0;
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":DMA buffer is empty!\n");
-+#endif
-+ }
-+}
-+
-+void __inline__ stop_dma(void) {
-+ stop_edma_transfer(DMA_TCD);
-+ stop_edma_transfer(DMA_TCD2);
-+}
-+
-+static int ssi_audio_dma_handler_empty(int channel, void *dev_id)
-+{
-+ return IRQ_HANDLED;
-+}
-+
-+static int ssi_audio_dma_handler(int channel, void *dev_id)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_dma_handler(channel=%d)\n", channel);
-+#endif
-+
-+ /* Clear DMA interrupt */
-+ stop_dma();
-+
-+ audio_device->dmaing = 0;
-+
-+ /* Update data pointers and counts */
-+ audio_start += audio_count;
-+ if (audio_start >= BUFSIZE)
-+ audio_start = 0;
-+ audio_count = 0;
-+
-+ /* Start new DMA buffer if we can */
-+ ssi_audio_dmabuf();
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void init_dma(void)
-+{
-+ /* SSI DMA Signals mapped to DMA request */
-+ MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_TIMDMA;
-+ init_edma();
-+}
-+
-+#endif /* CONFIG_SSIAUDIO_USE_EDMA */
-+
-+
-+/* Write CODEC register using SPI
-+ * address - CODEC register address
-+ * data - data to be written into register
-+ */
-+static int codec_write(u8 addr, u16 data)
-+{
-+ u16 spi_word;
-+
-+ if (audio_device==NULL || audio_device->spi==NULL)
-+ return -ENODEV;
-+
-+ spi_word = ((addr & 0x7F)<<9)|(data & 0x1FF);
-+ return spi_write(audio_device->spi, (const u8*)&spi_word, sizeof(spi_word));
-+}
-+
-+static inline void enable_ssi(void)
-+{
-+ if (audio_device==NULL || audio_device->ssi_enabled) return;
-+ audio_device->ssi_enabled = 1;
-+ MCF_SSI_CR |= MCF_SSI_CR_SSI_EN; /* enable SSI module */
-+ MCF_SSI_CR |= MCF_SSI_CR_TE; /* enable tranmitter */
-+}
-+
-+static inline void disable_ssi(void)
-+{
-+ if (audio_device==NULL || audio_device->ssi_enabled==0) return;
-+ MCF_SSI_CR &= ~MCF_SSI_CR_TE; /* disable transmitter */
-+ MCF_SSI_CR &= ~MCF_SSI_CR_SSI_EN; /* disable SSI module */
-+ audio_device->ssi_enabled = 0;
-+}
-+
-+/* Audio CODEC initialization */
-+/* TODO: also the SSI frequency/dividers must be adjusted */
-+static void adjust_codec_speed(void) {
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":adjust_codec_speed: %d\n", audio_device->speed);
-+#endif
-+
-+ if (audio_device->speed == 8000) {
-+ codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_8KHZ);
-+ } else if (audio_device->speed == 16000) {
-+ codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_16KHZ);
-+ } else if (audio_device->speed == 22000) {
-+ codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_22KHZ);
-+ } else if (audio_device->speed == 44000 || audio_device->speed == 44100) {
-+ codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_44KHZ);
-+ } else if (audio_device->speed == 48000) {
-+ codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_48KHZ);
-+ } else {
-+ /* default 44KHz */
-+ codec_write(CODEC_SAMPLE_RATE_REG,CODEC_SAMPLE_44KHZ);
-+ }
-+}
-+
-+static void codec_reset(void)
-+{
-+ codec_write(CODEC_RESET_REG, 0); /* reset the audio chip */
-+ udelay(1500); /* wait for reset */
-+}
-+
-+static void init_audio_codec(void)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":init_audio_codec()\n");
-+#endif
-+ codec_reset();
-+
-+ codec_write(CODEC_LEFT_IN_REG, 0x017);
-+ codec_write(CODEC_RIGHT_IN_REG, 0x017);
-+ codec_write(CODEC_POWER_DOWN_REG, 0x000); /* Turn off line input */
-+ codec_write(CODEC_DIGITAL_IF_FMT_REG, 0x00A); /* I2S slave mode */
-+ /* codec_write(CODEC_DIGITAL_IF_FMT_REG, 0x042); // I2S master mode */
-+ codec_write(CODEC_DIGITAL_APATH_REG, 0x007); /* Set A path */
-+
-+ /* set sample rate */
-+ adjust_codec_speed();
-+
-+ codec_write(CODEC_LEFT_HP_VOL_REG, 0x075); /* set volume */
-+ codec_write(CODEC_RIGHT_HP_VOL_REG, 0x075); /* set volume */
-+ codec_write(CODEC_DIGITAL_IF_ACT_REG, 1); /* Activate digital interface */
-+ codec_write(CODEC_ANALOG_APATH_REG, 0x0F2);
-+}
-+
-+
-+static void chip_init(void)
-+{
-+#ifdef CONFIG_SSIAUDIO_USE_EDMA
-+ init_dma();
-+#endif
-+
-+ /* Enable the SSI pins */
-+ MCF_GPIO_PAR_SSI = ( 0
-+ | MCF_GPIO_PAR_SSI_MCLK
-+ | MCF_GPIO_PAR_SSI_STXD(3)
-+ | MCF_GPIO_PAR_SSI_SRXD(3)
-+ | MCF_GPIO_PAR_SSI_FS(3)
-+ | MCF_GPIO_PAR_SSI_BCLK(3) );
-+
-+}
-+
-+static void init_ssi(void)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":init_ssi()\n");
-+#endif
-+
-+ /* Dividers are for MCF54445 on 266Mhz, the output is 44.1Khz*/
-+ /* Enable SSI clock in CCM */
-+ MCF_CCM_CDR = MCF_CCM_CDR_SSIDIV(47);
-+
-+ /* Issue a SSI reset */
-+ MCF_SSI_CR &= ~MCF_SSI_CR_SSI_EN; /* disable SSI module */
-+
-+ /* SSI module uses internal CPU clock */
-+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSISRC;
-+
-+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSIPUE;
-+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSIPUS_UP;
-+
-+ MCF_SSI_CR = 0
-+ | MCF_SSI_CR_CIS
-+ | MCF_SSI_CR_TCH /* Enable two channel mode */
-+ | MCF_SSI_CR_MCE /* Set clock out on SSI_MCLK pin */
-+ | MCF_SSI_CR_I2S_MASTER /* Set I2S master mode */
-+ | MCF_SSI_CR_SYN /* Enable synchronous mode */
-+ | MCF_SSI_CR_NET
-+ ;
-+
-+ MCF_SSI_TCR = 0
-+ | MCF_SSI_TCR_TXDIR /* internally generated bit clock */
-+ | MCF_SSI_TCR_TFDIR /* internally generated frame sync */
-+ | MCF_SSI_TCR_TSCKP /* Clock data on falling edge of bit clock */
-+ | MCF_SSI_TCR_TFSI /* Frame sync active low */
-+ | MCF_SSI_TCR_TEFS /* TX frame sync 1 bit before data */
-+ | MCF_SSI_TCR_TFEN0 /* TX FIFO 0 enabled */
-+ | MCF_SSI_TCR_TFEN1 /* TX FIFO 1 enabled */
-+ | MCF_SSI_TCR_TXBIT0
-+ ;
-+
-+ MCF_SSI_CCR = MCF_SSI_CCR_WL(7) /* 16 bit word length */
-+ | MCF_SSI_CCR_DC(1) /* Frame rate divider */
-+ | MCF_SSI_CCR_PM(0)
-+ | MCF_SSI_CCR_DIV2
-+ ;
-+
-+ MCF_SSI_FCSR = 0
-+ | MCF_SSI_FCSR_TFWM0(0)
-+ | MCF_SSI_FCSR_TFWM1(0)
-+ ;
-+
-+ MCF_SSI_IER = 0 // interrupts
-+#ifndef CONFIG_SSIAUDIO_USE_EDMA
-+ | MCF_SSI_IER_TIE /* transmit interrupts */
-+ | MCF_SSI_IER_TFE0 /* transmit FIFO 0 empty */
-+ | MCF_SSI_IER_TFE1 /* transmit FIFO 1 empty */
-+#else
-+ | MCF_SSI_IER_TDMAE /* DMA request enabled */
-+ | MCF_SSI_IER_TFE0 /* transmit FIFO 0 empty */
-+ | MCF_SSI_IER_TFE1 /* transmit FIFO 1 empty */
-+#endif
-+ ;
-+
-+#ifndef CONFIG_SSIAUDIO_USE_EDMA
-+ /* enable IRQ: SSI interrupt */
-+ MCF_INTC1_ICR(M5445x_AUDIO_IRQ_SOURCE) = M5445x_AUDIO_IRQ_LEVEL;
-+ MCF_INTC1_CIMR = M5445x_AUDIO_IRQ_SOURCE;
-+#endif
-+}
-+
-+#ifndef CONFIG_SSIAUDIO_USE_EDMA
-+/* interrupt for SSI */
-+static int ssi_audio_isr(int irq, void *dev_id)
-+{
-+ unsigned long *bp;
-+
-+ if (audio_txbusy==0) {
-+ return IRQ_HANDLED;
-+ }
-+
-+ spin_lock(&(audio_device->lock));
-+
-+ if (audio_start == audio_append) {
-+ disable_ssi();
-+ audio_txbusy = 0;
-+ } else {
-+ if (MCF_SSI_ISR & (MCF_SSI_ISR_TFE0|MCF_SSI_ISR_TFE1)) {
-+ bp = (unsigned long *) &audio_device->audio_buf[audio_start];
-+ if (audio_device->channel) {
-+ MCF_SSI_TX1 = *bp;
-+ audio_device->channel = 0;
-+ } else {
-+ MCF_SSI_TX0 = *bp;
-+ audio_device->channel = 1;
-+ }
-+ audio_start += 4;
-+ if (audio_start >= BUFSIZE)
-+ audio_start = 0;
-+ }
-+ }
-+
-+ spin_unlock(&(audio_device->lock));
-+
-+ return IRQ_HANDLED;
-+}
-+#endif
-+
-+/* Set initial driver playback defaults. */
-+static void init_driver_variables(void)
-+{
-+ audio_device->speed = 44100;
-+ audio_device->format = AFMT_S16_LE;
-+ audio_device->bits = 16;
-+ audio_device->stereo = 1;
-+ audio_device->ssi_enabled = 0;
-+
-+ audio_start = 0;
-+ audio_count = 0;
-+ audio_append = 0;
-+ audio_appstart = 0;
-+ audio_txbusy = 0;
-+ audio_device->dmaing = 0;
-+}
-+
-+/* open audio device */
-+static int ssi_audio_open(struct inode *inode, struct file *filp)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_open()\n");
-+#endif
-+
-+ if (audio_device==NULL) return (-ENODEV);
-+
-+ if (audio_device->isopen)
-+ return(-EBUSY);
-+
-+ spin_lock(&(audio_device->lock));
-+
-+ audio_device->isopen = 1;
-+
-+ init_driver_variables();
-+ init_ssi();
-+ init_audio_codec();
-+
-+ spin_unlock(&(audio_device->lock));
-+
-+ udelay(100);
-+
-+ return 0;
-+}
-+
-+/* close audio device */
-+static int ssi_audio_close(struct inode *inode, struct file *filp)
-+{
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_close()\n");
-+#endif
-+
-+ if (audio_device==NULL) return (-ENODEV);
-+
-+ ssi_audio_txdrain();
-+
-+ spin_lock(&(audio_device->lock));
-+
-+#ifdef CONFIG_SSIAUDIO_USE_EDMA
-+ stop_dma();
-+#endif
-+ disable_ssi();
-+ codec_reset();
-+ init_driver_variables();
-+ audio_device->isopen = 0;
-+
-+ spin_unlock(&(audio_device->lock));
-+ return 0;
-+}
-+
-+/* write to audio device */
-+static ssize_t ssi_audio_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
-+{
-+ unsigned long *dp, *buflp;
-+ unsigned short *bufwp;
-+ unsigned char *bufbp;
-+ unsigned int slen, bufcnt, i, s, e;
-+
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_write(buf=%x,count=%d)\n", (int) buf, count);
-+#endif
-+
-+ if (audio_device==NULL) return (-ENODEV);
-+
-+ if (count <= 0)
-+ return 0;
-+
-+ spin_lock(&(audio_device->lock));
-+
-+ buflp = (unsigned long *) buf;
-+ bufwp = (unsigned short *) buf;
-+ bufbp = (unsigned char *) buf;
-+
-+ bufcnt = count & ~0x3;
-+
-+ bufcnt <<= 1;
-+ if (audio_device->stereo == 0)
-+ bufcnt <<= 1;
-+ if (audio_device->bits == 8)
-+ bufcnt <<= 1;
-+
-+tryagain:
-+ /*
-+ * Get a snapshot of buffer, so we can figure out how
-+ * much data we can fit in...
-+ */
-+ s = audio_start;
-+ e = audio_append;
-+ dp = (unsigned long *) &(audio_device->audio_buf[e]);
-+
-+ slen = ((s > e) ? (s - e) : (BUFSIZE - (e - s))) - 4;
-+ if (slen > bufcnt)
-+ slen = bufcnt;
-+ if ((BUFSIZE - e) < slen)
-+ slen = BUFSIZE - e;
-+
-+ if (slen == 0) {
-+ if (signal_pending(current))
-+ return(-ERESTARTSYS);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(1);
-+ goto tryagain;
-+ }
-+
-+ /* For DMA we need to have data as 32 bit
-+ values (since SSI TX register is 32 bit).
-+ So, the incomming 16 bit data must be put to buffer as 32 bit values.
-+ Also, the endianess is converted if needed
-+ */
-+ if (audio_device->stereo) {
-+ if (audio_device->bits == 16) {
-+ if (audio_device->format==AFMT_S16_LE) {
-+ /*- convert endianess, probably could be done by SSI also */
-+ for (i = 0; (i < slen); i += 4) {
-+ unsigned short val = le16_to_cpu((*bufwp++));
-+ *dp++ = val;
-+ }
-+ } else {
-+ for (i = 0; (i < slen); i += 4) {
-+ *dp++ = *bufwp++;
-+ }
-+ }
-+ } else {
-+ for (i = 0; (i < slen); i += 4) {
-+ *dp = (((unsigned long) *bufbp++) << 24);
-+ *dp++ |= (((unsigned long) *bufbp++) << 8);
-+ }
-+ }
-+ } else {
-+ if (audio_device->bits == 16) {
-+ for (i = 0; (i < slen); i += 4) {
-+ *dp++ = (((unsigned long)*bufwp)<<16) | *bufwp;
-+ bufwp++;
-+ }
-+ } else {
-+ for (i = 0; (i < slen); i += 4) {
-+ *dp++ = (((unsigned long) *bufbp) << 24) |
-+ (((unsigned long) *bufbp) << 8);
-+ bufbp++;
-+ }
-+ }
-+ }
-+
-+ e += slen;
-+ if (e >= BUFSIZE)
-+ e = 0;
-+ audio_append = e;
-+
-+ /* If not outputing audio, then start now */
-+ if (audio_txbusy == 0) {
-+ audio_txbusy++;
-+ audio_device->channel = 0;
-+ enable_ssi();
-+#ifdef CONFIG_SSIAUDIO_USE_EDMA
-+ ssi_audio_dmabuf(); /* start first DMA transfer */
-+#endif
-+ }
-+
-+ bufcnt -= slen;
-+
-+ if (bufcnt > 0)
-+ goto tryagain;
-+
-+ spin_unlock(&(audio_device->lock));
-+
-+ return count;
-+}
-+
-+/* ioctl: control the driver */
-+static int ssi_audio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-+{
-+ long val;
-+ int rc = 0;
-+
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_ioctl(cmd=%x,arg=%x)\n", (int) cmd, (int) arg);
-+#endif
-+
-+ if (audio_device==NULL) return (-ENODEV);
-+
-+ switch (cmd) {
-+
-+ case SNDCTL_DSP_SPEED:
-+ if (access_ok(VERIFY_READ, (void *) arg, sizeof(val))) {
-+ get_user(val, (unsigned long *) arg);
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME ":ssi_audio_ioctl: SNDCTL_DSP_SPEED: %ld\n", val);
-+#endif
-+ ssi_audio_txdrain();
-+ audio_device->speed = val;
-+ init_audio_codec();
-+ } else {
-+ rc = -EINVAL;
-+ }
-+ break;
-+
-+ case SNDCTL_DSP_SAMPLESIZE:
-+ if (access_ok(VERIFY_READ, (void *) arg, sizeof(val))) {
-+ get_user(val, (unsigned long *) arg);
-+ ssi_audio_txdrain();
-+ ssi_audio_setsamplesize(val);
-+ } else {
-+ rc = -EINVAL;
-+ }
-+ break;
-+
-+ case SNDCTL_DSP_STEREO:
-+ if (access_ok(VERIFY_READ, (void *) arg, sizeof(val))) {
-+ get_user(val, (unsigned long *) arg);
-+ ssi_audio_txdrain();
-+ audio_device->stereo = val;
-+ } else {
-+ rc = -EINVAL;
-+ }
-+ break;
-+
-+ case SNDCTL_DSP_GETBLKSIZE:
-+ if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(long)))
-+ put_user(BUFSIZE, (long *) arg);
-+ else
-+ rc = -EINVAL;
-+ break;
-+
-+ case SNDCTL_DSP_SYNC:
-+ ssi_audio_txdrain();
-+ break;
-+
-+ default:
-+ rc = -EINVAL;
-+ break;
-+ }
-+
-+ return rc;
-+}
-+
-+/****************************************************************************/
-+
-+struct file_operations ssi_audio_fops = {
-+ open: ssi_audio_open, /* open */
-+ release: ssi_audio_close, /* close */
-+ write: ssi_audio_write, /* write */
-+ ioctl: ssi_audio_ioctl, /* ioctl */
-+};
-+
-+/* initialize audio driver */
-+static int __devinit ssi_audio_probe(struct spi_device *spi)
-+{
-+ struct ssi_audio *audio;
-+ int err;
-+
-+#ifdef AUDIO_DEBUG
-+ printk(DRIVER_NAME": probe\n");
-+#endif
-+
-+ if (!spi->irq) {
-+ dev_dbg(&spi->dev, "no IRQ?\n");
-+ return -ENODEV;
-+ }
-+
-+ /* don't exceed max specified sample rate */
-+ if (spi->max_speed_hz > MAX_SPEED_HZ) {
-+ dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
-+ (spi->max_speed_hz)/1000);
-+ return -EINVAL;
-+ }
-+
-+ /* register charcter device */
-+ if (register_chrdev(SOUND_MAJOR, SOUND_DEVICE_NAME, &ssi_audio_fops) < 0) {
-+ printk(KERN_WARNING DRIVER_NAME ": failed to register major %d\n", SOUND_MAJOR);
-+ dev_dbg(&spi->dev, DRIVER_NAME ": failed to register major %d\n", SOUND_MAJOR);
-+ return -ENODEV;
-+ }
-+
-+ audio = kzalloc(sizeof(struct ssi_audio), GFP_KERNEL);
-+ if (!audio) {
-+ err = -ENOMEM;
-+ goto err_out;
-+ }
-+
-+ /* DMA buffer must be from GFP_DMA zone, so it will not be cached */
-+ audio->audio_buf = kmalloc(BUFSIZE, GFP_DMA);
-+ if (audio->audio_buf == NULL) {
-+ dev_dbg(&spi->dev, DRIVER_NAME ": failed to allocate DMA[%d] buffer\n", BUFSIZE);
-+ err = -ENOMEM;
-+ goto err_free_mem;
-+ }
-+
-+ audio_device = audio;
-+
-+ dev_set_drvdata(&spi->dev, audio);
-+ spi->dev.power.power_state = PMSG_ON;
-+
-+ audio->spi = spi;
-+
-+#ifndef CONFIG_SSIAUDIO_USE_EDMA
-+ if (request_irq(spi->irq, ssi_audio_isr, SA_INTERRUPT, spi->dev.bus_id, audio)) {
-+ dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
-+ err = -EBUSY;
-+ goto err_free_mem;
-+ }
-+
-+#else
-+ /* request 2 eDMA channels since two channel output mode is used */
-+ if (request_edma_channel(DMA_TCD,
-+ ssi_audio_dma_handler_empty,
-+ NULL,
-+ audio,
-+ &(audio_device->lock),
-+ DRIVER_NAME
-+ )!=0)
-+ {
-+ dev_dbg(&spi->dev, "DMA channel %d busy?\n", DMA_TCD);
-+ err = -EBUSY;
-+ goto err_free_mem;
-+ }
-+ if (request_edma_channel(DMA_TCD2,
-+ ssi_audio_dma_handler,
-+ NULL,
-+ audio,
-+ &(audio_device->lock),
-+ DRIVER_NAME
-+ )!=0)
-+ {
-+ dev_dbg(&spi->dev, "DMA channel %d busy?\n", DMA_TCD2);
-+ err = -EBUSY;
-+ goto err_free_mem;
-+ }
-+
-+#endif
-+ chip_init();
-+ printk(DRIVER_NAME ": Probed successfully\n");
-+
-+ return 0;
-+
-+ err_free_mem:
-+ kfree(audio);
-+ audio_device = NULL;
-+ err_out:
-+ unregister_chrdev(SOUND_MAJOR, SOUND_DEVICE_NAME);
-+ return err;
-+}
-+
-+static int __devexit ssi_audio_remove(struct spi_device *spi)
-+{
-+ struct ssi_audio *audio = dev_get_drvdata(&spi->dev);
-+
-+ ssi_audio_txdrain();
-+#ifndef CONFIG_SSIAUDIO_USE_EDMA
-+ free_irq(spi->irq, audio);
-+#else
-+ free_edma_channel(DMA_TCD, audio);
-+ free_edma_channel(DMA_TCD2, audio);
-+#endif
-+ kfree(audio->audio_buf);
-+ kfree(audio);
-+ audio_device = NULL;
-+ unregister_chrdev(SOUND_MAJOR, SOUND_DEVICE_NAME);
-+ dev_dbg(&spi->dev, "unregistered audio\n");
-+ return 0;
-+}
-+
-+static int ssi_audio_suspend(struct spi_device *spi, pm_message_t message) {
-+ return 0;
-+}
-+
-+static int ssi_audio_resume(struct spi_device *spi) {
-+ return 0;
-+}
-+
-+static struct spi_driver ssi_audio_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .bus = &spi_bus_type,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = ssi_audio_probe,
-+ .remove = __devexit_p(ssi_audio_remove),
-+ .suspend = ssi_audio_suspend,
-+ .resume = ssi_audio_resume,
-+};
-+
-+static int __init ssi_audio_init(void)
-+{
-+ return spi_register_driver(&ssi_audio_driver);
-+}
-+module_init(ssi_audio_init);
-+
-+static void __exit ssi_audio_exit(void)
-+{
-+ spi_unregister_driver(&ssi_audio_driver);
-+}
-+module_exit(ssi_audio_exit);
-+
-+MODULE_DESCRIPTION("SSI/I2S Audio Driver");
-+MODULE_LICENSE("GPL");
---- a/include/asm-m68k/coldfire_edma.h
-+++ b/include/asm-m68k/coldfire_edma.h
-@@ -1,39 +1,102 @@
-+/*
-+ * coldfire_edma.h - eDMA driver for Coldfire MCF5445x
-+ *
-+ * Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
-+ *
-+ * Copyright Freescale Semiconductor, Inc. 2007
-+ *
-+ * 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.
-+ */
-+
- #ifndef _LINUX_COLDFIRE_DMA_H
- #define _LINUX_COLDFIRE_DMA_H
-
- #include <linux/interrupt.h>
-+#include <asm/mcf5445x_edma.h>
-
--#define EDMA_DRIVER_NAME "ColdFire-eDMA"
--#define DMA_DEV_MINOR 1
-+#define EDMA_DRIVER_NAME "ColdFire-eDMA"
-+#define DMA_DEV_MINOR 1
-
- #define EDMA_INT_CHANNEL_BASE 8
- #define EDMA_INT_CONTROLLER_BASE 64
- #define EDMA_CHANNELS 16
--
-+
- #define EDMA_IRQ_LEVEL 5
--
-+
- typedef irqreturn_t (*edma_irq_handler)(int, void *);
- typedef void (*edma_error_handler)(int, void *);
--
-+
-+/* Setup transfer control descriptor (TCD)
-+ * channel - descriptor number
-+ * source - source address
-+ * dest - destination address
-+ * attr - attributes
-+ * soff - source offset
-+ * nbytes - number of bytes to be transfered in minor loop
-+ * slast - last source address adjustment
-+ * citer - major loop count
-+ * biter - beggining minor loop count
-+ * doff - destination offset
-+ * dlast_sga - last destination address adjustment
-+ * major_int - generate interrupt after each major loop
-+ * disable_req - disable DMA request after major loop
-+ */
- void set_edma_params(int channel, u32 source, u32 dest,
-- u32 attr, u32 soff, u32 nbytes, u32 slast,
-- u32 citer, u32 biter, u32 doff, u32 dlast_sga);
--
--void start_edma_transfer(int channel, int major_int);
--
--void stop_edma_transfer(int channel);
--
--void confirm_edma_interrupt_handled(int channel);
--
-+ u32 attr, u32 soff, u32 nbytes, u32 slast,
-+ u32 citer, u32 biter, u32 doff, u32 dlast_sga,
-+ int major_int, int disable_req);
-+
-+/* Starts eDMA transfer on specified channel
-+ * channel - eDMA TCD number
-+ */
-+static inline void start_edma_transfer(int channel)
-+{
-+ MCF_EDMA_SERQ = channel;
-+ MCF_EDMA_SSRT = channel;
-+}
-+
-+/* Stops eDMA transfer
-+ * channel - eDMA TCD number
-+ */
-+static inline void stop_edma_transfer(int channel)
-+{
-+ MCF_EDMA_CINT = channel;
-+ MCF_EDMA_CERQ = channel;
-+}
-+
-+
-+/* Confirm that interrupt has been handled
-+ * channel - eDMA TCD number
-+ */
-+static inline void confirm_edma_interrupt_handled(int channel)
-+{
-+ MCF_EDMA_CINT = channel;
-+}
-+
-+/* Initialize eDMA controller */
- void init_edma(void);
--
--int request_edma_channel(int channel,
-- edma_irq_handler handler,
-- edma_error_handler error_handler,
-- void *dev,
-- spinlock_t *lock,
-- const char *device_id);
--
-+
-+/* Request eDMA channel:
-+ * channel - eDMA TCD number
-+ * handler - channel IRQ callback
-+ * error_handler - error interrupt handler callback for channel
-+ * dev - device
-+ * lock - spinlock to be locked (can be NULL)
-+ * device_id - device driver name for proc file system output
-+ */
-+int request_edma_channel(int channel,
-+ edma_irq_handler handler,
-+ edma_error_handler error_handler,
-+ void *dev,
-+ spinlock_t *lock,
-+ const char *device_id);
-+
-+/* Free eDMA channel
-+ * channel - eDMA TCD number
-+ * dev - device
-+ */
- int free_edma_channel(int channel, void *dev);
--
- #endif
---- /dev/null
-+++ b/include/linux/spi/mcfqspi.h
-@@ -0,0 +1,80 @@
-+/****************************************************************************/
-+
-+/*
-+ * mcfqspi.c - Master QSPI controller for the ColdFire processors
-+ *
-+ * (C) Copyright 2005, Intec Automation,
-+ * Mike Lavender (mike@steroidmicros)
-+ *
-+
-+ 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 MCFQSPI_H_
-+#define MCFQSPI_H_
-+
-+#define QSPI_CS_INIT 0x01
-+#define QSPI_CS_ASSERT 0x02
-+#define QSPI_CS_DROP 0x04
-+
-+#define QSPIIOCS_DOUT_HIZ 1 /* QMR[DOHIE] set hi-z dout between transfers */
-+#define QSPIIOCS_BITS 2 /* QMR[BITS] set transfer size */
-+#define QSPIIOCG_BITS 3 /* QMR[BITS] get transfer size */
-+#define QSPIIOCS_CPOL 4 /* QMR[CPOL] set SCK inactive state */
-+#define QSPIIOCS_CPHA 5 /* QMR[CPHA] set SCK phase, 1=rising edge */
-+#define QSPIIOCS_BAUD 6 /* QMR[BAUD] set SCK baud rate divider */
-+#define QSPIIOCS_QCD 7 /* QDLYR[QCD] set start delay */
-+#define QSPIIOCS_DTL 8 /* QDLYR[DTL] set after delay */
-+#define QSPIIOCS_CONT 9 /* continuous CS asserted during transfer */
-+#define QSPIIOCS_READDATA 10 /* set data send during read */
-+#define QSPIIOCS_ODD_MOD 11 /* if length of buffer is a odd number, 16-bit transfers */
-+ /* are finalized with a 8-bit transfer */
-+#define QSPIIOCS_DSP_MOD 12 /* transfers are bounded to 15/30 bytes (a multiple of 3 bytes = 1 DSPword) */
-+#define QSPIIOCS_POLL_MOD 13 /* driver uses polling instead of interrupts */
-+
-+#define QSPIIOCS_SET_CSIV 14 /* sets CSIV flag (cs inactive level) */
-+
-+#ifdef CONFIG_M520x
-+#undef MCF_GPIO_PAR_QSPI
-+#define MCF_GPIO_PAR_QSPI (0xA4034)
-+#endif
-+
-+struct coldfire_spi_master {
-+ u16 bus_num;
-+ u16 num_chipselect;
-+ u8 irq_source;
-+ u32 irq_vector;
-+ u32 irq_mask;
-+ u8 irq_lp;
-+ u8 par_val;
-+ u16 par_val16;
-+ void (*cs_control)(u8 cs, u8 command);
-+};
-+
-+
-+struct coldfire_spi_chip {
-+ u8 mode;
-+ u8 bits_per_word;
-+ u8 del_cs_to_clk;
-+ u8 del_after_trans;
-+ u16 void_write_data;
-+};
-+
-+typedef struct qspi_read_data {
-+ __u32 length;
-+ __u8 *buf; /* data to send during read */
-+ unsigned int loop : 1;
-+} qspi_read_data;
-+#endif /*MCFQSPI_H_*/