gpio: gpio-rcar: Support S2RAM

This patch adds an implementation that saves and restores the state of
GPIO configuration on suspend and resume.

Signed-off-by: Hien Dang <hien.dang.eb@renesas.com>
Signed-off-by: Takeshi Kihara <takeshi.kihara.df@renesas.com>
[Modify structure of the bank info to simplify a saving registers]
[Remove DEV_PM_OPS macro]
Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>
Tested-by: Nguyen Viet Dung <dung.nguyen.aj@renesas.com>
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Hien Dang 2018-02-05 04:15:02 +09:00 committed by Linus Walleij
parent 62c16234bb
commit 51750fb167

View file

@ -31,6 +31,16 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
struct gpio_rcar_bank_info {
u32 iointsel;
u32 inoutsel;
u32 outdt;
u32 posneg;
u32 edglevel;
u32 bothedge;
u32 intmsk;
};
struct gpio_rcar_priv {
void __iomem *base;
spinlock_t lock;
@ -41,6 +51,7 @@ struct gpio_rcar_priv {
unsigned int irq_parent;
bool has_both_edge_trigger;
bool needs_clk;
struct gpio_rcar_bank_info bank_info;
};
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
@ -531,11 +542,66 @@ static int gpio_rcar_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int gpio_rcar_suspend(struct device *dev)
{
struct gpio_rcar_priv *p = dev_get_drvdata(dev);
p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL);
p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL);
p->bank_info.outdt = gpio_rcar_read(p, OUTDT);
p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
if (p->has_both_edge_trigger)
p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);
return 0;
}
static int gpio_rcar_resume(struct device *dev)
{
struct gpio_rcar_priv *p = dev_get_drvdata(dev);
unsigned int offset;
u32 mask;
for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {
mask = BIT(offset);
/* I/O pin */
if (!(p->bank_info.iointsel & mask)) {
if (p->bank_info.inoutsel & mask)
gpio_rcar_direction_output(
&p->gpio_chip, offset,
!!(p->bank_info.outdt & mask));
else
gpio_rcar_direction_input(&p->gpio_chip,
offset);
} else {
/* Interrupt pin */
gpio_rcar_config_interrupt_input_mode(
p,
offset,
!(p->bank_info.posneg & mask),
!(p->bank_info.edglevel & mask),
!!(p->bank_info.bothedge & mask));
if (p->bank_info.intmsk & mask)
gpio_rcar_write(p, MSKCLR, mask);
}
}
return 0;
}
#endif /* CONFIG_PM_SLEEP*/
static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume);
static struct platform_driver gpio_rcar_device_driver = {
.probe = gpio_rcar_probe,
.remove = gpio_rcar_remove,
.driver = {
.name = "gpio_rcar",
.pm = &gpio_rcar_pm_ops,
.of_match_table = of_match_ptr(gpio_rcar_of_table),
}
};