Add support of suspend, resume function to support deep sleep. Also make sure of SRAM initialization during resume.
Signed-off-by: Raghav Dogra <rag...@freescale.com> --- drivers/memory/fsl_ifc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fsl_ifc.h | 6 ++++++ 2 files changed, 62 insertions(+) diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index e87459f..163ccf2 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/compiler.h> #include <linux/spinlock.h> +#include <linux/delay.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/io.h> @@ -35,6 +36,9 @@ struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev; EXPORT_SYMBOL(fsl_ifc_ctrl_dev); +#define FSL_IFC_V1_3_0 0x01030000 +#define IFC_TIMEOUT_MSECS 100000 /* 100ms */ + /* * convert_ifc_address - convert the base address * @addr_base: base address of the memory bank @@ -308,6 +312,53 @@ err: return ret; } +#ifdef CONFIG_PM_SLEEP +/* save ifc registers */ +static int fsl_ifc_suspend(struct device *dev) +{ + struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev); + struct fsl_ifc_regs __iomem *ifc = ctrl->regs; + + ctrl->saved_regs = kzalloc(sizeof(struct fsl_ifc_regs), GFP_KERNEL); + if (!ctrl->saved_regs) + return -ENOMEM; + + _memcpy_fromio(ctrl->saved_regs, ifc, sizeof(struct fsl_ifc_regs)); + + return 0; +} + +/* restore ifc registers */ +static int fsl_ifc_resume(struct device *dev) +{ + struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev); + struct fsl_ifc_regs __iomem *ifc = ctrl->regs; + uint32_t ver = 0, ncfgr, status; + + if (ctrl->saved_regs) { + _memcpy_toio(ifc, ctrl->saved_regs, + sizeof(struct fsl_ifc_regs)); + kfree(ctrl->saved_regs); + ctrl->saved_regs = NULL; + } + + ver = in_be32(&ctrl->regs->ifc_rev); + ncfgr = in_be32(&ifc->ifc_nand.ncfgr); + if (ver >= FSL_IFC_V1_3_0) { + out_be32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN); + + /* wait for SRAM_INIT bit to be clear or timeout */ + status = spin_event_timeout(!(in_be32(&ifc->ifc_nand.ncfgr) + & IFC_NAND_SRAM_INIT_EN), + IFC_TIMEOUT_MSECS, 0); + if (!status) + dev_err(ctrl->dev, "Timeout waiting for IFC SRAM INIT"); + } + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static const struct of_device_id fsl_ifc_match[] = { { .compatible = "fsl,ifc", @@ -315,10 +366,15 @@ static const struct of_device_id fsl_ifc_match[] = { {}, }; +static const struct dev_pm_ops ifc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fsl_ifc_suspend, fsl_ifc_resume) +}; + static struct platform_driver fsl_ifc_ctrl_driver = { .driver = { .name = "fsl-ifc", .of_match_table = fsl_ifc_match, + .pm = &ifc_pm_ops, }, .probe = fsl_ifc_ctrl_probe, .remove = fsl_ifc_ctrl_remove, diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h index 0023088..2776df2 100644 --- a/include/linux/fsl_ifc.h +++ b/include/linux/fsl_ifc.h @@ -270,6 +270,8 @@ */ /* Auto Boot Mode */ #define IFC_NAND_NCFGR_BOOT 0x80000000 +/* SRAM INIT EN */ +#define IFC_NAND_SRAM_INIT_EN 0x20000000 /* Addressing Mode-ROW0+n/COL0 */ #define IFC_NAND_NCFGR_ADDR_MODE_RC0 0x00000000 /* Addressing Mode-ROW0+n/COL0+n */ @@ -841,6 +843,10 @@ struct fsl_ifc_ctrl { u32 nand_stat; wait_queue_head_t nand_wait; +#ifdef CONFIG_PM_SLEEP + /* save regs when system go to deep-sleep */ + struct fsl_ifc_regs *saved_regs; +#endif bool little_endian; }; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/