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 /drivers/spi/spi-dw.c | |
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>
Diffstat (limited to 'drivers/spi/spi-dw.c')
-rw-r--r-- | drivers/spi/spi-dw.c | 183 |
1 files changed, 15 insertions, 168 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; |