diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/pxa2xx_spi.c | 59 |
1 files changed, 48 insertions, 11 deletions
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 34c7c9875681..a7b9070e1b46 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c | |||
@@ -144,7 +144,6 @@ struct driver_data { | |||
144 | size_t tx_map_len; | 144 | size_t tx_map_len; |
145 | u8 n_bytes; | 145 | u8 n_bytes; |
146 | u32 dma_width; | 146 | u32 dma_width; |
147 | int cs_change; | ||
148 | int (*write)(struct driver_data *drv_data); | 147 | int (*write)(struct driver_data *drv_data); |
149 | int (*read)(struct driver_data *drv_data); | 148 | int (*read)(struct driver_data *drv_data); |
150 | irqreturn_t (*transfer_handler)(struct driver_data *drv_data); | 149 | irqreturn_t (*transfer_handler)(struct driver_data *drv_data); |
@@ -406,8 +405,45 @@ static void giveback(struct driver_data *drv_data) | |||
406 | struct spi_transfer, | 405 | struct spi_transfer, |
407 | transfer_list); | 406 | transfer_list); |
408 | 407 | ||
408 | /* Delay if requested before any change in chip select */ | ||
409 | if (last_transfer->delay_usecs) | ||
410 | udelay(last_transfer->delay_usecs); | ||
411 | |||
412 | /* Drop chip select UNLESS cs_change is true or we are returning | ||
413 | * a message with an error, or next message is for another chip | ||
414 | */ | ||
409 | if (!last_transfer->cs_change) | 415 | if (!last_transfer->cs_change) |
410 | drv_data->cs_control(PXA2XX_CS_DEASSERT); | 416 | drv_data->cs_control(PXA2XX_CS_DEASSERT); |
417 | else { | ||
418 | struct spi_message *next_msg; | ||
419 | |||
420 | /* Holding of cs was hinted, but we need to make sure | ||
421 | * the next message is for the same chip. Don't waste | ||
422 | * time with the following tests unless this was hinted. | ||
423 | * | ||
424 | * We cannot postpone this until pump_messages, because | ||
425 | * after calling msg->complete (below) the driver that | ||
426 | * sent the current message could be unloaded, which | ||
427 | * could invalidate the cs_control() callback... | ||
428 | */ | ||
429 | |||
430 | /* get a pointer to the next message, if any */ | ||
431 | spin_lock_irqsave(&drv_data->lock, flags); | ||
432 | if (list_empty(&drv_data->queue)) | ||
433 | next_msg = NULL; | ||
434 | else | ||
435 | next_msg = list_entry(drv_data->queue.next, | ||
436 | struct spi_message, queue); | ||
437 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
438 | |||
439 | /* see if the next and current messages point | ||
440 | * to the same chip | ||
441 | */ | ||
442 | if (next_msg && next_msg->spi != msg->spi) | ||
443 | next_msg = NULL; | ||
444 | if (!next_msg || msg->state == ERROR_STATE) | ||
445 | drv_data->cs_control(PXA2XX_CS_DEASSERT); | ||
446 | } | ||
411 | 447 | ||
412 | msg->state = NULL; | 448 | msg->state = NULL; |
413 | if (msg->complete) | 449 | if (msg->complete) |
@@ -490,10 +526,9 @@ static void dma_transfer_complete(struct driver_data *drv_data) | |||
490 | msg->actual_length += drv_data->len - | 526 | msg->actual_length += drv_data->len - |
491 | (drv_data->rx_end - drv_data->rx); | 527 | (drv_data->rx_end - drv_data->rx); |
492 | 528 | ||
493 | /* Release chip select if requested, transfer delays are | 529 | /* Transfer delays and chip select release are |
494 | * handled in pump_transfers */ | 530 | * handled in pump_transfers or giveback |
495 | if (drv_data->cs_change) | 531 | */ |
496 | drv_data->cs_control(PXA2XX_CS_DEASSERT); | ||
497 | 532 | ||
498 | /* Move to next transfer */ | 533 | /* Move to next transfer */ |
499 | msg->state = next_transfer(drv_data); | 534 | msg->state = next_transfer(drv_data); |
@@ -602,10 +637,9 @@ static void int_transfer_complete(struct driver_data *drv_data) | |||
602 | drv_data->cur_msg->actual_length += drv_data->len - | 637 | drv_data->cur_msg->actual_length += drv_data->len - |
603 | (drv_data->rx_end - drv_data->rx); | 638 | (drv_data->rx_end - drv_data->rx); |
604 | 639 | ||
605 | /* Release chip select if requested, transfer delays are | 640 | /* Transfer delays and chip select release are |
606 | * handled in pump_transfers */ | 641 | * handled in pump_transfers or giveback |
607 | if (drv_data->cs_change) | 642 | */ |
608 | drv_data->cs_control(PXA2XX_CS_DEASSERT); | ||
609 | 643 | ||
610 | /* Move to next transfer */ | 644 | /* Move to next transfer */ |
611 | drv_data->cur_msg->state = next_transfer(drv_data); | 645 | drv_data->cur_msg->state = next_transfer(drv_data); |
@@ -840,13 +874,17 @@ static void pump_transfers(unsigned long data) | |||
840 | return; | 874 | return; |
841 | } | 875 | } |
842 | 876 | ||
843 | /* Delay if requested at end of transfer*/ | 877 | /* Delay if requested at end of transfer before CS change */ |
844 | if (message->state == RUNNING_STATE) { | 878 | if (message->state == RUNNING_STATE) { |
845 | previous = list_entry(transfer->transfer_list.prev, | 879 | previous = list_entry(transfer->transfer_list.prev, |
846 | struct spi_transfer, | 880 | struct spi_transfer, |
847 | transfer_list); | 881 | transfer_list); |
848 | if (previous->delay_usecs) | 882 | if (previous->delay_usecs) |
849 | udelay(previous->delay_usecs); | 883 | udelay(previous->delay_usecs); |
884 | |||
885 | /* Drop chip select only if cs_change is requested */ | ||
886 | if (previous->cs_change) | ||
887 | drv_data->cs_control(PXA2XX_CS_DEASSERT); | ||
850 | } | 888 | } |
851 | 889 | ||
852 | /* Check transfer length */ | 890 | /* Check transfer length */ |
@@ -878,7 +916,6 @@ static void pump_transfers(unsigned long data) | |||
878 | drv_data->len = transfer->len & DCMD_LENGTH; | 916 | drv_data->len = transfer->len & DCMD_LENGTH; |
879 | drv_data->write = drv_data->tx ? chip->write : null_writer; | 917 | drv_data->write = drv_data->tx ? chip->write : null_writer; |
880 | drv_data->read = drv_data->rx ? chip->read : null_reader; | 918 | drv_data->read = drv_data->rx ? chip->read : null_reader; |
881 | drv_data->cs_change = transfer->cs_change; | ||
882 | 919 | ||
883 | /* Change speed and bit per word on a per transfer */ | 920 | /* Change speed and bit per word on a per transfer */ |
884 | cr0 = chip->cr0; | 921 | cr0 = chip->cr0; |