diff options
| -rw-r--r-- | drivers/mtd/nand/omap2.c | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 3578c633e97e..27293e328517 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
| @@ -137,7 +137,8 @@ struct omap_nand_info { | |||
| 137 | unsigned long mem_size; | 137 | unsigned long mem_size; |
| 138 | struct completion comp; | 138 | struct completion comp; |
| 139 | struct dma_chan *dma; | 139 | struct dma_chan *dma; |
| 140 | int gpmc_irq; | 140 | int gpmc_irq_fifo; |
| 141 | int gpmc_irq_count; | ||
| 141 | enum { | 142 | enum { |
| 142 | OMAP_NAND_IO_READ = 0, /* read */ | 143 | OMAP_NAND_IO_READ = 0, /* read */ |
| 143 | OMAP_NAND_IO_WRITE, /* write */ | 144 | OMAP_NAND_IO_WRITE, /* write */ |
| @@ -553,14 +554,12 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) | |||
| 553 | { | 554 | { |
| 554 | struct omap_nand_info *info = (struct omap_nand_info *) dev; | 555 | struct omap_nand_info *info = (struct omap_nand_info *) dev; |
| 555 | u32 bytes; | 556 | u32 bytes; |
| 556 | u32 irq_stat; | ||
| 557 | 557 | ||
| 558 | irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); | ||
| 559 | bytes = readl(info->reg.gpmc_prefetch_status); | 558 | bytes = readl(info->reg.gpmc_prefetch_status); |
| 560 | bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); | 559 | bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); |
| 561 | bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ | 560 | bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ |
| 562 | if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ | 561 | if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ |
| 563 | if (irq_stat & 0x2) | 562 | if (this_irq == info->gpmc_irq_count) |
| 564 | goto done; | 563 | goto done; |
| 565 | 564 | ||
| 566 | if (info->buf_len && (info->buf_len < bytes)) | 565 | if (info->buf_len && (info->buf_len < bytes)) |
| @@ -577,20 +576,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) | |||
| 577 | (u32 *)info->buf, bytes >> 2); | 576 | (u32 *)info->buf, bytes >> 2); |
| 578 | info->buf = info->buf + bytes; | 577 | info->buf = info->buf + bytes; |
| 579 | 578 | ||
| 580 | if (irq_stat & 0x2) | 579 | if (this_irq == info->gpmc_irq_count) |
| 581 | goto done; | 580 | goto done; |
| 582 | } | 581 | } |
| 583 | gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); | ||
| 584 | 582 | ||
| 585 | return IRQ_HANDLED; | 583 | return IRQ_HANDLED; |
| 586 | 584 | ||
| 587 | done: | 585 | done: |
| 588 | complete(&info->comp); | 586 | complete(&info->comp); |
| 589 | /* disable irq */ | ||
| 590 | gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0); | ||
| 591 | 587 | ||
| 592 | /* clear status */ | 588 | disable_irq_nosync(info->gpmc_irq_fifo); |
| 593 | gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); | 589 | disable_irq_nosync(info->gpmc_irq_count); |
| 594 | 590 | ||
| 595 | return IRQ_HANDLED; | 591 | return IRQ_HANDLED; |
| 596 | } | 592 | } |
| @@ -624,9 +620,9 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) | |||
| 624 | goto out_copy; | 620 | goto out_copy; |
| 625 | 621 | ||
| 626 | info->buf_len = len; | 622 | info->buf_len = len; |
| 627 | /* enable irq */ | 623 | |
| 628 | gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, | 624 | enable_irq(info->gpmc_irq_count); |
| 629 | (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); | 625 | enable_irq(info->gpmc_irq_fifo); |
| 630 | 626 | ||
| 631 | /* waiting for read to complete */ | 627 | /* waiting for read to complete */ |
| 632 | wait_for_completion(&info->comp); | 628 | wait_for_completion(&info->comp); |
| @@ -674,12 +670,13 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, | |||
| 674 | goto out_copy; | 670 | goto out_copy; |
| 675 | 671 | ||
| 676 | info->buf_len = len; | 672 | info->buf_len = len; |
| 677 | /* enable irq */ | 673 | |
| 678 | gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, | 674 | enable_irq(info->gpmc_irq_count); |
| 679 | (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); | 675 | enable_irq(info->gpmc_irq_fifo); |
| 680 | 676 | ||
| 681 | /* waiting for write to complete */ | 677 | /* waiting for write to complete */ |
| 682 | wait_for_completion(&info->comp); | 678 | wait_for_completion(&info->comp); |
| 679 | |||
| 683 | /* wait for data to flushed-out before reset the prefetch */ | 680 | /* wait for data to flushed-out before reset the prefetch */ |
| 684 | tim = 0; | 681 | tim = 0; |
| 685 | limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); | 682 | limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); |
| @@ -1300,9 +1297,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
| 1300 | info->nand.options = pdata->devsize; | 1297 | info->nand.options = pdata->devsize; |
| 1301 | info->nand.options |= NAND_SKIP_BBTSCAN; | 1298 | info->nand.options |= NAND_SKIP_BBTSCAN; |
| 1302 | 1299 | ||
| 1303 | /* NAND write protect off */ | ||
| 1304 | gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0); | ||
| 1305 | |||
| 1306 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1300 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1307 | if (res == NULL) { | 1301 | if (res == NULL) { |
| 1308 | err = -EINVAL; | 1302 | err = -EINVAL; |
| @@ -1392,17 +1386,39 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
| 1392 | break; | 1386 | break; |
| 1393 | 1387 | ||
| 1394 | case NAND_OMAP_PREFETCH_IRQ: | 1388 | case NAND_OMAP_PREFETCH_IRQ: |
| 1395 | err = request_irq(pdata->gpmc_irq, | 1389 | info->gpmc_irq_fifo = platform_get_irq(pdev, 0); |
| 1396 | omap_nand_irq, IRQF_SHARED, "gpmc-nand", info); | 1390 | if (info->gpmc_irq_fifo <= 0) { |
| 1391 | dev_err(&pdev->dev, "error getting fifo irq\n"); | ||
| 1392 | err = -ENODEV; | ||
| 1393 | goto out_release_mem_region; | ||
| 1394 | } | ||
| 1395 | err = request_irq(info->gpmc_irq_fifo, omap_nand_irq, | ||
| 1396 | IRQF_SHARED, "gpmc-nand-fifo", info); | ||
| 1397 | if (err) { | 1397 | if (err) { |
| 1398 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", | 1398 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", |
| 1399 | pdata->gpmc_irq, err); | 1399 | info->gpmc_irq_fifo, err); |
| 1400 | info->gpmc_irq_fifo = 0; | ||
| 1401 | goto out_release_mem_region; | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | info->gpmc_irq_count = platform_get_irq(pdev, 1); | ||
| 1405 | if (info->gpmc_irq_count <= 0) { | ||
| 1406 | dev_err(&pdev->dev, "error getting count irq\n"); | ||
| 1407 | err = -ENODEV; | ||
| 1408 | goto out_release_mem_region; | ||
| 1409 | } | ||
| 1410 | err = request_irq(info->gpmc_irq_count, omap_nand_irq, | ||
| 1411 | IRQF_SHARED, "gpmc-nand-count", info); | ||
| 1412 | if (err) { | ||
| 1413 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", | ||
| 1414 | info->gpmc_irq_count, err); | ||
| 1415 | info->gpmc_irq_count = 0; | ||
| 1400 | goto out_release_mem_region; | 1416 | goto out_release_mem_region; |
| 1401 | } else { | ||
| 1402 | info->gpmc_irq = pdata->gpmc_irq; | ||
| 1403 | info->nand.read_buf = omap_read_buf_irq_pref; | ||
| 1404 | info->nand.write_buf = omap_write_buf_irq_pref; | ||
| 1405 | } | 1417 | } |
| 1418 | |||
| 1419 | info->nand.read_buf = omap_read_buf_irq_pref; | ||
| 1420 | info->nand.write_buf = omap_write_buf_irq_pref; | ||
| 1421 | |||
| 1406 | break; | 1422 | break; |
| 1407 | 1423 | ||
| 1408 | default: | 1424 | default: |
| @@ -1490,6 +1506,10 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
| 1490 | out_release_mem_region: | 1506 | out_release_mem_region: |
| 1491 | if (info->dma) | 1507 | if (info->dma) |
| 1492 | dma_release_channel(info->dma); | 1508 | dma_release_channel(info->dma); |
| 1509 | if (info->gpmc_irq_count > 0) | ||
| 1510 | free_irq(info->gpmc_irq_count, info); | ||
| 1511 | if (info->gpmc_irq_fifo > 0) | ||
| 1512 | free_irq(info->gpmc_irq_fifo, info); | ||
| 1493 | release_mem_region(info->phys_base, info->mem_size); | 1513 | release_mem_region(info->phys_base, info->mem_size); |
| 1494 | out_free_info: | 1514 | out_free_info: |
| 1495 | kfree(info); | 1515 | kfree(info); |
| @@ -1508,8 +1528,10 @@ static int omap_nand_remove(struct platform_device *pdev) | |||
| 1508 | if (info->dma) | 1528 | if (info->dma) |
| 1509 | dma_release_channel(info->dma); | 1529 | dma_release_channel(info->dma); |
| 1510 | 1530 | ||
| 1511 | if (info->gpmc_irq) | 1531 | if (info->gpmc_irq_count > 0) |
| 1512 | free_irq(info->gpmc_irq, info); | 1532 | free_irq(info->gpmc_irq_count, info); |
| 1533 | if (info->gpmc_irq_fifo > 0) | ||
| 1534 | free_irq(info->gpmc_irq_fifo, info); | ||
| 1513 | 1535 | ||
| 1514 | /* Release NAND device, its internal structures and partitions */ | 1536 | /* Release NAND device, its internal structures and partitions */ |
| 1515 | nand_release(&info->mtd); | 1537 | nand_release(&info->mtd); |
