[ARM] 5546/1: ARM PL022 SSP/SPI driver v3
[safe/jmp/linux-2.6] / drivers / spi / omap2_mcspi.c
index 3cdab13..d6d0c5d 100644 (file)
@@ -35,8 +35,8 @@
 
 #include <linux/spi/spi.h>
 
-#include <asm/arch/dma.h>
-#include <asm/arch/clock.h>
+#include <mach/dma.h>
+#include <mach/clock.h>
 
 
 #define OMAP2_MCSPI_MAX_FREQ           48000000
@@ -119,12 +119,14 @@ struct omap2_mcspi {
        struct clk              *fck;
        /* Virtual base address of the controller */
        void __iomem            *base;
+       unsigned long           phys;
        /* SPI1 has 4 channels, while SPI2 has 2 */
        struct omap2_mcspi_dma  *dma_channels;
 };
 
 struct omap2_mcspi_cs {
        void __iomem            *base;
+       unsigned long           phys;
        int                     word_len;
 };
 
@@ -233,7 +235,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        c = count;
        word_len = cs->word_len;
 
-       base = (unsigned long) io_v2p(cs->base);
+       base = cs->phys;
        tx_reg = base + OMAP2_MCSPI_TX0;
        rx_reg = base + OMAP2_MCSPI_RX0;
        rx = xfer->rx_buf;
@@ -350,6 +352,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                tx = xfer->tx_buf;
 
                do {
+                       c -= 1;
                        if (tx != NULL) {
                                if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -380,7 +383,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                                word_len, *(rx - 1));
 #endif
                        }
-                       c -= 1;
                } while (c);
        } else if (word_len <= 16) {
                u16             *rx;
@@ -389,6 +391,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
+                       c -= 2;
                        if (tx != NULL) {
                                if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -419,7 +422,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                                word_len, *(rx - 1));
 #endif
                        }
-                       c -= 2;
                } while (c);
        } else if (word_len <= 32) {
                u32             *rx;
@@ -428,6 +430,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                rx = xfer->rx_buf;
                tx = xfer->tx_buf;
                do {
+                       c -= 4;
                        if (tx != NULL) {
                                if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -458,7 +461,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                                word_len, *(rx - 1));
 #endif
                        }
-                       c -= 4;
                } while (c);
        }
 
@@ -633,6 +635,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                if (!cs)
                        return -ENOMEM;
                cs->base = mcspi->base + spi->chip_select * 0x14;
+               cs->phys = mcspi->phys + spi->chip_select * 0x14;
                spi->controller_state = cs;
        }
 
@@ -836,7 +839,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
                if (tx_buf != NULL) {
                        t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
                                        len, DMA_TO_DEVICE);
-                       if (dma_mapping_error(t->tx_dma)) {
+                       if (dma_mapping_error(&spi->dev, t->tx_dma)) {
                                dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
                                                'T', len);
                                return -EINVAL;
@@ -845,7 +848,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
                if (rx_buf != NULL) {
                        t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len,
                                        DMA_FROM_DEVICE);
-                       if (dma_mapping_error(t->rx_dma)) {
+                       if (dma_mapping_error(&spi->dev, t->rx_dma)) {
                                dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
                                                'R', len);
                                if (tx_buf != NULL)
@@ -915,6 +918,28 @@ static u8 __initdata spi2_txdma_id[] = {
        OMAP24XX_DMA_SPI2_TX1,
 };
 
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+static u8 __initdata spi3_rxdma_id[] = {
+       OMAP24XX_DMA_SPI3_RX0,
+       OMAP24XX_DMA_SPI3_RX1,
+};
+
+static u8 __initdata spi3_txdma_id[] = {
+       OMAP24XX_DMA_SPI3_TX0,
+       OMAP24XX_DMA_SPI3_TX1,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static u8 __initdata spi4_rxdma_id[] = {
+       OMAP34XX_DMA_SPI4_RX0,
+};
+
+static u8 __initdata spi4_txdma_id[] = {
+       OMAP34XX_DMA_SPI4_TX0,
+};
+#endif
+
 static int __init omap2_mcspi_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
@@ -935,7 +960,20 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                txdma_id = spi2_txdma_id;
                num_chipselect = 2;
                break;
-       /* REVISIT omap2430 has a third McSPI ... */
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+       case 3:
+               rxdma_id = spi3_rxdma_id;
+               txdma_id = spi3_txdma_id;
+               num_chipselect = 2;
+               break;
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       case 4:
+               rxdma_id = spi4_rxdma_id;
+               txdma_id = spi4_txdma_id;
+               num_chipselect = 1;
+               break;
+#endif
        default:
                return -EINVAL;
        }
@@ -965,25 +1003,31 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                goto err1;
        }
        if (!request_mem_region(r->start, (r->end - r->start) + 1,
-                       pdev->dev.bus_id)) {
+                       dev_name(&pdev->dev))) {
                status = -EBUSY;
                goto err1;
        }
 
-       mcspi->base = (void __iomem *) io_p2v(r->start);
+       mcspi->phys = r->start;
+       mcspi->base = ioremap(r->start, r->end - r->start + 1);
+       if (!mcspi->base) {
+               dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
+               status = -ENOMEM;
+               goto err1aa;
+       }
 
        INIT_WORK(&mcspi->work, omap2_mcspi_work);
 
        spin_lock_init(&mcspi->lock);
        INIT_LIST_HEAD(&mcspi->msg_queue);
 
-       mcspi->ick = clk_get(&pdev->dev, "mcspi_ick");
+       mcspi->ick = clk_get(&pdev->dev, "ick");
        if (IS_ERR(mcspi->ick)) {
                dev_dbg(&pdev->dev, "can't get mcspi_ick\n");
                status = PTR_ERR(mcspi->ick);
                goto err1a;
        }
-       mcspi->fck = clk_get(&pdev->dev, "mcspi_fck");
+       mcspi->fck = clk_get(&pdev->dev, "fck");
        if (IS_ERR(mcspi->fck)) {
                dev_dbg(&pdev->dev, "can't get mcspi_fck\n");
                status = PTR_ERR(mcspi->fck);
@@ -1020,6 +1064,8 @@ err3:
 err2:
        clk_put(mcspi->ick);
 err1a:
+       iounmap(mcspi->base);
+err1aa:
        release_mem_region(r->start, (r->end - r->start) + 1);
 err1:
        spi_master_put(master);
@@ -1032,6 +1078,7 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *dma_channels;
        struct resource         *r;
+       void __iomem *base;
 
        master = dev_get_drvdata(&pdev->dev);
        mcspi = spi_master_get_devdata(master);
@@ -1043,12 +1090,17 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, (r->end - r->start) + 1);
 
+       base = mcspi->base;
        spi_unregister_master(master);
+       iounmap(base);
        kfree(dma_channels);
 
        return 0;
 }
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:omap2_mcspi");
+
 static struct platform_driver omap2_mcspi_driver = {
        .driver = {
                .name =         "omap2_mcspi",