gpu: nvgpu: Increase PBDMA timeout
[linux-3.10.git] / drivers / spi / spi-orion.c
index dfd04e9..66a5f82 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/clk.h>
 #include <asm/unaligned.h>
 
 #define ORION_SPI_DATA_IN_REG          0x0c
 #define ORION_SPI_INT_CAUSE_REG                0x10
 
+#define ORION_SPI_MODE_CPOL            (1 << 11)
+#define ORION_SPI_MODE_CPHA            (1 << 12)
 #define ORION_SPI_IF_8_16_BIT_MODE     (1 << 5)
 #define ORION_SPI_CLK_PRESCALE_MASK    0x1F
+#define ORION_SPI_MODE_MASK            (ORION_SPI_MODE_CPOL | \
+                                        ORION_SPI_MODE_CPHA)
 
 struct orion_spi {
-       struct work_struct      work;
-
-       /* Lock access to transfer list.        */
-       spinlock_t              lock;
-
-       struct list_head        msg_queue;
        struct spi_master       *master;
        void __iomem            *base;
        unsigned int            max_speed;
        unsigned int            min_speed;
-       struct orion_spi_info   *spi_info;
        struct clk              *clk;
 };
 
-static struct workqueue_struct *orion_spi_wq;
-
 static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
 {
        return orion_spi->base + reg;
@@ -131,6 +127,23 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
        return 0;
 }
 
+static void
+orion_spi_mode_set(struct spi_device *spi)
+{
+       u32 reg;
+       struct orion_spi *orion_spi;
+
+       orion_spi = spi_master_get_devdata(spi->master);
+
+       reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
+       reg &= ~ORION_SPI_MODE_MASK;
+       if (spi->mode & SPI_CPOL)
+               reg |= ORION_SPI_MODE_CPOL;
+       if (spi->mode & SPI_CPHA)
+               reg |= ORION_SPI_MODE_CPHA;
+       writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
+}
+
 /*
  * called only when no transfer is active on the bus
  */
@@ -150,6 +163,8 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        if ((t != NULL) && t->bits_per_word)
                bits_per_word = t->bits_per_word;
 
+       orion_spi_mode_set(spi);
+
        rc = orion_spi_baudrate_set(spi, speed);
        if (rc)
                return rc;
@@ -277,76 +292,81 @@ out:
 }
 
 
-static void orion_spi_work(struct work_struct *work)
+static int orion_spi_transfer_one_message(struct spi_master *master,
+                                          struct spi_message *m)
 {
-       struct orion_spi *orion_spi =
-               container_of(work, struct orion_spi, work);
-
-       spin_lock_irq(&orion_spi->lock);
-       while (!list_empty(&orion_spi->msg_queue)) {
-               struct spi_message *m;
-               struct spi_device *spi;
-               struct spi_transfer *t = NULL;
-               int par_override = 0;
-               int status = 0;
-               int cs_active = 0;
-
-               m = container_of(orion_spi->msg_queue.next, struct spi_message,
-                                queue);
+       struct orion_spi *orion_spi = spi_master_get_devdata(master);
+       struct spi_device *spi = m->spi;
+       struct spi_transfer *t = NULL;
+       int par_override = 0;
+       int status = 0;
+       int cs_active = 0;
 
-               list_del_init(&m->queue);
-               spin_unlock_irq(&orion_spi->lock);
+       /* Load defaults */
+       status = orion_spi_setup_transfer(spi, NULL);
 
-               spi = m->spi;
+       if (status < 0)
+               goto msg_done;
 
-               /* Load defaults */
-               status = orion_spi_setup_transfer(spi, NULL);
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               /* make sure buffer length is even when working in 16
+                * bit mode*/
+               if ((t->bits_per_word == 16) && (t->len & 1)) {
+                       dev_err(&spi->dev,
+                               "message rejected : "
+                               "odd data length %d while in 16 bit mode\n",
+                               t->len);
+                       status = -EIO;
+                       goto msg_done;
+               }
 
-               if (status < 0)
+               if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
+                       dev_err(&spi->dev,
+                               "message rejected : "
+                               "device min speed (%d Hz) exceeds "
+                               "required transfer speed (%d Hz)\n",
+                               orion_spi->min_speed, t->speed_hz);
+                       status = -EIO;
                        goto msg_done;
+               }
 
-               list_for_each_entry(t, &m->transfers, transfer_list) {
-                       if (par_override || t->speed_hz || t->bits_per_word) {
-                               par_override = 1;
-                               status = orion_spi_setup_transfer(spi, t);
-                               if (status < 0)
-                                       break;
-                               if (!t->speed_hz && !t->bits_per_word)
-                                       par_override = 0;
-                       }
-
-                       if (!cs_active) {
-                               orion_spi_set_cs(orion_spi, 1);
-                               cs_active = 1;
-                       }
-
-                       if (t->len)
-                               m->actual_length +=
-                                       orion_spi_write_read(spi, t);
-
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
-
-                       if (t->cs_change) {
-                               orion_spi_set_cs(orion_spi, 0);
-                               cs_active = 0;
-                       }
+               if (par_override || t->speed_hz || t->bits_per_word) {
+                       par_override = 1;
+                       status = orion_spi_setup_transfer(spi, t);
+                       if (status < 0)
+                               break;
+                       if (!t->speed_hz && !t->bits_per_word)
+                               par_override = 0;
                }
 
-msg_done:
-               if (cs_active)
-                       orion_spi_set_cs(orion_spi, 0);
+               if (!cs_active) {
+                       orion_spi_set_cs(orion_spi, 1);
+                       cs_active = 1;
+               }
+
+               if (t->len)
+                       m->actual_length += orion_spi_write_read(spi, t);
 
-               m->status = status;
-               m->complete(m->context);
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
 
-               spin_lock_irq(&orion_spi->lock);
+               if (t->cs_change) {
+                       orion_spi_set_cs(orion_spi, 0);
+                       cs_active = 0;
+               }
        }
 
-       spin_unlock_irq(&orion_spi->lock);
+msg_done:
+       if (cs_active)
+               orion_spi_set_cs(orion_spi, 0);
+
+       m->status = status;
+       spi_finalize_current_message(master);
+
+       return 0;
 }
 
-static int __init orion_spi_reset(struct orion_spi *orion_spi)
+static int orion_spi_reset(struct orion_spi *orion_spi)
 {
        /* Verify that the CS is deasserted */
        orion_spi_set_cs(orion_spi, 0);
@@ -376,85 +396,15 @@ static int orion_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
-       struct orion_spi *orion_spi;
-       struct spi_transfer *t = NULL;
-       unsigned long flags;
-
-       m->actual_length = 0;
-       m->status = 0;
-
-       /* reject invalid messages and transfers */
-       if (list_empty(&m->transfers) || !m->complete)
-               return -EINVAL;
-
-       orion_spi = spi_master_get_devdata(spi->master);
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               unsigned int bits_per_word = spi->bits_per_word;
-
-               if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "invalid transfer data buffers\n");
-                       goto msg_rejected;
-               }
-
-               if (t->bits_per_word)
-                       bits_per_word = t->bits_per_word;
-
-               if ((bits_per_word != 8) && (bits_per_word != 16)) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "invalid transfer bits_per_word (%d bits)\n",
-                               bits_per_word);
-                       goto msg_rejected;
-               }
-               /*make sure buffer length is even when working in 16 bit mode*/
-               if ((t->bits_per_word == 16) && (t->len & 1)) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "odd data length (%d) while in 16 bit mode\n",
-                               t->len);
-                       goto msg_rejected;
-               }
-
-               if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "device min speed (%d Hz) exceeds "
-                               "required transfer speed (%d Hz)\n",
-                               orion_spi->min_speed, t->speed_hz);
-                       goto msg_rejected;
-               }
-       }
-
-
-       spin_lock_irqsave(&orion_spi->lock, flags);
-       list_add_tail(&m->queue, &orion_spi->msg_queue);
-       queue_work(orion_spi_wq, &orion_spi->work);
-       spin_unlock_irqrestore(&orion_spi->lock, flags);
-
-       return 0;
-msg_rejected:
-       /* Message rejected and not queued */
-       m->status = -EINVAL;
-       if (m->complete)
-               m->complete(m->context);
-       return -EINVAL;
-}
-
-static int __init orion_spi_probe(struct platform_device *pdev)
+static int orion_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct orion_spi *spi;
        struct resource *r;
-       struct orion_spi_info *spi_info;
        unsigned long tclk_hz;
        int status = 0;
-
-       spi_info = pdev->dev.platform_data;
+       const u32 *iprop;
+       int size;
 
        master = spi_alloc_master(&pdev->dev, sizeof *spi);
        if (master == NULL) {
@@ -464,19 +414,24 @@ static int __init orion_spi_probe(struct platform_device *pdev)
 
        if (pdev->id != -1)
                master->bus_num = pdev->id;
+       if (pdev->dev.of_node) {
+               iprop = of_get_property(pdev->dev.of_node, "cell-index",
+                                       &size);
+               if (iprop && size == sizeof(*iprop))
+                       master->bus_num = *iprop;
+       }
 
        /* we support only mode 0, and no options */
-       master->mode_bits = 0;
+       master->mode_bits = SPI_CPHA | SPI_CPOL;
 
        master->setup = orion_spi_setup;
-       master->transfer = orion_spi_transfer;
+       master->transfer_one_message = orion_spi_transfer_one_message;
        master->num_chipselect = ORION_NUM_CHIPSELECTS;
 
        dev_set_drvdata(&pdev->dev, master);
 
        spi = spi_master_get_devdata(master);
        spi->master = master;
-       spi->spi_info = spi_info;
 
        spi->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(spi->clk)) {
@@ -503,14 +458,10 @@ static int __init orion_spi_probe(struct platform_device *pdev)
        }
        spi->base = ioremap(r->start, SZ_1K);
 
-       INIT_WORK(&spi->work, orion_spi_work);
-
-       spin_lock_init(&spi->lock);
-       INIT_LIST_HEAD(&spi->msg_queue);
-
        if (orion_spi_reset(spi) < 0)
                goto out_rel_mem;
 
+       master->dev.of_node = pdev->dev.of_node;
        status = spi_register_master(master);
        if (status < 0)
                goto out_rel_mem;
@@ -528,17 +479,15 @@ out:
 }
 
 
-static int __exit orion_spi_remove(struct platform_device *pdev)
+static int orion_spi_remove(struct platform_device *pdev)
 {
        struct spi_master *master;
-       struct orion_spi *spi;
        struct resource *r;
+       struct orion_spi *spi;
 
        master = dev_get_drvdata(&pdev->dev);
        spi = spi_master_get_devdata(master);
 
-       cancel_work_sync(&spi->work);
-
        clk_disable_unprepare(spi->clk);
        clk_put(spi->clk);
 
@@ -552,33 +501,23 @@ static int __exit orion_spi_remove(struct platform_device *pdev)
 
 MODULE_ALIAS("platform:" DRIVER_NAME);
 
+static const struct of_device_id orion_spi_of_match_table[] = {
+       { .compatible = "marvell,orion-spi", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
+
 static struct platform_driver orion_spi_driver = {
        .driver = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(orion_spi_of_match_table),
        },
-       .remove         = __exit_p(orion_spi_remove),
+       .probe          = orion_spi_probe,
+       .remove         = orion_spi_remove,
 };
 
-static int __init orion_spi_init(void)
-{
-       orion_spi_wq = create_singlethread_workqueue(
-                               orion_spi_driver.driver.name);
-       if (orion_spi_wq == NULL)
-               return -ENOMEM;
-
-       return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
-}
-module_init(orion_spi_init);
-
-static void __exit orion_spi_exit(void)
-{
-       flush_workqueue(orion_spi_wq);
-       platform_driver_unregister(&orion_spi_driver);
-
-       destroy_workqueue(orion_spi_wq);
-}
-module_exit(orion_spi_exit);
+module_platform_driver(orion_spi_driver);
 
 MODULE_DESCRIPTION("Orion SPI driver");
 MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");