aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorDeepak Sikri <deepak.sikri@st.com>2011-11-18 04:50:12 -0500
committerGrant Likely <grant.likely@secretlab.ca>2012-01-04 02:37:37 -0500
commite198a8de14d4bb122b821432fadb28eedd4b4507 (patch)
tree7e44821222a4a67ce96e39c7b58d9d690336fdf6 /drivers/gpio
parentaedd4fdf69293fc5379129294239b09da2a7c3ec (diff)
GPIO/pl061: Add suspend resume capability
This patch adds the suspend and resume operations in the driver. The patch ensures the data save and restore for the device registers during the suspend and resume operations respectively. Signed-off-by: Deepak Sikri <deepak.sikri@st.com> Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Acked-by: Baruch Siach <baruch@tkos.co.il> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio')
-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,