arm:omap:nand - Add support for suspend/resume
authorPhilip, Avinash <avinashphilip@ti.com>
Tue, 10 Jan 2012 11:42:50 +0000 (17:12 +0530)
committerVaibhav Hiremath <hvaibhav@ti.com>
Mon, 23 Jan 2012 19:14:47 +0000 (00:44 +0530)
suspend/resume entry  points added in NAND driver by disabling/enabling
the clocks for NAND controller and ELM module.
controller clock  member is added to omap_nand_info and
omap_nand_platform_data structure.
On suspend waiting for ongoing mtd operation to finish on
mtd->suspend().

Signed-off-by: Philip, Avinash <avinashphilip@ti.com>
arch/arm/mach-omap2/elm.c
arch/arm/mach-omap2/gpmc-nand.c
arch/arm/mach-omap2/gpmc.c
arch/arm/plat-omap/include/plat/elm.h
arch/arm/plat-omap/include/plat/gpmc.h
arch/arm/plat-omap/include/plat/nand.h
drivers/mtd/nand/omap2.c

index 2dad4685f3f0677dc5d7802a5718b76b5f9bfee9..dab6cf2afe4b67cf0a23df3593c5692e313975b2 100644 (file)
@@ -23,6 +23,7 @@
 
 static void  __iomem *elm_base;
 static struct completion elm_completion;
+static struct clk *elm_clk;
 
 static void elm_write_reg(int idx, u32 val)
 {
@@ -148,11 +149,22 @@ static irqreturn_t elm_isr(int this_irq, void *dev_id)
        return IRQ_NONE;
 }
 
+void elm_clk_enable(void)
+{
+       clk_enable(elm_clk);
+}
+EXPORT_SYMBOL(elm_clk_enable);
+
+void elm_clk_disable(void)
+{
+       clk_disable(elm_clk);
+}
+EXPORT_SYMBOL(elm_clk_disable);
+
 static int __devinit omap_elm_probe(struct platform_device *pdev)
 {
        struct resource *res = NULL, *irq = NULL;
        int             ret_status = 0;
-       static struct clk *elm_clk;
 
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
index 8ad210bda9a996072df12625382875fee0b75c26..3771450e3a629123276149bc92898d1cf7782750 100644 (file)
@@ -107,6 +107,7 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data)
                gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1);
        }
 
+       gpmc_nand_data->ctrl_clk = gpmc_clock();
        err = platform_device_register(&gpmc_nand_device);
        if (err < 0) {
                dev_err(dev, "Unable to register NAND device\n");
index ec61ed8e3180c7c6d50a90bd8560c8fa5f29766d..45b0e341ac0d6c09269befbf952f1576ed405d98 100644 (file)
@@ -763,6 +763,11 @@ static int __init gpmc_init(void)
 }
 postcore_initcall(gpmc_init);
 
+struct clk *gpmc_clock(void)
+{
+       return gpmc_l3_clk;
+}
+
 static irqreturn_t gpmc_handle_irq(int irq, void *dev)
 {
        u8 cs;
index 6d81645df2aa5a47a83da812e77b2ab446d3ce59..dc5a54bb2d251cdfdfc1dcb79cde5cd43abaad3d 100644 (file)
 
 extern int elm_decode_bch_error(int bch_type, char *ecc_calc,
                unsigned int *err_loc);
+extern void elm_clk_enable(void);
+extern void elm_clk_disable(void);
 #endif /* TI81_ELM_H */
index 44c1f430e2bb06d1ca4769ed8c3c489615950ea8..6a791c6cfb17fbad4987d87b2ce6be8beaca648b 100644 (file)
@@ -156,6 +156,7 @@ extern int gpmc_read_status(int cmd);
 extern int gpmc_cs_configure(int cs, int cmd, int wval);
 extern int gpmc_nand_read(int cs, int cmd);
 extern int gpmc_nand_write(int cs, int cmd, int wval);
+extern struct clk *gpmc_clock(void);
 
 int gpmc_enable_hwecc(int ecc, int cs, int mode, int dev_width, int ecc_size);
 int gpmc_calculate_ecc(int ecc, int cs, const u_char *dat, u_char *ecc_code);
index 67fc5060183ea28f137f20862863e62cb99ccf74..b9422ef469a8c6e605125db549f6809cf0e86f03 100644 (file)
@@ -29,6 +29,7 @@ struct omap_nand_platform_data {
        unsigned long           phys_base;
        int                     devsize;
        enum omap_ecc           ecc_opt;
+       struct clk              *ctrl_clk;
 };
 
 /* minimum size for IO mapping */
index acacb308fd75a414aeefdbdd7a5d890bdba5fd25..c462c5b3c8a995528bbfacc80087ec8ecb4f3b50 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
 
 #include <plat/dma.h>
 #include <plat/gpmc.h>
@@ -140,6 +141,7 @@ struct omap_nand_info {
        u_char                          *buf;
        int                             buf_len;
        int                             ecc_opt;
+       struct clk                      *ctrl_clk;
 };
 
 /**
@@ -1117,6 +1119,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
 
        info->pdev = pdev;
 
+       info->ctrl_clk          = pdata->ctrl_clk;
        info->gpmc_cs           = pdata->cs;
        info->phys_base         = pdata->phys_base;
 
@@ -1338,9 +1341,39 @@ static int omap_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int omap_nand_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+
+       mtd->suspend(mtd);
+       clk_disable(info->ctrl_clk);
+       elm_clk_disable();
+       return 0;
+}
+
+static int omap_nand_resume(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+
+       elm_clk_enable();
+       clk_enable(info->ctrl_clk);
+       mtd->resume(mtd);
+       return 0;
+}
+#endif
+
 static struct platform_driver omap_nand_driver = {
        .probe          = omap_nand_probe,
        .remove         = omap_nand_remove,
+#ifdef CONFIG_PM
+       .suspend        = omap_nand_suspend,
+       .resume         = omap_nand_resume,
+#endif
        .driver         = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,