diff options
Diffstat (limited to 'drivers/mtd/onenand/omap2.c')
-rw-r--r-- | drivers/mtd/onenand/omap2.c | 80 |
1 files changed, 61 insertions, 19 deletions
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index d0894ca7798b..ac31f461cc1c 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
36 | #include <linux/io.h> | 36 | #include <linux/io.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/regulator/consumer.h> | ||
38 | 39 | ||
39 | #include <asm/mach/flash.h> | 40 | #include <asm/mach/flash.h> |
40 | #include <plat/gpmc.h> | 41 | #include <plat/gpmc.h> |
@@ -63,8 +64,13 @@ struct omap2_onenand { | |||
63 | int dma_channel; | 64 | int dma_channel; |
64 | int freq; | 65 | int freq; |
65 | int (*setup)(void __iomem *base, int freq); | 66 | int (*setup)(void __iomem *base, int freq); |
67 | struct regulator *regulator; | ||
66 | }; | 68 | }; |
67 | 69 | ||
70 | #ifdef CONFIG_MTD_PARTITIONS | ||
71 | static const char *part_probes[] = { "cmdlinepart", NULL, }; | ||
72 | #endif | ||
73 | |||
68 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) | 74 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) |
69 | { | 75 | { |
70 | struct omap2_onenand *c = data; | 76 | struct omap2_onenand *c = data; |
@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl, | |||
108 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) | 114 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) |
109 | { | 115 | { |
110 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | 116 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); |
117 | struct onenand_chip *this = mtd->priv; | ||
111 | unsigned int intr = 0; | 118 | unsigned int intr = 0; |
112 | unsigned int ctrl; | 119 | unsigned int ctrl, ctrl_mask; |
113 | unsigned long timeout; | 120 | unsigned long timeout; |
114 | u32 syscfg; | 121 | u32 syscfg; |
115 | 122 | ||
@@ -180,7 +187,8 @@ retry: | |||
180 | if (result == 0) { | 187 | if (result == 0) { |
181 | /* Timeout after 20ms */ | 188 | /* Timeout after 20ms */ |
182 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | 189 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); |
183 | if (ctrl & ONENAND_CTRL_ONGO) { | 190 | if (ctrl & ONENAND_CTRL_ONGO && |
191 | !this->ongoing) { | ||
184 | /* | 192 | /* |
185 | * The operation seems to be still going | 193 | * The operation seems to be still going |
186 | * so give it some more time. | 194 | * so give it some more time. |
@@ -269,7 +277,11 @@ retry: | |||
269 | return -EIO; | 277 | return -EIO; |
270 | } | 278 | } |
271 | 279 | ||
272 | if (ctrl & 0xFE9F) | 280 | ctrl_mask = 0xFE9F; |
281 | if (this->ongoing) | ||
282 | ctrl_mask &= ~0x8000; | ||
283 | |||
284 | if (ctrl & ctrl_mask) | ||
273 | wait_warn("unexpected controller status", state, ctrl, intr); | 285 | wait_warn("unexpected controller status", state, ctrl, intr); |
274 | 286 | ||
275 | return 0; | 287 | return 0; |
@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev) | |||
591 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); | 603 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); |
592 | } | 604 | } |
593 | 605 | ||
606 | static int omap2_onenand_enable(struct mtd_info *mtd) | ||
607 | { | ||
608 | int ret; | ||
609 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
610 | |||
611 | ret = regulator_enable(c->regulator); | ||
612 | if (ret != 0) | ||
613 | dev_err(&c->pdev->dev, "cant enable regulator\n"); | ||
614 | |||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static int omap2_onenand_disable(struct mtd_info *mtd) | ||
619 | { | ||
620 | int ret; | ||
621 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
622 | |||
623 | ret = regulator_disable(c->regulator); | ||
624 | if (ret != 0) | ||
625 | dev_err(&c->pdev->dev, "cant disable regulator\n"); | ||
626 | |||
627 | return ret; | ||
628 | } | ||
629 | |||
594 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) | 630 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) |
595 | { | 631 | { |
596 | struct omap_onenand_platform_data *pdata; | 632 | struct omap_onenand_platform_data *pdata; |
@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
705 | } | 741 | } |
706 | } | 742 | } |
707 | 743 | ||
744 | if (pdata->regulator_can_sleep) { | ||
745 | c->regulator = regulator_get(&pdev->dev, "vonenand"); | ||
746 | if (IS_ERR(c->regulator)) { | ||
747 | dev_err(&pdev->dev, "Failed to get regulator\n"); | ||
748 | goto err_release_dma; | ||
749 | } | ||
750 | c->onenand.enable = omap2_onenand_enable; | ||
751 | c->onenand.disable = omap2_onenand_disable; | ||
752 | } | ||
753 | |||
708 | if ((r = onenand_scan(&c->mtd, 1)) < 0) | 754 | if ((r = onenand_scan(&c->mtd, 1)) < 0) |
709 | goto err_release_dma; | 755 | goto err_release_regulator; |
710 | 756 | ||
711 | switch ((c->onenand.version_id >> 4) & 0xf) { | 757 | switch ((c->onenand.version_id >> 4) & 0xf) { |
712 | case 0: | 758 | case 0: |
@@ -727,13 +773,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
727 | } | 773 | } |
728 | 774 | ||
729 | #ifdef CONFIG_MTD_PARTITIONS | 775 | #ifdef CONFIG_MTD_PARTITIONS |
730 | if (pdata->parts != NULL) | 776 | r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); |
731 | r = add_mtd_partitions(&c->mtd, pdata->parts, | 777 | if (r > 0) |
732 | pdata->nr_parts); | 778 | r = add_mtd_partitions(&c->mtd, c->parts, r); |
779 | else if (pdata->parts != NULL) | ||
780 | r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts); | ||
733 | else | 781 | else |
734 | #endif | 782 | #endif |
735 | r = add_mtd_device(&c->mtd); | 783 | r = add_mtd_device(&c->mtd); |
736 | if (r < 0) | 784 | if (r) |
737 | goto err_release_onenand; | 785 | goto err_release_onenand; |
738 | 786 | ||
739 | platform_set_drvdata(pdev, c); | 787 | platform_set_drvdata(pdev, c); |
@@ -742,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
742 | 790 | ||
743 | err_release_onenand: | 791 | err_release_onenand: |
744 | onenand_release(&c->mtd); | 792 | onenand_release(&c->mtd); |
793 | err_release_regulator: | ||
794 | regulator_put(c->regulator); | ||
745 | err_release_dma: | 795 | err_release_dma: |
746 | if (c->dma_channel != -1) | 796 | if (c->dma_channel != -1) |
747 | omap_free_dma(c->dma_channel); | 797 | omap_free_dma(c->dma_channel); |
@@ -757,6 +807,7 @@ err_release_mem_region: | |||
757 | err_free_cs: | 807 | err_free_cs: |
758 | gpmc_cs_free(c->gpmc_cs); | 808 | gpmc_cs_free(c->gpmc_cs); |
759 | err_kfree: | 809 | err_kfree: |
810 | kfree(c->parts); | ||
760 | kfree(c); | 811 | kfree(c); |
761 | 812 | ||
762 | return r; | 813 | return r; |
@@ -766,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) | |||
766 | { | 817 | { |
767 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); | 818 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); |
768 | 819 | ||
769 | BUG_ON(c == NULL); | ||
770 | |||
771 | #ifdef CONFIG_MTD_PARTITIONS | ||
772 | if (c->parts) | ||
773 | del_mtd_partitions(&c->mtd); | ||
774 | else | ||
775 | del_mtd_device(&c->mtd); | ||
776 | #else | ||
777 | del_mtd_device(&c->mtd); | ||
778 | #endif | ||
779 | |||
780 | onenand_release(&c->mtd); | 820 | onenand_release(&c->mtd); |
821 | regulator_put(c->regulator); | ||
781 | if (c->dma_channel != -1) | 822 | if (c->dma_channel != -1) |
782 | omap_free_dma(c->dma_channel); | 823 | omap_free_dma(c->dma_channel); |
783 | omap2_onenand_shutdown(pdev); | 824 | omap2_onenand_shutdown(pdev); |
@@ -789,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) | |||
789 | iounmap(c->onenand.base); | 830 | iounmap(c->onenand.base); |
790 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); | 831 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); |
791 | gpmc_cs_free(c->gpmc_cs); | 832 | gpmc_cs_free(c->gpmc_cs); |
833 | kfree(c->parts); | ||
792 | kfree(c); | 834 | kfree(c); |
793 | 835 | ||
794 | return 0; | 836 | return 0; |