Replaces the deprecated master->transfer function with master->transfer_one_message and let the SPI subsystem do the message queueing instead of doing it locally.
Signed-off-by: Stefan Kristiansson <stefan.kristians...@saunalahti.fi> --- drivers/spi/spi-oc-simple.c | 223 ++++++++++++++------------------------------ 1 file changed, 71 insertions(+), 152 deletions(-) diff --git a/drivers/spi/spi-oc-simple.c b/drivers/spi/spi-oc-simple.c index 3c8e9b9..3938a26 100644 --- a/drivers/spi/spi-oc-simple.c +++ b/drivers/spi/spi-oc-simple.c @@ -51,20 +51,12 @@ #define OCSPI_SPER_ESPR 0x03 struct ocspi { - 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; }; -static struct workqueue_struct *ocspi_wq; - static inline u8 ocspi_read(struct ocspi* ocspi, unsigned int reg) { return ioread8(ocspi->base + reg); @@ -250,73 +242,90 @@ out: return xfer->len - count; } -static void ocspi_work(struct work_struct *work) +static int ocspi_transfer_one_message(struct spi_master *master, + struct spi_message *m) { - struct ocspi *ocspi = - container_of(work, struct ocspi, work); + struct ocspi *ocspi = 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; + - spin_lock_irq(&ocspi->lock); - while (!list_empty(&ocspi->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; + /* Load defaults */ + status = ocspi_setup_transfer(spi, NULL); - m = container_of(ocspi->msg_queue.next, struct spi_message, - queue); + if (status < 0) + goto msg_done; - list_del_init(&m->queue); - spin_unlock_irq(&ocspi->lock); + list_for_each_entry(t, &m->transfers, transfer_list) { + unsigned int bits_per_word = spi->bits_per_word; - spi = m->spi; + if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { + dev_err(&spi->dev, + "message rejected : " + "invalid transfer data buffers\n"); + status = -EIO; + goto msg_done; + } - /* Load defaults */ - status = ocspi_setup_transfer(spi, NULL); + if ((t != NULL) && t->bits_per_word) + bits_per_word = t->bits_per_word; - if (status < 0) + if ((bits_per_word != 8)) { + dev_err(&spi->dev, + "message rejected : " + "invalid transfer bits_per_word (%d bits)\n", + bits_per_word); + 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 = ocspi_setup_transfer(spi, t); - if (status < 0) - break; - if (!t->speed_hz && !t->bits_per_word) - par_override = 0; - } - - if (!cs_active) { - ocspi_set_cs(ocspi, (1 << spi->chip_select)); - cs_active = 1; - } - - if (t->len) - m->actual_length += - ocspi_write_read(spi, t); - - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (t->cs_change) { - ocspi_set_cs(ocspi, 0); - cs_active = 0; - } + if (t->speed_hz && t->speed_hz < ocspi->min_speed) { + dev_err(&spi->dev, + "message rejected : " + "device min speed (%d Hz) exceeds " + "required transfer speed (%d Hz)\n", + ocspi->min_speed, t->speed_hz); + status = -EIO; + goto msg_done; } -msg_done: - if (cs_active) - ocspi_set_cs(ocspi, 0); + if (par_override || t->speed_hz || t->bits_per_word) { + par_override = 1; + status = ocspi_setup_transfer(spi, t); + if (status < 0) + break; + if (!t->speed_hz && !t->bits_per_word) + par_override = 0; + } - m->status = status; - m->complete(m->context); + if (!cs_active) { + ocspi_set_cs(ocspi, (1 << spi->chip_select)); + cs_active = 1; + } + + if (t->len) + m->actual_length += ocspi_write_read(spi, t); + + if (t->delay_usecs) + udelay(t->delay_usecs); - spin_lock_irq(&ocspi->lock); + if (t->cs_change) { + ocspi_set_cs(ocspi, 0); + cs_active = 0; + } } - spin_unlock_irq(&ocspi->lock); +msg_done: + if (cs_active) + ocspi_set_cs(ocspi, 0); + + m->status = status; + spi_finalize_current_message(master); + + return 0; } static int ocspi_reset(struct ocspi *ocspi) @@ -359,72 +368,6 @@ static int ocspi_setup(struct spi_device *spi) return 0; } -/* - * The transfer function enqueues a message for sending to the - * spi_device. May be called at any time and should thus not touch - * registers. - */ -static int ocspi_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct ocspi *ocspi; - 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; - } - - ocspi = 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 != NULL) && t->bits_per_word) - bits_per_word = t->bits_per_word; - - if (bits_per_word != 8) { - dev_err(&spi->dev, - "message rejected : " - "invalid transfer bits_per_word (%d bits)\n", - bits_per_word); - goto msg_rejected; - } - - if (t->speed_hz && t->speed_hz < ocspi->min_speed) { - dev_err(&spi->dev, - "message rejected : " - "device min speed (%d Hz) exceeds " - "required transfer speed (%d Hz)\n", - ocspi->min_speed, t->speed_hz); - goto msg_rejected; - } - } - - spin_lock_irqsave(&ocspi->lock, flags); - list_add_tail(&m->queue, &ocspi->msg_queue); - queue_work(ocspi_wq, &ocspi->work); - spin_unlock_irqrestore(&ocspi->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 ocspi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -450,7 +393,7 @@ static int ocspi_probe(struct platform_device *pdev) master->mode_bits = SPI_MODE_3; master->setup = ocspi_setup; - master->transfer = ocspi_transfer; + master->transfer_one_message = ocspi_transfer_one_message; master->num_chipselect = OCSPI_NUM_CHIPSELECTS; #ifdef CONFIG_OF master->dev.of_node = pdev->dev.of_node; @@ -478,11 +421,6 @@ static int ocspi_probe(struct platform_device *pdev) spi->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); - INIT_WORK(&spi->work, ocspi_work); - - spin_lock_init(&spi->lock); - INIT_LIST_HEAD(&spi->msg_queue); - ocspi_reset(spi); status = spi_register_master(master); @@ -504,8 +442,6 @@ static int ocspi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); spi = spi_master_get_devdata(master); - cancel_work_sync(&spi->work); - spi_unregister_master(master); return 0; @@ -533,30 +469,13 @@ static struct platform_driver ocspi_driver = { static int __init ocspi_init(void) { - int status; - - ocspi_wq = create_singlethread_workqueue( - ocspi_driver.driver.name); - - if (ocspi_wq == NULL) - return -ENOMEM; - - status = platform_driver_register(&ocspi_driver); - - if (status) { - destroy_workqueue(ocspi_wq); - }; - - return status; + return platform_driver_register(&ocspi_driver); } module_init(ocspi_init); static void __exit ocspi_exit(void) { - flush_workqueue(ocspi_wq); platform_driver_unregister(&ocspi_driver); - - destroy_workqueue(ocspi_wq); } module_exit(ocspi_exit); -- 1.8.1.2 _______________________________________________ Linux mailing list Linux@lists.openrisc.net http://lists.openrisc.net/listinfo/linux