From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751979AbbG3UOj (ORCPT ); Thu, 30 Jul 2015 16:14:39 -0400 Received: from mail-pd0-f193.google.com ([209.85.192.193]:35946 "EHLO mail-pd0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750880AbbG3UOh (ORCPT ); Thu, 30 Jul 2015 16:14:37 -0400 Date: Thu, 30 Jul 2015 13:14:31 -0700 From: Dmitry Torokhov To: Wolfram Sang Cc: Mika Westerberg , "Rafael J. Wysocki" , Ulf Hansson , Vignesh R , Tony Lindgren , Rob Herring , Mark Rutland , linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] i2c: allow specifying separate wakeup interrupt in device tree Message-ID: <20150730201431.GA5255@dtor-ws> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Instead of having each i2c driver individually parse device tree data in case it or platform supports separate wakeup interrupt, and handle enabling and disabling wakeup interrupts in their power management routines, let's have i2c core do that for us. Platforms wishing to specify separate wakeup interrupt for the device should use named interrupt syntax in their DTSes: interrupt-parent = <&intc1>; interrupts = <5 0>, <6 0>; interrupt-names = "irq", "wakeup"; This patch is inspired by work done by Vignesh R for pixcir_i2c_ts driver. Signed-off-by: Dmitry Torokhov --- drivers/i2c/i2c-core.c | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e6d4935..19e7a17 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -639,11 +640,13 @@ static int i2c_device_probe(struct device *dev) if (!client->irq) { int irq = -ENOENT; - if (dev->of_node) - irq = of_irq_get(dev->of_node, 0); - else if (ACPI_COMPANION(dev)) + if (dev->of_node) { + irq = of_irq_get_byname(dev->of_node, "irq"); + if (irq == -EINVAL || irq == -ENODATA) + irq = of_irq_get(dev->of_node, 0); + } else if (ACPI_COMPANION(dev)) { irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); - + } if (irq == -EPROBE_DEFER) return irq; if (irq < 0) @@ -659,20 +662,47 @@ static int i2c_device_probe(struct device *dev) if (!device_can_wakeup(&client->dev)) device_init_wakeup(&client->dev, client->flags & I2C_CLIENT_WAKE); + + if (device_can_wakeup(&client->dev)) { + int wakeirq = -ENOENT; + + if (dev->of_node) { + wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); + if (wakeirq == -EPROBE_DEFER) + return wakeirq; + } + + if (wakeirq > 0 && wakeirq != client->irq) + status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); + else if (client->irq > 0) + status = dev_pm_set_wake_irq(dev, wakeirq); + else + status = 0; + + if (status) + dev_warn(&client->dev, "failed to set up wakeup irq"); + } + dev_dbg(dev, "probe\n"); status = of_clk_set_defaults(dev->of_node, false); if (status < 0) - return status; + goto err_clear_wakeup_irq; status = dev_pm_domain_attach(&client->dev, true); if (status != -EPROBE_DEFER) { status = driver->probe(client, i2c_match_id(driver->id_table, client)); if (status) - dev_pm_domain_detach(&client->dev, true); + goto err_detach_pm_domain; } + return 0; + +err_detach_pm_domain: + dev_pm_domain_detach(&client->dev, true); +err_clear_wakeup_irq: + dev_pm_clear_wake_irq(&client->dev); return status; } @@ -692,6 +722,10 @@ static int i2c_device_remove(struct device *dev) } dev_pm_domain_detach(&client->dev, true); + + dev_pm_clear_wake_irq(&client->dev); + device_init_wakeup(&client->dev, 0); + return status; } -- 2.5.0.rc2.392.g76e840b -- Dmitry