aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/gpio-pl061.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 093c90bd3c1d..42a5d5672694 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -23,6 +23,7 @@
23#include <linux/amba/bus.h> 23#include <linux/amba/bus.h>
24#include <linux/amba/pl061.h> 24#include <linux/amba/pl061.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/pm.h>
26 27
27#define GPIODIR 0x400 28#define GPIODIR 0x400
28#define GPIOIS 0x404 29#define GPIOIS 0x404
@@ -35,6 +36,17 @@
35 36
36#define PL061_GPIO_NR 8 37#define PL061_GPIO_NR 8
37 38
39#ifdef CONFIG_PM
40struct pl061_context_save_regs {
41 u8 gpio_data;
42 u8 gpio_dir;
43 u8 gpio_is;
44 u8 gpio_ibe;
45 u8 gpio_iev;
46 u8 gpio_ie;
47};
48#endif
49
38struct pl061_gpio { 50struct pl061_gpio {
39 /* We use a list of pl061_gpio structs for each trigger IRQ in the main 51 /* We use a list of pl061_gpio structs for each trigger IRQ in the main
40 * interrupts controller of the system. We need this to support systems 52 * interrupts controller of the system. We need this to support systems
@@ -54,6 +66,10 @@ struct pl061_gpio {
54 void __iomem *base; 66 void __iomem *base;
55 unsigned irq_base; 67 unsigned irq_base;
56 struct gpio_chip gc; 68 struct gpio_chip gc;
69
70#ifdef CONFIG_PM
71 struct pl061_context_save_regs csave_regs;
72#endif
57}; 73};
58 74
59static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) 75static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
@@ -330,6 +346,8 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
330 irq_set_chip_data(i + chip->irq_base, chip); 346 irq_set_chip_data(i + chip->irq_base, chip);
331 } 347 }
332 348
349 amba_set_drvdata(dev, chip);
350
333 return 0; 351 return 0;
334 352
335iounmap: 353iounmap:
@@ -342,6 +360,53 @@ free_mem:
342 return ret; 360 return ret;
343} 361}
344 362
363#ifdef CONFIG_PM
364static int pl061_suspend(struct device *dev)
365{
366 struct pl061_gpio *chip = dev_get_drvdata(dev);
367 int offset;
368
369 chip->csave_regs.gpio_data = 0;
370 chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR);
371 chip->csave_regs.gpio_is = readb(chip->base + GPIOIS);
372 chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE);
373 chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV);
374 chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE);
375
376 for (offset = 0; offset < PL061_GPIO_NR; offset++) {
377 if (chip->csave_regs.gpio_dir & (1 << offset))
378 chip->csave_regs.gpio_data |=
379 pl061_get_value(&chip->gc, offset) << offset;
380 }
381
382 return 0;
383}
384
385static int pl061_resume(struct device *dev)
386{
387 struct pl061_gpio *chip = dev_get_drvdata(dev);
388 int offset;
389
390 for (offset = 0; offset < PL061_GPIO_NR; offset++) {
391 if (chip->csave_regs.gpio_dir & (1 << offset))
392 pl061_direction_output(&chip->gc, offset,
393 chip->csave_regs.gpio_data &
394 (1 << offset));
395 else
396 pl061_direction_input(&chip->gc, offset);
397 }
398
399 writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS);
400 writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE);
401 writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV);
402 writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE);
403
404 return 0;
405}
406
407static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
408#endif
409
345static struct amba_id pl061_ids[] = { 410static struct amba_id pl061_ids[] = {
346 { 411 {
347 .id = 0x00041061, 412 .id = 0x00041061,
@@ -353,6 +418,9 @@ static struct amba_id pl061_ids[] = {
353static struct amba_driver pl061_gpio_driver = { 418static struct amba_driver pl061_gpio_driver = {
354 .drv = { 419 .drv = {
355 .name = "pl061_gpio", 420 .name = "pl061_gpio",
421#ifdef CONFIG_PM
422 .pm = &pl061_dev_pm_ops,
423#endif
356 }, 424 },
357 .id_table = pl061_ids, 425 .id_table = pl061_ids,
358 .probe = pl061_probe, 426 .probe = pl061_probe,