From patchwork Fri May 31 10:13:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hebbar, Gururaja" X-Patchwork-Id: 2641831 Return-Path: X-Original-To: patchwork-davinci@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from devils.ext.ti.com (devils.ext.ti.com [198.47.26.153]) by patchwork2.kernel.org (Postfix) with ESMTP id 1F91CDFB79 for ; Fri, 31 May 2013 10:13:09 +0000 (UTC) Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id r4VABNRC017134; Fri, 31 May 2013 05:11:23 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id r4VABN2k003661; Fri, 31 May 2013 05:11:23 -0500 Received: from dlelxv23.itg.ti.com (172.17.1.198) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.2.342.3; Fri, 31 May 2013 05:11:23 -0500 Received: from linux.omap.com (dlelxs01.itg.ti.com [157.170.227.31]) by dlelxv23.itg.ti.com (8.13.8/8.13.8) with ESMTP id r4VABNK3006001; Fri, 31 May 2013 05:11:23 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 30DC080626; Fri, 31 May 2013 05:11:23 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dlelxv90.itg.ti.com (dlelxv90.itg.ti.com [172.17.2.17]) by linux.omap.com (Postfix) with ESMTP id 56CAE8062A for ; Fri, 31 May 2013 05:11:17 -0500 (CDT) Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id r4VABGFQ003487; Fri, 31 May 2013 05:11:16 -0500 Received: from dlelxv23.itg.ti.com (172.17.1.198) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.2.342.3; Fri, 31 May 2013 05:11:16 -0500 Received: from ucmsshproxy.india.ext.ti.com (dbdp20.itg.ti.com [172.24.170.38]) by dlelxv23.itg.ti.com (8.13.8/8.13.8) with SMTP id r4VABBOm005846; Fri, 31 May 2013 05:11:11 -0500 Received: from symphony.india.ext.ti.com (unknown [192.168.247.13]) by ucmsshproxy.india.ext.ti.com (Postfix) with ESMTP id 7E7FE158004; Fri, 31 May 2013 15:41:10 +0530 (IST) Received: from ubuntu-psp-linux.india.ext.ti.com (ubuntu-psp-linux [192.168.247.46]) by symphony.india.ext.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id r4VAB9R05835; Fri, 31 May 2013 15:41:09 +0530 (IST) From: Hebbar Gururaja To: , , , Subject: [PATCH 02/11] leds: leds-gpio: Enhance pinctrl support Date: Fri, 31 May 2013 15:43:02 +0530 Message-ID: <1369995191-20855-3-git-send-email-gururaja.hebbar@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1369995191-20855-1-git-send-email-gururaja.hebbar@ti.com> References: <1369995191-20855-1-git-send-email-gururaja.hebbar@ti.com> MIME-Version: 1.0 CC: , , , Bryan Wu , , Richard Purdie , , X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com Amend leds-gpio driver to optionally take a pin control handle and set the state of the pins to: - "default" on boot, resume - "sleep" on suspend() By optionally putting the pins into sleep state in the suspend callback we can accomplish two things. - One is to minimize current leakage from pins and thus save power, - second, we can prevent the IP from driving pins output in an uncontrolled manner, which may happen if the power domain drops the domain regulator. If any of the above pin states are missing in dt, a warning message about the missing state is displayed. If certain pin-states are not available, to remove this warning message pass respective state name with null phandler. Signed-off-by: Hebbar Gururaja Cc: Bryan Wu Cc: Richard Purdie Cc: linux-leds@vger.kernel.org --- :100644 100644 b02b679... b094e52... M drivers/leds/leds-gpio.c drivers/leds/leds-gpio.c | 81 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index b02b679..b094e52 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -153,6 +153,10 @@ static void delete_gpio_led(struct gpio_led_data *led) struct gpio_leds_priv { int num_leds; + /* Two optional pin states - default & sleep */ + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_sleep; struct gpio_led_data leds[]; }; @@ -162,6 +166,43 @@ static inline int sizeof_gpio_leds_priv(int num_leds) (sizeof(struct gpio_led_data) * num_leds); } +/* Use pinctrl API for gpio configuration */ +static void gpio_led_get_pinctrl(struct gpio_leds_priv *priv, + struct platform_device *pdev) +{ + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!IS_ERR(priv->pinctrl)) { + priv->pins_default = pinctrl_lookup_state(priv->pinctrl, + PINCTRL_STATE_DEFAULT); + /* enable pins to be muxed in and configured */ + if (IS_ERR(priv->pins_default)) + dev_dbg(&pdev->dev, + "could not get default pinstate\n"); + else + if (pinctrl_select_state(priv->pinctrl, + priv->pins_default)) + dev_err(&pdev->dev, + "could not set default pins\n"); + + priv->pins_sleep = pinctrl_lookup_state(priv->pinctrl, + PINCTRL_STATE_SLEEP); + if (IS_ERR(priv->pins_sleep)) + dev_dbg(&pdev->dev, + "could not get sleep pinstate\n"); + } else { + /* + * Since we continue even when pinctrl node is not found, + * Invalidate pins as not available. This is to make sure that + * IS_ERR(pins_xxx) results in failure when used. + */ + priv->pins_default = ERR_PTR(-ENODATA); + priv->pins_sleep = ERR_PTR(-ENODATA); + + dev_dbg(&pdev->dev, + "pins are not configured from the driver\n"); + } +} + /* Code to create from OpenFirmware platform devices */ #ifdef CONFIG_OF_GPIO static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) @@ -184,6 +225,8 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) if (!priv) return ERR_PTR(-ENOMEM); + gpio_led_get_pinctrl(priv, pdev); + for_each_child_of_node(np, child) { struct gpio_led led = {}; enum of_gpio_flags flags; @@ -236,14 +279,8 @@ static int gpio_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct gpio_leds_priv *priv; - struct pinctrl *pinctrl; int i, ret = 0; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, - "pins are not configured from the driver\n"); - if (pdata && pdata->num_leds) { priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(pdata->num_leds), @@ -251,6 +288,8 @@ static int gpio_led_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + gpio_led_get_pinctrl(priv, pdev); + priv->num_leds = pdata->num_leds; for (i = 0; i < priv->num_leds; i++) { ret = create_gpio_led(&pdata->leds[i], @@ -287,6 +326,32 @@ static int gpio_led_remove(struct platform_device *pdev) return 0; } +static int gpio_led_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct gpio_leds_priv *priv = platform_get_drvdata(pdev); + + /* Optionally let pins go into sleep states */ + if (!IS_ERR(priv->pins_sleep)) + if (pinctrl_select_state(priv->pinctrl, priv->pins_sleep)) + dev_err(&pdev->dev, + "could not set pins to sleep state\n"); + + return 0; +} + +static int gpio_led_resume(struct platform_device *pdev) +{ + struct gpio_leds_priv *priv = platform_get_drvdata(pdev); + + /* Optionaly enable pins to be muxed in and configured */ + if (!IS_ERR(priv->pins_default)) + if (pinctrl_select_state(priv->pinctrl, priv->pins_default)) + dev_err(&pdev->dev, "could not set default pins\n"); + + return 0; +} + static struct platform_driver gpio_led_driver = { .probe = gpio_led_probe, .remove = gpio_led_remove, @@ -295,6 +360,10 @@ static struct platform_driver gpio_led_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_gpio_leds_match), }, +#ifdef CONFIG_PM + .suspend = gpio_led_suspend, + .resume = gpio_led_resume, +#endif }; module_platform_driver(gpio_led_driver);