]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/mtd/onenand/omap2.c
mtd: add "platform:" prefix for platform modalias
[mv-sheeva.git] / drivers / mtd / onenand / omap2.c
index fd406348fdfd5b269cbadb8c10de362320ba4bb7..c849cacf4b2faab2679f1231982f6cb12e0aa192 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/mach/flash.h>
 #include <plat/gpmc.h>
@@ -63,8 +64,13 @@ struct omap2_onenand {
        int dma_channel;
        int freq;
        int (*setup)(void __iomem *base, int freq);
+       struct regulator *regulator;
 };
 
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL,  };
+#endif
+
 static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
 {
        struct omap2_onenand *c = data;
@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl,
 static int omap2_onenand_wait(struct mtd_info *mtd, int state)
 {
        struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+       struct onenand_chip *this = mtd->priv;
        unsigned int intr = 0;
-       unsigned int ctrl;
+       unsigned int ctrl, ctrl_mask;
        unsigned long timeout;
        u32 syscfg;
 
@@ -180,7 +187,8 @@ retry:
                        if (result == 0) {
                                /* Timeout after 20ms */
                                ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
-                               if (ctrl & ONENAND_CTRL_ONGO) {
+                               if (ctrl & ONENAND_CTRL_ONGO &&
+                                   !this->ongoing) {
                                        /*
                                         * The operation seems to be still going
                                         * so give it some more time.
@@ -269,7 +277,11 @@ retry:
                return -EIO;
        }
 
-       if (ctrl & 0xFE9F)
+       ctrl_mask = 0xFE9F;
+       if (this->ongoing)
+               ctrl_mask &= ~0x8000;
+
+       if (ctrl & ctrl_mask)
                wait_warn("unexpected controller status", state, ctrl, intr);
 
        return 0;
@@ -309,7 +321,7 @@ static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
                goto out_copy;
 
        /* panic_write() may be in an interrupt context */
-       if (in_interrupt())
+       if (in_interrupt() || oops_in_progress)
                goto out_copy;
 
        if (buf >= high_memory) {
@@ -386,7 +398,7 @@ static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
                goto out_copy;
 
        /* panic_write() may be in an interrupt context */
-       if (in_interrupt())
+       if (in_interrupt() || oops_in_progress)
                goto out_copy;
 
        if (buf >= high_memory) {
@@ -403,7 +415,7 @@ static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
 
        dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE);
        dma_dst = c->phys_base + bram_offset;
-       if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+       if (dma_mapping_error(&c->pdev->dev, dma_src)) {
                dev_err(&c->pdev->dev,
                        "Couldn't DMA map a %d byte buffer\n",
                        count);
@@ -426,7 +438,7 @@ static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
                if (*done)
                        break;
 
-       dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+       dma_unmap_single(&c->pdev->dev, dma_src, count, DMA_TO_DEVICE);
 
        if (!*done) {
                dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
@@ -521,7 +533,7 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
        dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count,
                                 DMA_TO_DEVICE);
        dma_dst = c->phys_base + bram_offset;
-       if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+       if (dma_mapping_error(&c->pdev->dev, dma_src)) {
                dev_err(&c->pdev->dev,
                        "Couldn't DMA map a %d byte buffer\n",
                        count);
@@ -539,7 +551,7 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
        omap_start_dma(c->dma_channel);
        wait_for_completion(&c->dma_done);
 
-       dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+       dma_unmap_single(&c->pdev->dev, dma_src, count, DMA_TO_DEVICE);
 
        return 0;
 }
@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
        memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
 }
 
+static int omap2_onenand_enable(struct mtd_info *mtd)
+{
+       int ret;
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+
+       ret = regulator_enable(c->regulator);
+       if (ret != 0)
+               dev_err(&c->pdev->dev, "cant enable regulator\n");
+
+       return ret;
+}
+
+static int omap2_onenand_disable(struct mtd_info *mtd)
+{
+       int ret;
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+
+       ret = regulator_disable(c->regulator);
+       if (ret != 0)
+               dev_err(&c->pdev->dev, "cant disable regulator\n");
+
+       return ret;
+}
+
 static int __devinit omap2_onenand_probe(struct platform_device *pdev)
 {
        struct omap_onenand_platform_data *pdata;
@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
                }
        }
 
+       if (pdata->regulator_can_sleep) {
+               c->regulator = regulator_get(&pdev->dev, "vonenand");
+               if (IS_ERR(c->regulator)) {
+                       dev_err(&pdev->dev,  "Failed to get regulator\n");
+                       goto err_release_dma;
+               }
+               c->onenand.enable = omap2_onenand_enable;
+               c->onenand.disable = omap2_onenand_disable;
+       }
+
        if ((r = onenand_scan(&c->mtd, 1)) < 0)
-               goto err_release_dma;
+               goto err_release_regulator;
 
        switch ((c->onenand.version_id >> 4) & 0xf) {
        case 0:
@@ -721,16 +767,21 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
        case 3:
                c->freq = 83;
                break;
+       case 4:
+               c->freq = 104;
+               break;
        }
 
 #ifdef CONFIG_MTD_PARTITIONS
-       if (pdata->parts != NULL)
-               r = add_mtd_partitions(&c->mtd, pdata->parts,
-                                      pdata->nr_parts);
+       r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0);
+       if (r > 0)
+               r = add_mtd_partitions(&c->mtd, c->parts, r);
+       else if (pdata->parts != NULL)
+               r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts);
        else
 #endif
                r = add_mtd_device(&c->mtd);
-       if (r < 0)
+       if (r)
                goto err_release_onenand;
 
        platform_set_drvdata(pdev, c);
@@ -739,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
 
 err_release_onenand:
        onenand_release(&c->mtd);
+err_release_regulator:
+       regulator_put(c->regulator);
 err_release_dma:
        if (c->dma_channel != -1)
                omap_free_dma(c->dma_channel);
@@ -754,6 +807,7 @@ err_release_mem_region:
 err_free_cs:
        gpmc_cs_free(c->gpmc_cs);
 err_kfree:
+       kfree(c->parts);
        kfree(c);
 
        return r;
@@ -763,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
 {
        struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
 
-       BUG_ON(c == NULL);
-
-#ifdef CONFIG_MTD_PARTITIONS
-       if (c->parts)
-               del_mtd_partitions(&c->mtd);
-       else
-               del_mtd_device(&c->mtd);
-#else
-       del_mtd_device(&c->mtd);
-#endif
-
        onenand_release(&c->mtd);
+       regulator_put(c->regulator);
        if (c->dma_channel != -1)
                omap_free_dma(c->dma_channel);
        omap2_onenand_shutdown(pdev);
@@ -786,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
        iounmap(c->onenand.base);
        release_mem_region(c->phys_base, ONENAND_IO_SIZE);
        gpmc_cs_free(c->gpmc_cs);
+       kfree(c->parts);
        kfree(c);
 
        return 0;
@@ -815,7 +860,7 @@ static void __exit omap2_onenand_exit(void)
 module_init(omap2_onenand_init);
 module_exit(omap2_onenand_exit);
 
-MODULE_ALIAS(DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");
 MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");