diff options
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 68 |
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 | ||
40 | struct 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 | |||
38 | struct pl061_gpio { | 50 | struct 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 | ||
59 | static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) | 75 | static 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 | ||
335 | iounmap: | 353 | iounmap: |
@@ -342,6 +360,53 @@ free_mem: | |||
342 | return ret; | 360 | return ret; |
343 | } | 361 | } |
344 | 362 | ||
363 | #ifdef CONFIG_PM | ||
364 | static 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 | |||
385 | static 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 | |||
407 | static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); | ||
408 | #endif | ||
409 | |||
345 | static struct amba_id pl061_ids[] = { | 410 | static struct amba_id pl061_ids[] = { |
346 | { | 411 | { |
347 | .id = 0x00041061, | 412 | .id = 0x00041061, |
@@ -353,6 +418,9 @@ static struct amba_id pl061_ids[] = { | |||
353 | static struct amba_driver pl061_gpio_driver = { | 418 | static 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, |