diff options
| -rw-r--r-- | drivers/spi/spi_bfin5xx.c | 235 |
1 files changed, 185 insertions, 50 deletions
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index b8352546c589..3736c3596a41 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
| @@ -92,6 +92,9 @@ struct driver_data { | |||
| 92 | dma_addr_t rx_dma; | 92 | dma_addr_t rx_dma; |
| 93 | dma_addr_t tx_dma; | 93 | dma_addr_t tx_dma; |
| 94 | 94 | ||
| 95 | int irq_requested; | ||
| 96 | int spi_irq; | ||
| 97 | |||
| 95 | size_t rx_map_len; | 98 | size_t rx_map_len; |
| 96 | size_t tx_map_len; | 99 | size_t tx_map_len; |
| 97 | u8 n_bytes; | 100 | u8 n_bytes; |
| @@ -115,6 +118,7 @@ struct chip_data { | |||
| 115 | u16 cs_chg_udelay; /* Some devices require > 255usec delay */ | 118 | u16 cs_chg_udelay; /* Some devices require > 255usec delay */ |
| 116 | u32 cs_gpio; | 119 | u32 cs_gpio; |
| 117 | u16 idle_tx_val; | 120 | u16 idle_tx_val; |
| 121 | u8 pio_interrupt; /* use spi data irq */ | ||
| 118 | void (*write) (struct driver_data *); | 122 | void (*write) (struct driver_data *); |
| 119 | void (*read) (struct driver_data *); | 123 | void (*read) (struct driver_data *); |
| 120 | void (*duplex) (struct driver_data *); | 124 | void (*duplex) (struct driver_data *); |
| @@ -525,6 +529,79 @@ static void bfin_spi_giveback(struct driver_data *drv_data) | |||
| 525 | msg->complete(msg->context); | 529 | msg->complete(msg->context); |
| 526 | } | 530 | } |
| 527 | 531 | ||
| 532 | /* spi data irq handler */ | ||
| 533 | static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) | ||
| 534 | { | ||
| 535 | struct driver_data *drv_data = dev_id; | ||
| 536 | struct chip_data *chip = drv_data->cur_chip; | ||
| 537 | struct spi_message *msg = drv_data->cur_msg; | ||
| 538 | int n_bytes = drv_data->n_bytes; | ||
| 539 | |||
| 540 | /* wait until transfer finished. */ | ||
| 541 | while (!(read_STAT(drv_data) & BIT_STAT_RXS)) | ||
| 542 | cpu_relax(); | ||
| 543 | |||
| 544 | if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) || | ||
| 545 | (drv_data->rx && drv_data->rx >= (drv_data->rx_end - n_bytes))) { | ||
| 546 | /* last read */ | ||
| 547 | if (drv_data->rx) { | ||
| 548 | dev_dbg(&drv_data->pdev->dev, "last read\n"); | ||
| 549 | if (n_bytes == 2) | ||
| 550 | *(u16 *) (drv_data->rx) = read_RDBR(drv_data); | ||
| 551 | else if (n_bytes == 1) | ||
| 552 | *(u8 *) (drv_data->rx) = read_RDBR(drv_data); | ||
| 553 | drv_data->rx += n_bytes; | ||
| 554 | } | ||
| 555 | |||
| 556 | msg->actual_length += drv_data->len_in_bytes; | ||
| 557 | if (drv_data->cs_change) | ||
| 558 | bfin_spi_cs_deactive(drv_data, chip); | ||
| 559 | /* Move to next transfer */ | ||
| 560 | msg->state = bfin_spi_next_transfer(drv_data); | ||
| 561 | |||
| 562 | disable_irq(drv_data->spi_irq); | ||
| 563 | |||
| 564 | /* Schedule transfer tasklet */ | ||
| 565 | tasklet_schedule(&drv_data->pump_transfers); | ||
| 566 | return IRQ_HANDLED; | ||
| 567 | } | ||
| 568 | |||
| 569 | if (drv_data->rx && drv_data->tx) { | ||
| 570 | /* duplex */ | ||
| 571 | dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n"); | ||
| 572 | if (drv_data->n_bytes == 2) { | ||
| 573 | *(u16 *) (drv_data->rx) = read_RDBR(drv_data); | ||
| 574 | write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); | ||
| 575 | } else if (drv_data->n_bytes == 1) { | ||
| 576 | *(u8 *) (drv_data->rx) = read_RDBR(drv_data); | ||
| 577 | write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); | ||
| 578 | } | ||
| 579 | } else if (drv_data->rx) { | ||
| 580 | /* read */ | ||
| 581 | dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n"); | ||
| 582 | if (drv_data->n_bytes == 2) | ||
| 583 | *(u16 *) (drv_data->rx) = read_RDBR(drv_data); | ||
| 584 | else if (drv_data->n_bytes == 1) | ||
| 585 | *(u8 *) (drv_data->rx) = read_RDBR(drv_data); | ||
| 586 | write_TDBR(drv_data, chip->idle_tx_val); | ||
| 587 | } else if (drv_data->tx) { | ||
| 588 | /* write */ | ||
| 589 | dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n"); | ||
| 590 | bfin_spi_dummy_read(drv_data); | ||
| 591 | if (drv_data->n_bytes == 2) | ||
| 592 | write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); | ||
| 593 | else if (drv_data->n_bytes == 1) | ||
| 594 | write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); | ||
| 595 | } | ||
| 596 | |||
| 597 | if (drv_data->tx) | ||
| 598 | drv_data->tx += n_bytes; | ||
| 599 | if (drv_data->rx) | ||
| 600 | drv_data->rx += n_bytes; | ||
| 601 | |||
| 602 | return IRQ_HANDLED; | ||
| 603 | } | ||
| 604 | |||
| 528 | static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) | 605 | static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) |
| 529 | { | 606 | { |
| 530 | struct driver_data *drv_data = dev_id; | 607 | struct driver_data *drv_data = dev_id; |
| @@ -700,6 +777,7 @@ static void bfin_spi_pump_transfers(unsigned long data) | |||
| 700 | 777 | ||
| 701 | default: | 778 | default: |
| 702 | /* No change, the same as default setting */ | 779 | /* No change, the same as default setting */ |
| 780 | transfer->bits_per_word = chip->bits_per_word; | ||
| 703 | drv_data->n_bytes = chip->n_bytes; | 781 | drv_data->n_bytes = chip->n_bytes; |
| 704 | width = chip->width; | 782 | width = chip->width; |
| 705 | drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer; | 783 | drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer; |
| @@ -842,60 +920,86 @@ static void bfin_spi_pump_transfers(unsigned long data) | |||
| 842 | dma_enable_irq(drv_data->dma_channel); | 920 | dma_enable_irq(drv_data->dma_channel); |
| 843 | local_irq_restore(flags); | 921 | local_irq_restore(flags); |
| 844 | 922 | ||
| 845 | } else { | 923 | return; |
| 846 | /* IO mode write then read */ | 924 | } |
| 847 | dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); | ||
| 848 | 925 | ||
| 849 | /* we always use SPI_WRITE mode. SPI_READ mode | 926 | if (chip->pio_interrupt) { |
| 850 | seems to have problems with setting up the | 927 | /* use write mode. spi irq should have been disabled */ |
| 851 | output value in TDBR prior to the transfer. */ | 928 | cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD)); |
| 852 | write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); | 929 | write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); |
| 853 | 930 | ||
| 854 | if (full_duplex) { | 931 | /* discard old RX data and clear RXS */ |
| 855 | /* full duplex mode */ | 932 | bfin_spi_dummy_read(drv_data); |
| 856 | BUG_ON((drv_data->tx_end - drv_data->tx) != | ||
| 857 | (drv_data->rx_end - drv_data->rx)); | ||
| 858 | dev_dbg(&drv_data->pdev->dev, | ||
| 859 | "IO duplex: cr is 0x%x\n", cr); | ||
| 860 | |||
| 861 | drv_data->duplex(drv_data); | ||
| 862 | |||
| 863 | if (drv_data->tx != drv_data->tx_end) | ||
| 864 | tranf_success = 0; | ||
| 865 | } else if (drv_data->tx != NULL) { | ||
| 866 | /* write only half duplex */ | ||
| 867 | dev_dbg(&drv_data->pdev->dev, | ||
| 868 | "IO write: cr is 0x%x\n", cr); | ||
| 869 | 933 | ||
| 870 | drv_data->write(drv_data); | 934 | /* start transfer */ |
| 935 | if (drv_data->tx == NULL) | ||
| 936 | write_TDBR(drv_data, chip->idle_tx_val); | ||
| 937 | else { | ||
| 938 | if (transfer->bits_per_word == 8) | ||
| 939 | write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); | ||
| 940 | else if (transfer->bits_per_word == 16) | ||
| 941 | write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); | ||
| 942 | drv_data->tx += drv_data->n_bytes; | ||
| 943 | } | ||
| 871 | 944 | ||
| 872 | if (drv_data->tx != drv_data->tx_end) | 945 | /* once TDBR is empty, interrupt is triggered */ |
| 873 | tranf_success = 0; | 946 | enable_irq(drv_data->spi_irq); |
| 874 | } else if (drv_data->rx != NULL) { | 947 | return; |
| 875 | /* read only half duplex */ | 948 | } |
| 876 | dev_dbg(&drv_data->pdev->dev, | ||
| 877 | "IO read: cr is 0x%x\n", cr); | ||
| 878 | 949 | ||
| 879 | drv_data->read(drv_data); | 950 | /* IO mode */ |
| 880 | if (drv_data->rx != drv_data->rx_end) | 951 | dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n"); |
| 881 | tranf_success = 0; | 952 | |
| 882 | } | 953 | /* we always use SPI_WRITE mode. SPI_READ mode |
| 954 | seems to have problems with setting up the | ||
| 955 | output value in TDBR prior to the transfer. */ | ||
| 956 | write_CTRL(drv_data, (cr | CFG_SPI_WRITE)); | ||
| 957 | |||
| 958 | if (full_duplex) { | ||
| 959 | /* full duplex mode */ | ||
| 960 | BUG_ON((drv_data->tx_end - drv_data->tx) != | ||
| 961 | (drv_data->rx_end - drv_data->rx)); | ||
| 962 | dev_dbg(&drv_data->pdev->dev, | ||
| 963 | "IO duplex: cr is 0x%x\n", cr); | ||
| 964 | |||
| 965 | drv_data->duplex(drv_data); | ||
| 966 | |||
| 967 | if (drv_data->tx != drv_data->tx_end) | ||
| 968 | tranf_success = 0; | ||
| 969 | } else if (drv_data->tx != NULL) { | ||
| 970 | /* write only half duplex */ | ||
| 971 | dev_dbg(&drv_data->pdev->dev, | ||
| 972 | "IO write: cr is 0x%x\n", cr); | ||
| 973 | |||
| 974 | drv_data->write(drv_data); | ||
| 975 | |||
| 976 | if (drv_data->tx != drv_data->tx_end) | ||
| 977 | tranf_success = 0; | ||
| 978 | } else if (drv_data->rx != NULL) { | ||
| 979 | /* read only half duplex */ | ||
| 980 | dev_dbg(&drv_data->pdev->dev, | ||
| 981 | "IO read: cr is 0x%x\n", cr); | ||
| 982 | |||
| 983 | drv_data->read(drv_data); | ||
| 984 | if (drv_data->rx != drv_data->rx_end) | ||
| 985 | tranf_success = 0; | ||
| 986 | } | ||
| 883 | 987 | ||
| 884 | if (!tranf_success) { | 988 | if (!tranf_success) { |
| 885 | dev_dbg(&drv_data->pdev->dev, | 989 | dev_dbg(&drv_data->pdev->dev, |
| 886 | "IO write error!\n"); | 990 | "IO write error!\n"); |
| 887 | message->state = ERROR_STATE; | 991 | message->state = ERROR_STATE; |
| 888 | } else { | 992 | } else { |
| 889 | /* Update total byte transfered */ | 993 | /* Update total byte transfered */ |
| 890 | message->actual_length += drv_data->len_in_bytes; | 994 | message->actual_length += drv_data->len_in_bytes; |
| 891 | /* Move to next transfer of this msg */ | 995 | /* Move to next transfer of this msg */ |
| 892 | message->state = bfin_spi_next_transfer(drv_data); | 996 | message->state = bfin_spi_next_transfer(drv_data); |
| 893 | if (drv_data->cs_change) | 997 | if (drv_data->cs_change) |
| 894 | bfin_spi_cs_deactive(drv_data, chip); | 998 | bfin_spi_cs_deactive(drv_data, chip); |
| 895 | } | ||
| 896 | /* Schedule next transfer tasklet */ | ||
| 897 | tasklet_schedule(&drv_data->pump_transfers); | ||
| 898 | } | 999 | } |
| 1000 | |||
| 1001 | /* Schedule next transfer tasklet */ | ||
| 1002 | tasklet_schedule(&drv_data->pump_transfers); | ||
| 899 | } | 1003 | } |
| 900 | 1004 | ||
| 901 | /* pop a msg from queue and kick off real transfer */ | 1005 | /* pop a msg from queue and kick off real transfer */ |
| @@ -1047,6 +1151,7 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
| 1047 | chip->cs_chg_udelay = chip_info->cs_chg_udelay; | 1151 | chip->cs_chg_udelay = chip_info->cs_chg_udelay; |
| 1048 | chip->cs_gpio = chip_info->cs_gpio; | 1152 | chip->cs_gpio = chip_info->cs_gpio; |
| 1049 | chip->idle_tx_val = chip_info->idle_tx_val; | 1153 | chip->idle_tx_val = chip_info->idle_tx_val; |
| 1154 | chip->pio_interrupt = chip_info->pio_interrupt; | ||
| 1050 | } | 1155 | } |
| 1051 | 1156 | ||
| 1052 | /* translate common spi framework into our register */ | 1157 | /* translate common spi framework into our register */ |
| @@ -1096,6 +1201,11 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
| 1096 | goto error; | 1201 | goto error; |
| 1097 | } | 1202 | } |
| 1098 | 1203 | ||
| 1204 | if (chip->enable_dma && chip->pio_interrupt) { | ||
| 1205 | dev_err(&spi->dev, "enable_dma is set, " | ||
| 1206 | "do not set pio_interrupt\n"); | ||
| 1207 | goto error; | ||
| 1208 | } | ||
| 1099 | /* | 1209 | /* |
| 1100 | * if any one SPI chip is registered and wants DMA, request the | 1210 | * if any one SPI chip is registered and wants DMA, request the |
| 1101 | * DMA channel for it | 1211 | * DMA channel for it |
| @@ -1119,6 +1229,18 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
| 1119 | dma_disable_irq(drv_data->dma_channel); | 1229 | dma_disable_irq(drv_data->dma_channel); |
| 1120 | } | 1230 | } |
| 1121 | 1231 | ||
| 1232 | if (chip->pio_interrupt && !drv_data->irq_requested) { | ||
| 1233 | ret = request_irq(drv_data->spi_irq, bfin_spi_pio_irq_handler, | ||
| 1234 | IRQF_DISABLED, "BFIN_SPI", drv_data); | ||
| 1235 | if (ret) { | ||
| 1236 | dev_err(&spi->dev, "Unable to register spi IRQ\n"); | ||
| 1237 | goto error; | ||
| 1238 | } | ||
| 1239 | drv_data->irq_requested = 1; | ||
| 1240 | /* we use write mode, spi irq has to be disabled here */ | ||
| 1241 | disable_irq(drv_data->spi_irq); | ||
| 1242 | } | ||
| 1243 | |||
| 1122 | if (chip->chip_select_num == 0) { | 1244 | if (chip->chip_select_num == 0) { |
| 1123 | ret = gpio_request(chip->cs_gpio, spi->modalias); | 1245 | ret = gpio_request(chip->cs_gpio, spi->modalias); |
| 1124 | if (ret) { | 1246 | if (ret) { |
| @@ -1328,11 +1450,19 @@ static int __init bfin_spi_probe(struct platform_device *pdev) | |||
| 1328 | goto out_error_ioremap; | 1450 | goto out_error_ioremap; |
| 1329 | } | 1451 | } |
| 1330 | 1452 | ||
| 1331 | drv_data->dma_channel = platform_get_irq(pdev, 0); | 1453 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
| 1332 | if (drv_data->dma_channel < 0) { | 1454 | if (res == NULL) { |
| 1333 | dev_err(dev, "No DMA channel specified\n"); | 1455 | dev_err(dev, "No DMA channel specified\n"); |
| 1334 | status = -ENOENT; | 1456 | status = -ENOENT; |
| 1335 | goto out_error_no_dma_ch; | 1457 | goto out_error_free_io; |
| 1458 | } | ||
| 1459 | drv_data->dma_channel = res->start; | ||
| 1460 | |||
| 1461 | drv_data->spi_irq = platform_get_irq(pdev, 0); | ||
| 1462 | if (drv_data->spi_irq < 0) { | ||
| 1463 | dev_err(dev, "No spi pio irq specified\n"); | ||
| 1464 | status = -ENOENT; | ||
| 1465 | goto out_error_free_io; | ||
| 1336 | } | 1466 | } |
| 1337 | 1467 | ||
| 1338 | /* Initial and start queue */ | 1468 | /* Initial and start queue */ |
| @@ -1375,7 +1505,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev) | |||
| 1375 | 1505 | ||
| 1376 | out_error_queue_alloc: | 1506 | out_error_queue_alloc: |
| 1377 | bfin_spi_destroy_queue(drv_data); | 1507 | bfin_spi_destroy_queue(drv_data); |
| 1378 | out_error_no_dma_ch: | 1508 | out_error_free_io: |
| 1379 | iounmap((void *) drv_data->regs_base); | 1509 | iounmap((void *) drv_data->regs_base); |
| 1380 | out_error_ioremap: | 1510 | out_error_ioremap: |
| 1381 | out_error_get_res: | 1511 | out_error_get_res: |
| @@ -1407,6 +1537,11 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev) | |||
| 1407 | free_dma(drv_data->dma_channel); | 1537 | free_dma(drv_data->dma_channel); |
| 1408 | } | 1538 | } |
| 1409 | 1539 | ||
| 1540 | if (drv_data->irq_requested) { | ||
| 1541 | free_irq(drv_data->spi_irq, drv_data); | ||
| 1542 | drv_data->irq_requested = 0; | ||
| 1543 | } | ||
| 1544 | |||
| 1410 | /* Disconnect from the SPI framework */ | 1545 | /* Disconnect from the SPI framework */ |
| 1411 | spi_unregister_master(drv_data->master); | 1546 | spi_unregister_master(drv_data->master); |
| 1412 | 1547 | ||
