aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/spi-pl022.c72
1 files changed, 37 insertions, 35 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 13988a3024bb..1cff8ad470d1 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -340,6 +340,10 @@ struct vendor_data {
340 * @cur_msg: Pointer to current spi_message being processed 340 * @cur_msg: Pointer to current spi_message being processed
341 * @cur_transfer: Pointer to current spi_transfer 341 * @cur_transfer: Pointer to current spi_transfer
342 * @cur_chip: pointer to current clients chip(assigned from controller_state) 342 * @cur_chip: pointer to current clients chip(assigned from controller_state)
343 * @next_msg_cs_active: the next message in the queue has been examined
344 * and it was found that it uses the same chip select as the previous
345 * message, so we left it active after the previous transfer, and it's
346 * active already.
343 * @tx: current position in TX buffer to be read 347 * @tx: current position in TX buffer to be read
344 * @tx_end: end position in TX buffer to be read 348 * @tx_end: end position in TX buffer to be read
345 * @rx: current position in RX buffer to be written 349 * @rx: current position in RX buffer to be written
@@ -373,6 +377,7 @@ struct pl022 {
373 struct spi_message *cur_msg; 377 struct spi_message *cur_msg;
374 struct spi_transfer *cur_transfer; 378 struct spi_transfer *cur_transfer;
375 struct chip_data *cur_chip; 379 struct chip_data *cur_chip;
380 bool next_msg_cs_active;
376 void *tx; 381 void *tx;
377 void *tx_end; 382 void *tx_end;
378 void *rx; 383 void *rx;
@@ -445,23 +450,9 @@ static void giveback(struct pl022 *pl022)
445 struct spi_transfer *last_transfer; 450 struct spi_transfer *last_transfer;
446 unsigned long flags; 451 unsigned long flags;
447 struct spi_message *msg; 452 struct spi_message *msg;
448 void (*curr_cs_control) (u32 command); 453 pl022->next_msg_cs_active = false;
449 454
450 /* 455 last_transfer = list_entry(pl022->cur_msg->transfers.prev,
451 * This local reference to the chip select function
452 * is needed because we set curr_chip to NULL
453 * as a step toward termininating the message.
454 */
455 curr_cs_control = pl022->cur_chip->cs_control;
456 spin_lock_irqsave(&pl022->queue_lock, flags);
457 msg = pl022->cur_msg;
458 pl022->cur_msg = NULL;
459 pl022->cur_transfer = NULL;
460 pl022->cur_chip = NULL;
461 queue_work(pl022->workqueue, &pl022->pump_messages);
462 spin_unlock_irqrestore(&pl022->queue_lock, flags);
463
464 last_transfer = list_entry(msg->transfers.prev,
465 struct spi_transfer, 456 struct spi_transfer,
466 transfer_list); 457 transfer_list);
467 458
@@ -473,18 +464,13 @@ static void giveback(struct pl022 *pl022)
473 */ 464 */
474 udelay(last_transfer->delay_usecs); 465 udelay(last_transfer->delay_usecs);
475 466
476 /* 467 if (!last_transfer->cs_change) {
477 * Drop chip select UNLESS cs_change is true or we are returning
478 * a message with an error, or next message is for another chip
479 */
480 if (!last_transfer->cs_change)
481 curr_cs_control(SSP_CHIP_DESELECT);
482 else {
483 struct spi_message *next_msg; 468 struct spi_message *next_msg;
484 469
485 /* Holding of cs was hinted, but we need to make sure 470 /*
486 * the next message is for the same chip. Don't waste 471 * cs_change was not set. We can keep the chip select
487 * time with the following tests unless this was hinted. 472 * enabled if there is message in the queue and it is
473 * for the same spi device.
488 * 474 *
489 * We cannot postpone this until pump_messages, because 475 * We cannot postpone this until pump_messages, because
490 * after calling msg->complete (below) the driver that 476 * after calling msg->complete (below) the driver that
@@ -501,14 +487,26 @@ static void giveback(struct pl022 *pl022)
501 struct spi_message, queue); 487 struct spi_message, queue);
502 spin_unlock_irqrestore(&pl022->queue_lock, flags); 488 spin_unlock_irqrestore(&pl022->queue_lock, flags);
503 489
504 /* see if the next and current messages point 490 /*
505 * to the same chip 491 * see if the next and current messages point
492 * to the same spi device.
506 */ 493 */
507 if (next_msg && next_msg->spi != msg->spi) 494 if (next_msg && next_msg->spi != pl022->cur_msg->spi)
508 next_msg = NULL; 495 next_msg = NULL;
509 if (!next_msg || msg->state == STATE_ERROR) 496 if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
510 curr_cs_control(SSP_CHIP_DESELECT); 497 pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
498 else
499 pl022->next_msg_cs_active = true;
511 } 500 }
501
502 spin_lock_irqsave(&pl022->queue_lock, flags);
503 msg = pl022->cur_msg;
504 pl022->cur_msg = NULL;
505 pl022->cur_transfer = NULL;
506 pl022->cur_chip = NULL;
507 queue_work(pl022->workqueue, &pl022->pump_messages);
508 spin_unlock_irqrestore(&pl022->queue_lock, flags);
509
512 msg->state = NULL; 510 msg->state = NULL;
513 if (msg->complete) 511 if (msg->complete)
514 msg->complete(msg->context); 512 msg->complete(msg->context);
@@ -1350,7 +1348,7 @@ static void pump_transfers(unsigned long data)
1350 */ 1348 */
1351 udelay(previous->delay_usecs); 1349 udelay(previous->delay_usecs);
1352 1350
1353 /* Drop chip select only if cs_change is requested */ 1351 /* Reselect chip select only if cs_change was requested */
1354 if (previous->cs_change) 1352 if (previous->cs_change)
1355 pl022->cur_chip->cs_control(SSP_CHIP_SELECT); 1353 pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
1356 } else { 1354 } else {
@@ -1389,8 +1387,10 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022)
1389 */ 1387 */
1390 u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM; 1388 u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM;
1391 1389
1392 /* Enable target chip */ 1390 /* Enable target chip, if not already active */
1393 pl022->cur_chip->cs_control(SSP_CHIP_SELECT); 1391 if (!pl022->next_msg_cs_active)
1392 pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
1393
1394 if (set_up_next_transfer(pl022, pl022->cur_transfer)) { 1394 if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
1395 /* Error path */ 1395 /* Error path */
1396 pl022->cur_msg->state = STATE_ERROR; 1396 pl022->cur_msg->state = STATE_ERROR;
@@ -1445,7 +1445,8 @@ static void do_polling_transfer(struct pl022 *pl022)
1445 } else { 1445 } else {
1446 /* STATE_START */ 1446 /* STATE_START */
1447 message->state = STATE_RUNNING; 1447 message->state = STATE_RUNNING;
1448 pl022->cur_chip->cs_control(SSP_CHIP_SELECT); 1448 if (!pl022->next_msg_cs_active)
1449 pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
1449 } 1450 }
1450 1451
1451 /* Configuration Changing Per Transfer */ 1452 /* Configuration Changing Per Transfer */
@@ -1604,6 +1605,7 @@ static int start_queue(struct pl022 *pl022)
1604 pl022->cur_msg = NULL; 1605 pl022->cur_msg = NULL;
1605 pl022->cur_transfer = NULL; 1606 pl022->cur_transfer = NULL;
1606 pl022->cur_chip = NULL; 1607 pl022->cur_chip = NULL;
1608 pl022->next_msg_cs_active = false;
1607 spin_unlock_irqrestore(&pl022->queue_lock, flags); 1609 spin_unlock_irqrestore(&pl022->queue_lock, flags);
1608 1610
1609 queue_work(pl022->workqueue, &pl022->pump_messages); 1611 queue_work(pl022->workqueue, &pl022->pump_messages);