Commit ad2a99af authored by Mark Brown's avatar Mark Brown Committed by Grant Likely

spi/s3c64xx: Convert to using core message queue

Convert the s3c64xx driver to using the new message queue factored out of
the pl022 driver by Linus Walleij, saving us a nice block of code and
getting the benefits of improvements implemented in the core.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent 5e8afa34
...@@ -128,8 +128,6 @@ ...@@ -128,8 +128,6 @@
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
#define SUSPND (1<<0)
#define SPIBUSY (1<<1)
#define RXBUSY (1<<2) #define RXBUSY (1<<2)
#define TXBUSY (1<<3) #define TXBUSY (1<<3)
...@@ -144,10 +142,8 @@ struct s3c64xx_spi_dma_data { ...@@ -144,10 +142,8 @@ struct s3c64xx_spi_dma_data {
* @clk: Pointer to the spi clock. * @clk: Pointer to the spi clock.
* @src_clk: Pointer to the clock used to generate SPI signals. * @src_clk: Pointer to the clock used to generate SPI signals.
* @master: Pointer to the SPI Protocol master. * @master: Pointer to the SPI Protocol master.
* @workqueue: Work queue for the SPI xfer requests.
* @cntrlr_info: Platform specific data for the controller this driver manages. * @cntrlr_info: Platform specific data for the controller this driver manages.
* @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint. * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
* @work: Work
* @queue: To log SPI xfer requests. * @queue: To log SPI xfer requests.
* @lock: Controller specific lock. * @lock: Controller specific lock.
* @state: Set of FLAGS to indicate status. * @state: Set of FLAGS to indicate status.
...@@ -167,10 +163,8 @@ struct s3c64xx_spi_driver_data { ...@@ -167,10 +163,8 @@ struct s3c64xx_spi_driver_data {
struct clk *src_clk; struct clk *src_clk;
struct platform_device *pdev; struct platform_device *pdev;
struct spi_master *master; struct spi_master *master;
struct workqueue_struct *workqueue;
struct s3c64xx_spi_info *cntrlr_info; struct s3c64xx_spi_info *cntrlr_info;
struct spi_device *tgl_spi; struct spi_device *tgl_spi;
struct work_struct work;
struct list_head queue; struct list_head queue;
spinlock_t lock; spinlock_t lock;
unsigned long sfr_start; unsigned long sfr_start;
...@@ -637,9 +631,10 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, ...@@ -637,9 +631,10 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
} }
} }
static void handle_msg(struct s3c64xx_spi_driver_data *sdd, static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
struct spi_device *spi = msg->spi; struct spi_device *spi = msg->spi;
struct s3c64xx_spi_csinfo *cs = spi->controller_data; struct s3c64xx_spi_csinfo *cs = spi->controller_data;
...@@ -771,13 +766,15 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, ...@@ -771,13 +766,15 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
if (msg->complete) if (msg->complete)
msg->complete(msg->context); msg->complete(msg->context);
spi_finalize_current_message(master);
return 0;
} }
static void s3c64xx_spi_work(struct work_struct *work) static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
{ {
struct s3c64xx_spi_driver_data *sdd = container_of(work, struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
struct s3c64xx_spi_driver_data, work);
unsigned long flags;
/* Acquire DMA channels */ /* Acquire DMA channels */
while (!acquire_dma(sdd)) while (!acquire_dma(sdd))
...@@ -785,61 +782,18 @@ static void s3c64xx_spi_work(struct work_struct *work) ...@@ -785,61 +782,18 @@ static void s3c64xx_spi_work(struct work_struct *work)
pm_runtime_get_sync(&sdd->pdev->dev); pm_runtime_get_sync(&sdd->pdev->dev);
spin_lock_irqsave(&sdd->lock, flags); return 0;
}
while (!list_empty(&sdd->queue)
&& !(sdd->state & SUSPND)) {
struct spi_message *msg;
msg = container_of(sdd->queue.next, struct spi_message, queue);
list_del_init(&msg->queue);
/* Set Xfer busy flag */
sdd->state |= SPIBUSY;
spin_unlock_irqrestore(&sdd->lock, flags);
handle_msg(sdd, msg);
spin_lock_irqsave(&sdd->lock, flags);
sdd->state &= ~SPIBUSY;
}
spin_unlock_irqrestore(&sdd->lock, flags); static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
/* Free DMA channels */ /* Free DMA channels */
sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client); sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client); sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
pm_runtime_put(&sdd->pdev->dev); pm_runtime_put(&sdd->pdev->dev);
}
static int s3c64xx_spi_transfer(struct spi_device *spi,
struct spi_message *msg)
{
struct s3c64xx_spi_driver_data *sdd;
unsigned long flags;
sdd = spi_master_get_devdata(spi->master);
spin_lock_irqsave(&sdd->lock, flags);
if (sdd->state & SUSPND) {
spin_unlock_irqrestore(&sdd->lock, flags);
return -ESHUTDOWN;
}
msg->status = -EINPROGRESS;
msg->actual_length = 0;
list_add_tail(&msg->queue, &sdd->queue);
queue_work(sdd->workqueue, &sdd->work);
spin_unlock_irqrestore(&sdd->lock, flags);
return 0; return 0;
} }
...@@ -879,13 +833,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi) ...@@ -879,13 +833,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
} }
} }
if (sdd->state & SUSPND) {
spin_unlock_irqrestore(&sdd->lock, flags);
dev_err(&spi->dev,
"setup: SPI-%d not active!\n", spi->master->bus_num);
return -ESHUTDOWN;
}
spin_unlock_irqrestore(&sdd->lock, flags); spin_unlock_irqrestore(&sdd->lock, flags);
if (spi->bits_per_word != 8 if (spi->bits_per_word != 8
...@@ -1073,7 +1020,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1073,7 +1020,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->setup = s3c64xx_spi_setup; master->setup = s3c64xx_spi_setup;
master->transfer = s3c64xx_spi_transfer; master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
master->transfer_one_message = s3c64xx_spi_transfer_one_message;
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs; master->num_chipselect = sci->num_cs;
master->dma_alignment = 8; master->dma_alignment = 8;
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
...@@ -1128,27 +1077,18 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1128,27 +1077,18 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
goto err6; goto err6;
} }
sdd->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (sdd->workqueue == NULL) {
dev_err(&pdev->dev, "Unable to create workqueue\n");
ret = -ENOMEM;
goto err7;
}
/* Setup Deufult Mode */ /* Setup Deufult Mode */
s3c64xx_spi_hwinit(sdd, pdev->id); s3c64xx_spi_hwinit(sdd, pdev->id);
spin_lock_init(&sdd->lock); spin_lock_init(&sdd->lock);
init_completion(&sdd->xfer_completion); init_completion(&sdd->xfer_completion);
INIT_WORK(&sdd->work, s3c64xx_spi_work);
INIT_LIST_HEAD(&sdd->queue); INIT_LIST_HEAD(&sdd->queue);
ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd); ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd);
if (ret != 0) { if (ret != 0) {
dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
irq, ret); irq, ret);
goto err8; goto err7;
} }
writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN | writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
...@@ -1158,7 +1098,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1158,7 +1098,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
if (spi_register_master(master)) { if (spi_register_master(master)) {
dev_err(&pdev->dev, "cannot register SPI master\n"); dev_err(&pdev->dev, "cannot register SPI master\n");
ret = -EBUSY; ret = -EBUSY;
goto err9; goto err8;
} }
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d " dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
...@@ -1172,10 +1112,8 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1172,10 +1112,8 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
return 0; return 0;
err9:
free_irq(irq, sdd);
err8: err8:
destroy_workqueue(sdd->workqueue); free_irq(irq, sdd);
err7: err7:
clk_disable(sdd->src_clk); clk_disable(sdd->src_clk);
err6: err6:
...@@ -1201,25 +1139,15 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) ...@@ -1201,25 +1139,15 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
struct resource *mem_res; struct resource *mem_res;
unsigned long flags;
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
spin_lock_irqsave(&sdd->lock, flags);
sdd->state |= SUSPND;
spin_unlock_irqrestore(&sdd->lock, flags);
while (sdd->state & SPIBUSY)
msleep(10);
spi_unregister_master(master); spi_unregister_master(master);
writel(0, sdd->regs + S3C64XX_SPI_INT_EN); writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
free_irq(platform_get_irq(pdev, 0), sdd); free_irq(platform_get_irq(pdev, 0), sdd);
destroy_workqueue(sdd->workqueue);
clk_disable(sdd->src_clk); clk_disable(sdd->src_clk);
clk_put(sdd->src_clk); clk_put(sdd->src_clk);
...@@ -1243,14 +1171,8 @@ static int s3c64xx_spi_suspend(struct device *dev) ...@@ -1243,14 +1171,8 @@ static int s3c64xx_spi_suspend(struct device *dev)
{ {
struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
unsigned long flags;
spin_lock_irqsave(&sdd->lock, flags);
sdd->state |= SUSPND;
spin_unlock_irqrestore(&sdd->lock, flags);
while (sdd->state & SPIBUSY) spi_master_suspend(master);
msleep(10);
/* Disable the clock */ /* Disable the clock */
clk_disable(sdd->src_clk); clk_disable(sdd->src_clk);
...@@ -1267,7 +1189,6 @@ static int s3c64xx_spi_resume(struct device *dev) ...@@ -1267,7 +1189,6 @@ static int s3c64xx_spi_resume(struct device *dev)
struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
unsigned long flags;
sci->cfg_gpio(pdev); sci->cfg_gpio(pdev);
...@@ -1277,9 +1198,7 @@ static int s3c64xx_spi_resume(struct device *dev) ...@@ -1277,9 +1198,7 @@ static int s3c64xx_spi_resume(struct device *dev)
s3c64xx_spi_hwinit(sdd, pdev->id); s3c64xx_spi_hwinit(sdd, pdev->id);
spin_lock_irqsave(&sdd->lock, flags); spi_master_resume(master);
sdd->state &= ~SUSPND;
spin_unlock_irqrestore(&sdd->lock, flags);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment