Skip to content

Commit

Permalink
gpio: rcar: Prevent module clock disable when wake-up is enabled
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Linus Walleij <[email protected]>
  • Loading branch information
geertu authored and linusw committed Mar 26, 2015
1 parent 3dc1e68 commit ab82fa7
Showing 1 changed file with 31 additions and 2 deletions.
33 changes: 31 additions & 2 deletions drivers/gpio/gpio-rcar.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/

#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
Expand All @@ -37,6 +38,8 @@ struct gpio_rcar_priv {
struct platform_device *pdev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
unsigned int irq_parent;
struct clk *clk;
};

#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
Expand Down Expand Up @@ -169,6 +172,25 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}

static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
gpio_chip);

irq_set_irq_wake(p->irq_parent, on);

if (!p->clk)
return 0;

if (on)
clk_enable(p->clk);
else
clk_disable(p->clk);

return 0;
}

static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
{
struct gpio_rcar_priv *p = dev_id;
Expand Down Expand Up @@ -367,6 +389,12 @@ static int gpio_rcar_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, p);

p->clk = devm_clk_get(dev, NULL);
if (IS_ERR(p->clk)) {
dev_warn(dev, "unable to get clock\n");
p->clk = NULL;
}

pm_runtime_enable(dev);
pm_runtime_get_sync(dev);

Expand Down Expand Up @@ -404,8 +432,8 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->irq_mask = gpio_rcar_irq_disable;
irq_chip->irq_unmask = gpio_rcar_irq_enable;
irq_chip->irq_set_type = gpio_rcar_irq_set_type;
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED
| IRQCHIP_MASK_ON_SUSPEND;
irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;

ret = gpiochip_add(gpio_chip);
if (ret) {
Expand All @@ -420,6 +448,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
goto err1;
}

p->irq_parent = irq->start;
if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
IRQF_SHARED, name, p)) {
dev_err(dev, "failed to request IRQ\n");
Expand Down

0 comments on commit ab82fa7

Please sign in to comment.