diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-07 15:15:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-07 15:15:36 -0500 |
commit | fbce1c234feedb5270468aa4b1770c1cab58a960 (patch) | |
tree | 7391d7bcce50eab43c750c4055b056ab1892d6b2 /drivers/spi | |
parent | 7affca3537d74365128e477b40c529d6f2fe86c8 (diff) | |
parent | d0ad5e89256c351ddd40167152c24a88efcb0f6d (diff) |
Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux-2.6
Changes queued in gpio/next for the start of the 3.3 merge window
* tag 'gpio-for-linus-20120104' of git://git.secretlab.ca/git/linux-2.6:
gpio: Add decode of WM8994 GPIO configuration
gpio: Convert GPIO drivers to module_platform_driver
gpio: Fix typo in comment in Samsung driver
gpio: Explicitly index samsung_gpio_cfgs
gpio: Add Linus Walleij as gpio co-maintainer
of: Add device tree selftests
of: create of_phandle_args to simplify return of phandle parsing data
gpio/powerpc: Eliminate duplication of of_get_named_gpio_flags()
gpio/microblaze: Eliminate duplication of of_get_named_gpio_flags()
gpiolib: output basic details and consolidate gpio device drivers
pch_gpio: Change company name OKI SEMICONDUCTOR to LAPIS Semiconductor
pch_gpio: Support new device LAPIS Semiconductor ML7831 IOH
spi/pl022: make the chip deselect handling thread safe
spi/pl022: add support for pm_runtime autosuspend
spi/pl022: disable the PL022 block when unused
spi/pl022: move device disable to workqueue thread
spi/pl022: skip default configuration before suspending
spi/pl022: fix build warnings
spi/pl022: only enable RX interrupts when TX is complete
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-pl022.c | 141 |
1 files changed, 85 insertions, 56 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 7026af195683..f1f5efbc3404 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,19 +487,29 @@ 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); |
515 | /* This message is completed, so let's turn off the clocks & power */ | ||
516 | pm_runtime_put(&pl022->adev->dev); | ||
517 | } | 513 | } |
518 | 514 | ||
519 | /** | 515 | /** |
@@ -1244,9 +1240,9 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) | |||
1244 | 1240 | ||
1245 | if ((pl022->tx == pl022->tx_end) && (flag == 0)) { | 1241 | if ((pl022->tx == pl022->tx_end) && (flag == 0)) { |
1246 | flag = 1; | 1242 | flag = 1; |
1247 | /* Disable Transmit interrupt */ | 1243 | /* Disable Transmit interrupt, enable receive interrupt */ |
1248 | writew(readw(SSP_IMSC(pl022->virtbase)) & | 1244 | writew((readw(SSP_IMSC(pl022->virtbase)) & |
1249 | (~SSP_IMSC_MASK_TXIM), | 1245 | ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM, |
1250 | SSP_IMSC(pl022->virtbase)); | 1246 | SSP_IMSC(pl022->virtbase)); |
1251 | } | 1247 | } |
1252 | 1248 | ||
@@ -1352,7 +1348,7 @@ static void pump_transfers(unsigned long data) | |||
1352 | */ | 1348 | */ |
1353 | udelay(previous->delay_usecs); | 1349 | udelay(previous->delay_usecs); |
1354 | 1350 | ||
1355 | /* Drop chip select only if cs_change is requested */ | 1351 | /* Reselect chip select only if cs_change was requested */ |
1356 | if (previous->cs_change) | 1352 | if (previous->cs_change) |
1357 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | 1353 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); |
1358 | } else { | 1354 | } else { |
@@ -1379,15 +1375,22 @@ static void pump_transfers(unsigned long data) | |||
1379 | } | 1375 | } |
1380 | 1376 | ||
1381 | err_config_dma: | 1377 | err_config_dma: |
1382 | writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); | 1378 | /* enable all interrupts except RX */ |
1379 | writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase)); | ||
1383 | } | 1380 | } |
1384 | 1381 | ||
1385 | static void do_interrupt_dma_transfer(struct pl022 *pl022) | 1382 | static void do_interrupt_dma_transfer(struct pl022 *pl022) |
1386 | { | 1383 | { |
1387 | u32 irqflags = ENABLE_ALL_INTERRUPTS; | 1384 | /* |
1385 | * Default is to enable all interrupts except RX - | ||
1386 | * this will be enabled once TX is complete | ||
1387 | */ | ||
1388 | u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM; | ||
1389 | |||
1390 | /* Enable target chip, if not already active */ | ||
1391 | if (!pl022->next_msg_cs_active) | ||
1392 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | ||
1388 | 1393 | ||
1389 | /* Enable target chip */ | ||
1390 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | ||
1391 | if (set_up_next_transfer(pl022, pl022->cur_transfer)) { | 1394 | if (set_up_next_transfer(pl022, pl022->cur_transfer)) { |
1392 | /* Error path */ | 1395 | /* Error path */ |
1393 | pl022->cur_msg->state = STATE_ERROR; | 1396 | pl022->cur_msg->state = STATE_ERROR; |
@@ -1442,7 +1445,8 @@ static void do_polling_transfer(struct pl022 *pl022) | |||
1442 | } else { | 1445 | } else { |
1443 | /* STATE_START */ | 1446 | /* STATE_START */ |
1444 | message->state = STATE_RUNNING; | 1447 | message->state = STATE_RUNNING; |
1445 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | 1448 | if (!pl022->next_msg_cs_active) |
1449 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | ||
1446 | } | 1450 | } |
1447 | 1451 | ||
1448 | /* Configuration Changing Per Transfer */ | 1452 | /* Configuration Changing Per Transfer */ |
@@ -1504,14 +1508,28 @@ static void pump_messages(struct work_struct *work) | |||
1504 | struct pl022 *pl022 = | 1508 | struct pl022 *pl022 = |
1505 | container_of(work, struct pl022, pump_messages); | 1509 | container_of(work, struct pl022, pump_messages); |
1506 | unsigned long flags; | 1510 | unsigned long flags; |
1511 | bool was_busy = false; | ||
1507 | 1512 | ||
1508 | /* Lock queue and check for queue work */ | 1513 | /* Lock queue and check for queue work */ |
1509 | spin_lock_irqsave(&pl022->queue_lock, flags); | 1514 | spin_lock_irqsave(&pl022->queue_lock, flags); |
1510 | if (list_empty(&pl022->queue) || !pl022->running) { | 1515 | if (list_empty(&pl022->queue) || !pl022->running) { |
1516 | if (pl022->busy) { | ||
1517 | /* nothing more to do - disable spi/ssp and power off */ | ||
1518 | writew((readw(SSP_CR1(pl022->virtbase)) & | ||
1519 | (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); | ||
1520 | |||
1521 | if (pl022->master_info->autosuspend_delay > 0) { | ||
1522 | pm_runtime_mark_last_busy(&pl022->adev->dev); | ||
1523 | pm_runtime_put_autosuspend(&pl022->adev->dev); | ||
1524 | } else { | ||
1525 | pm_runtime_put(&pl022->adev->dev); | ||
1526 | } | ||
1527 | } | ||
1511 | pl022->busy = false; | 1528 | pl022->busy = false; |
1512 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1529 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
1513 | return; | 1530 | return; |
1514 | } | 1531 | } |
1532 | |||
1515 | /* Make sure we are not already running a message */ | 1533 | /* Make sure we are not already running a message */ |
1516 | if (pl022->cur_msg) { | 1534 | if (pl022->cur_msg) { |
1517 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1535 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
@@ -1522,7 +1540,10 @@ static void pump_messages(struct work_struct *work) | |||
1522 | list_entry(pl022->queue.next, struct spi_message, queue); | 1540 | list_entry(pl022->queue.next, struct spi_message, queue); |
1523 | 1541 | ||
1524 | list_del_init(&pl022->cur_msg->queue); | 1542 | list_del_init(&pl022->cur_msg->queue); |
1525 | pl022->busy = true; | 1543 | if (pl022->busy) |
1544 | was_busy = true; | ||
1545 | else | ||
1546 | pl022->busy = true; | ||
1526 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1547 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
1527 | 1548 | ||
1528 | /* Initial message state */ | 1549 | /* Initial message state */ |
@@ -1532,12 +1553,14 @@ static void pump_messages(struct work_struct *work) | |||
1532 | 1553 | ||
1533 | /* Setup the SPI using the per chip configuration */ | 1554 | /* Setup the SPI using the per chip configuration */ |
1534 | pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); | 1555 | pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); |
1535 | /* | 1556 | if (!was_busy) |
1536 | * We enable the core voltage and clocks here, then the clocks | 1557 | /* |
1537 | * and core will be disabled when giveback() is called in each method | 1558 | * We enable the core voltage and clocks here, then the clocks |
1538 | * (poll/interrupt/DMA) | 1559 | * and core will be disabled when this workqueue is run again |
1539 | */ | 1560 | * and there is no more work to be done. |
1540 | pm_runtime_get_sync(&pl022->adev->dev); | 1561 | */ |
1562 | pm_runtime_get_sync(&pl022->adev->dev); | ||
1563 | |||
1541 | restore_state(pl022); | 1564 | restore_state(pl022); |
1542 | flush(pl022); | 1565 | flush(pl022); |
1543 | 1566 | ||
@@ -1582,6 +1605,7 @@ static int start_queue(struct pl022 *pl022) | |||
1582 | pl022->cur_msg = NULL; | 1605 | pl022->cur_msg = NULL; |
1583 | pl022->cur_transfer = NULL; | 1606 | pl022->cur_transfer = NULL; |
1584 | pl022->cur_chip = NULL; | 1607 | pl022->cur_chip = NULL; |
1608 | pl022->next_msg_cs_active = false; | ||
1585 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1609 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
1586 | 1610 | ||
1587 | queue_work(pl022->workqueue, &pl022->pump_messages); | 1611 | queue_work(pl022->workqueue, &pl022->pump_messages); |
@@ -1881,7 +1905,7 @@ static int pl022_setup(struct spi_device *spi) | |||
1881 | { | 1905 | { |
1882 | struct pl022_config_chip const *chip_info; | 1906 | struct pl022_config_chip const *chip_info; |
1883 | struct chip_data *chip; | 1907 | struct chip_data *chip; |
1884 | struct ssp_clock_params clk_freq = {0, }; | 1908 | struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0}; |
1885 | int status = 0; | 1909 | int status = 0; |
1886 | struct pl022 *pl022 = spi_master_get_devdata(spi->master); | 1910 | struct pl022 *pl022 = spi_master_get_devdata(spi->master); |
1887 | unsigned int bits = spi->bits_per_word; | 1911 | unsigned int bits = spi->bits_per_word; |
@@ -2231,7 +2255,17 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2231 | dev_dbg(dev, "probe succeeded\n"); | 2255 | dev_dbg(dev, "probe succeeded\n"); |
2232 | 2256 | ||
2233 | /* let runtime pm put suspend */ | 2257 | /* let runtime pm put suspend */ |
2234 | pm_runtime_put(dev); | 2258 | if (platform_info->autosuspend_delay > 0) { |
2259 | dev_info(&adev->dev, | ||
2260 | "will use autosuspend for runtime pm, delay %dms\n", | ||
2261 | platform_info->autosuspend_delay); | ||
2262 | pm_runtime_set_autosuspend_delay(dev, | ||
2263 | platform_info->autosuspend_delay); | ||
2264 | pm_runtime_use_autosuspend(dev); | ||
2265 | pm_runtime_put_autosuspend(dev); | ||
2266 | } else { | ||
2267 | pm_runtime_put(dev); | ||
2268 | } | ||
2235 | return 0; | 2269 | return 0; |
2236 | 2270 | ||
2237 | err_spi_register: | 2271 | err_spi_register: |
@@ -2305,11 +2339,6 @@ static int pl022_suspend(struct device *dev) | |||
2305 | return status; | 2339 | return status; |
2306 | } | 2340 | } |
2307 | 2341 | ||
2308 | amba_vcore_enable(pl022->adev); | ||
2309 | amba_pclk_enable(pl022->adev); | ||
2310 | load_ssp_default_config(pl022); | ||
2311 | amba_pclk_disable(pl022->adev); | ||
2312 | amba_vcore_disable(pl022->adev); | ||
2313 | dev_dbg(dev, "suspended\n"); | 2342 | dev_dbg(dev, "suspended\n"); |
2314 | return 0; | 2343 | return 0; |
2315 | } | 2344 | } |