diff options
author | Geert Uytterhoeven <geert+renesas@glider.be> | 2015-03-18 14:41:09 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-03-26 05:25:32 -0400 |
commit | ab82fa7da4dce5c728730d7aa0e11a2cbc9266da (patch) | |
tree | 9dbd5bda183455a012a4dba19a507cc5c3c14767 /drivers/gpio/gpio-rcar.c | |
parent | 3dc1e6852115b3163e7dacc76bbcb78ccff29421 (diff) |
gpio: rcar: Prevent module clock disable when wake-up is enabled
When the GPIO module is needed for wake-up, it's module clock must not
be disabled. Hence implement irq_chip.irq_set_wake(), which
increments/decrements the clock's enable_count when needed, and forwards
the wake-up state to the upstream interrupt controller.
This fixes wake-up from s2ram using gpio-keys when using a PM Domain to
manage the module clock.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-rcar.c')
-rw-r--r-- | drivers/gpio/gpio-rcar.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index d96166ca1b42..fd3977465948 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/clk.h> | ||
17 | #include <linux/err.h> | 18 | #include <linux/err.h> |
18 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
@@ -37,6 +38,8 @@ struct gpio_rcar_priv { | |||
37 | struct platform_device *pdev; | 38 | struct platform_device *pdev; |
38 | struct gpio_chip gpio_chip; | 39 | struct gpio_chip gpio_chip; |
39 | struct irq_chip irq_chip; | 40 | struct irq_chip irq_chip; |
41 | unsigned int irq_parent; | ||
42 | struct clk *clk; | ||
40 | }; | 43 | }; |
41 | 44 | ||
42 | #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ | 45 | #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ |
@@ -169,6 +172,25 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) | |||
169 | return 0; | 172 | return 0; |
170 | } | 173 | } |
171 | 174 | ||
175 | static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) | ||
176 | { | ||
177 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | ||
178 | struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, | ||
179 | gpio_chip); | ||
180 | |||
181 | irq_set_irq_wake(p->irq_parent, on); | ||
182 | |||
183 | if (!p->clk) | ||
184 | return 0; | ||
185 | |||
186 | if (on) | ||
187 | clk_enable(p->clk); | ||
188 | else | ||
189 | clk_disable(p->clk); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
172 | static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) | 194 | static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) |
173 | { | 195 | { |
174 | struct gpio_rcar_priv *p = dev_id; | 196 | struct gpio_rcar_priv *p = dev_id; |
@@ -367,6 +389,12 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
367 | 389 | ||
368 | platform_set_drvdata(pdev, p); | 390 | platform_set_drvdata(pdev, p); |
369 | 391 | ||
392 | p->clk = devm_clk_get(dev, NULL); | ||
393 | if (IS_ERR(p->clk)) { | ||
394 | dev_warn(dev, "unable to get clock\n"); | ||
395 | p->clk = NULL; | ||
396 | } | ||
397 | |||
370 | pm_runtime_enable(dev); | 398 | pm_runtime_enable(dev); |
371 | pm_runtime_get_sync(dev); | 399 | pm_runtime_get_sync(dev); |
372 | 400 | ||
@@ -404,8 +432,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
404 | irq_chip->irq_mask = gpio_rcar_irq_disable; | 432 | irq_chip->irq_mask = gpio_rcar_irq_disable; |
405 | irq_chip->irq_unmask = gpio_rcar_irq_enable; | 433 | irq_chip->irq_unmask = gpio_rcar_irq_enable; |
406 | irq_chip->irq_set_type = gpio_rcar_irq_set_type; | 434 | irq_chip->irq_set_type = gpio_rcar_irq_set_type; |
407 | irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED | 435 | irq_chip->irq_set_wake = gpio_rcar_irq_set_wake; |
408 | | IRQCHIP_MASK_ON_SUSPEND; | 436 | irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; |
409 | 437 | ||
410 | ret = gpiochip_add(gpio_chip); | 438 | ret = gpiochip_add(gpio_chip); |
411 | if (ret) { | 439 | if (ret) { |
@@ -420,6 +448,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
420 | goto err1; | 448 | goto err1; |
421 | } | 449 | } |
422 | 450 | ||
451 | p->irq_parent = irq->start; | ||
423 | if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, | 452 | if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, |
424 | IRQF_SHARED, name, p)) { | 453 | IRQF_SHARED, name, p)) { |
425 | dev_err(dev, "failed to request IRQ\n"); | 454 | dev_err(dev, "failed to request IRQ\n"); |