All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hector Palacios <hector.palacios@digi.com>
To: linux-gpio@vger.kernel.org
Cc: linus.walleij@linaro.org,
	"fabio.estevam@freescale.com" <fabio.estevam@freescale.com>,
	zonque@gmail.com, "shawn.guo@linaro.org" <shawn.guo@linaro.org>
Subject: mxs gpios as wakeup interrupts and irq_set_wake() hook
Date: Thu, 21 Nov 2013 11:19:28 +0100	[thread overview]
Message-ID: <528DDE30.4090509@digi.com> (raw)

Hello,

I was trying to have GPIOs be able to wake up my ARM i.MX28 system from suspend but 
noticed that the existing hook irq_set_wake() in the driver

	ct->chip.irq_set_wake = mxs_gpio_set_wake_irq;

was never called when I enabled a gpio as wakeup via the sysfs:

	echo enabled > /sys/class/gpio/gpio107/device/power/wakeup

The implementation of the hook itself is:

static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
{
	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
	struct mxs_gpio_port *port = gc->private;

	if (enable)
		enable_irq_wake(port->irq);
	else
		disable_irq_wake(port->irq);

	return 0;
}

which looks to me like a cyclic call because the irq_set_wake() hook is called from 
set_irq_wake_real() which is called from irq_set_irq_wake() which is called from 
enable_irq_wake(). And this last function is what the driver's hook implementation is 
doing.
I was expecting that enable_irq_wake() was fired somehow from the kernel when I enable 
the wakeup descriptor in the sysfs, but I guess it works in a different way.

Instead, I implemented suspend/resume calls in the gpio driver that fire the 
enable_irq_wake/disable_irq_wake if the device can_wakeup flag is set (this is what 
the sysfs does). I took this model from the serial driver.
This works but, could anyone tell me if this approach correct for gpio?

@@ -174,6 +174,7 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
  	}
  }

+#ifdef CONFIG_PM_SLEEP
  /*
   * Set interrupt number "irq" in the GPIO as a wake-up source.
   * While system is running, all registered GPIO interrupts need to have
@@ -196,6 +197,33 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int 
enable)
  	return 0;
  }

+static int mxs_gpio_suspend(struct device *dev)
+{
+	struct platform_device *pdev =
+			container_of(dev, struct platform_device, dev);
+	int irq = platform_get_irq(pdev, 0);
+
+	/* Enable wakeup irq before suspending, if device can wakeup */
+	if (device_may_wakeup(dev))
+		return enable_irq_wake(irq);
+
+	return 0;
+}
+
+static int mxs_gpio_resume(struct device *dev)
+{
+	struct platform_device *pdev =
+			container_of(dev, struct platform_device, dev);
+	int irq = platform_get_irq(pdev, 0);
+
+	/* Disable wakeup irq on resume, if device can wakeup */
+	if (device_may_wakeup(dev))
+		return disable_irq_wake(irq);
+
+	return 0;
+}
+#endif
+
  static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
  {
  	struct irq_chip_generic *gc;
@@ -210,7 +238,9 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, 
int irq_base)
  	ct->chip.irq_mask = irq_gc_mask_clr_bit;
  	ct->chip.irq_unmask = irq_gc_mask_set_bit;
  	ct->chip.irq_set_type = mxs_gpio_set_irq_type;
+#ifdef CONFIG_PM_SLEEP
  	ct->chip.irq_set_wake = mxs_gpio_set_wake_irq;
+#endif
  	ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
  	ct->regs.mask = PINCTRL_IRQEN(port);

@@ -320,6 +350,10 @@ static int mxs_gpio_probe(struct platform_device *pdev)
  	/* gpio-mxs can be a generic irq chip */
  	mxs_gpio_init_gc(port, irq_base);

+#ifdef CONFIG_PM_SLEEP
+	device_set_wakeup_capable(&pdev->dev, 1);
+#endif
+
  	/* setup one handler for each entry */
  	irq_set_chained_handler(port->irq, mxs_gpio_irq_handler);
  	irq_set_handler_data(port->irq, port);
@@ -348,11 +382,16 @@ out_irqdesc_free:
  	return err;
  }

+static const struct dev_pm_ops mxs_gpio_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mxs_gpio_suspend, mxs_gpio_resume)
+};
+
  static struct platform_driver mxs_gpio_driver = {
  	.driver		= {
  		.name	= "gpio-mxs",
  		.owner	= THIS_MODULE,
  		.of_match_table = mxs_gpio_dt_ids,
+		.pm	= &mxs_gpio_pm_ops,
  	},
  	.probe		= mxs_gpio_probe,
  	.id_table	= mxs_gpio_ids,


Best regards,
--
Hector Palacios

             reply	other threads:[~2013-11-21 10:26 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-21 10:19 Hector Palacios [this message]
2013-11-21 16:35 ` mxs gpios as wakeup interrupts and irq_set_wake() hook Fabio Estevam
2013-11-21 17:32   ` Hector Palacios
2013-11-21 17:45     ` Fabio Estevam
2013-11-27 14:00 ` Linus Walleij

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=528DDE30.4090509@digi.com \
    --to=hector.palacios@digi.com \
    --cc=fabio.estevam@freescale.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=shawn.guo@linaro.org \
    --cc=zonque@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.