diff options
| author | Baruch Siach <baruch@tkos.co.il> | 2014-01-31 05:07:44 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@linaro.org> | 2014-04-24 13:01:05 -0400 |
| commit | ec37e8e1f0e376776dde5e9539af414d2ec31f71 (patch) | |
| tree | 95f7a70b3b9838d15852cbc0c749917f3ce1fe0c | |
| parent | c9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff) | |
spi: dw: migrate to generic queue infrastructure
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Mark Brown <broonie@linaro.org>
| -rw-r--r-- | drivers/spi/spi-dw.c | 183 | ||||
| -rw-r--r-- | drivers/spi/spi-dw.h | 8 |
2 files changed, 15 insertions, 176 deletions
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 712ac5629cd4..357869a704d6 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c | |||
| @@ -36,9 +36,6 @@ | |||
| 36 | #define DONE_STATE ((void *)2) | 36 | #define DONE_STATE ((void *)2) |
| 37 | #define ERROR_STATE ((void *)-1) | 37 | #define ERROR_STATE ((void *)-1) |
| 38 | 38 | ||
| 39 | #define QUEUE_RUNNING 0 | ||
| 40 | #define QUEUE_STOPPED 1 | ||
| 41 | |||
| 42 | #define MRST_SPI_DEASSERT 0 | 39 | #define MRST_SPI_DEASSERT 0 |
| 43 | #define MRST_SPI_ASSERT 1 | 40 | #define MRST_SPI_ASSERT 1 |
| 44 | 41 | ||
| @@ -263,18 +260,14 @@ static int map_dma_buffers(struct dw_spi *dws) | |||
| 263 | static void giveback(struct dw_spi *dws) | 260 | static void giveback(struct dw_spi *dws) |
| 264 | { | 261 | { |
| 265 | struct spi_transfer *last_transfer; | 262 | struct spi_transfer *last_transfer; |
| 266 | unsigned long flags; | ||
| 267 | struct spi_message *msg; | 263 | struct spi_message *msg; |
| 268 | 264 | ||
| 269 | spin_lock_irqsave(&dws->lock, flags); | ||
| 270 | msg = dws->cur_msg; | 265 | msg = dws->cur_msg; |
| 271 | dws->cur_msg = NULL; | 266 | dws->cur_msg = NULL; |
| 272 | dws->cur_transfer = NULL; | 267 | dws->cur_transfer = NULL; |
| 273 | dws->prev_chip = dws->cur_chip; | 268 | dws->prev_chip = dws->cur_chip; |
| 274 | dws->cur_chip = NULL; | 269 | dws->cur_chip = NULL; |
| 275 | dws->dma_mapped = 0; | 270 | dws->dma_mapped = 0; |
| 276 | queue_work(dws->workqueue, &dws->pump_messages); | ||
| 277 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 278 | 271 | ||
| 279 | last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, | 272 | last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, |
| 280 | transfer_list); | 273 | transfer_list); |
| @@ -282,9 +275,7 @@ static void giveback(struct dw_spi *dws) | |||
| 282 | if (!last_transfer->cs_change && dws->cs_control) | 275 | if (!last_transfer->cs_change && dws->cs_control) |
| 283 | dws->cs_control(MRST_SPI_DEASSERT); | 276 | dws->cs_control(MRST_SPI_DEASSERT); |
| 284 | 277 | ||
| 285 | msg->state = NULL; | 278 | spi_finalize_current_message(dws->master); |
| 286 | if (msg->complete) | ||
| 287 | msg->complete(msg->context); | ||
| 288 | } | 279 | } |
| 289 | 280 | ||
| 290 | static void int_error_stop(struct dw_spi *dws, const char *msg) | 281 | static void int_error_stop(struct dw_spi *dws, const char *msg) |
| @@ -529,30 +520,12 @@ early_exit: | |||
| 529 | return; | 520 | return; |
| 530 | } | 521 | } |
| 531 | 522 | ||
| 532 | static void pump_messages(struct work_struct *work) | 523 | static int dw_spi_transfer_one_message(struct spi_master *master, |
| 524 | struct spi_message *msg) | ||
| 533 | { | 525 | { |
| 534 | struct dw_spi *dws = | 526 | struct dw_spi *dws = spi_master_get_devdata(master); |
| 535 | container_of(work, struct dw_spi, pump_messages); | ||
| 536 | unsigned long flags; | ||
| 537 | |||
| 538 | /* Lock queue and check for queue work */ | ||
| 539 | spin_lock_irqsave(&dws->lock, flags); | ||
| 540 | if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) { | ||
| 541 | dws->busy = 0; | ||
| 542 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 543 | return; | ||
| 544 | } | ||
| 545 | |||
| 546 | /* Make sure we are not already running a message */ | ||
| 547 | if (dws->cur_msg) { | ||
| 548 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 549 | return; | ||
| 550 | } | ||
| 551 | |||
| 552 | /* Extract head of queue */ | ||
| 553 | dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue); | ||
| 554 | list_del_init(&dws->cur_msg->queue); | ||
| 555 | 527 | ||
| 528 | dws->cur_msg = msg; | ||
| 556 | /* Initial message state*/ | 529 | /* Initial message state*/ |
| 557 | dws->cur_msg->state = START_STATE; | 530 | dws->cur_msg->state = START_STATE; |
| 558 | dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, | 531 | dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, |
| @@ -560,46 +533,9 @@ static void pump_messages(struct work_struct *work) | |||
| 560 | transfer_list); | 533 | transfer_list); |
| 561 | dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); | 534 | dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); |
| 562 | 535 | ||
| 563 | /* Mark as busy and launch transfers */ | 536 | /* Launch transfers */ |
| 564 | tasklet_schedule(&dws->pump_transfers); | 537 | tasklet_schedule(&dws->pump_transfers); |
| 565 | 538 | ||
| 566 | dws->busy = 1; | ||
| 567 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 568 | } | ||
| 569 | |||
| 570 | /* spi_device use this to queue in their spi_msg */ | ||
| 571 | static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg) | ||
| 572 | { | ||
| 573 | struct dw_spi *dws = spi_master_get_devdata(spi->master); | ||
| 574 | unsigned long flags; | ||
| 575 | |||
| 576 | spin_lock_irqsave(&dws->lock, flags); | ||
| 577 | |||
| 578 | if (dws->run == QUEUE_STOPPED) { | ||
| 579 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 580 | return -ESHUTDOWN; | ||
| 581 | } | ||
| 582 | |||
| 583 | msg->actual_length = 0; | ||
| 584 | msg->status = -EINPROGRESS; | ||
| 585 | msg->state = START_STATE; | ||
| 586 | |||
| 587 | list_add_tail(&msg->queue, &dws->queue); | ||
| 588 | |||
| 589 | if (dws->run == QUEUE_RUNNING && !dws->busy) { | ||
| 590 | |||
| 591 | if (dws->cur_transfer || dws->cur_msg) | ||
| 592 | queue_work(dws->workqueue, | ||
| 593 | &dws->pump_messages); | ||
| 594 | else { | ||
| 595 | /* If no other data transaction in air, just go */ | ||
| 596 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 597 | pump_messages(&dws->pump_messages); | ||
| 598 | return 0; | ||
| 599 | } | ||
| 600 | } | ||
| 601 | |||
| 602 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 603 | return 0; | 539 | return 0; |
| 604 | } | 540 | } |
| 605 | 541 | ||
| @@ -664,79 +600,10 @@ static int dw_spi_setup(struct spi_device *spi) | |||
| 664 | return 0; | 600 | return 0; |
| 665 | } | 601 | } |
| 666 | 602 | ||
| 667 | static int init_queue(struct dw_spi *dws) | 603 | static void dw_spi_cleanup(struct spi_device *spi) |
| 668 | { | ||
| 669 | INIT_LIST_HEAD(&dws->queue); | ||
| 670 | spin_lock_init(&dws->lock); | ||
| 671 | |||
| 672 | dws->run = QUEUE_STOPPED; | ||
| 673 | dws->busy = 0; | ||
| 674 | |||
| 675 | tasklet_init(&dws->pump_transfers, | ||
| 676 | pump_transfers, (unsigned long)dws); | ||
| 677 | |||
| 678 | INIT_WORK(&dws->pump_messages, pump_messages); | ||
| 679 | dws->workqueue = create_singlethread_workqueue( | ||
| 680 | dev_name(dws->master->dev.parent)); | ||
| 681 | if (dws->workqueue == NULL) | ||
| 682 | return -EBUSY; | ||
| 683 | |||
| 684 | return 0; | ||
| 685 | } | ||
| 686 | |||
| 687 | static int start_queue(struct dw_spi *dws) | ||
| 688 | { | 604 | { |
| 689 | unsigned long flags; | 605 | struct chip_data *chip = spi_get_ctldata(spi); |
| 690 | 606 | kfree(chip); | |
| 691 | spin_lock_irqsave(&dws->lock, flags); | ||
| 692 | |||
| 693 | if (dws->run == QUEUE_RUNNING || dws->busy) { | ||
| 694 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 695 | return -EBUSY; | ||
| 696 | } | ||
| 697 | |||
| 698 | dws->run = QUEUE_RUNNING; | ||
| 699 | dws->cur_msg = NULL; | ||
| 700 | dws->cur_transfer = NULL; | ||
| 701 | dws->cur_chip = NULL; | ||
| 702 | dws->prev_chip = NULL; | ||
| 703 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 704 | |||
| 705 | queue_work(dws->workqueue, &dws->pump_messages); | ||
| 706 | |||
| 707 | return 0; | ||
| 708 | } | ||
| 709 | |||
| 710 | static int stop_queue(struct dw_spi *dws) | ||
| 711 | { | ||
| 712 | unsigned long flags; | ||
| 713 | unsigned limit = 50; | ||
| 714 | int status = 0; | ||
| 715 | |||
| 716 | spin_lock_irqsave(&dws->lock, flags); | ||
| 717 | dws->run = QUEUE_STOPPED; | ||
| 718 | while ((!list_empty(&dws->queue) || dws->busy) && limit--) { | ||
| 719 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 720 | msleep(10); | ||
| 721 | spin_lock_irqsave(&dws->lock, flags); | ||
| 722 | } | ||
| 723 | |||
| 724 | if (!list_empty(&dws->queue) || dws->busy) | ||
| 725 | status = -EBUSY; | ||
| 726 | spin_unlock_irqrestore(&dws->lock, flags); | ||
| 727 | |||
| 728 | return status; | ||
| 729 | } | ||
| 730 | |||
| 731 | static int destroy_queue(struct dw_spi *dws) | ||
| 732 | { | ||
| 733 | int status; | ||
| 734 | |||
| 735 | status = stop_queue(dws); | ||
| 736 | if (status != 0) | ||
| 737 | return status; | ||
| 738 | destroy_workqueue(dws->workqueue); | ||
| 739 | return 0; | ||
| 740 | } | 607 | } |
| 741 | 608 | ||
| 742 | /* Restart the controller, disable all interrupts, clean rx fifo */ | 609 | /* Restart the controller, disable all interrupts, clean rx fifo */ |
| @@ -794,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) | |||
| 794 | master->bus_num = dws->bus_num; | 661 | master->bus_num = dws->bus_num; |
| 795 | master->num_chipselect = dws->num_cs; | 662 | master->num_chipselect = dws->num_cs; |
| 796 | master->setup = dw_spi_setup; | 663 | master->setup = dw_spi_setup; |
| 797 | master->transfer = dw_spi_transfer; | 664 | master->transfer_one_message = dw_spi_transfer_one_message; |
| 798 | master->max_speed_hz = dws->max_freq; | 665 | master->max_speed_hz = dws->max_freq; |
| 799 | 666 | ||
| 800 | /* Basic HW init */ | 667 | /* Basic HW init */ |
| @@ -808,33 +675,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) | |||
| 808 | } | 675 | } |
| 809 | } | 676 | } |
| 810 | 677 | ||
| 811 | /* Initial and start queue */ | 678 | tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws); |
| 812 | ret = init_queue(dws); | ||
| 813 | if (ret) { | ||
| 814 | dev_err(&master->dev, "problem initializing queue\n"); | ||
| 815 | goto err_diable_hw; | ||
| 816 | } | ||
| 817 | ret = start_queue(dws); | ||
| 818 | if (ret) { | ||
| 819 | dev_err(&master->dev, "problem starting queue\n"); | ||
| 820 | goto err_diable_hw; | ||
| 821 | } | ||
| 822 | 679 | ||
| 823 | spi_master_set_devdata(master, dws); | 680 | spi_master_set_devdata(master, dws); |
| 824 | ret = devm_spi_register_master(dev, master); | 681 | ret = devm_spi_register_master(dev, master); |
| 825 | if (ret) { | 682 | if (ret) { |
| 826 | dev_err(&master->dev, "problem registering spi master\n"); | 683 | dev_err(&master->dev, "problem registering spi master\n"); |
| 827 | goto err_queue_alloc; | 684 | goto err_dma_exit; |
| 828 | } | 685 | } |
| 829 | 686 | ||
| 830 | mrst_spi_debugfs_init(dws); | 687 | mrst_spi_debugfs_init(dws); |
| 831 | return 0; | 688 | return 0; |
| 832 | 689 | ||
| 833 | err_queue_alloc: | 690 | err_dma_exit: |
| 834 | destroy_queue(dws); | ||
| 835 | if (dws->dma_ops && dws->dma_ops->dma_exit) | 691 | if (dws->dma_ops && dws->dma_ops->dma_exit) |
| 836 | dws->dma_ops->dma_exit(dws); | 692 | dws->dma_ops->dma_exit(dws); |
| 837 | err_diable_hw: | ||
| 838 | spi_enable_chip(dws, 0); | 693 | spi_enable_chip(dws, 0); |
| 839 | err_free_master: | 694 | err_free_master: |
| 840 | spi_master_put(master); | 695 | spi_master_put(master); |
| @@ -844,18 +699,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host); | |||
| 844 | 699 | ||
| 845 | void dw_spi_remove_host(struct dw_spi *dws) | 700 | void dw_spi_remove_host(struct dw_spi *dws) |
| 846 | { | 701 | { |
| 847 | int status = 0; | ||
| 848 | |||
| 849 | if (!dws) | 702 | if (!dws) |
| 850 | return; | 703 | return; |
| 851 | mrst_spi_debugfs_remove(dws); | 704 | mrst_spi_debugfs_remove(dws); |
| 852 | 705 | ||
| 853 | /* Remove the queue */ | ||
| 854 | status = destroy_queue(dws); | ||
| 855 | if (status != 0) | ||
| 856 | dev_err(&dws->master->dev, | ||
| 857 | "dw_spi_remove: workqueue will not complete, message memory not freed\n"); | ||
| 858 | |||
| 859 | if (dws->dma_ops && dws->dma_ops->dma_exit) | 706 | if (dws->dma_ops && dws->dma_ops->dma_exit) |
| 860 | dws->dma_ops->dma_exit(dws); | 707 | dws->dma_ops->dma_exit(dws); |
| 861 | spi_enable_chip(dws, 0); | 708 | spi_enable_chip(dws, 0); |
| @@ -868,7 +715,7 @@ int dw_spi_suspend_host(struct dw_spi *dws) | |||
| 868 | { | 715 | { |
| 869 | int ret = 0; | 716 | int ret = 0; |
| 870 | 717 | ||
| 871 | ret = stop_queue(dws); | 718 | ret = spi_master_suspend(dws->master); |
| 872 | if (ret) | 719 | if (ret) |
| 873 | return ret; | 720 | return ret; |
| 874 | spi_enable_chip(dws, 0); | 721 | spi_enable_chip(dws, 0); |
| @@ -882,7 +729,7 @@ int dw_spi_resume_host(struct dw_spi *dws) | |||
| 882 | int ret; | 729 | int ret; |
| 883 | 730 | ||
| 884 | spi_hw_init(dws); | 731 | spi_hw_init(dws); |
| 885 | ret = start_queue(dws); | 732 | ret = spi_master_resume(dws->master); |
| 886 | if (ret) | 733 | if (ret) |
| 887 | dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); | 734 | dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); |
| 888 | return ret; | 735 | return ret; |
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 587643dae11e..3fd7ab599ab4 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h | |||
| @@ -104,14 +104,6 @@ struct dw_spi { | |||
| 104 | u16 bus_num; | 104 | u16 bus_num; |
| 105 | u16 num_cs; /* supported slave numbers */ | 105 | u16 num_cs; /* supported slave numbers */ |
| 106 | 106 | ||
| 107 | /* Driver message queue */ | ||
| 108 | struct workqueue_struct *workqueue; | ||
| 109 | struct work_struct pump_messages; | ||
| 110 | spinlock_t lock; | ||
| 111 | struct list_head queue; | ||
| 112 | int busy; | ||
| 113 | int run; | ||
| 114 | |||
| 115 | /* Message Transfer pump */ | 107 | /* Message Transfer pump */ |
| 116 | struct tasklet_struct pump_transfers; | 108 | struct tasklet_struct pump_transfers; |
| 117 | 109 | ||
