diff options
| -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; |
