aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Martinez Canillas <javier.martinez@collabora.co.uk>2015-06-12 01:43:15 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-06-16 05:34:41 -0400
commit6fd4899a54a522ccd6a24fea2318d3b515b95945 (patch)
treeb42d7ddeaee568223b0b1f59f203db9b43474c62
parent55963c9f20d03124eefb4c365e1ca1f485fc3974 (diff)
irqchip: exynos-combiner: Save IRQ enable set on suspend
The Exynos interrupt combiner IP loses its state when the SoC enters into a low power state during a Suspend-to-RAM. This means that if a IRQ is used as a source, the interrupts for the devices are disabled when the system is resumed from a sleep state so are not triggered. Save the interrupt enable set register for each combiner group and restore it after resume to make sure that the interrupts are enabled. Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Kukjin Kim <kgene@kernel.org> Cc: Tomasz Figa <tomasz.figa@gmail.com> Cc: Doug Anderson <dianders@chromium.org> Cc: linux-arm-kernel@lists.infradead.org Cc: Peter Chubb <peter.chubb@nicta.com.au> Cc: Shuah Khan <shuahkhan@gmail.com> Cc: Chanho Park <parkch98@gmail.com> Cc: Sudeep Holla <sudeep.holla@arm.com> Link: http://lkml.kernel.org/r/1434087795-13990-1-git-send-email-javier.martinez@collabora.co.uk Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/irqchip/exynos-combiner.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index a57a3a1f339f..5c82e3bdafdf 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -13,6 +13,7 @@
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/io.h> 14#include <linux/io.h>
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/syscore_ops.h>
16#include <linux/irqdomain.h> 17#include <linux/irqdomain.h>
17#include <linux/irqchip/chained_irq.h> 18#include <linux/irqchip/chained_irq.h>
18#include <linux/interrupt.h> 19#include <linux/interrupt.h>
@@ -34,9 +35,14 @@ struct combiner_chip_data {
34 unsigned int irq_mask; 35 unsigned int irq_mask;
35 void __iomem *base; 36 void __iomem *base;
36 unsigned int parent_irq; 37 unsigned int parent_irq;
38#ifdef CONFIG_PM
39 u32 pm_save;
40#endif
37}; 41};
38 42
43static struct combiner_chip_data *combiner_data;
39static struct irq_domain *combiner_irq_domain; 44static struct irq_domain *combiner_irq_domain;
45static unsigned int max_nr = 20;
40 46
41static inline void __iomem *combiner_base(struct irq_data *data) 47static inline void __iomem *combiner_base(struct irq_data *data)
42{ 48{
@@ -170,12 +176,10 @@ static const struct irq_domain_ops combiner_irq_domain_ops = {
170}; 176};
171 177
172static void __init combiner_init(void __iomem *combiner_base, 178static void __init combiner_init(void __iomem *combiner_base,
173 struct device_node *np, 179 struct device_node *np)
174 unsigned int max_nr)
175{ 180{
176 int i, irq; 181 int i, irq;
177 unsigned int nr_irq; 182 unsigned int nr_irq;
178 struct combiner_chip_data *combiner_data;
179 183
180 nr_irq = max_nr * IRQ_IN_COMBINER; 184 nr_irq = max_nr * IRQ_IN_COMBINER;
181 185
@@ -201,11 +205,59 @@ static void __init combiner_init(void __iomem *combiner_base,
201 } 205 }
202} 206}
203 207
208#ifdef CONFIG_PM
209
210/**
211 * combiner_suspend - save interrupt combiner state before suspend
212 *
213 * Save the interrupt enable set register for all combiner groups since
214 * the state is lost when the system enters into a sleep state.
215 *
216 */
217static int combiner_suspend(void)
218{
219 int i;
220
221 for (i = 0; i < max_nr; i++)
222 combiner_data[i].pm_save =
223 __raw_readl(combiner_data[i].base + COMBINER_ENABLE_SET);
224
225 return 0;
226}
227
228/**
229 * combiner_resume - restore interrupt combiner state after resume
230 *
231 * Restore the interrupt enable set register for all combiner groups since
232 * the state is lost when the system enters into a sleep state on suspend.
233 *
234 */
235static void combiner_resume(void)
236{
237 int i;
238
239 for (i = 0; i < max_nr; i++) {
240 __raw_writel(combiner_data[i].irq_mask,
241 combiner_data[i].base + COMBINER_ENABLE_CLEAR);
242 __raw_writel(combiner_data[i].pm_save,
243 combiner_data[i].base + COMBINER_ENABLE_SET);
244 }
245}
246
247#else
248#define combiner_suspend NULL
249#define combiner_resume NULL
250#endif
251
252static struct syscore_ops combiner_syscore_ops = {
253 .suspend = combiner_suspend,
254 .resume = combiner_resume,
255};
256
204static int __init combiner_of_init(struct device_node *np, 257static int __init combiner_of_init(struct device_node *np,
205 struct device_node *parent) 258 struct device_node *parent)
206{ 259{
207 void __iomem *combiner_base; 260 void __iomem *combiner_base;
208 unsigned int max_nr = 20;
209 261
210 combiner_base = of_iomap(np, 0); 262 combiner_base = of_iomap(np, 0);
211 if (!combiner_base) { 263 if (!combiner_base) {
@@ -219,7 +271,9 @@ static int __init combiner_of_init(struct device_node *np,
219 __func__, max_nr); 271 __func__, max_nr);
220 } 272 }
221 273
222 combiner_init(combiner_base, np, max_nr); 274 combiner_init(combiner_base, np);
275
276 register_syscore_ops(&combiner_syscore_ops);
223 277
224 return 0; 278 return 0;
225} 279}