]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/mtd/devices/spear_smi.c
Merge branch 'for-3.7' of git://linux-nfs.org/~bfields/linux
[karo-tx-linux.git] / drivers / mtd / devices / spear_smi.c
index 67960362681e7f7a72933aaf87b5ffa515c36cfa..dcc3c9511530c064e93d91f941e90023a81fc3d3 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/param.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/spear_smi.h>
@@ -240,8 +241,8 @@ static int spear_smi_read_sr(struct spear_smi *dev, u32 bank)
        /* copy dev->status (lower 16 bits) in order to release lock */
        if (ret > 0)
                ret = dev->status & 0xffff;
-       else
-               ret = -EIO;
+       else if (ret == 0)
+               ret = -ETIMEDOUT;
 
        /* restore the ctrl regs state */
        writel(ctrlreg1, dev->io_base + SMI_CR1);
@@ -269,16 +270,19 @@ static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank,
        finish = jiffies + timeout;
        do {
                status = spear_smi_read_sr(dev, bank);
-               if (status < 0)
-                       continue; /* try till timeout */
-               else if (!(status & SR_WIP))
+               if (status < 0) {
+                       if (status == -ETIMEDOUT)
+                               continue; /* try till finish */
+                       return status;
+               } else if (!(status & SR_WIP)) {
                        return 0;
+               }
 
                cond_resched();
        } while (!time_after_eq(jiffies, finish));
 
        dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n");
-       return status;
+       return -EBUSY;
 }
 
 /**
@@ -335,6 +339,9 @@ static void spear_smi_hw_init(struct spear_smi *dev)
        val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8);
 
        mutex_lock(&dev->lock);
+       /* clear all interrupt conditions */
+       writel(0, dev->io_base + SMI_SR);
+
        writel(val, dev->io_base + SMI_CR1);
        mutex_unlock(&dev->lock);
 }
@@ -391,11 +398,11 @@ static int spear_smi_write_enable(struct spear_smi *dev, u32 bank)
        writel(ctrlreg1, dev->io_base + SMI_CR1);
        writel(0, dev->io_base + SMI_CR2);
 
-       if (ret <= 0) {
+       if (ret == 0) {
                ret = -EIO;
                dev_err(&dev->pdev->dev,
                        "smi controller failed on write enable\n");
-       } else {
+       } else if (ret > 0) {
                /* check whether write mode status is set for required bank */
                if (dev->status & (1 << (bank + WM_SHIFT)))
                        ret = 0;
@@ -462,10 +469,10 @@ static int spear_smi_erase_sector(struct spear_smi *dev,
        ret = wait_event_interruptible_timeout(dev->cmd_complete,
                        dev->status & TFF, SMI_CMD_TIMEOUT);
 
-       if (ret <= 0) {
+       if (ret == 0) {
                ret = -EIO;
                dev_err(&dev->pdev->dev, "sector erase failed\n");
-       } else
+       } else if (ret > 0)
                ret = 0; /* success */
 
        /* restore ctrl regs */
@@ -820,7 +827,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
        if (!flash_info)
                return -ENODEV;
 
-       flash = kzalloc(sizeof(*flash), GFP_ATOMIC);
+       flash = devm_kzalloc(&pdev->dev, sizeof(*flash), GFP_ATOMIC);
        if (!flash)
                return -ENOMEM;
        flash->bank = bank;
@@ -831,15 +838,13 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
        flash_index = spear_smi_probe_flash(dev, bank);
        if (flash_index < 0) {
                dev_info(&dev->pdev->dev, "smi-nor%d not found\n", bank);
-               ret = flash_index;
-               goto err_probe;
+               return flash_index;
        }
        /* map the memory for nor flash chip */
-       flash->base_addr = ioremap(flash_info->mem_base, flash_info->size);
-       if (!flash->base_addr) {
-               ret = -EIO;
-               goto err_probe;
-       }
+       flash->base_addr = devm_ioremap(&pdev->dev, flash_info->mem_base,
+                                       flash_info->size);
+       if (!flash->base_addr)
+               return -EIO;
 
        dev->flash[bank] = flash;
        flash->mtd.priv = dev;
@@ -881,17 +886,10 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
                                        count);
        if (ret) {
                dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret);
-               goto err_map;
+               return ret;
        }
 
        return 0;
-
-err_map:
-       iounmap(flash->base_addr);
-
-err_probe:
-       kfree(flash);
-       return ret;
 }
 
 /**
@@ -928,20 +926,13 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
                }
        } else {
                pdata = dev_get_platdata(&pdev->dev);
-               if (pdata < 0) {
+               if (!pdata) {
                        ret = -ENODEV;
                        dev_err(&pdev->dev, "no platform data\n");
                        goto err;
                }
        }
 
-       smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!smi_base) {
-               ret = -ENODEV;
-               dev_err(&pdev->dev, "invalid smi base address\n");
-               goto err;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = -ENODEV;
@@ -949,32 +940,26 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
                goto err;
        }
 
-       dev = kzalloc(sizeof(*dev), GFP_ATOMIC);
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_ATOMIC);
        if (!dev) {
                ret = -ENOMEM;
                dev_err(&pdev->dev, "mem alloc fail\n");
                goto err;
        }
 
-       smi_base = request_mem_region(smi_base->start, resource_size(smi_base),
-                       pdev->name);
-       if (!smi_base) {
-               ret = -EBUSY;
-               dev_err(&pdev->dev, "request mem region fail\n");
-               goto err_mem;
-       }
+       smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       dev->io_base = ioremap(smi_base->start, resource_size(smi_base));
+       dev->io_base = devm_request_and_ioremap(&pdev->dev, smi_base);
        if (!dev->io_base) {
                ret = -EIO;
-               dev_err(&pdev->dev, "ioremap fail\n");
-               goto err_ioremap;
+               dev_err(&pdev->dev, "devm_request_and_ioremap fail\n");
+               goto err;
        }
 
        dev->pdev = pdev;
        dev->clk_rate = pdata->clk_rate;
 
-       if (dev->clk_rate < 0 || dev->clk_rate > SMI_MAX_CLOCK_FREQ)
+       if (dev->clk_rate > SMI_MAX_CLOCK_FREQ)
                dev->clk_rate = SMI_MAX_CLOCK_FREQ;
 
        dev->num_flashes = pdata->num_flashes;
@@ -984,17 +969,18 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
                dev->num_flashes = MAX_NUM_FLASH_CHIP;
        }
 
-       dev->clk = clk_get(&pdev->dev, NULL);
+       dev->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                ret = PTR_ERR(dev->clk);
-               goto err_clk;
+               goto err;
        }
 
        ret = clk_prepare_enable(dev->clk);
        if (ret)
-               goto err_clk_prepare_enable;
+               goto err;
 
-       ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev);
+       ret = devm_request_irq(&pdev->dev, irq, spear_smi_int_handler, 0,
+                              pdev->name, dev);
        if (ret) {
                dev_err(&dev->pdev->dev, "SMI IRQ allocation failed\n");
                goto err_irq;
@@ -1017,18 +1003,9 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
        return 0;
 
 err_bank_setup:
-       free_irq(irq, dev);
        platform_set_drvdata(pdev, NULL);
 err_irq:
        clk_disable_unprepare(dev->clk);
-err_clk_prepare_enable:
-       clk_put(dev->clk);
-err_clk:
-       iounmap(dev->io_base);
-err_ioremap:
-       release_mem_region(smi_base->start, resource_size(smi_base));
-err_mem:
-       kfree(dev);
 err:
        return ret;
 }
@@ -1042,11 +1019,8 @@ err:
 static int __devexit spear_smi_remove(struct platform_device *pdev)
 {
        struct spear_smi *dev;
-       struct spear_smi_plat_data *pdata;
        struct spear_snor_flash *flash;
-       struct resource *smi_base;
-       int ret;
-       int i, irq;
+       int ret, i;
 
        dev = platform_get_drvdata(pdev);
        if (!dev) {
@@ -1054,8 +1028,6 @@ static int __devexit spear_smi_remove(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       pdata = dev_get_platdata(&pdev->dev);
-
        /* clean up for all nor flash */
        for (i = 0; i < dev->num_flashes; i++) {
                flash = dev->flash[i];
@@ -1066,49 +1038,41 @@ static int __devexit spear_smi_remove(struct platform_device *pdev)
                ret = mtd_device_unregister(&flash->mtd);
                if (ret)
                        dev_err(&pdev->dev, "error removing mtd\n");
-
-               iounmap(flash->base_addr);
-               kfree(flash);
        }
 
-       irq = platform_get_irq(pdev, 0);
-       free_irq(irq, dev);
-
        clk_disable_unprepare(dev->clk);
-       clk_put(dev->clk);
-       iounmap(dev->io_base);
-       kfree(dev);
-
-       smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(smi_base->start, resource_size(smi_base));
        platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
-int spear_smi_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM
+static int spear_smi_suspend(struct device *dev)
 {
-       struct spear_smi *dev = platform_get_drvdata(pdev);
+       struct spear_smi *sdev = dev_get_drvdata(dev);
 
-       if (dev && dev->clk)
-               clk_disable_unprepare(dev->clk);
+       if (sdev && sdev->clk)
+               clk_disable_unprepare(sdev->clk);
 
        return 0;
 }
 
-int spear_smi_resume(struct platform_device *pdev)
+static int spear_smi_resume(struct device *dev)
 {
-       struct spear_smi *dev = platform_get_drvdata(pdev);
+       struct spear_smi *sdev = dev_get_drvdata(dev);
        int ret = -EPERM;
 
-       if (dev && dev->clk)
-               ret = clk_prepare_enable(dev->clk);
+       if (sdev && sdev->clk)
+               ret = clk_prepare_enable(sdev->clk);
 
        if (!ret)
-               spear_smi_hw_init(dev);
+               spear_smi_hw_init(sdev);
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id spear_smi_id_table[] = {
        { .compatible = "st,spear600-smi" },
@@ -1123,11 +1087,12 @@ static struct platform_driver spear_smi_driver = {
                .bus = &platform_bus_type,
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(spear_smi_id_table),
+#ifdef CONFIG_PM
+               .pm = &spear_smi_pm_ops,
+#endif
        },
        .probe = spear_smi_probe,
        .remove = __devexit_p(spear_smi_remove),
-       .suspend = spear_smi_suspend,
-       .resume = spear_smi_resume,
 };
 
 static int spear_smi_init(void)