]> Pileus Git - ~andy/linux/blobdiff - drivers/spi/spi-omap-100k.c
Merge remote-tracking branch 'spi/topic/pdata' into spi-next
[~andy/linux] / drivers / spi / spi-omap-100k.c
index ee25670f8cfd127341fff7ddc16562a7e512507d..69ecf05757dda6d5f8fc42f7718f7754af43f03c 100644 (file)
 #define SPI_SHUTDOWN   1
 
 struct omap1_spi100k {
-       struct work_struct      work;
-
-       /* lock protects queue and registers */
-       spinlock_t              lock;
-       struct list_head        msg_queue;
        struct spi_master       *master;
        struct clk              *ick;
        struct clk              *fck;
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs {
        int                     word_len;
 };
 
-static struct workqueue_struct *omap1_spi100k_wq;
-
 #define MOD_REG_BIT(val, mask, set) do { \
        if (set) \
                val |= mask; \
@@ -310,170 +303,102 @@ static int omap1_spi100k_setup(struct spi_device *spi)
 
        spi100k_open(spi->master);
 
-       clk_enable(spi100k->ick);
-       clk_enable(spi100k->fck);
+       clk_prepare_enable(spi100k->ick);
+       clk_prepare_enable(spi100k->fck);
 
        ret = omap1_spi100k_setup_transfer(spi, NULL);
 
-       clk_disable(spi100k->ick);
-       clk_disable(spi100k->fck);
+       clk_disable_unprepare(spi100k->ick);
+       clk_disable_unprepare(spi100k->fck);
 
        return ret;
 }
 
-static void omap1_spi100k_work(struct work_struct *work)
+static int omap1_spi100k_prepare_hardware(struct spi_master *master)
 {
-       struct omap1_spi100k    *spi100k;
-       int status = 0;
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
 
-       spi100k = container_of(work, struct omap1_spi100k, work);
-       spin_lock_irq(&spi100k->lock);
+       clk_prepare_enable(spi100k->ick);
+       clk_prepare_enable(spi100k->fck);
 
-       clk_enable(spi100k->ick);
-       clk_enable(spi100k->fck);
+       return 0;
+}
 
-       /* We only enable one channel at a time -- the one whose message is
-        * at the head of the queue -- although this controller would gladly
-        * arbitrate among multiple channels.  This corresponds to "single
-        * channel" master mode.  As a side effect, we need to manage the
-        * chipselect with the FORCE bit ... CS != channel enable.
-        */
-        while (!list_empty(&spi100k->msg_queue)) {
-               struct spi_message              *m;
-               struct spi_device               *spi;
-               struct spi_transfer             *t = NULL;
-               int                             cs_active = 0;
-               struct omap1_spi100k_cs         *cs;
-               int                             par_override = 0;
-
-               m = container_of(spi100k->msg_queue.next, struct spi_message,
-                                queue);
-
-               list_del_init(&m->queue);
-               spin_unlock_irq(&spi100k->lock);
-
-               spi = m->spi;
-               cs = spi->controller_state;
-
-               list_for_each_entry(t, &m->transfers, transfer_list) {
-                       if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-                               status = -EINVAL;
+static int omap1_spi100k_transfer_one_message(struct spi_master *master,
+                                             struct spi_message *m)
+{
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+       struct spi_device *spi = m->spi;
+       struct spi_transfer *t = NULL;
+       int cs_active = 0;
+       int par_override = 0;
+       int status = 0;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+                       status = -EINVAL;
+                       break;
+               }
+               if (par_override || t->speed_hz || t->bits_per_word) {
+                       par_override = 1;
+                       status = omap1_spi100k_setup_transfer(spi, t);
+                       if (status < 0)
                                break;
-                       }
-                       if (par_override || t->speed_hz || t->bits_per_word) {
-                               par_override = 1;
-                               status = omap1_spi100k_setup_transfer(spi, t);
-                               if (status < 0)
-                                       break;
-                               if (!t->speed_hz && !t->bits_per_word)
-                                       par_override = 0;
-                       }
+                       if (!t->speed_hz && !t->bits_per_word)
+                               par_override = 0;
+               }
 
-                       if (!cs_active) {
-                               omap1_spi100k_force_cs(spi100k, 1);
-                               cs_active = 1;
-                       }
+               if (!cs_active) {
+                       omap1_spi100k_force_cs(spi100k, 1);
+                       cs_active = 1;
+               }
 
-                       if (t->len) {
-                               unsigned count;
+               if (t->len) {
+                       unsigned count;
 
-                               count = omap1_spi100k_txrx_pio(spi, t);
-                               m->actual_length += count;
+                       count = omap1_spi100k_txrx_pio(spi, t);
+                       m->actual_length += count;
 
-                               if (count != t->len) {
-                                       status = -EIO;
-                                       break;
-                               }
+                       if (count != t->len) {
+                               status = -EIO;
+                               break;
                        }
+               }
 
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
 
-                       /* ignore the "leave it on after last xfer" hint */
+               /* ignore the "leave it on after last xfer" hint */
 
-                       if (t->cs_change) {
-                               omap1_spi100k_force_cs(spi100k, 0);
-                               cs_active = 0;
-                       }
-               }
-
-               /* Restore defaults if they were overriden */
-               if (par_override) {
-                       par_override = 0;
-                       status = omap1_spi100k_setup_transfer(spi, NULL);
+               if (t->cs_change) {
+                       omap1_spi100k_force_cs(spi100k, 0);
+                       cs_active = 0;
                }
+       }
 
-               if (cs_active)
-                       omap1_spi100k_force_cs(spi100k, 0);
+       /* Restore defaults if they were overriden */
+       if (par_override) {
+               par_override = 0;
+               status = omap1_spi100k_setup_transfer(spi, NULL);
+       }
 
-               m->status = status;
-               m->complete(m->context);
+       if (cs_active)
+               omap1_spi100k_force_cs(spi100k, 0);
 
-               spin_lock_irq(&spi100k->lock);
-       }
+       m->status = status;
 
-       clk_disable(spi100k->ick);
-       clk_disable(spi100k->fck);
-       spin_unlock_irq(&spi100k->lock);
+       spi_finalize_current_message(master);
 
-       if (status < 0)
-               printk(KERN_WARNING "spi transfer failed with %d\n", status);
+       return status;
 }
 
-static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
+static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
 {
-       struct omap1_spi100k    *spi100k;
-       unsigned long           flags;
-       struct spi_transfer     *t;
-
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
-
-       spi100k = spi_master_get_devdata(spi->master);
-
-       /* Don't accept new work if we're shutting down */
-       if (spi100k->state == SPI_SHUTDOWN)
-               return -ESHUTDOWN;
-
-       /* reject invalid messages and transfers */
-       if (list_empty(&m->transfers) || !m->complete)
-               return -EINVAL;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               const void      *tx_buf = t->tx_buf;
-               void            *rx_buf = t->rx_buf;
-               unsigned        len = t->len;
-
-               if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
-                               || (len && !(rx_buf || tx_buf))) {
-                       dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
-                                       t->speed_hz,
-                                       len,
-                                       tx_buf ? "tx" : "",
-                                       rx_buf ? "rx" : "",
-                                       t->bits_per_word);
-                       return -EINVAL;
-               }
-
-               if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
-                       dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
-                                       t->speed_hz,
-                                       OMAP1_SPI100K_MAX_FREQ/(1<<16));
-                       return -EINVAL;
-               }
-
-       }
-
-       spin_lock_irqsave(&spi100k->lock, flags);
-       list_add_tail(&m->queue, &spi100k->msg_queue);
-       queue_work(omap1_spi100k_wq, &spi100k->work);
-       spin_unlock_irqrestore(&spi100k->lock, flags);
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
 
-       return 0;
-}
+       clk_disable_unprepare(spi100k->ick);
+       clk_disable_unprepare(spi100k->fck);
 
-static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
-{
        return 0;
 }
 
@@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
               master->bus_num = pdev->id;
 
        master->setup = omap1_spi100k_setup;
-       master->transfer = omap1_spi100k_transfer;
+       master->transfer_one_message = omap1_spi100k_transfer_one_message;
+       master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
+       master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
        master->cleanup = NULL;
        master->num_chipselect = 2;
        master->mode_bits = MODEBITS;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+       master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
+       master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
 
        platform_set_drvdata(pdev, master);
 
@@ -512,42 +441,31 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
         * You should allocate this with ioremap() before initializing
         * the SPI.
         */
-       spi100k->base = (void __iomem *) pdev->dev.platform_data;
-
-       INIT_WORK(&spi100k->work, omap1_spi100k_work);
+       spi100k->base = (void __iomem *)dev_get_platdata(&pdev->dev);
 
-       spin_lock_init(&spi100k->lock);
-       INIT_LIST_HEAD(&spi100k->msg_queue);
-       spi100k->ick = clk_get(&pdev->dev, "ick");
+       spi100k->ick = devm_clk_get(&pdev->dev, "ick");
        if (IS_ERR(spi100k->ick)) {
                dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
                status = PTR_ERR(spi100k->ick);
-               goto err1;
+               goto err;
        }
 
-       spi100k->fck = clk_get(&pdev->dev, "fck");
+       spi100k->fck = devm_clk_get(&pdev->dev, "fck");
        if (IS_ERR(spi100k->fck)) {
                dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
                status = PTR_ERR(spi100k->fck);
-               goto err2;
+               goto err;
        }
 
-       if (omap1_spi100k_reset(spi100k) < 0)
-               goto err3;
-
        status = spi_register_master(master);
        if (status < 0)
-               goto err3;
+               goto err;
 
        spi100k->state = SPI_RUNNING;
 
        return status;
 
-err3:
-       clk_put(spi100k->fck);
-err2:
-       clk_put(spi100k->ick);
-err1:
+err:
        spi_master_put(master);
        return status;
 }
@@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
        struct spi_master       *master;
        struct omap1_spi100k    *spi100k;
        struct resource         *r;
-       unsigned                limit = 500;
-       unsigned long           flags;
        int                     status = 0;
 
        master = platform_get_drvdata(pdev);
        spi100k = spi_master_get_devdata(master);
 
-       spin_lock_irqsave(&spi100k->lock, flags);
-
-       spi100k->state = SPI_SHUTDOWN;
-       while (!list_empty(&spi100k->msg_queue) && limit--) {
-               spin_unlock_irqrestore(&spi100k->lock, flags);
-               msleep(10);
-               spin_lock_irqsave(&spi100k->lock, flags);
-       }
-
-       if (!list_empty(&spi100k->msg_queue))
-               status = -EBUSY;
-
-       spin_unlock_irqrestore(&spi100k->lock, flags);
-
        if (status != 0)
                return status;
 
-       clk_put(spi100k->fck);
-       clk_put(spi100k->ick);
-
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        spi_unregister_master(master);
@@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = {
                .name           = "omap1_spi100k",
                .owner          = THIS_MODULE,
        },
+       .probe          = omap1_spi100k_probe,
        .remove         = omap1_spi100k_remove,
 };
 
-
-static int __init omap1_spi100k_init(void)
-{
-       omap1_spi100k_wq = create_singlethread_workqueue(
-                       omap1_spi100k_driver.driver.name);
-
-       if (omap1_spi100k_wq == NULL)
-               return -1;
-
-       return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe);
-}
-
-static void __exit omap1_spi100k_exit(void)
-{
-       platform_driver_unregister(&omap1_spi100k_driver);
-
-       destroy_workqueue(omap1_spi100k_wq);
-}
-
-module_init(omap1_spi100k_init);
-module_exit(omap1_spi100k_exit);
+module_platform_driver(omap1_spi100k_driver);
 
 MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
 MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");