diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2013-01-22 05:26:26 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-01-26 02:21:37 -0500 |
commit | 7f86bde90e2e1f693d93922fc0f4d50f001ce1a5 (patch) | |
tree | 9c6a8df5f8b08d5b3b9a2f79ff703327ac263ecc /drivers/spi | |
parent | 2b9b84f497638ebd60a762cb1c7fa7b4ff7dce4d (diff) |
spi/pxa2xx: convert to the pump message infrastructure
The SPI core provides infrastructure for standard message queueing so use
that instead of handling everything in the driver. This simplifies the
driver.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 212 |
1 files changed, 12 insertions, 200 deletions
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index ef0a78650e96..a241891355db 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c | |||
@@ -85,9 +85,6 @@ DEFINE_SSP_REG(SSPSP, 0x2c) | |||
85 | #define DONE_STATE ((void*)2) | 85 | #define DONE_STATE ((void*)2) |
86 | #define ERROR_STATE ((void*)-1) | 86 | #define ERROR_STATE ((void*)-1) |
87 | 87 | ||
88 | #define QUEUE_RUNNING 0 | ||
89 | #define QUEUE_STOPPED 1 | ||
90 | |||
91 | struct driver_data { | 88 | struct driver_data { |
92 | /* Driver model hookup */ | 89 | /* Driver model hookup */ |
93 | struct platform_device *pdev; | 90 | struct platform_device *pdev; |
@@ -117,14 +114,6 @@ struct driver_data { | |||
117 | u32 clear_sr; | 114 | u32 clear_sr; |
118 | u32 mask_sr; | 115 | u32 mask_sr; |
119 | 116 | ||
120 | /* Driver message queue */ | ||
121 | struct workqueue_struct *workqueue; | ||
122 | struct work_struct pump_messages; | ||
123 | spinlock_t lock; | ||
124 | struct list_head queue; | ||
125 | int busy; | ||
126 | int run; | ||
127 | |||
128 | /* Message Transfer pump */ | 117 | /* Message Transfer pump */ |
129 | struct tasklet_struct pump_transfers; | 118 | struct tasklet_struct pump_transfers; |
130 | 119 | ||
@@ -173,8 +162,6 @@ struct chip_data { | |||
173 | void (*cs_control)(u32 command); | 162 | void (*cs_control)(u32 command); |
174 | }; | 163 | }; |
175 | 164 | ||
176 | static void pump_messages(struct work_struct *work); | ||
177 | |||
178 | static void cs_assert(struct driver_data *drv_data) | 165 | static void cs_assert(struct driver_data *drv_data) |
179 | { | 166 | { |
180 | struct chip_data *chip = drv_data->cur_chip; | 167 | struct chip_data *chip = drv_data->cur_chip; |
@@ -444,15 +431,11 @@ static void unmap_dma_buffers(struct driver_data *drv_data) | |||
444 | static void giveback(struct driver_data *drv_data) | 431 | static void giveback(struct driver_data *drv_data) |
445 | { | 432 | { |
446 | struct spi_transfer* last_transfer; | 433 | struct spi_transfer* last_transfer; |
447 | unsigned long flags; | ||
448 | struct spi_message *msg; | 434 | struct spi_message *msg; |
449 | 435 | ||
450 | spin_lock_irqsave(&drv_data->lock, flags); | ||
451 | msg = drv_data->cur_msg; | 436 | msg = drv_data->cur_msg; |
452 | drv_data->cur_msg = NULL; | 437 | drv_data->cur_msg = NULL; |
453 | drv_data->cur_transfer = NULL; | 438 | drv_data->cur_transfer = NULL; |
454 | queue_work(drv_data->workqueue, &drv_data->pump_messages); | ||
455 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
456 | 439 | ||
457 | last_transfer = list_entry(msg->transfers.prev, | 440 | last_transfer = list_entry(msg->transfers.prev, |
458 | struct spi_transfer, | 441 | struct spi_transfer, |
@@ -481,13 +464,7 @@ static void giveback(struct driver_data *drv_data) | |||
481 | */ | 464 | */ |
482 | 465 | ||
483 | /* get a pointer to the next message, if any */ | 466 | /* get a pointer to the next message, if any */ |
484 | spin_lock_irqsave(&drv_data->lock, flags); | 467 | next_msg = spi_get_next_queued_message(drv_data->master); |
485 | if (list_empty(&drv_data->queue)) | ||
486 | next_msg = NULL; | ||
487 | else | ||
488 | next_msg = list_entry(drv_data->queue.next, | ||
489 | struct spi_message, queue); | ||
490 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
491 | 468 | ||
492 | /* see if the next and current messages point | 469 | /* see if the next and current messages point |
493 | * to the same chip | 470 | * to the same chip |
@@ -498,10 +475,7 @@ static void giveback(struct driver_data *drv_data) | |||
498 | cs_deassert(drv_data); | 475 | cs_deassert(drv_data); |
499 | } | 476 | } |
500 | 477 | ||
501 | msg->state = NULL; | 478 | spi_finalize_current_message(drv_data->master); |
502 | if (msg->complete) | ||
503 | msg->complete(msg->context); | ||
504 | |||
505 | drv_data->cur_chip = NULL; | 479 | drv_data->cur_chip = NULL; |
506 | } | 480 | } |
507 | 481 | ||
@@ -1176,31 +1150,12 @@ static void pump_transfers(unsigned long data) | |||
1176 | write_SSCR1(cr1, reg); | 1150 | write_SSCR1(cr1, reg); |
1177 | } | 1151 | } |
1178 | 1152 | ||
1179 | static void pump_messages(struct work_struct *work) | 1153 | static int pxa2xx_spi_transfer_one_message(struct spi_master *master, |
1154 | struct spi_message *msg) | ||
1180 | { | 1155 | { |
1181 | struct driver_data *drv_data = | 1156 | struct driver_data *drv_data = spi_master_get_devdata(master); |
1182 | container_of(work, struct driver_data, pump_messages); | ||
1183 | unsigned long flags; | ||
1184 | |||
1185 | /* Lock queue and check for queue work */ | ||
1186 | spin_lock_irqsave(&drv_data->lock, flags); | ||
1187 | if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) { | ||
1188 | drv_data->busy = 0; | ||
1189 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1190 | return; | ||
1191 | } | ||
1192 | |||
1193 | /* Make sure we are not already running a message */ | ||
1194 | if (drv_data->cur_msg) { | ||
1195 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1196 | return; | ||
1197 | } | ||
1198 | |||
1199 | /* Extract head of queue */ | ||
1200 | drv_data->cur_msg = list_entry(drv_data->queue.next, | ||
1201 | struct spi_message, queue); | ||
1202 | list_del_init(&drv_data->cur_msg->queue); | ||
1203 | 1157 | ||
1158 | drv_data->cur_msg = msg; | ||
1204 | /* Initial message state*/ | 1159 | /* Initial message state*/ |
1205 | drv_data->cur_msg->state = START_STATE; | 1160 | drv_data->cur_msg->state = START_STATE; |
1206 | drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, | 1161 | drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, |
@@ -1213,34 +1168,6 @@ static void pump_messages(struct work_struct *work) | |||
1213 | 1168 | ||
1214 | /* Mark as busy and launch transfers */ | 1169 | /* Mark as busy and launch transfers */ |
1215 | tasklet_schedule(&drv_data->pump_transfers); | 1170 | tasklet_schedule(&drv_data->pump_transfers); |
1216 | |||
1217 | drv_data->busy = 1; | ||
1218 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1219 | } | ||
1220 | |||
1221 | static int transfer(struct spi_device *spi, struct spi_message *msg) | ||
1222 | { | ||
1223 | struct driver_data *drv_data = spi_master_get_devdata(spi->master); | ||
1224 | unsigned long flags; | ||
1225 | |||
1226 | spin_lock_irqsave(&drv_data->lock, flags); | ||
1227 | |||
1228 | if (drv_data->run == QUEUE_STOPPED) { | ||
1229 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1230 | return -ESHUTDOWN; | ||
1231 | } | ||
1232 | |||
1233 | msg->actual_length = 0; | ||
1234 | msg->status = -EINPROGRESS; | ||
1235 | msg->state = START_STATE; | ||
1236 | |||
1237 | list_add_tail(&msg->queue, &drv_data->queue); | ||
1238 | |||
1239 | if (drv_data->run == QUEUE_RUNNING && !drv_data->busy) | ||
1240 | queue_work(drv_data->workqueue, &drv_data->pump_messages); | ||
1241 | |||
1242 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1243 | |||
1244 | return 0; | 1171 | return 0; |
1245 | } | 1172 | } |
1246 | 1173 | ||
@@ -1438,94 +1365,6 @@ static void cleanup(struct spi_device *spi) | |||
1438 | kfree(chip); | 1365 | kfree(chip); |
1439 | } | 1366 | } |
1440 | 1367 | ||
1441 | static int init_queue(struct driver_data *drv_data) | ||
1442 | { | ||
1443 | INIT_LIST_HEAD(&drv_data->queue); | ||
1444 | spin_lock_init(&drv_data->lock); | ||
1445 | |||
1446 | drv_data->run = QUEUE_STOPPED; | ||
1447 | drv_data->busy = 0; | ||
1448 | |||
1449 | tasklet_init(&drv_data->pump_transfers, | ||
1450 | pump_transfers, (unsigned long)drv_data); | ||
1451 | |||
1452 | INIT_WORK(&drv_data->pump_messages, pump_messages); | ||
1453 | drv_data->workqueue = create_singlethread_workqueue( | ||
1454 | dev_name(drv_data->master->dev.parent)); | ||
1455 | if (drv_data->workqueue == NULL) | ||
1456 | return -EBUSY; | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | static int start_queue(struct driver_data *drv_data) | ||
1462 | { | ||
1463 | unsigned long flags; | ||
1464 | |||
1465 | spin_lock_irqsave(&drv_data->lock, flags); | ||
1466 | |||
1467 | if (drv_data->run == QUEUE_RUNNING || drv_data->busy) { | ||
1468 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1469 | return -EBUSY; | ||
1470 | } | ||
1471 | |||
1472 | drv_data->run = QUEUE_RUNNING; | ||
1473 | drv_data->cur_msg = NULL; | ||
1474 | drv_data->cur_transfer = NULL; | ||
1475 | drv_data->cur_chip = NULL; | ||
1476 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1477 | |||
1478 | queue_work(drv_data->workqueue, &drv_data->pump_messages); | ||
1479 | |||
1480 | return 0; | ||
1481 | } | ||
1482 | |||
1483 | static int stop_queue(struct driver_data *drv_data) | ||
1484 | { | ||
1485 | unsigned long flags; | ||
1486 | unsigned limit = 500; | ||
1487 | int status = 0; | ||
1488 | |||
1489 | spin_lock_irqsave(&drv_data->lock, flags); | ||
1490 | |||
1491 | /* This is a bit lame, but is optimized for the common execution path. | ||
1492 | * A wait_queue on the drv_data->busy could be used, but then the common | ||
1493 | * execution path (pump_messages) would be required to call wake_up or | ||
1494 | * friends on every SPI message. Do this instead */ | ||
1495 | drv_data->run = QUEUE_STOPPED; | ||
1496 | while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { | ||
1497 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1498 | msleep(10); | ||
1499 | spin_lock_irqsave(&drv_data->lock, flags); | ||
1500 | } | ||
1501 | |||
1502 | if (!list_empty(&drv_data->queue) || drv_data->busy) | ||
1503 | status = -EBUSY; | ||
1504 | |||
1505 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
1506 | |||
1507 | return status; | ||
1508 | } | ||
1509 | |||
1510 | static int destroy_queue(struct driver_data *drv_data) | ||
1511 | { | ||
1512 | int status; | ||
1513 | |||
1514 | status = stop_queue(drv_data); | ||
1515 | /* we are unloading the module or failing to load (only two calls | ||
1516 | * to this routine), and neither call can handle a return value. | ||
1517 | * However, destroy_workqueue calls flush_workqueue, and that will | ||
1518 | * block until all work is done. If the reason that stop_queue | ||
1519 | * timed out is that the work will never finish, then it does no | ||
1520 | * good to call destroy_workqueue, so return anyway. */ | ||
1521 | if (status != 0) | ||
1522 | return status; | ||
1523 | |||
1524 | destroy_workqueue(drv_data->workqueue); | ||
1525 | |||
1526 | return 0; | ||
1527 | } | ||
1528 | |||
1529 | static int pxa2xx_spi_probe(struct platform_device *pdev) | 1368 | static int pxa2xx_spi_probe(struct platform_device *pdev) |
1530 | { | 1369 | { |
1531 | struct device *dev = &pdev->dev; | 1370 | struct device *dev = &pdev->dev; |
@@ -1573,7 +1412,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) | |||
1573 | master->dma_alignment = DMA_ALIGNMENT; | 1412 | master->dma_alignment = DMA_ALIGNMENT; |
1574 | master->cleanup = cleanup; | 1413 | master->cleanup = cleanup; |
1575 | master->setup = setup; | 1414 | master->setup = setup; |
1576 | master->transfer = transfer; | 1415 | master->transfer_one_message = pxa2xx_spi_transfer_one_message; |
1577 | 1416 | ||
1578 | drv_data->ssp_type = ssp->type; | 1417 | drv_data->ssp_type = ssp->type; |
1579 | drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT); | 1418 | drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT); |
@@ -1646,31 +1485,19 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) | |||
1646 | write_SSTO(0, drv_data->ioaddr); | 1485 | write_SSTO(0, drv_data->ioaddr); |
1647 | write_SSPSP(0, drv_data->ioaddr); | 1486 | write_SSPSP(0, drv_data->ioaddr); |
1648 | 1487 | ||
1649 | /* Initial and start queue */ | 1488 | tasklet_init(&drv_data->pump_transfers, pump_transfers, |
1650 | status = init_queue(drv_data); | 1489 | (unsigned long)drv_data); |
1651 | if (status != 0) { | ||
1652 | dev_err(&pdev->dev, "problem initializing queue\n"); | ||
1653 | goto out_error_clock_enabled; | ||
1654 | } | ||
1655 | status = start_queue(drv_data); | ||
1656 | if (status != 0) { | ||
1657 | dev_err(&pdev->dev, "problem starting queue\n"); | ||
1658 | goto out_error_clock_enabled; | ||
1659 | } | ||
1660 | 1490 | ||
1661 | /* Register with the SPI framework */ | 1491 | /* Register with the SPI framework */ |
1662 | platform_set_drvdata(pdev, drv_data); | 1492 | platform_set_drvdata(pdev, drv_data); |
1663 | status = spi_register_master(master); | 1493 | status = spi_register_master(master); |
1664 | if (status != 0) { | 1494 | if (status != 0) { |
1665 | dev_err(&pdev->dev, "problem registering spi master\n"); | 1495 | dev_err(&pdev->dev, "problem registering spi master\n"); |
1666 | goto out_error_queue_alloc; | 1496 | goto out_error_clock_enabled; |
1667 | } | 1497 | } |
1668 | 1498 | ||
1669 | return status; | 1499 | return status; |
1670 | 1500 | ||
1671 | out_error_queue_alloc: | ||
1672 | destroy_queue(drv_data); | ||
1673 | |||
1674 | out_error_clock_enabled: | 1501 | out_error_clock_enabled: |
1675 | clk_disable(ssp->clk); | 1502 | clk_disable(ssp->clk); |
1676 | 1503 | ||
@@ -1693,26 +1520,11 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) | |||
1693 | { | 1520 | { |
1694 | struct driver_data *drv_data = platform_get_drvdata(pdev); | 1521 | struct driver_data *drv_data = platform_get_drvdata(pdev); |
1695 | struct ssp_device *ssp; | 1522 | struct ssp_device *ssp; |
1696 | int status = 0; | ||
1697 | 1523 | ||
1698 | if (!drv_data) | 1524 | if (!drv_data) |
1699 | return 0; | 1525 | return 0; |
1700 | ssp = drv_data->ssp; | 1526 | ssp = drv_data->ssp; |
1701 | 1527 | ||
1702 | /* Remove the queue */ | ||
1703 | status = destroy_queue(drv_data); | ||
1704 | if (status != 0) | ||
1705 | /* the kernel does not check the return status of this | ||
1706 | * this routine (mod->exit, within the kernel). Therefore | ||
1707 | * nothing is gained by returning from here, the module is | ||
1708 | * going away regardless, and we should not leave any more | ||
1709 | * resources allocated than necessary. We cannot free the | ||
1710 | * message memory in drv_data->queue, but we can release the | ||
1711 | * resources below. I think the kernel should honor -EBUSY | ||
1712 | * returns but... */ | ||
1713 | dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not " | ||
1714 | "complete, message memory not freed\n"); | ||
1715 | |||
1716 | /* Disable the SSP at the peripheral and SOC level */ | 1528 | /* Disable the SSP at the peripheral and SOC level */ |
1717 | write_SSCR0(0, drv_data->ioaddr); | 1529 | write_SSCR0(0, drv_data->ioaddr); |
1718 | clk_disable(ssp->clk); | 1530 | clk_disable(ssp->clk); |
@@ -1755,7 +1567,7 @@ static int pxa2xx_spi_suspend(struct device *dev) | |||
1755 | struct ssp_device *ssp = drv_data->ssp; | 1567 | struct ssp_device *ssp = drv_data->ssp; |
1756 | int status = 0; | 1568 | int status = 0; |
1757 | 1569 | ||
1758 | status = stop_queue(drv_data); | 1570 | status = spi_master_suspend(drv_data->master); |
1759 | if (status != 0) | 1571 | if (status != 0) |
1760 | return status; | 1572 | return status; |
1761 | write_SSCR0(0, drv_data->ioaddr); | 1573 | write_SSCR0(0, drv_data->ioaddr); |
@@ -1781,7 +1593,7 @@ static int pxa2xx_spi_resume(struct device *dev) | |||
1781 | clk_enable(ssp->clk); | 1593 | clk_enable(ssp->clk); |
1782 | 1594 | ||
1783 | /* Start the queue running */ | 1595 | /* Start the queue running */ |
1784 | status = start_queue(drv_data); | 1596 | status = spi_master_resume(drv_data->master); |
1785 | if (status != 0) { | 1597 | if (status != 0) { |
1786 | dev_err(dev, "problem starting queue (%d)\n", status); | 1598 | dev_err(dev, "problem starting queue (%d)\n", status); |
1787 | return status; | 1599 | return status; |