diff options
author | Fugang Duan <fugang.duan@nxp.com> | 2017-11-20 15:55:40 +0800 |
---|---|---|
committer | Fugang Duan <fugang.duan@nxp.com> | 2017-11-20 16:52:04 +0800 |
commit | a117ec62e26f6ac945f014ea1a26f5068eea0b07 (patch) | |
tree | e0a9f3b1c0ac745ca7ddb2baa9f0cbc7c40f5c0e | |
parent | 0da9c6582d4ad97422ca5317bda38d85e19bbb33 (diff) |
MLK-16909 irqchip: imx-irqsteer: restore registers after power off
Once irqsteer controller is power off during suspend, the registers
are lost, it should restore the registers after resume back.
BuildInfo:
- SCFW a479ff78, IMX-MKIMAGE ff9860c5, ATF 923651a
- U-Boot 2017.03-00691-g96cf020
Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
Tested-by: Pandy.gao <pandy.gao@nxp.com>
Acked-by: Pandy.gao <pandy.gao@nxp.com>
-rw-r--r-- | drivers/irqchip/irq-imx-irqsteer.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c index 2e8f04a2a0fb..6aa0a68e7873 100644 --- a/drivers/irqchip/irq-imx-irqsteer.c +++ b/drivers/irqchip/irq-imx-irqsteer.c @@ -33,6 +33,7 @@ struct irqsteer_irqchip_data { int channum; int endian; /* 0: littel endian; 1: big endian */ struct irq_domain *domain; + int *saved_reg; unsigned int irqstat[]; }; @@ -168,6 +169,10 @@ static int imx_irqsteer_probe(struct platform_device *pdev) if (!irqsteer_data) return -ENOMEM; + irqsteer_data->saved_reg = devm_kzalloc(&pdev->dev, sizeof(int) * + (channum + 1), GFP_KERNEL); + if (!irqsteer_data->saved_reg) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irqsteer_data->regs = devm_ioremap_resource(&pdev->dev, res); @@ -235,6 +240,58 @@ static int imx_irqsteer_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static void imx_irqsteer_save_regs(struct irqsteer_irqchip_data *data) +{ + int num; + + data->saved_reg[0] = readl_relaxed(data->regs + CHANCTRL); + for (num = 0; num < data->channum; num++) + data->saved_reg[num + 1] = readl_relaxed(data->regs + CHANMASK(num)); +} + +static void imx_irqsteer_restore_regs(struct irqsteer_irqchip_data *data) +{ + int num; + + writel_relaxed(data->saved_reg[0], data->regs + CHANCTRL); + for (num = 0; num < data->channum; num++) + writel_relaxed(data->saved_reg[num + 1], data->regs + CHANMASK(num)); +} + +static int imx_irqsteer_suspend(struct device *dev) +{ + struct irqsteer_irqchip_data *irqsteer_data = dev_get_drvdata(dev); + + imx_irqsteer_save_regs(irqsteer_data); + clk_disable_unprepare(irqsteer_data->ipg_clk); + + return 0; +} + +static int imx_irqsteer_resume(struct device *dev) +{ + struct irqsteer_irqchip_data *irqsteer_data = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(irqsteer_data->ipg_clk); + if (ret) { + dev_err(dev, "failed to enable ipg clk: %d\n", ret); + return ret; + } + imx_irqsteer_restore_regs(irqsteer_data); + + return 0; +} + +static const struct dev_pm_ops imx_irqsteer_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_irqsteer_suspend, imx_irqsteer_resume) +}; +#define IMX_IRQSTEER_PM (&imx_irqsteer_pm_ops) +#else +#define IMX_IRQSTEER_PM NULL +#endif + static const struct of_device_id imx_irqsteer_id[] = { { .compatible = "nxp,imx-irqsteer", }, {}, @@ -244,6 +301,7 @@ static struct platform_driver imx_irqsteer_driver = { .driver = { .name = "imx-irqsteer", .of_match_table = imx_irqsteer_id, + .pm = IMX_IRQSTEER_PM, }, .probe = imx_irqsteer_probe, .remove = imx_irqsteer_remove, |