From patchwork Mon Jun 10 16:59:32 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Shiyan X-Patchwork-Id: 2698441 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork2.kernel.org (Postfix) with ESMTP id 6D7ACDF264 for ; Mon, 10 Jun 2013 17:00:49 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Um5SG-0002um-Ew; Mon, 10 Jun 2013 17:00:28 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Um5S8-0007kA-Ru; Mon, 10 Jun 2013 17:00:20 +0000 Received: from smtp49.i.mail.ru ([94.100.177.109]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Um5Rv-0007iP-6A for linux-arm-kernel@lists.infradead.org; Mon, 10 Jun 2013 17:00:09 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=h3mTF6tIT8kQXOXasI+L8d4ixnvXfVFbLvCaze96iIQ=; b=aAKSjPzxMlC4RYMf8l7m4njmbUb0OyTNJgQ5tLLQh20CGaPY07NdnyZ6I4m6gwUXvkhXffJ7vFJLv0DASruauKAM8uZulXP0XTga19qxpdyyWvX79ZrpsFeRZlUuCBmQuEWducYA519438sPb8Oo4UcD6yUkPzn1j0ghfxa2iK0=; Received: from [188.134.40.128] (port=17839 helo=shc.zet) by smtp49.i.mail.ru with esmtpa (envelope-from ) id 1Um5RX-0000Zb-Bk; Mon, 10 Jun 2013 20:59:43 +0400 From: Alexander Shiyan To: linux-arm-kernel@lists.infradead.org Subject: [PATCH v4 3/3] leds: leds-mc13783: Add devicetree support Date: Mon, 10 Jun 2013 20:59:32 +0400 Message-Id: <1370883572-877-3-git-send-email-shc_work@mail.ru> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1370883572-877-1-git-send-email-shc_work@mail.ru> References: <1370883572-877-1-git-send-email-shc_work@mail.ru> X-Spam: Not detected X-Mras: Ok X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130610_130007_723439_51BD9C87 X-CRM114-Status: GOOD ( 14.57 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (shc_work[at]mail.ru) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Russell King , Alexander Shiyan , Bryan Wu , Rob Herring , Richard Purdie , Sascha Hauer , Grant Likely , linux-leds@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Signed-off-by: Alexander Shiyan --- Documentation/devicetree/bindings/mfd/mc13xxx.txt | 39 +++++++++++++ drivers/leds/leds-mc13783.c | 69 +++++++++++++++++++---- 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt index abd9e3c..96c7f3a 100644 --- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -12,6 +12,13 @@ Optional properties: Sub-nodes: - regulators : Contain the regulator nodes. The regulators are bound using their names as listed below with their registers and bits for enabling. +- leds : Contain the led nodes and initial register values in property + "led_control". Number of register depends of used IC, for MC13783 is 6, + for MC13892 is 4. See datasheet for bits definitions of these register. + Each led node should contain "id", which is described below, and "max_cur" + which selects value current depending on the led (Values should be taken + from IC datasheet). Optional properties "label" and "linux,default-trigger" + is described in Documentation/devicetree/bindings/leds/common.txt MC13783 regulators: sw1a : regulator SW1A (register 24, bit 0) @@ -72,6 +79,28 @@ MC13892 regulators: The bindings details of individual regulator device can be found in: Documentation/devicetree/bindings/regulator/regulator.txt +MC13783 LED IDs: + 0 : Main display + 1 : AUX display + 2 : Keypad + 3 : Red 1 + 4 : Green 1 + 5 : Blue 1 + 6 : Red 2 + 7 : Green 2 + 8 : Blue 2 + 9 : Red 3 + 10 : Green 3 + 11 : Blue 3 + +MC13892 LED IDs: + 12 : Main display + 13 : AUX display + 14 : Keypad + 15 : Red + 16 : Green + 17 : Blue + Examples: ecspi@70010000 { /* ECSPI1 */ @@ -89,6 +118,16 @@ ecspi@70010000 { /* ECSPI1 */ interrupt-parent = <&gpio0>; interrupts = <8>; + leds { + led_control = <0x0 0x0 0x0 0x0>; + led_r { + id = <15>; + label = "system:red:live"; + linux,default-trigger = "heartbeat"; + max-cur = <6>; + }; + }; + regulators { sw1_reg: mc13892__sw1 { regulator-min-microvolt = <600000>; diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index f656fd5..65a06a8 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -207,35 +208,55 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent); struct mc13xxx_led_devtype *devtype = (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data; + struct device_node *parent, *child = NULL; struct mc13xxx_leds *leds; - int i, id, num_leds, ret; - u32 reg, init_led = 0; + int i, id, num_leds, ret = -EINVAL; + u32 reg, ctrls[MAX_LED_CONTROL_REGS], init_led = 0; - if (!pdata) { + of_node_get(pdev->dev.parent->of_node); + parent = of_find_node_by_name(pdev->dev.parent->of_node, "leds"); + if (!parent && !pdata) { dev_err(&pdev->dev, "Missing platform data\n"); return -ENODEV; } - num_leds = pdata->num_leds; + if (parent) + num_leds = of_get_child_count(parent); + else + num_leds = pdata->num_leds; if ((num_leds < 1) || (num_leds > (devtype->led_max - devtype->led_min + 1))) { dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds); - return -EINVAL; + goto out_node_put; } leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) + sizeof(struct mc13xxx_leds), GFP_KERNEL); - if (!leds) - return -ENOMEM; + if (!leds) { + ret = -ENOMEM; + goto out_node_put; + } leds->devtype = devtype; leds->num_leds = num_leds; platform_set_drvdata(pdev, leds); + if (parent) { + ret = of_property_read_u32_array(parent, "led_control", ctrls, + devtype->num_regs); + if (ret) { + dev_err(&pdev->dev, "Missing led_control settings\n"); + goto out_node_put; + } + } + mc13xxx_lock(mcdev); for (i = 0; i < devtype->num_regs; i++) { - reg = pdata->led_control[i]; + if (parent) + reg = ctrls[i]; + else + reg = pdata->led_control[i]; WARN_ON(reg >= (1 << 24)); ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg); if (ret) @@ -250,14 +271,34 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) for (i = 0; i < num_leds; i++) { const char *name, *trig; + const __be32 *prop; char max_current; ret = -EINVAL; - id = pdata->led[i].id; - name = pdata->led[i].name; - trig = pdata->led[i].default_trigger; - max_current = pdata->led[i].max_current; + if (parent) { + child = of_get_next_child(parent, child); + prop = of_get_property(child, "id", NULL); + if (!prop) { + dev_err(&pdev->dev, "Missing LED ID\n"); + break; + } else + id = be32_to_cpu(*prop); + name = of_get_property(child, "label", NULL); + trig = of_get_property(child, "linux,default-trigger", + NULL); + prop = of_get_property(child, "max-cur", NULL); + if (!prop) { + dev_err(&pdev->dev, "Missing LED max-cur\n"); + break; + } else + max_current = be32_to_cpu(*prop); + } else { + id = pdata->led[i].id; + name = pdata->led[i].name; + trig = pdata->led[i].default_trigger; + max_current = pdata->led[i].max_current; + } if ((id > devtype->led_max) || (id < devtype->led_min)) { dev_err(&pdev->dev, "Invalid ID %i\n", id); @@ -299,6 +340,10 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) cancel_work_sync(&leds->led[i].work); } +out_node_put: + if (parent) + of_node_put(parent); + return ret; }