USB: New device ID for ftdi_sio driver
[safe/jmp/linux-2.6] / drivers / spi / spi_imx.c
index 6ccf8a1..c730d05 100644 (file)
                                                        32.768 KHz Clock */
 
 /* SPI DMA Register Bit Fields & Masks */
-#define SPI_DMA_RHDMA  (0xF << 4)      /* RXFIFO Half Status */
+#define SPI_DMA_RHDMA  (0x1 << 4)      /* RXFIFO Half Status */
 #define SPI_DMA_RFDMA  (0x1 << 5)      /* RXFIFO Full Status */
 #define SPI_DMA_TEDMA  (0x1 << 6)      /* TXFIFO Empty Status */
 #define SPI_DMA_THDMA  (0x1 << 7)      /* TXFIFO Half Status */
 #define SPI_FIFO_BYTE_WIDTH            (2)
 #define SPI_FIFO_OVERFLOW_MARGIN       (2)
 
-/* DMA burst lenght for half full/empty request trigger */
+/* DMA burst length for half full/empty request trigger */
 #define SPI_DMA_BLR                    (SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)
 
 /* Dummy char output to achieve reads.
@@ -270,19 +270,26 @@ struct chip_data {
 
 static void pump_messages(struct work_struct *work);
 
-static int flush(struct driver_data *drv_data)
+static void flush(struct driver_data *drv_data)
 {
-       unsigned long limit = loops_per_jiffy << 1;
        void __iomem *regs = drv_data->regs;
-       volatile u32 d;
+       u32 control;
 
        dev_dbg(&drv_data->pdev->dev, "flush\n");
+
+       /* Wait for end of transaction */
        do {
-               while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR)
-                       d = readl(regs + SPI_RXDATA);
-       } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--);
+               control = readl(regs + SPI_CONTROL);
+       } while (control & SPI_CONTROL_XCH);
 
-       return limit;
+       /* Release chip select if requested, transfer delays are
+          handled in pump_transfers */
+       if (drv_data->cs_change)
+               drv_data->cs_control(SPI_CS_DEASSERT);
+
+       /* Disable SPI to flush FIFOs */
+       writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL);
+       writel(control, regs + SPI_CONTROL);
 }
 
 static void restore_state(struct driver_data *drv_data)
@@ -570,6 +577,7 @@ static void giveback(struct spi_message *message, struct driver_data *drv_data)
        writel(0, regs + SPI_INT_STATUS);
        writel(0, regs + SPI_DMA);
 
+       /* Unconditioned deselct */
        drv_data->cs_control(SPI_CS_DEASSERT);
 
        message->state = NULL;
@@ -592,13 +600,10 @@ static void dma_err_handler(int channel, void *data, int errcode)
        /* Disable both rx and tx dma channels */
        imx_dma_disable(drv_data->rx_channel);
        imx_dma_disable(drv_data->tx_channel);
-
-       if (flush(drv_data) == 0)
-               dev_err(&drv_data->pdev->dev,
-                               "dma_err_handler - flush failed\n");
-
        unmap_dma_buffers(drv_data);
 
+       flush(drv_data);
+
        msg->state = ERROR_STATE;
        tasklet_schedule(&drv_data->pump_transfers);
 }
@@ -612,8 +617,7 @@ static void dma_tx_handler(int channel, void *data)
        imx_dma_disable(channel);
 
        /* Now waits for TX FIFO empty */
-       writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE,
-                       drv_data->regs + SPI_INT_STATUS);
+       writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS);
 }
 
 static irqreturn_t dma_transfer(struct driver_data *drv_data)
@@ -621,19 +625,18 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
        u32 status;
        struct spi_message *msg = drv_data->cur_msg;
        void __iomem *regs = drv_data->regs;
-       unsigned long limit;
 
        status = readl(regs + SPI_INT_STATUS);
 
-       if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) {
+       if ((status & (SPI_INTEN_RO | SPI_STATUS_RO))
+                       == (SPI_INTEN_RO | SPI_STATUS_RO)) {
                writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
 
+               imx_dma_disable(drv_data->tx_channel);
                imx_dma_disable(drv_data->rx_channel);
                unmap_dma_buffers(drv_data);
 
-               if (flush(drv_data) == 0)
-                       dev_err(&drv_data->pdev->dev,
-                               "dma_transfer - flush failed\n");
+               flush(drv_data);
 
                dev_warn(&drv_data->pdev->dev,
                                "dma_transfer - fifo overun\n");
@@ -649,20 +652,17 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
 
                if (drv_data->rx) {
                        /* Wait end of transfer before read trailing data */
-                       limit = loops_per_jiffy << 1;
-                       while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) &&
-                                       limit--);
-
-                       if (limit == 0)
-                               dev_err(&drv_data->pdev->dev,
-                                       "dma_transfer - end of tx failed\n");
-                       else
-                               dev_dbg(&drv_data->pdev->dev,
-                                       "dma_transfer - end of tx\n");
+                       while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH)
+                               cpu_relax();
 
                        imx_dma_disable(drv_data->rx_channel);
                        unmap_dma_buffers(drv_data);
 
+                       /* Release chip select if requested, transfer delays are
+                          handled in pump_transfers() */
+                       if (drv_data->cs_change)
+                               drv_data->cs_control(SPI_CS_DEASSERT);
+
                        /* Calculate number of trailing data and read them */
                        dev_dbg(&drv_data->pdev->dev,
                                "dma_transfer - test = 0x%08X\n",
@@ -676,19 +676,12 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
                        /* Write only transfer */
                        unmap_dma_buffers(drv_data);
 
-                       if (flush(drv_data) == 0)
-                               dev_err(&drv_data->pdev->dev,
-                                       "dma_transfer - flush failed\n");
+                       flush(drv_data);
                }
 
                /* End of transfer, update total byte transfered */
                msg->actual_length += drv_data->len;
 
-               /* Release chip select if requested, transfer delays are
-                  handled in pump_transfers() */
-               if (drv_data->cs_change)
-                       drv_data->cs_control(SPI_CS_DEASSERT);
-
                /* Move to next transfer */
                msg->state = next_transfer(drv_data);
 
@@ -711,44 +704,43 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
 
        status = readl(regs + SPI_INT_STATUS);
 
-       while (status & SPI_STATUS_TH) {
+       if (status & SPI_INTEN_TE) {
+               /* TXFIFO Empty Interrupt on the last transfered word */
+               writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
                dev_dbg(&drv_data->pdev->dev,
-                       "interrupt_wronly_transfer - status = 0x%08X\n", status);
+                       "interrupt_wronly_transfer - end of tx\n");
 
-               /* Pump data */
-               if (write(drv_data)) {
-                       writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
-                               regs + SPI_INT_STATUS);
+               flush(drv_data);
 
-                       dev_dbg(&drv_data->pdev->dev,
-                               "interrupt_wronly_transfer - end of tx\n");
+               /* Update total byte transfered */
+               msg->actual_length += drv_data->len;
 
-                       if (flush(drv_data) == 0)
-                               dev_err(&drv_data->pdev->dev,
-                                       "interrupt_wronly_transfer - "
-                                       "flush failed\n");
+               /* Move to next transfer */
+               msg->state = next_transfer(drv_data);
 
-                       /* End of transfer, update total byte transfered */
-                       msg->actual_length += drv_data->len;
+               /* Schedule transfer tasklet */
+               tasklet_schedule(&drv_data->pump_transfers);
 
-                       /* Release chip select if requested, transfer delays are
-                          handled in pump_transfers */
-                       if (drv_data->cs_change)
-                               drv_data->cs_control(SPI_CS_DEASSERT);
+               return IRQ_HANDLED;
+       } else {
+               while (status & SPI_STATUS_TH) {
+                       dev_dbg(&drv_data->pdev->dev,
+                               "interrupt_wronly_transfer - status = 0x%08X\n",
+                               status);
 
-                       /* Move to next transfer */
-                       msg->state = next_transfer(drv_data);
+                       /* Pump data */
+                       if (write(drv_data)) {
+                               /* End of TXFIFO writes,
+                                  now wait until TXFIFO is empty */
+                               writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+                               return IRQ_HANDLED;
+                       }
 
-                       /* Schedule transfer tasklet */
-                       tasklet_schedule(&drv_data->pump_transfers);
+                       status = readl(regs + SPI_INT_STATUS);
 
-                       return IRQ_HANDLED;
+                       /* We did something */
+                       handled = IRQ_HANDLED;
                }
-
-               status = readl(regs + SPI_INT_STATUS);
-
-               /* We did something */
-               handled = IRQ_HANDLED;
        }
 
        return handled;
@@ -758,45 +750,31 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
 {
        struct spi_message *msg = drv_data->cur_msg;
        void __iomem *regs = drv_data->regs;
-       u32 status;
+       u32 status, control;
        irqreturn_t handled = IRQ_NONE;
        unsigned long limit;
 
        status = readl(regs + SPI_INT_STATUS);
 
-       while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+       if (status & SPI_INTEN_TE) {
+               /* TXFIFO Empty Interrupt on the last transfered word */
+               writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
                dev_dbg(&drv_data->pdev->dev,
-                       "interrupt_transfer - status = 0x%08X\n", status);
-
-               if (status & SPI_STATUS_RO) {
-                       writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
-                               regs + SPI_INT_STATUS);
-
-                       dev_warn(&drv_data->pdev->dev,
-                               "interrupt_transfer - fifo overun\n"
-                               "    data not yet written = %d\n"
-                               "    data not yet read    = %d\n",
-                               data_to_write(drv_data),
-                               data_to_read(drv_data));
-
-                       if (flush(drv_data) == 0)
-                               dev_err(&drv_data->pdev->dev,
-                                       "interrupt_transfer - flush failed\n");
-
-                       msg->state = ERROR_STATE;
-                       tasklet_schedule(&drv_data->pump_transfers);
+                       "interrupt_transfer - end of tx\n");
 
-                       return IRQ_HANDLED;
-               }
-
-               /* Pump data */
-               read(drv_data);
-               if (write(drv_data)) {
-                       writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
-                               regs + SPI_INT_STATUS);
+               if (msg->state == ERROR_STATE) {
+                       /* RXFIFO overrun was detected and message aborted */
+                       flush(drv_data);
+               } else {
+                       /* Wait for end of transaction */
+                       do {
+                               control = readl(regs + SPI_CONTROL);
+                       } while (control & SPI_CONTROL_XCH);
 
-                       dev_dbg(&drv_data->pdev->dev,
-                               "interrupt_transfer - end of tx\n");
+                       /* Release chip select if requested, transfer delays are
+                          handled in pump_transfers */
+                       if (drv_data->cs_change)
+                               drv_data->cs_control(SPI_CS_DEASSERT);
 
                        /* Read trailing bytes */
                        limit = loops_per_jiffy << 1;
@@ -810,27 +788,54 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
                                dev_dbg(&drv_data->pdev->dev,
                                        "interrupt_transfer - end of rx\n");
 
-                       /* End of transfer, update total byte transfered */
+                       /* Update total byte transfered */
                        msg->actual_length += drv_data->len;
 
-                       /* Release chip select if requested, transfer delays are
-                          handled in pump_transfers */
-                       if (drv_data->cs_change)
-                               drv_data->cs_control(SPI_CS_DEASSERT);
-
                        /* Move to next transfer */
                        msg->state = next_transfer(drv_data);
+               }
 
-                       /* Schedule transfer tasklet */
-                       tasklet_schedule(&drv_data->pump_transfers);
+               /* Schedule transfer tasklet */
+               tasklet_schedule(&drv_data->pump_transfers);
 
-                       return IRQ_HANDLED;
-               }
+               return IRQ_HANDLED;
+       } else {
+               while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+                       dev_dbg(&drv_data->pdev->dev,
+                               "interrupt_transfer - status = 0x%08X\n",
+                               status);
+
+                       if (status & SPI_STATUS_RO) {
+                               /* RXFIFO overrun, abort message end wait
+                                  until TXFIFO is empty */
+                               writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+
+                               dev_warn(&drv_data->pdev->dev,
+                                       "interrupt_transfer - fifo overun\n"
+                                       "    data not yet written = %d\n"
+                                       "    data not yet read    = %d\n",
+                                       data_to_write(drv_data),
+                                       data_to_read(drv_data));
 
-               status = readl(regs + SPI_INT_STATUS);
+                               msg->state = ERROR_STATE;
 
-               /* We did something */
-               handled = IRQ_HANDLED;
+                               return IRQ_HANDLED;
+                       }
+
+                       /* Pump data */
+                       read(drv_data);
+                       if (write(drv_data)) {
+                               /* End of TXFIFO writes,
+                                  now wait until TXFIFO is empty */
+                               writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+                               return IRQ_HANDLED;
+                       }
+
+                       status = readl(regs + SPI_INT_STATUS);
+
+                       /* We did something */
+                       handled = IRQ_HANDLED;
+               }
        }
 
        return handled;
@@ -1163,6 +1168,9 @@ msg_rejected:
        return -EINVAL;
 }
 
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
 /* On first setup bad values must free chip_data memory since will cause
    spi_new_device to fail. Bad value setup from protocol driver are simply not
    applied and notified to the calling driver. */
@@ -1174,6 +1182,12 @@ static int setup(struct spi_device *spi)
        u32 tmp;
        int status = 0;
 
+       if (spi->mode & ~MODEBITS) {
+               dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+                       spi->mode & ~MODEBITS);
+               return -EINVAL;
+       }
+
        /* Get controller data */
        chip_info = spi->controller_data;
 
@@ -1185,7 +1199,7 @@ static int setup(struct spi_device *spi)
                chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
                if (!chip) {
                        dev_err(&spi->dev,
-                               "setup - cannot allocate controller state");
+                               "setup - cannot allocate controller state\n");
                        return -ENOMEM;
                }
                chip->control = SPI_DEFAULT_CONTROL;
@@ -1197,7 +1211,7 @@ static int setup(struct spi_device *spi)
                        if (!chip_info) {
                                dev_err(&spi->dev,
                                        "setup - "
-                                       "cannot allocate controller data");
+                                       "cannot allocate controller data\n");
                                status = -ENOMEM;
                                goto err_first_setup;
                        }
@@ -1245,21 +1259,6 @@ static int setup(struct spi_device *spi)
 
        /* SPI mode */
        tmp = spi->mode;
-       if (tmp & SPI_LSB_FIRST) {
-               status = -EINVAL;
-               if (first_setup) {
-                       dev_err(&spi->dev,
-                               "setup - "
-                               "HW doesn't support LSB first transfer\n");
-                       goto err_first_setup;
-               } else {
-                       dev_err(&spi->dev,
-                               "setup - "
-                               "HW doesn't support LSB first transfer, "
-                               "default to MSB first\n");
-                       spi->mode &= ~SPI_LSB_FIRST;
-               }
-       }
        if (tmp & SPI_CS_HIGH) {
                u32_EDIT(chip->control,
                                SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH);
@@ -1355,19 +1354,19 @@ static int setup(struct spi_device *spi)
                spi->bits_per_word,
                spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
                spi->max_speed_hz);
+       return status;
 
 err_first_setup:
        kfree(chip);
        return status;
 }
 
-static void cleanup(const struct spi_device *spi)
+static void cleanup(struct spi_device *spi)
 {
-       struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
-       kfree(chip);
+       kfree(spi_get_ctldata(spi));
 }
 
-static int init_queue(struct driver_data *drv_data)
+static int __init init_queue(struct driver_data *drv_data)
 {
        INIT_LIST_HEAD(&drv_data->queue);
        spin_lock_init(&drv_data->lock);
@@ -1380,7 +1379,7 @@ static int init_queue(struct driver_data *drv_data)
 
        INIT_WORK(&drv_data->work, pump_messages);
        drv_data->workqueue = create_singlethread_workqueue(
-                                       drv_data->master->cdev.dev->bus_id);
+                                       drv_data->master->dev.parent->bus_id);
        if (drv_data->workqueue == NULL)
                return -EBUSY;
 
@@ -1450,7 +1449,7 @@ static int destroy_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static int spi_imx_probe(struct platform_device *pdev)
+static int __init spi_imx_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct spi_imx_master *platform_info;
@@ -1628,7 +1627,7 @@ err_no_mem:
        return status;
 }
 
-static int __devexit spi_imx_remove(struct platform_device *pdev)
+static int __exit spi_imx_remove(struct platform_device *pdev)
 {
        struct driver_data *drv_data = platform_get_drvdata(pdev);
        int irq;
@@ -1692,17 +1691,6 @@ static void spi_imx_shutdown(struct platform_device *pdev)
 }
 
 #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 spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
 {
@@ -1739,14 +1727,15 @@ static int spi_imx_resume(struct platform_device *pdev)
 #define spi_imx_resume NULL
 #endif /* CONFIG_PM */
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:spi_imx");
+
 static struct platform_driver driver = {
        .driver = {
-               .name = "imx-spi",
-               .bus = &platform_bus_type,
+               .name = "spi_imx",
                .owner = THIS_MODULE,
        },
-       .probe = spi_imx_probe,
-       .remove = __devexit_p(spi_imx_remove),
+       .remove = __exit_p(spi_imx_remove),
        .shutdown = spi_imx_shutdown,
        .suspend = spi_imx_suspend,
        .resume = spi_imx_resume,
@@ -1754,7 +1743,7 @@ static struct platform_driver driver = {
 
 static int __init spi_imx_init(void)
 {
-       return platform_driver_register(&driver);
+       return platform_driver_probe(&driver, spi_imx_probe);
 }
 module_init(spi_imx_init);
 
@@ -1765,5 +1754,5 @@ static void __exit spi_imx_exit(void)
 module_exit(spi_imx_exit);
 
 MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
-MODULE_DESCRIPTION("iMX SPI Contoller Driver");
+MODULE_DESCRIPTION("iMX SPI Controller Driver");
 MODULE_LICENSE("GPL");