diff options
author | Mark Brown <broonie@linaro.org> | 2013-10-25 04:51:29 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-10-25 04:51:29 -0400 |
commit | 8211e6b8facd9d0da3e8f6e51657cba8b0af19da (patch) | |
tree | 2f73c2ae7cbbab24bd93998f6f63264eee5c1269 /drivers/spi/spi.c | |
parent | c25b2c9eb36502f81c59df764074a475249a4550 (diff) | |
parent | 0732a9d2a1551e3be5fd8a3ea680deb3d9e56193 (diff) |
Merge remote-tracking branch 'spi/topic/loop' into spi-next
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r-- | drivers/spi/spi.c | 130 |
1 files changed, 129 insertions, 1 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 99c05f639e1b..8d05accf706c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -39,6 +39,9 @@ | |||
39 | #include <linux/ioport.h> | 39 | #include <linux/ioport.h> |
40 | #include <linux/acpi.h> | 40 | #include <linux/acpi.h> |
41 | 41 | ||
42 | #define CREATE_TRACE_POINTS | ||
43 | #include <trace/events/spi.h> | ||
44 | |||
42 | static void spidev_release(struct device *dev) | 45 | static void spidev_release(struct device *dev) |
43 | { | 46 | { |
44 | struct spi_device *spi = to_spi_device(dev); | 47 | struct spi_device *spi = to_spi_device(dev); |
@@ -525,6 +528,95 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) | |||
525 | 528 | ||
526 | /*-------------------------------------------------------------------------*/ | 529 | /*-------------------------------------------------------------------------*/ |
527 | 530 | ||
531 | static void spi_set_cs(struct spi_device *spi, bool enable) | ||
532 | { | ||
533 | if (spi->mode & SPI_CS_HIGH) | ||
534 | enable = !enable; | ||
535 | |||
536 | if (spi->cs_gpio >= 0) | ||
537 | gpio_set_value(spi->cs_gpio, !enable); | ||
538 | else if (spi->master->set_cs) | ||
539 | spi->master->set_cs(spi, !enable); | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * spi_transfer_one_message - Default implementation of transfer_one_message() | ||
544 | * | ||
545 | * This is a standard implementation of transfer_one_message() for | ||
546 | * drivers which impelment a transfer_one() operation. It provides | ||
547 | * standard handling of delays and chip select management. | ||
548 | */ | ||
549 | static int spi_transfer_one_message(struct spi_master *master, | ||
550 | struct spi_message *msg) | ||
551 | { | ||
552 | struct spi_transfer *xfer; | ||
553 | bool cur_cs = true; | ||
554 | bool keep_cs = false; | ||
555 | int ret = 0; | ||
556 | |||
557 | spi_set_cs(msg->spi, true); | ||
558 | |||
559 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | ||
560 | trace_spi_transfer_start(msg, xfer); | ||
561 | |||
562 | INIT_COMPLETION(master->xfer_completion); | ||
563 | |||
564 | ret = master->transfer_one(master, msg->spi, xfer); | ||
565 | if (ret < 0) { | ||
566 | dev_err(&msg->spi->dev, | ||
567 | "SPI transfer failed: %d\n", ret); | ||
568 | goto out; | ||
569 | } | ||
570 | |||
571 | if (ret > 0) | ||
572 | wait_for_completion(&master->xfer_completion); | ||
573 | |||
574 | trace_spi_transfer_stop(msg, xfer); | ||
575 | |||
576 | if (msg->status != -EINPROGRESS) | ||
577 | goto out; | ||
578 | |||
579 | if (xfer->delay_usecs) | ||
580 | udelay(xfer->delay_usecs); | ||
581 | |||
582 | if (xfer->cs_change) { | ||
583 | if (list_is_last(&xfer->transfer_list, | ||
584 | &msg->transfers)) { | ||
585 | keep_cs = true; | ||
586 | } else { | ||
587 | cur_cs = !cur_cs; | ||
588 | spi_set_cs(msg->spi, cur_cs); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | msg->actual_length += xfer->len; | ||
593 | } | ||
594 | |||
595 | out: | ||
596 | if (ret != 0 || !keep_cs) | ||
597 | spi_set_cs(msg->spi, false); | ||
598 | |||
599 | if (msg->status == -EINPROGRESS) | ||
600 | msg->status = ret; | ||
601 | |||
602 | spi_finalize_current_message(master); | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * spi_finalize_current_transfer - report completion of a transfer | ||
609 | * | ||
610 | * Called by SPI drivers using the core transfer_one_message() | ||
611 | * implementation to notify it that the current interrupt driven | ||
612 | * transfer has finised and the next one may be scheduled. | ||
613 | */ | ||
614 | void spi_finalize_current_transfer(struct spi_master *master) | ||
615 | { | ||
616 | complete(&master->xfer_completion); | ||
617 | } | ||
618 | EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); | ||
619 | |||
528 | /** | 620 | /** |
529 | * spi_pump_messages - kthread work function which processes spi message queue | 621 | * spi_pump_messages - kthread work function which processes spi message queue |
530 | * @work: pointer to kthread work struct contained in the master struct | 622 | * @work: pointer to kthread work struct contained in the master struct |
@@ -559,6 +651,7 @@ static void spi_pump_messages(struct kthread_work *work) | |||
559 | pm_runtime_mark_last_busy(master->dev.parent); | 651 | pm_runtime_mark_last_busy(master->dev.parent); |
560 | pm_runtime_put_autosuspend(master->dev.parent); | 652 | pm_runtime_put_autosuspend(master->dev.parent); |
561 | } | 653 | } |
654 | trace_spi_master_idle(master); | ||
562 | return; | 655 | return; |
563 | } | 656 | } |
564 | 657 | ||
@@ -587,6 +680,9 @@ static void spi_pump_messages(struct kthread_work *work) | |||
587 | } | 680 | } |
588 | } | 681 | } |
589 | 682 | ||
683 | if (!was_busy) | ||
684 | trace_spi_master_busy(master); | ||
685 | |||
590 | if (!was_busy && master->prepare_transfer_hardware) { | 686 | if (!was_busy && master->prepare_transfer_hardware) { |
591 | ret = master->prepare_transfer_hardware(master); | 687 | ret = master->prepare_transfer_hardware(master); |
592 | if (ret) { | 688 | if (ret) { |
@@ -599,6 +695,20 @@ static void spi_pump_messages(struct kthread_work *work) | |||
599 | } | 695 | } |
600 | } | 696 | } |
601 | 697 | ||
698 | trace_spi_message_start(master->cur_msg); | ||
699 | |||
700 | if (master->prepare_message) { | ||
701 | ret = master->prepare_message(master, master->cur_msg); | ||
702 | if (ret) { | ||
703 | dev_err(&master->dev, | ||
704 | "failed to prepare message: %d\n", ret); | ||
705 | master->cur_msg->status = ret; | ||
706 | spi_finalize_current_message(master); | ||
707 | return; | ||
708 | } | ||
709 | master->cur_msg_prepared = true; | ||
710 | } | ||
711 | |||
602 | ret = master->transfer_one_message(master, master->cur_msg); | 712 | ret = master->transfer_one_message(master, master->cur_msg); |
603 | if (ret) { | 713 | if (ret) { |
604 | dev_err(&master->dev, | 714 | dev_err(&master->dev, |
@@ -680,6 +790,7 @@ void spi_finalize_current_message(struct spi_master *master) | |||
680 | { | 790 | { |
681 | struct spi_message *mesg; | 791 | struct spi_message *mesg; |
682 | unsigned long flags; | 792 | unsigned long flags; |
793 | int ret; | ||
683 | 794 | ||
684 | spin_lock_irqsave(&master->queue_lock, flags); | 795 | spin_lock_irqsave(&master->queue_lock, flags); |
685 | mesg = master->cur_msg; | 796 | mesg = master->cur_msg; |
@@ -688,9 +799,20 @@ void spi_finalize_current_message(struct spi_master *master) | |||
688 | queue_kthread_work(&master->kworker, &master->pump_messages); | 799 | queue_kthread_work(&master->kworker, &master->pump_messages); |
689 | spin_unlock_irqrestore(&master->queue_lock, flags); | 800 | spin_unlock_irqrestore(&master->queue_lock, flags); |
690 | 801 | ||
802 | if (master->cur_msg_prepared && master->unprepare_message) { | ||
803 | ret = master->unprepare_message(master, mesg); | ||
804 | if (ret) { | ||
805 | dev_err(&master->dev, | ||
806 | "failed to unprepare message: %d\n", ret); | ||
807 | } | ||
808 | } | ||
809 | master->cur_msg_prepared = false; | ||
810 | |||
691 | mesg->state = NULL; | 811 | mesg->state = NULL; |
692 | if (mesg->complete) | 812 | if (mesg->complete) |
693 | mesg->complete(mesg->context); | 813 | mesg->complete(mesg->context); |
814 | |||
815 | trace_spi_message_done(mesg); | ||
694 | } | 816 | } |
695 | EXPORT_SYMBOL_GPL(spi_finalize_current_message); | 817 | EXPORT_SYMBOL_GPL(spi_finalize_current_message); |
696 | 818 | ||
@@ -805,6 +927,8 @@ static int spi_master_initialize_queue(struct spi_master *master) | |||
805 | 927 | ||
806 | master->queued = true; | 928 | master->queued = true; |
807 | master->transfer = spi_queued_transfer; | 929 | master->transfer = spi_queued_transfer; |
930 | if (!master->transfer_one_message) | ||
931 | master->transfer_one_message = spi_transfer_one_message; | ||
808 | 932 | ||
809 | /* Initialize and start queue */ | 933 | /* Initialize and start queue */ |
810 | ret = spi_init_queue(master); | 934 | ret = spi_init_queue(master); |
@@ -1205,6 +1329,7 @@ int spi_register_master(struct spi_master *master) | |||
1205 | spin_lock_init(&master->bus_lock_spinlock); | 1329 | spin_lock_init(&master->bus_lock_spinlock); |
1206 | mutex_init(&master->bus_lock_mutex); | 1330 | mutex_init(&master->bus_lock_mutex); |
1207 | master->bus_lock_flag = 0; | 1331 | master->bus_lock_flag = 0; |
1332 | init_completion(&master->xfer_completion); | ||
1208 | 1333 | ||
1209 | /* register the device, then userspace will see it. | 1334 | /* register the device, then userspace will see it. |
1210 | * registration fails if the bus ID is in use. | 1335 | * registration fails if the bus ID is in use. |
@@ -1451,6 +1576,10 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) | |||
1451 | struct spi_master *master = spi->master; | 1576 | struct spi_master *master = spi->master; |
1452 | struct spi_transfer *xfer; | 1577 | struct spi_transfer *xfer; |
1453 | 1578 | ||
1579 | message->spi = spi; | ||
1580 | |||
1581 | trace_spi_message_submit(message); | ||
1582 | |||
1454 | if (list_empty(&message->transfers)) | 1583 | if (list_empty(&message->transfers)) |
1455 | return -EINVAL; | 1584 | return -EINVAL; |
1456 | if (!message->complete) | 1585 | if (!message->complete) |
@@ -1550,7 +1679,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) | |||
1550 | } | 1679 | } |
1551 | } | 1680 | } |
1552 | 1681 | ||
1553 | message->spi = spi; | ||
1554 | message->status = -EINPROGRESS; | 1682 | message->status = -EINPROGRESS; |
1555 | return master->transfer(spi, message); | 1683 | return master->transfer(spi, message); |
1556 | } | 1684 | } |