diff options
author | Imre Kaloz <kaloz@openwrt.org> | 2010-11-22 13:31:46 +0000 |
---|---|---|
committer | Imre Kaloz <kaloz@openwrt.org> | 2010-11-22 13:31:46 +0000 |
commit | d6ea3e24d49f94051305b5191edd10d213f92bf3 (patch) | |
tree | d92ba23cf07ca211cd6100bb144831295b2bea54 /target/linux/coldfire/patches/080-mcfv4e_dspi_update.patch | |
parent | d066a4c712aae3cd1aaa5108f7cd2cae81c6343b (diff) | |
download | master-31e0f0ae-d6ea3e24d49f94051305b5191edd10d213f92bf3.tar.gz master-31e0f0ae-d6ea3e24d49f94051305b5191edd10d213f92bf3.tar.bz2 master-31e0f0ae-d6ea3e24d49f94051305b5191edd10d213f92bf3.zip |
remove 2.6.25 support
SVN-Revision: 24088
Diffstat (limited to 'target/linux/coldfire/patches/080-mcfv4e_dspi_update.patch')
-rw-r--r-- | target/linux/coldfire/patches/080-mcfv4e_dspi_update.patch | 1378 |
1 files changed, 0 insertions, 1378 deletions
diff --git a/target/linux/coldfire/patches/080-mcfv4e_dspi_update.patch b/target/linux/coldfire/patches/080-mcfv4e_dspi_update.patch deleted file mode 100644 index a157616732..0000000000 --- a/target/linux/coldfire/patches/080-mcfv4e_dspi_update.patch +++ /dev/null @@ -1,1378 +0,0 @@ -From 771f4741de2cd8a103d96cd1e8281926448ff56d Mon Sep 17 00:00:00 2001 -From: Kurt Mahan <kmahan@freescale.com> -Date: Tue, 15 Jul 2008 11:44:08 -0600 -Subject: [PATCH] Fix DSPI driver. - -Update to latest Matt Coldfire driver. Fix timing issues with -M547x/M548x END-OF-QUEUE notification. - -LTIBName: mcfv4e-dspi-update -Signed-off-by: Kurt Mahan <kmahan@freescale.com> ---- - arch/m68k/coldfire/m547x_8x-devices.c | 35 +- - drivers/spi/Kconfig | 6 + - drivers/spi/Makefile | 2 +- - drivers/spi/dspi_mcf.c | 1217 +++++++++++++++++++++++++++++++++ - include/asm-m68k/mcfdspi.h | 48 ++ - 5 files changed, 1296 insertions(+), 12 deletions(-) - create mode 100644 drivers/spi/dspi_mcf.c - create mode 100644 include/asm-m68k/mcfdspi.h - ---- a/arch/m68k/coldfire/m547x_8x-devices.c -+++ b/arch/m68k/coldfire/m547x_8x-devices.c -@@ -26,26 +26,40 @@ - */ - - /* number of supported SPI selects */ --#define SPI_NUM_CHIPSELECTS 4 -+#define SPI_NUM_CHIPSELECTS 8 - - void coldfire_spi_cs_control(u8 cs, u8 command) - { - /* nothing special required */ - } - -+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) -+static struct coldfire_spi_chip spidev_chip_info = { -+ .bits_per_word = 8, -+}; -+#endif -+ - static struct spi_board_info spi_board_info[] = { -- /* no board info */ -+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) -+ { -+ .modalias = "spidev", -+ .max_speed_hz = 16000000, /* max clk (SCK) speed in HZ */ -+ .bus_num = 1, -+ .chip_select = 0, /* CS0 */ -+ .controller_data = &spidev_chip_info, -+ } -+#endif - }; - - static int spi_irq_list[] = { -- /* IRQ, ICR Offset, ICR Val, Mask */ -- 64 + ISC_DSPI_OVRFW, 0, 0, 0, -- 64 + ISC_DSPI_RFOF, 0, 0, 0, -- 64 + ISC_DSPI_RFDF, 0, 0, 0, -- 64 + ISC_DSPI_TFUF, 0, 0, 0, -- 64 + ISC_DSPI_TCF, 0, 0, 0, -- 64 + ISC_DSPI_TFFF, 0, 0, 0, -- 64 + ISC_DSPI_EOQF, 0, 0, 0, -+ /* IRQ, ICR Offset, ICR Val,Mask */ -+ 64 + ISC_DSPI_OVRFW, ISC_DSPI_OVRFW, 0x18, 0, -+ 64 + ISC_DSPI_RFOF, ISC_DSPI_RFOF, 0x18, 0, -+ 64 + ISC_DSPI_RFDF, ISC_DSPI_RFDF, 0x18, 0, -+ 64 + ISC_DSPI_TFUF, ISC_DSPI_TFUF, 0x18, 0, -+ 64 + ISC_DSPI_TCF, ISC_DSPI_TCF, 0x18, 0, -+ 64 + ISC_DSPI_TFFF, ISC_DSPI_TFFF, 0x18, 0, -+ 64 + ISC_DSPI_EOQF, ISC_DSPI_EOQF, 0x18, 0, - 0,0,0,0, - }; - -@@ -120,7 +134,6 @@ static int __init m547x_8x_spi_init(void - /* register device */ - retval = platform_device_register(&coldfire_spi); - if (retval < 0) { -- printk(KERN_ERR "SPI-m547x_8x: platform_device_register failed with code=%d\n", retval); - goto out; - } - ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -130,6 +130,12 @@ config SPI_COLDFIRE - Tested with the 5282 processor, but should also work with other - Coldfire variants. - -+config SPI_DSPI -+ tristate "Coldfire DSPI" -+ depends on SPI_MASTER && COLDFIRE -+ help -+ SPI driver for Coldfire DSPI driver only. -+ - config SPI_COLDFIRE_DSPI_EDMA - boolean "Coldfire DSPI master driver uses eDMA" - depends on SPI_MASTER && COLDFIRE && SPI_COLDFIRE && EXPERIMENTAL && COLDFIRE_EDMA ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -19,7 +19,7 @@ obj-$(CONFIG_SPI_BITBANG) += spi_bitban - 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_COLDFIRE) += spi_coldfire.o -+obj-$(CONFIG_SPI_DSPI) += dspi_mcf.o - obj-$(CONFIG_SPI_GPIO) += spi_gpio.o - obj-$(CONFIG_SPI_IMX) += spi_imx.o - obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o ---- /dev/null -+++ b/drivers/spi/dspi_mcf.c -@@ -0,0 +1,1217 @@ -+/* -+ * dspi_mcf.c - DSPI controller for ColdFire processors -+ * -+ * -+ * Matt Waddel Matt.Waddel@freescale.com -+ * Copyright Freescale Semiconductor, Inc. 2008 -+ * -+ * M547x/M548x changes by Kurt Mahan kmahan@freescale.com -+ * Copyright Freescale Semiconductor, Inc. 2008 -+ * -+ * Based on spi_coldfire.c done by: -+ * Andrey Butok -+ * Yaroslav Vinogradov -+ * Copyright Freescale Semiconductor, Inc. 2006-2007 -+ * Mike Lavender (mike@steroidmicros) -+ * (C) Copyright 2005, Intec Automation, -+ * -+ * 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 -+ * -+ *************************************************************************** -+ * Changes: -+ * v0.002 M547x/M548x support. -+ * v0.001 Initial version. Coldfire DSPI master driver. -+ ****************************************************************************/ -+ -+/* -+ * 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/mcfsim.h> -+#include <asm/mcfqspi.h> -+#include <asm/coldfire.h> -+#include <linux/io.h> -+#include <asm/mcfdspi.h> -+#include <linux/dma-mapping.h> -+ -+#undef DSPI_COLDFIRE_DEBUG -+ -+#ifdef DSPI_COLDFIRE_DEBUG -+#define DBG(fmt, args...) \ -+ printk(KERN_INFO "[%s] " fmt , __FUNCTION__, ## args) -+#else -+#define DBG(fmt, args...) do {} while (0) -+#endif -+ -+#if defined(CONFIG_M54455) -+#include <asm/mcf5445x_dspi.h> -+#if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA) -+ #include <asm/mcf5445x_edma.h> -+#endif -+#endif -+ -+#if defined(CONFIG_M547X_8X) -+#include <asm/virtconvert.h> -+#include <asm/m5485dspi.h> -+#endif -+ -+#if defined(CONFIG_SPI_COLDFIRE_DSPI_EDMA) -+#include <asm/mcf_edma.h> -+#define SPI_DSPI_EDMA -+#define EDMA_BUFSIZE_KMALLOC (DSPI_FIFO_SIZE*4) -+#define DSPI_DMA_RX_TCD MCF_EDMA_CHAN_DSPI_RX -+#define DSPI_DMA_TX_TCD MCF_EDMA_CHAN_DSPI_TX -+#endif -+ -+#define DSPI_BITS MCF_DSPI_DCTAR_FMSZ(0xF) -+#define DSPI_BITS_16 MCF_DSPI_DCTAR_FMSZ(0xF) -+#define DSPI_BITS_8 MCF_DSPI_DCTAR_FMSZ(0x7) -+#define DSPI_FIFO_SIZE 16 -+ -+#define DRIVER_NAME "Coldfire DSPI" -+ -+/****************************************************************************/ -+ -+/* -+ * Local constants and macros -+ */ -+ -+#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 DSPI_MCR { -+ 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; -+}; -+ -+struct DSPI_CTAR { -+ 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; -+}; -+ -+struct chip_data { -+ /* dspi data */ -+ union { -+ u32 mcr_val; -+ struct DSPI_MCR mcr; -+ }; -+ union { -+ u32 ctar_val; -+ struct DSPI_CTAR ctar; -+ }; -+ 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; /* 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; -+ 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 */ -+ -+#if defined(SPI_DSPI_EDMA) -+ void *edma_tx_buf; -+ void *edma_rx_buf; -+#endif -+ -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ u16 *par; /* Pin assignment register */ -+#else -+ u8 *par; /* Pin assignment register */ -+#endif -+ 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 -+ */ -+ -+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; -+ -+ DBG("\n"); -+ /* 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); -+ -+ if (drv_data->cur_transfer->transfer_list.next -+ == &msg->transfers) /* last transfer */ -+ drv_data->cur_transfer->cs_change = 1; -+ -+ return RUNNING_STATE; -+ } else -+ return DONE_STATE; -+} -+ -+ -+static inline int is_word_transfer(struct driver_data *drv_data) -+{ -+ return ((*(drv_data->ctar+drv_data->cs) & DSPI_BITS_16) == -+ DSPI_BITS_8) ? 0 : 1; -+} -+ -+static inline void set_8bit_transfer_mode(struct driver_data *drv_data) -+{ -+ DBG("\n"); -+ *(drv_data->ctar+drv_data->cs) = -+ (*(drv_data->ctar + drv_data->cs) & ~DSPI_BITS) | DSPI_BITS_8; -+} -+ -+static inline void set_16bit_transfer_mode(struct driver_data *drv_data) -+{ -+ DBG("\n"); -+ *(drv_data->ctar+drv_data->cs) = -+ (*(drv_data->ctar + drv_data->cs) & ~DSPI_BITS) | DSPI_BITS_16; -+} -+ -+static unsigned char hz_to_spi_baud(int pbr, int dbr, int speed_hz) -+{ -+ int pbr_tbl[4] = {2, 3, 5, 7}; /* Valid baud rate pre-scaler values */ -+ int brs[16] = { 2, 4, 6, 8, -+ 16, 32, 64, 128, -+ 256, 512, 1024, 2048, -+ 4096, 8192, 16384, 32768 }; -+ int temp, index = 0; -+ -+ if ((pbr < 0) || (pbr > 3) || -+ (dbr < 0) || (dbr > 1)) -+ return 15; /* table indexes out of range, go slow */ -+ -+ temp = ((((MCF_CLK / 2) / pbr_tbl[pbr]) * (1 + dbr)) / speed_hz); -+ -+ while (temp >= brs[index]) -+ if (index++ >= 15) -+ break; -+ -+ DBG("baud rate scaler = 0x%x - %d\n", index, brs[index]); -+ return(index); -+} -+ -+static int write(struct driver_data *drv_data) -+{ -+ int tx_count = 0; -+ int tx_word = is_word_transfer(drv_data); -+ u16 d16; -+ u8 d8; -+ u32 dspi_pushr = 0; -+ int first = 1; -+#if defined(SPI_DSPI_EDMA) -+ u32 *edma_wr = (u32 *)(drv_data->edma_tx_buf); -+#endif -+ -+ /* 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; -+ } -+ -+ while ((drv_data->tx < drv_data->tx_end) && (tx_count < DSPI_FIFO_SIZE)) { -+// DBG("while\n"); -+ 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->cs) | -+ MCF_DSPI_DTFR_CONT; -+ -+ drv_data->tx += 2; -+ } 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_CTAS(drv_data->cs) | -+ MCF_DSPI_DTFR_CONT; -+ -+ drv_data->tx++; -+ } -+ -+ if (drv_data->tx == drv_data->tx_end -+ || tx_count == DSPI_FIFO_SIZE-1) { -+ /* last transfer in the queue */ -+ dspi_pushr |= MCF_DSPI_DTFR_EOQ; -+ if ((drv_data->cs_change) -+ && (drv_data->tx == drv_data->tx_end)) -+ dspi_pushr &= ~MCF_DSPI_DTFR_CONT; -+#ifdef CONFIG_M547X_8X -+ /* EOQ gets missed if we don't delay */ -+ udelay(100); -+#endif -+ } else if (tx_word && ((drv_data->tx_end - drv_data->tx) == 1)) -+ dspi_pushr |= MCF_DSPI_DTFR_EOQ; -+ -+ 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; -+#endif -+ tx_count++; -+ } -+ -+#if defined(SPI_DSPI_EDMA) -+ if (tx_count > 0) { -+ -+ mcf_edma_set_tcd_params(DSPI_DMA_TX_TCD, -+ virt_to_phys(drv_data->edma_tx_buf), -+ (u32)drv_data->dspi_dtfr, -+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT -+ | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, -+ 4, /* soff */ -+ 4 * tx_count, /* nbytes */ -+ 0, /* slast */ -+ 1, /* citer */ -+ 1, /* biter */ -+ 0, /* doff */ -+ 0, /* dlastsga */ -+ 0, /* major_int */ -+ 1); /* disable_req */ -+ -+ mcf_edma_set_tcd_params(DSPI_DMA_RX_TCD, -+ (u32)drv_data->dspi_drfr, -+ virt_to_phys(drv_data->edma_rx_buf), -+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT -+ | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, -+ 0, /* soff */ -+ 4 * tx_count, /* nbytes */ -+ 0, /* slast */ -+ 1, /* citer */ -+ 1, /* biter */ -+ 4, /* doff */ -+ 0, /* dlastsga */ -+ 0, /* major_int */ -+ 1); /* disable_req */ -+ -+ mcf_edma_start_transfer(DSPI_DMA_TX_TCD); -+ } -+#endif -+ return (tx_count * (tx_word + 1)); -+} -+ -+static int read(struct driver_data *drv_data) -+{ -+ int rx_count = 0; -+ int rx_word = is_word_transfer(drv_data); -+ u16 d; -+#if defined(SPI_DSPI_EDMA) -+ u32 *rx_edma = (u32 *) drv_data->edma_rx_buf; -+ -+ /* receive SPI data */ -+ mcf_edma_start_transfer(DSPI_DMA_RX_TCD); -+#endif -+ while ((drv_data->rx < drv_data->rx_end) -+ && (rx_count < DSPI_FIFO_SIZE)) { -+ -+ 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++; -+ DBG("rxd=0x%x\n", d); -+ } -+ return rx_count; -+} -+ -+ -+static inline void dspi_setup_chip(struct driver_data *drv_data) -+{ -+ struct chip_data *chip = drv_data->cur_chip; -+ -+ DBG("\n"); -+ *drv_data->mcr = chip->mcr_val; -+ *(drv_data->ctar+drv_data->cs) = chip->ctar_val; -+ *drv_data->dspi_rser = MCF_DSPI_DRSER_EOQFE; -+} -+ -+#if defined(SPI_DSPI_EDMA) -+static int edma_tx_handler(int channel, void *dev) -+{ -+ DBG("\n"); -+ if (channel == DSPI_DMA_TX_TCD) -+ mcf_edma_stop_transfer(DSPI_DMA_TX_TCD); -+ return IRQ_HANDLED; -+} -+ -+static int edma_rx_handler(int channel, void *dev) -+{ -+ DBG("\n"); -+ if (channel == DSPI_DMA_RX_TCD) -+ mcf_edma_stop_transfer(DSPI_DMA_RX_TCD); -+ return IRQ_HANDLED; -+} -+#endif -+ -+static irqreturn_t dspi_interrupt(int irq, void *dev_id) -+{ -+ struct driver_data *drv_data = (struct driver_data *)dev_id; -+ struct spi_message *msg = drv_data->cur_msg; -+ -+ /* Clear all flags immediately */ -+ *drv_data->dspi_sr = MCF_DSPI_DSR_EOQF; -+ -+ if (!drv_data->cur_msg || !drv_data->cur_msg->state) { -+#if !defined(SPI_DSPI_EDMA) -+ u32 irq_status = *drv_data->dspi_sr; -+ /* if eDMA is used it happens some time (at least once)*/ -+ printk(KERN_ERR "Bad message or transfer state handler. \ -+ IRQ status = %x\n", irq_status); -+#endif -+ return IRQ_NONE; -+ } -+ -+ DBG("\n"); -+ /* -+ * 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) -+ set_16bit_transfer_mode(drv_data); -+ -+ msg->state = next_transfer(drv_data); -+ } else { -+ /* not finished yet - keep going */ -+ msg->actual_length += write(drv_data); -+ return IRQ_HANDLED; -+ } -+ -+ 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; -+ DBG("\n"); -+ -+ 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; -+ DBG("\n"); -+ /* 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) { -+ dspi_setup_chip(drv_data); -+ -+ if (drv_data->cs_control) -+ 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; -+ -+ 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; -+ if (transfer->speed_hz) { -+ *(drv_data->ctar + drv_data->cs) = \ -+ ((chip->ctar_val & ~0xF) | \ -+ hz_to_spi_baud(chip->ctar.pbr, \ -+ chip->ctar.dbr, \ -+ transfer->speed_hz)); -+ } -+ -+ message->state = RUNNING_STATE; -+ /* Go baby, go */ -+ local_irq_save(flags); -+ message->actual_length += write(drv_data); -+ local_irq_restore(flags); -+} -+ -+ -+static void pump_messages(struct work_struct *work) -+{ -+ struct driver_data *drv_data; -+ unsigned long flags; -+ DBG("\n"); -+ -+ 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); -+ -+ if (drv_data->cur_transfer->transfer_list.next -+ == &drv_data->cur_msg->transfers) -+ drv_data->cur_transfer->cs_change = 1; /* last */ -+ -+ -+ /* 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; -+ -+ DBG("\n"); -+ 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 chip_data *chip; -+ struct coldfire_dspi_chip *chip_info -+ = (struct coldfire_dspi_chip *)spi->controller_data; -+ DBG("\n"); -+ -+ /* 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; -+ } -+ -+ chip->mcr.master = 1; -+ chip->mcr.cont_scke = 0; -+ chip->mcr.dconf = 0; -+ chip->mcr.frz = 0; -+ chip->mcr.mtfe = 0; -+ 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 "Invalid wordsize\n"); -+ kfree(chip); -+ return -ENODEV; -+ } -+ -+ chip->void_write_data = chip_info->void_write_data; -+ -+ if (spi->max_speed_hz != 0) -+ chip_info->br = hz_to_spi_baud(chip_info->pbr, chip_info->dbr, \ -+ spi->max_speed_hz); -+ -+ chip->ctar.cpha = (spi->mode & SPI_CPHA) ? 1 : 0; -+ chip->ctar.cpol = (spi->mode & SPI_CPOL) ? 1 : 0; -+ chip->ctar.lsbfe = (spi->mode & SPI_LSB_FIRST) ? 1 : 0; -+ chip->ctar.dbr = chip_info->dbr; -+ chip->ctar.pbr = chip_info->pbr; -+ chip->ctar.br = chip_info->br; -+ chip->ctar.pcssck = chip_info->pcssck; -+ chip->ctar.pasc = chip_info->pasc; -+ chip->ctar.pdt = chip_info->pdt; -+ chip->ctar.cssck = chip_info->cssck; -+ chip->ctar.asc = chip_info->asc; -+ chip->ctar.dt = chip_info->dt; -+ -+ 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->workqueue = create_singlethread_workqueue( -+ drv_data->master->dev.parent->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(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) -+ dma_addr_t dma_handle; -+#endif -+ -+ platform_info = (struct coldfire_spi_master *)dev->platform_data; -+ -+ master = spi_alloc_master(dev, sizeof(struct driver_data)); -+ if (!master) -+ return -ENOMEM; -+ -+ drv_data = spi_master_get_devdata(master); -+ 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, "spi-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 = dma_alloc_coherent(NULL, EDMA_BUFSIZE_KMALLOC, \ -+ &dma_handle, 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 = dma_alloc_coherent(NULL, EDMA_BUFSIZE_KMALLOC, \ -+ &dma_handle, GFP_DMA); -+ if (!drv_data->edma_rx_buf) { -+ dma_free_coherent(NULL, EDMA_BUFSIZE_KMALLOC, \ -+ drv_data->edma_tx_buf, dma_handle); -+ kfree(drv_data->edma_tx_buf); -+ dev_dbg(dev, "cannot allocate eDMA RX memory\n"); -+ goto out_error_master_alloc; -+ } -+#endif -+ -+ drv_data->mcr = (void *)&MCF_DSPI_DMCR; -+ drv_data->ctar = (void *)&MCF_DSPI_DCTAR0; -+ drv_data->dspi_sr = (void *)&MCF_DSPI_DSR; -+ drv_data->dspi_rser = (void *)&MCF_DSPI_DRSER; -+ drv_data->dspi_dtfr = (void *)&MCF_DSPI_DTFR; -+ drv_data->dspi_drfr = (void *)&MCF_DSPI_DRFR; -+ -+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "spi-par"); -+ if (!memory_resource) { -+ dev_dbg(dev, "No spi-par memory\n"); -+ goto out_error_master_alloc; -+ } -+ drv_data->par = (void *)memory_resource->start; -+ -+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "spi-int-level"); -+ if (!memory_resource) { -+ dev_dbg(dev, "No spi-int-level memory\n"); -+ goto out_error_master_alloc; -+ } -+ drv_data->int_icr = (void *)memory_resource->start; -+ -+ memory_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "spi-int-mask"); -+ if (!memory_resource) { -+ dev_dbg(dev, "No spi-int-mask memory\n"); -+ goto out_error_master_alloc; -+ } -+ drv_data->int_mr = (void *)memory_resource->start; -+ -+ if (platform_info->irq_list) { -+ /* multiple IRQs */ -+ int *irqlist = platform_info->irq_list; -+ while ((irq = *irqlist++)) { -+ int off = *irqlist++; -+ int lvl = *irqlist++; -+ int msk = *irqlist++; -+ status = request_irq(irq, dspi_interrupt, IRQF_DISABLED, -+ dev->bus_id, drv_data); -+ if (status < 0) { -+ dev_err(&pdev->dev, -+ "Unable to attach ColdFire DSPI interrupt\n"); -+ goto out_error_master_alloc; -+ } -+ -+ if (lvl) -+ *(drv_data->int_icr + off) = lvl; -+ -+ if (msk) -+ *drv_data->int_mr &= ~msk; -+ } -+ } -+ else { -+ irq = platform_info->irq_vector; -+ -+ status = request_irq(platform_info->irq_vector, dspi_interrupt, -+ IRQF_DISABLED, dev->bus_id, drv_data); -+ if (status < 0) { -+ dev_err(&pdev->dev, "Unable to attach ColdFire DSPI interrupt\n"); -+ goto out_error_master_alloc; -+ } -+ -+ *drv_data->int_icr = platform_info->irq_lp; -+ *drv_data->int_mr &= ~platform_info->irq_mask; -+ } -+ -+ /* Now that we have all the addresses etc. Let's set it up */ -+ if (platform_info->par_val) -+ *drv_data->par = platform_info->par_val; -+ -+ /* Initial and start queue */ -+ status = init_queue(drv_data); -+ if (status != 0) { -+ dev_err(&pdev->dev, "Problem initializing DSPI queue\n"); -+ goto out_error_irq_alloc; -+ } -+ status = start_queue(drv_data); -+ if (status != 0) { -+ dev_err(&pdev->dev, "Problem starting DSPI 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 DSPI master\n"); -+ status = -EINVAL; -+ goto out_error_queue_alloc; -+ } -+ -+#if defined(SPI_DSPI_EDMA) -+ if (mcf_edma_request_channel(DSPI_DMA_TX_TCD, -+ edma_tx_handler, -+ NULL, -+ 0x0, -+ pdev, -+ NULL, /* spinlock */ -+ DRIVER_NAME) < 0){ -+ dev_err(&pdev->dev, "eDMA transmit channel request\n"); -+ status = -EINVAL; -+ goto out_error_queue_alloc; -+ } -+ -+ if (mcf_edma_request_channel(DSPI_DMA_RX_TCD, -+ edma_rx_handler, -+ NULL, -+ 0x0, -+ pdev, -+ NULL, /* spinlock */ -+ DRIVER_NAME) < 0){ -+ dev_err(&pdev->dev, "eDAM receive channel request\n"); -+ status = -EINVAL; -+ mcf_edma_free_channel(DSPI_DMA_TX_TCD, pdev); -+ goto out_error_queue_alloc; -+ } -+#endif -+ -+ printk(KERN_INFO "DSPI: Coldfire master initialized\n"); -+ return status; -+ -+out_error_queue_alloc: -+ destroy_queue(drv_data); -+ -+out_error_irq_alloc: -+ free_irq(platform_info->irq_vector, 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) -+ mcf_edma_free_channel(DSPI_DMA_TX_TCD, pdev); -+ mcf_edma_free_channel(DSPI_DMA_RX_TCD, pdev); -+#endif -+ -+ /* Remove the queue */ -+ status = destroy_queue(drv_data); -+ if (status != 0) -+ return status; -+ -+ /* 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 = coldfire_spi_remove(pdev); -+ -+ if (status != 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; -+ -+ return 0; -+} -+ -+static int coldfire_spi_resume(struct platform_device *pdev) -+{ -+ struct driver_data *drv_data = platform_get_drvdata(pdev); -+ int status = 0; -+ -+ /* 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); -+ -+MODULE_AUTHOR("Matt Waddel"); -+MODULE_DESCRIPTION("ColdFire DSPI Contoller"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/include/asm-m68k/mcfdspi.h -@@ -0,0 +1,48 @@ -+/* -+ * mcfdspi.h-DSPI controller for the ColdFire processors. -+ * -+ * Andrey Butok -+ * Copyright Freescale Semiconductor, Inc. 2008 -+ * -+ * This file is based on mcfqspi.h -+ * -+ * 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 -+ * -+ *************************************************************************** -+ * Changes: -+ * v0.001 25 March 2008 Andrey Butok -+ * Initial Release - developed on uClinux with 2.6.23 kernel. -+ * -+ */ -+ -+#ifndef MCFDSPI_H_ -+#define MCFDSPI_H_ -+ -+struct coldfire_dspi_chip { -+ u8 mode; -+ u8 bits_per_word; -+ u16 void_write_data; -+ /* Only used in master mode */ -+ u8 dbr; /* Double baud rate */ -+ u8 pbr; /* Baud rate prescaler */ -+ u8 br; /* Baud rate scaler */ -+ u8 pcssck; /* PCS to SCK delay prescaler */ -+ u8 pasc; /* After SCK delay prescaler */ -+ u8 pdt; /* Delay after transfer prescaler */ -+ u8 cssck; /* PCS to SCK delay scaler */ -+ u8 asc; /* After SCK delay scaler */ -+ u8 dt; /* Delay after transfer scaler */ -+}; -+#endif /*MCFDSPI_H_*/ |