diff options
Diffstat (limited to 'drivers/spi/spi-dw.c')
-rw-r--r-- | drivers/spi/spi-dw.c | 197 |
1 files changed, 22 insertions, 175 deletions
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 712ac5629cd4..29f33143b795 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/spi/spi.h> | 26 | #include <linux/spi/spi.h> |
27 | #include <linux/gpio.h> | ||
27 | 28 | ||
28 | #include "spi-dw.h" | 29 | #include "spi-dw.h" |
29 | 30 | ||
@@ -36,12 +37,6 @@ | |||
36 | #define DONE_STATE ((void *)2) | 37 | #define DONE_STATE ((void *)2) |
37 | #define ERROR_STATE ((void *)-1) | 38 | #define ERROR_STATE ((void *)-1) |
38 | 39 | ||
39 | #define QUEUE_RUNNING 0 | ||
40 | #define QUEUE_STOPPED 1 | ||
41 | |||
42 | #define MRST_SPI_DEASSERT 0 | ||
43 | #define MRST_SPI_ASSERT 1 | ||
44 | |||
45 | /* Slave spi_dev related */ | 40 | /* Slave spi_dev related */ |
46 | struct chip_data { | 41 | struct chip_data { |
47 | u16 cr0; | 42 | u16 cr0; |
@@ -263,28 +258,22 @@ static int map_dma_buffers(struct dw_spi *dws) | |||
263 | static void giveback(struct dw_spi *dws) | 258 | static void giveback(struct dw_spi *dws) |
264 | { | 259 | { |
265 | struct spi_transfer *last_transfer; | 260 | struct spi_transfer *last_transfer; |
266 | unsigned long flags; | ||
267 | struct spi_message *msg; | 261 | struct spi_message *msg; |
268 | 262 | ||
269 | spin_lock_irqsave(&dws->lock, flags); | ||
270 | msg = dws->cur_msg; | 263 | msg = dws->cur_msg; |
271 | dws->cur_msg = NULL; | 264 | dws->cur_msg = NULL; |
272 | dws->cur_transfer = NULL; | 265 | dws->cur_transfer = NULL; |
273 | dws->prev_chip = dws->cur_chip; | 266 | dws->prev_chip = dws->cur_chip; |
274 | dws->cur_chip = NULL; | 267 | dws->cur_chip = NULL; |
275 | dws->dma_mapped = 0; | 268 | dws->dma_mapped = 0; |
276 | queue_work(dws->workqueue, &dws->pump_messages); | ||
277 | spin_unlock_irqrestore(&dws->lock, flags); | ||
278 | 269 | ||
279 | last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, | 270 | last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, |
280 | transfer_list); | 271 | transfer_list); |
281 | 272 | ||
282 | if (!last_transfer->cs_change && dws->cs_control) | 273 | if (!last_transfer->cs_change) |
283 | dws->cs_control(MRST_SPI_DEASSERT); | 274 | spi_chip_sel(dws, dws->cur_msg->spi, 0); |
284 | 275 | ||
285 | msg->state = NULL; | 276 | spi_finalize_current_message(dws->master); |
286 | if (msg->complete) | ||
287 | msg->complete(msg->context); | ||
288 | } | 277 | } |
289 | 278 | ||
290 | static void int_error_stop(struct dw_spi *dws, const char *msg) | 279 | static void int_error_stop(struct dw_spi *dws, const char *msg) |
@@ -502,7 +491,7 @@ static void pump_transfers(unsigned long data) | |||
502 | dw_writew(dws, DW_SPI_CTRL0, cr0); | 491 | dw_writew(dws, DW_SPI_CTRL0, cr0); |
503 | 492 | ||
504 | spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); | 493 | spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); |
505 | spi_chip_sel(dws, spi->chip_select); | 494 | spi_chip_sel(dws, spi, 1); |
506 | 495 | ||
507 | /* Set the interrupt mask, for poll mode just disable all int */ | 496 | /* Set the interrupt mask, for poll mode just disable all int */ |
508 | spi_mask_intr(dws, 0xff); | 497 | spi_mask_intr(dws, 0xff); |
@@ -529,30 +518,12 @@ early_exit: | |||
529 | return; | 518 | return; |
530 | } | 519 | } |
531 | 520 | ||
532 | static void pump_messages(struct work_struct *work) | 521 | static int dw_spi_transfer_one_message(struct spi_master *master, |
522 | struct spi_message *msg) | ||
533 | { | 523 | { |
534 | struct dw_spi *dws = | 524 | 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 | 525 | ||
526 | dws->cur_msg = msg; | ||
556 | /* Initial message state*/ | 527 | /* Initial message state*/ |
557 | dws->cur_msg->state = START_STATE; | 528 | dws->cur_msg->state = START_STATE; |
558 | dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, | 529 | dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, |
@@ -560,46 +531,9 @@ static void pump_messages(struct work_struct *work) | |||
560 | transfer_list); | 531 | transfer_list); |
561 | dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); | 532 | dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); |
562 | 533 | ||
563 | /* Mark as busy and launch transfers */ | 534 | /* Launch transfers */ |
564 | tasklet_schedule(&dws->pump_transfers); | 535 | tasklet_schedule(&dws->pump_transfers); |
565 | 536 | ||
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; | 537 | return 0; |
604 | } | 538 | } |
605 | 539 | ||
@@ -608,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi) | |||
608 | { | 542 | { |
609 | struct dw_spi_chip *chip_info = NULL; | 543 | struct dw_spi_chip *chip_info = NULL; |
610 | struct chip_data *chip; | 544 | struct chip_data *chip; |
545 | int ret; | ||
611 | 546 | ||
612 | /* Only alloc on first setup */ | 547 | /* Only alloc on first setup */ |
613 | chip = spi_get_ctldata(spi); | 548 | chip = spi_get_ctldata(spi); |
@@ -661,81 +596,13 @@ static int dw_spi_setup(struct spi_device *spi) | |||
661 | | (spi->mode << SPI_MODE_OFFSET) | 596 | | (spi->mode << SPI_MODE_OFFSET) |
662 | | (chip->tmode << SPI_TMOD_OFFSET); | 597 | | (chip->tmode << SPI_TMOD_OFFSET); |
663 | 598 | ||
664 | return 0; | 599 | if (gpio_is_valid(spi->cs_gpio)) { |
665 | } | 600 | ret = gpio_direction_output(spi->cs_gpio, |
666 | 601 | !(spi->mode & SPI_CS_HIGH)); | |
667 | static int init_queue(struct dw_spi *dws) | 602 | if (ret) |
668 | { | 603 | return ret; |
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 | { | ||
689 | unsigned long flags; | ||
690 | |||
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 | } | 604 | } |
697 | 605 | ||
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; | 606 | return 0; |
740 | } | 607 | } |
741 | 608 | ||
@@ -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; |