diff options
Diffstat (limited to 'target/linux/ep93xx/patches-2.6.30/008-ep93xx-spi.patch')
-rw-r--r-- | target/linux/ep93xx/patches-2.6.30/008-ep93xx-spi.patch | 714 |
1 files changed, 0 insertions, 714 deletions
diff --git a/target/linux/ep93xx/patches-2.6.30/008-ep93xx-spi.patch b/target/linux/ep93xx/patches-2.6.30/008-ep93xx-spi.patch deleted file mode 100644 index 8292bbcf16..0000000000 --- a/target/linux/ep93xx/patches-2.6.30/008-ep93xx-spi.patch +++ /dev/null @@ -1,714 +0,0 @@ -Index: linux-2.6.30.9/drivers/spi/Kconfig -=================================================================== ---- linux-2.6.30.9.orig/drivers/spi/Kconfig 2009-11-24 21:09:23.000000000 +0100 -+++ linux-2.6.30.9/drivers/spi/Kconfig 2009-11-24 21:09:53.000000000 +0100 -@@ -125,6 +125,12 @@ - - If unsure, say N. - -+config SPI_EP93XX -+ tristate "EP93xx SSP SPI master" -+ depends on SPI_MASTER && ARCH_EP93XX && EXPERIMENTAL -+ help -+ This enables the EP93xx SPI master controller. -+ - config SPI_IMX - tristate "Freescale iMX SPI controller" - depends on ARCH_IMX && EXPERIMENTAL -Index: linux-2.6.30.9/drivers/spi/Makefile -=================================================================== ---- linux-2.6.30.9.orig/drivers/spi/Makefile 2009-11-24 21:09:23.000000000 +0100 -+++ linux-2.6.30.9/drivers/spi/Makefile 2009-11-24 21:09:53.000000000 +0100 -@@ -16,6 +16,7 @@ - obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o - obj-$(CONFIG_SPI_AU1550) += au1550_spi.o - obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o -+obj-$(CONFIG_SPI_EP93XX) += spi_ep93xx.o - obj-$(CONFIG_SPI_GPIO) += spi_gpio.o - obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o - obj-$(CONFIG_SPI_IMX) += spi_imx.o -Index: linux-2.6.30.9/drivers/spi/spi_ep93xx.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/spi/spi_ep93xx.c 2009-11-24 21:21:25.000000000 +0100 -@@ -0,0 +1,680 @@ -+/* -+ * linux/drivers/spi/spi_ep93xx.c -+ * -+ * Copyright (C) 2007 Manfred Gruber <m.gruber@tirol.com> -+ * Small changes by Peter Ivanov <ivanovp@gmail.com> to support MMC over SPI, 2008 -+ * SIM.ONE changes by Nuccio Raciti Simplemachine <nuccio.raciti@gmail.com> -+ * -+ * Based on pxa2xx_spi.c/spi_imx.c and bitbang.c driver -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include <linux/blkdev.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/spinlock.h> -+#include <linux/workqueue.h> -+ -+#include <linux/spi/spi.h> -+ -+#include <mach/hardware.h> -+#include <mach/ep93xx-regs.h> -+#include <asm/gpio.h> -+ -+/* #define SPI_EP93XX_DEBUG */ -+ -+#define DEFINE_SSP_REG(reg, off) \ -+ static inline u32 read_##reg(void *p) \ -+ { return __raw_readl(p + (off)); } \ -+ static inline void write_##reg(u32 v, void *p) \ -+ { __raw_writel(v, p + (off)); } -+ -+DEFINE_SSP_REG(SSPCR0, 0x00) -+DEFINE_SSP_REG(SSPCR1, 0x04) -+DEFINE_SSP_REG(SSPDR, 0x08) -+DEFINE_SSP_REG(SSPSR, 0x0c) -+DEFINE_SSP_REG(SSPCPSR, 0x10) -+DEFINE_SSP_REG(SSPIIR, 0x14) -+DEFINE_SSP_REG(SSPICR, 0x14) -+ -+/* Bits in SSPCR0 */ -+#define SSPCR0_DSS_MASK 0x0000000f -+#define SSPCR0_FRF_MASK 0x00000030 -+#define SSPCR0_FRF_SHIFT 4 -+#define SSPCR0_FRF_MOTOROLA (0 << SSPCR0_FRF_SHIFT) -+#define SSPCR0_FRF_TI (1 << SSPCR0_FRF_SHIFT) -+#define SSPCR0_FRF_NI (2 << SSPCR0_FRF_SHIFT) -+#define SSPCR0_SPO 0x00000040 -+#define SSPCR0_SPH 0x00000080 -+#define SSPCR0_SCR_MASK 0x0000ff00 -+#define SSPCR0_SCR_SHIFT 8 -+ -+/* Bits in SSPCR1 */ -+#define SSPC1_RIE 0x00000001 -+#define SSPC1_TIE 0x00000002 -+#define SSPC1_RORIE 0x00000004 -+#define SSPC1_LBM 0x00000008 -+#define SSPC1_SSE 0x00000010 -+#define SSPC1_MS 0x00000020 -+#define SSPC1_SOD 0x00000040 -+ -+/* Bits in SSPSR */ -+#define SSPSR_TFE 0x00000001 /* TX FIFO is empty */ -+#define SSPSR_TNF 0x00000002 /* TX FIFO is not full */ -+#define SSPSR_RNE 0x00000004 /* RX FIFO is not empty */ -+#define SSPSR_RFF 0x00000008 /* RX FIFO is full */ -+#define SSPSR_BSY 0x00000010 /* SSP is busy */ -+#define SSPSR_MASK 0x0000001F /* SSP is busy */ -+ -+/* Bits in SSPCPSR */ -+#define SSPCPSR_SCR_MASK 0x000000ff -+ -+/* Bits in SSPIIR */ -+#define SSPIIR_RIS 0x00000001 /* RX FIFO IRQ status */ -+#define SSPIIR_TIS 0x00000002 /* TX FIFO is not full */ -+#define SSPIIR_RORIS 0x00000004 /* RX FIFO is full */ -+ -+#define SPI_SSPCLK 7.4e6 -+#define SPI_SSPCLK_REV_E2 14.8e6 /* only for chip Rev E2 */ -+#define SPI_MAX_SPEED 3.7e6 -+#define SPI_MAX_SPEED_REV_E2 7.4e6 /* only for chip Rev E2 */ -+#define SPI_CPSDVR_DIV_MIN 2 -+#define SPI_CPSDVR_DIV_MAX 254 -+#define SPI_SCR_DIV_MIN 0 -+#define SPI_SCR_DIV_MAX 255 -+#define SPI_DATARATE_OK 0 -+#define SPI_DATARATE_NOK -1 -+ -+struct driver_data { -+ /* Driver model hookup */ -+ struct platform_device *pdev; -+ -+ /* SPI framework hookup */ -+ struct spi_master *master; -+ -+ /* SSP register addresses */ -+ void *ioaddr; -+ -+ /* SSP irq */ -+ int irq; -+ -+ struct list_head queue; -+ -+ /* SSP spinlock */ -+ spinlock_t lock; -+ -+ struct workqueue_struct *workqueue; -+ struct work_struct work; -+ -+ u8 busy; -+ u8 use_dma; -+}; -+ -+static unsigned ep93xx_txrx_8(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct driver_data *drv_data; -+ const u8 *tx = t->tx_buf; -+ u8 *rx = t->rx_buf; -+ unsigned count = t->len; -+ u8 byte; -+ int busy; -+ -+ drv_data = spi_master_get_devdata(spi->master); -+ -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_8: t->len %u \n", t->len); -+#endif -+ -+ while (likely(count > 0)) { -+ byte = 0; -+ if (tx) { -+ byte = *tx++; -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_8: write 0x%x \n", byte); -+#endif -+ } -+ -+ write_SSPDR(byte, drv_data->ioaddr); -+ busy = read_SSPSR(drv_data->ioaddr); -+ while (busy & SSPSR_BSY) { -+ cpu_relax(); -+ busy = read_SSPSR(drv_data->ioaddr); -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_8: delay. SSPSR: 0x%X\n", busy); -+#endif -+ } -+ byte = read_SSPDR(drv_data->ioaddr); -+ -+ if (rx) { -+ *rx++ = byte; -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_8: read 0x%x \n", byte); -+#endif -+ } -+ count -= 1; -+ } -+ return t->len - count; -+} -+ -+ -+static unsigned ep93xx_txrx_16(struct spi_device *spi, struct spi_transfer *t) -+{ -+ -+ struct driver_data *drv_data; -+ const u16 *tx = t->tx_buf; -+ u16 *rx = t->rx_buf; -+ unsigned count = t->len; -+ u16 word; -+ int busy; -+ -+ drv_data = spi_master_get_devdata(spi->master); -+ -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_16: t->len %u \n", t->len); -+#endif -+ while (likely(count > 0)) { -+ word = 0; -+ if (tx) { -+ word = *tx++; -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_16: write 0x%x \n", word); -+#endif -+ } -+ -+ write_SSPDR(word, drv_data->ioaddr); -+ busy = read_SSPSR(drv_data->ioaddr); -+ while (busy & SSPSR_BSY) { -+ cpu_relax(); -+ busy = read_SSPSR(drv_data->ioaddr); -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_8: delay.\n"); -+#endif -+ } -+ -+ word = read_SSPDR(drv_data->ioaddr); -+ -+ if (rx) { -+ *rx++ = word; -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "ep93xx_txrx_16: read 0x%x \n", word); -+#endif -+ } -+ count -= 2; -+ } -+ return t->len - count; -+} -+ -+static u32 spi_data_rate(u32 speed_hz, u32 *div_cpsdvr, u32 *div_scr, -+ struct driver_data *drv_data, struct spi_device *spi) -+{ -+ unsigned int spi_sspclk = SPI_SSPCLK; -+ unsigned int bus_speed_max = SPI_MAX_SPEED; -+ unsigned int bus_hz_tmp = 0; -+ u32 div_cpsdvr_tmp; -+ u32 div_scr_tmp; -+ u32 rv = SPI_DATARATE_NOK; -+ int chip_rev; -+ -+ /* Checking CHIP_ID */ -+ chip_rev = (__raw_readl (EP93XX_SYSCON_CHIP_ID) >> 28) & 0xF; -+ if (chip_rev == 7) -+ { -+ /* Chip version: Rev E2 */ -+ /* This device has double speed SSP clock */ -+ spi_sspclk = SPI_SSPCLK_REV_E2; -+ bus_speed_max = SPI_MAX_SPEED_REV_E2; -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "Chip Rev E2 detected! This device has double speed SSP clock.\n"); -+#endif -+ } -+ -+ *div_cpsdvr = SPI_CPSDVR_DIV_MAX; -+ *div_scr = SPI_SCR_DIV_MAX; -+ -+ for (div_cpsdvr_tmp = SPI_CPSDVR_DIV_MIN; -+ div_cpsdvr_tmp <= SPI_CPSDVR_DIV_MAX && rv; div_cpsdvr_tmp++) { -+ for (div_scr_tmp = SPI_SCR_DIV_MIN; -+ div_scr_tmp <= SPI_SCR_DIV_MAX && rv; div_scr_tmp++) { -+ bus_hz_tmp = spi_sspclk / (div_cpsdvr_tmp * (1 + div_scr_tmp)); -+ if (bus_hz_tmp <= speed_hz && bus_hz_tmp <= bus_speed_max) { -+ *div_cpsdvr = div_cpsdvr_tmp; -+ *div_scr = div_scr_tmp; -+ rv = SPI_DATARATE_OK; -+ } -+ } -+ } -+#ifdef SPI_EP93XX_DEBUG -+ dev_info(&spi->dev, -+ "Needed SPI bus frequency: %i Hz\n", speed_hz); -+ dev_info(&spi->dev, -+ "Actual SPI bus frequency: %i Hz\n", bus_hz_tmp); -+#endif -+ return rv; -+} -+ -+/* Supported modes (returns -EINVAL if not supported mode requested) */ -+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) -+ -+static int ep93xx_spi_setup(struct spi_device *spi) -+{ -+ struct driver_data *drv_data; -+ u16 val; -+ u32 div_scr; -+ u32 div_cpsdvr; -+ unsigned int bits = spi->bits_per_word; -+ unsigned long speed_hz = spi->max_speed_hz; -+ -+ drv_data = spi_master_get_devdata(spi->master); -+ -+ /* enable SSP */ -+ write_SSPCR1(SSPC1_SSE, drv_data->ioaddr); -+ /* Enable SSP and loopback mode (only for testing!) */ -+ /* write_SSPCR1(SSPC1_SSE | SSPC1_LBM, drv_data->ioaddr); */ -+ -+ if (bits == 0) -+ bits = 8; -+ if (bits < 4 || bits > 16) { -+ dev_err(&spi->dev, -+ "setup invalid bits_per_word %u (4 to 16)\n", bits); -+ return -EINVAL; -+ } else { -+ val = read_SSPCR0(drv_data->ioaddr); -+ val = val & ~SSPCR0_DSS_MASK ; -+ val = val | (bits-1); -+ write_SSPCR0(val, drv_data->ioaddr); -+#ifdef SPI_EP93XX_DEBUG -+ dev_info (&spi->dev, "Bits per word: %i\n", bits); -+#endif -+ } -+ -+ if (spi->mode & ~MODEBITS) { -+ dev_err(&spi->dev, "unsupported mode bits: %x\n", -+ spi->mode & ~MODEBITS); -+ return -EINVAL; -+ } else { -+ val = read_SSPCR0(drv_data->ioaddr); -+ val = val & ~SSPCR0_SPO; -+ val = val & ~SSPCR0_SPH; -+ if (spi->mode & SPI_CPOL) -+ { -+ val = val | SSPCR0_SPO; -+ } -+#ifdef SPI_EP93XX_DEBUG -+ dev_info (&spi->dev, "Clock polarity (CPOL): %s\n", (spi->mode & SPI_CPHA) ? "1" : "0"); -+#endif -+ if (spi->mode & SPI_CPHA) -+ { -+ val = val | SSPCR0_SPH; -+ } -+#ifdef SPI_EP93XX_DEBUG -+ dev_info (&spi->dev, "Clock phase (CPHA): %s\n", (spi->mode & SPI_CPHA) ? "1" : "0"); -+#endif -+ write_SSPCR0(val, drv_data->ioaddr); -+ } -+ -+ if (SPI_DATARATE_OK == (spi_data_rate(speed_hz, &div_cpsdvr, -+ &div_scr, drv_data, spi))) { -+ -+ val = read_SSPCPSR(drv_data->ioaddr); -+ val = val & ~SSPCPSR_SCR_MASK; -+ val = val | div_cpsdvr; -+#ifdef SPI_EP93XX_DEBUG -+ dev_info (&spi->dev, "SSPCPSR: 0x%X\n", val); -+#endif -+ write_SSPCPSR(val, drv_data->ioaddr); -+ -+ val = read_SSPCR0(drv_data->ioaddr); -+ val = val & ~SSPCR0_SCR_MASK; -+ val = val | (div_scr << SSPCR0_SCR_SHIFT); -+#ifdef SPI_EP93XX_DEBUG -+ dev_info (&spi->dev, "SSPCR0: 0x%X (div_scr: 0x%X)\n", val, div_scr); -+#endif -+ write_SSPCR0(val, drv_data->ioaddr); -+ } else -+ return -EINVAL; -+ -+ /* reenable */ -+ val = read_SSPCR1(drv_data->ioaddr); -+ val = val & ~SSPC1_SSE; -+ write_SSPCR1(val, drv_data->ioaddr); -+ val = read_SSPCR1(drv_data->ioaddr); -+ val = val | SSPC1_SSE; -+ write_SSPCR1(val, drv_data->ioaddr); -+#ifdef SPI_EP93XX_DEBUG -+ dev_info (&spi->dev, "Loopback mode: %s\n", (val & SSPC1_LBM) ? "On" : "Off"); -+#endif -+ -+ return 0; -+} -+ -+static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *m) -+{ -+ struct driver_data *drv_data; -+ unsigned long flags; -+ int status = 0; -+ -+ m->actual_length = 0; -+ m->status = -EINPROGRESS; -+ -+ drv_data = spi_master_get_devdata(spi->master); -+ -+ spin_lock_irqsave(&drv_data->lock, flags); -+ if (!spi->max_speed_hz) -+ status = -ENETDOWN; -+ else { -+ list_add_tail(&m->queue, &drv_data->queue); -+ queue_work(drv_data->workqueue, &drv_data->work); -+ } -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+ return status; -+} -+ -+static void ep93xx_work(struct work_struct *work) -+{ -+ struct driver_data *drv_data = -+ container_of(work, struct driver_data, work); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&drv_data->lock, flags); -+ drv_data->busy = 1; -+ -+ while (!list_empty(&drv_data->queue)) { -+ struct spi_message *m; -+ struct spi_device *spi; -+ struct spi_transfer *t = NULL; -+ int status; -+ -+ m = container_of(drv_data->queue.next, struct spi_message, -+ queue); -+ list_del_init(&m->queue); -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+ -+ spi = m->spi; -+ status = 0; -+ -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ -+ if (!t->tx_buf && !t->rx_buf && t->len) { -+ status = -EINVAL; -+ break; -+ } -+ -+ if (t->len) { -+ if (!m->is_dma_mapped) { -+ t->rx_dma = 0; -+ t->tx_dma = 0; -+ } -+ if (t->bits_per_word <= 8) -+ status = ep93xx_txrx_8(spi, t); -+ else -+ status = ep93xx_txrx_16(spi, t); -+ } -+ -+ if (status != t->len) { -+ if (status > 0) -+ status = -EMSGSIZE; -+ break; -+ } -+ m->actual_length += status; -+ status = 0; -+ -+ /* protocol tweaks before next transfer */ -+ if (t->delay_usecs) -+ udelay(t->delay_usecs); -+ -+ if (t->transfer_list.next == &m->transfers) -+ break; -+ } -+ -+ m->status = status; -+ m->complete(m->context); -+ -+ spin_lock_irqsave(&drv_data->lock, flags); -+ } -+ drv_data->busy = 0; -+ spin_unlock_irqrestore(&drv_data->lock, flags); -+} -+ -+static irqreturn_t ssp_int(int irq, void *dev_id) -+{ -+ struct driver_data *drv_data = dev_id; -+ u8 status; -+ status = read_SSPIIR(drv_data->ioaddr); -+ -+ if (status & SSPIIR_RORIS) { -+ dev_err(&drv_data->pdev->dev, "SPI rx overrun.\n"); -+ -+ /* We clear the overrun here ! */ -+ write_SSPICR(0, drv_data->ioaddr); -+ } -+ -+ /* RX interrupt */ -+ if (status & SSPIIR_RIS) -+ dev_info(&drv_data->pdev->dev, "SPI RX interrupt\n"); -+ -+ /* TX interrupt */ -+ if (status & SSPIIR_TIS) -+ dev_info(&drv_data->pdev->dev, "SPI TX interrupt\n"); -+ -+ write_SSPICR(0, drv_data->ioaddr); -+ return IRQ_HANDLED; -+} -+ -+static int __init ep93xx_spi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct spi_master *master; -+ struct driver_data *drv_data = 0; -+ struct resource *memory_resource; -+ int status = 0; -+ u16 val; -+ -+ /* Allocate master with space for drv_data and null dma buffer */ -+ master = spi_alloc_master(dev, sizeof(struct driver_data)); -+ if (!master) { -+ dev_err(&pdev->dev, "cannot alloc spi_master\n"); -+ return -ENOMEM; -+ } -+ drv_data = spi_master_get_devdata(master); -+ drv_data->master = master; -+ drv_data->pdev = pdev; -+ -+ master->num_chipselect = EP93XX_GPIO_LINE_H(7) + 1; -+ master->bus_num = pdev->id; -+ master->setup = ep93xx_spi_setup; -+ master->transfer = ep93xx_spi_transfer; -+ -+ spin_lock_init(&drv_data->lock); -+ INIT_LIST_HEAD(&drv_data->queue); -+ -+ /* Setup register addresses */ -+ memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!memory_resource) { -+ dev_err(&pdev->dev, "memory resources not defined\n"); -+ status = -EIO; -+ goto out_error_master_alloc; -+ } else { -+ drv_data->ioaddr = ioremap(memory_resource->start, -+ memory_resource->end - memory_resource->start); -+ if (drv_data->ioaddr == NULL) { -+ dev_err(&pdev->dev, "ioremap failed\n"); -+ status = -EIO; -+ goto out_error_master_alloc; -+ } -+ } -+ -+ /* Attach to IRQ */ -+ drv_data->irq = platform_get_irq(pdev, 0); -+ if (drv_data->irq < 0) -+ return drv_data->irq; -+ -+ if (drv_data->irq <= 0) { -+ dev_err(&pdev->dev, "IRQ resource not defined\n"); -+ status = -ENODEV; -+ goto out_error_master_alloc; -+ } -+ -+ status = request_irq(drv_data->irq, ssp_int, 0, "ep93xx-spi", drv_data); -+ if (status < 0) { -+ dev_err(&pdev->dev, "cannot get SPI IRQ 0\n"); -+ goto out_error_master_alloc; -+ } -+ -+ /* SSP default configuration, enable */ -+ write_SSPCR1(SSPC1_SSE, drv_data->ioaddr); -+ -+ /* run as master */ -+ val = read_SSPCR1(drv_data->ioaddr); -+ val = val & ~SSPC1_MS; -+ write_SSPCR1(val, drv_data->ioaddr); -+ -+ /* frame format to Motorola SPI Format */ -+ val = read_SSPCR0(drv_data->ioaddr); -+ val = val & ~SSPCR0_FRF_MASK ; -+ val = val | SSPCR0_FRF_MOTOROLA; -+ write_SSPCR0(val, drv_data->ioaddr); -+ -+ /* enable interrupts */ -+ val = read_SSPCR1(drv_data->ioaddr); -+ /* for now only overrun is handled */ -+ /* val = val | SSPC1_RIE | SSPC1_TIE | SSPC1_RORIE; */ -+ val = val | SSPC1_RORIE; -+ write_SSPCR1(val, drv_data->ioaddr); -+ -+ /* SSP default configuration, re enable */ -+ val = read_SSPCR1(drv_data->ioaddr); -+ val = val & ~SSPC1_SSE; -+ write_SSPCR1(val, drv_data->ioaddr); -+ val = read_SSPCR1(drv_data->ioaddr); -+ val = val | SSPC1_SSE; -+ write_SSPCR1(val, drv_data->ioaddr); -+ -+ /* Register with the SPI framework */ -+ platform_set_drvdata(pdev, drv_data); -+ status = spi_register_master(master); -+ if (status != 0) { -+ dev_err(&pdev->dev, "cannot register SPI master\n"); -+ goto out_error_master_alloc; -+ } else -+ dev_info(&pdev->dev, "SPI Controller initalized\n"); -+ -+ INIT_WORK(&drv_data->work, ep93xx_work); -+ spin_lock_init(&drv_data->lock); -+ INIT_LIST_HEAD(&drv_data->queue); -+ -+ /* this task is the only thing to touch the SPI bits */ -+ drv_data->busy = 0; -+ drv_data->workqueue = create_singlethread_workqueue( -+ dev_name(drv_data->master->dev.parent)); -+/* drv_data->master->cdev.dev->bus_id); */ -+ if (drv_data->workqueue == NULL) { -+ status = -EBUSY; -+ goto out_error_free_irq; -+ } -+ -+ return status; -+ -+out_error_free_irq: -+ free_irq(drv_data->irq, master); -+out_error_master_alloc: -+ if (drv_data->ioaddr != NULL) -+ iounmap(drv_data->ioaddr); -+ spi_master_put(master); -+ return status; -+} -+ -+static int __exit ep93xx_spi_remove(struct platform_device *pdev) -+{ -+ struct driver_data *drv_data = platform_get_drvdata(pdev); -+ u8 val; -+ -+ WARN_ON(!list_empty(&drv_data->queue)); -+ -+ destroy_workqueue(drv_data->workqueue); -+ -+ /* switch off SSP*/ -+ val = read_SSPCR1(drv_data->ioaddr); -+ val = val & ~SSPC1_SSE; -+ write_SSPCR1(val, drv_data->ioaddr); -+ -+ /* release irqs */ -+ if (drv_data->irq > 0) -+ free_irq(drv_data->irq, drv_data); -+ -+ /* Disconnect from the SPI framework */ -+ spi_unregister_master(drv_data->master); -+ spi_master_put(drv_data->master); -+ -+ if (drv_data->ioaddr != NULL) -+ iounmap(drv_data->ioaddr); -+ -+ /* Prevent double remove */ -+ platform_set_drvdata(pdev, NULL); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int ep93xx_spi_suspend(struct platform_device *pdev, pm_message_t msg) -+{ -+ return 0; -+} -+ -+static int ep93xx_spi_resume(struct platform_device *pdev) -+{ -+ return 0; -+} -+ -+#else -+#define ep93xx_spi_suspend NULL -+#define ep93xx_spi_resume NULL -+#endif -+ -+struct platform_driver ep93xx_spi_device = { -+ .remove = __exit_p(ep93xx_spi_remove), -+#ifdef CONFIG_PM -+ .suspend = ep93xx_spi_suspend, -+ .resume = ep93xx_spi_resume, -+#endif -+ .driver = { -+ .name = "ep93xx-spi", -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init ep93xx_spi_init(void) -+{ -+ return platform_driver_probe(&ep93xx_spi_device, ep93xx_spi_probe); -+} -+ -+void __exit ep93xx_spi_exit(void) -+{ -+ platform_driver_unregister(&ep93xx_spi_device); -+} -+ -+module_init(ep93xx_spi_init); -+module_exit(ep93xx_spi_exit); -+ -+MODULE_DESCRIPTION("EP93XX SPI Driver"); -+MODULE_AUTHOR("Manfred Gruber, <m.gruber@tirol.com>"); -+MODULE_LICENSE("GPL"); |