From patchwork Thu Jun 9 09:44:25 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 9166597 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5480F60832 for ; Thu, 9 Jun 2016 09:50:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 434BA28328 for ; Thu, 9 Jun 2016 09:50:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 378EA28338; Thu, 9 Jun 2016 09:50:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A924028328 for ; Thu, 9 Jun 2016 09:50:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751140AbcFIJth (ORCPT ); Thu, 9 Jun 2016 05:49:37 -0400 Received: from mailout1.w1.samsung.com ([210.118.77.11]:58853 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933538AbcFIJpD (ORCPT ); Thu, 9 Jun 2016 05:45:03 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O8I006EV0EUYW70@mailout1.w1.samsung.com>; Thu, 09 Jun 2016 10:44:55 +0100 (BST) X-AuditID: cbfec7f4-f796c6d000001486-96-57593a962310 Received: from eusync1.samsung.com ( [203.254.199.211]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 97.E6.05254.69A39575; Thu, 9 Jun 2016 10:44:54 +0100 (BST) Received: from AMDC2174.DIGITAL.local ([106.120.53.17]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O8I006RA0EHZZ10@eusync1.samsung.com>; Thu, 09 Jun 2016 10:44:54 +0100 (BST) From: Krzysztof Kozlowski To: Ulf Hansson , Rob Herring , Pawel Moll , Mark Rutland , Ian Campbell , Kumar Gala , Krzysztof Kozlowski , Sebastian Reichel , Dmitry Eremin-Solenikov , David Woodhouse , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , Hans de Goede , Jean-Christophe Plagniol-Villard , Tomi Valkeinen , Heiko Stuebner , linux-mmc@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger.kernel.org, linux-fbdev@vger.kernel.org, hzpeterchen@gmail.com Cc: Bartlomiej Zolnierkiewicz Subject: [RFC v4 08/14] power: pwrseq: simple: Add support for regulators and generic property Date: Thu, 09 Jun 2016 11:44:25 +0200 Message-id: <1465465471-28740-9-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1465465471-28740-1-git-send-email-k.kozlowski@samsung.com> References: <1465465471-28740-1-git-send-email-k.kozlowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzWRXUiTYRiGe7+/zeXwY5p+TBAaSCVmzmW9SCwPAl86MShaBdGWfsyhU9mc aCcpMrDB1Jw6kdT8z7/W5kRzTUuHqwRdmsvEDHUH/sEKRQwta5PO7vu5L7gOHi4u6CSEXFVu AavJVeSIKB4x9cc9d74u5a4scaY2CVrrLSSsXfFRsNrnx2Gza5qET7tNOKzcbiFhWZuFgttu MwaPVrdIaJi3UXB6sxvArXUx3PtcjkHbmpeE7yt+kHBu5BkFXUeVAO4YXQDWz4xisLVTj8OO L58wWGXuJ+DLlXUM6p0uDpxyFEBL8yIF3f2y1GjU19QH0FyFEUOvG75xUHfXLoUGXsShTc8S gWw9Tyi05H1DobHGPg4aaH+M/KPzFKqw9wA05G3CkXthCEM7tpgbYfd4VzLZHFUhq7kglfOy rJ3VZL5HWrRh+UmUAL3EAEK4DH2RMe7oyeMcyXiWLZQB8LgCugMwjo5yznEpxZiaDQMeoCha wgx0tQepCHqWwyzMDmGBAachMzjYywnkcFrO2Fv8RCATdCwz0joWVPDpNMa3aATHuhjmw6Qp eA+hEbO6vBYUCP4xzjYTVQX4z8GJHnCK1WXkax8q1eIErUKt1eUqEzLy1DZw/L3dYdA2mTIO aC4QhfLPZd6RCUhFobZYPQ4YLi6K4O9fvisT8DMVxY9YTd4DjS6H1Y6DaC4hiuI3jvhvCWil ooDNZtl8VvN/xbghwhJgjpIaw/eydR7Vx/RlrzJSungpTWIF/qupC3XpoZLvZ+o0E0JWvp9d /ovzm9XZI2TJZx2RebC4zDmTluwoTJRbpcPXb0q/FvWq+KWJaid2Okpmi1Wa4mneq5q3hfFI MCueOHhnPyw5vCZX8cwNYULf6NqU8mTcwf3bRUkiQpulEMfhGq3iL4Wqq865AgAA Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some devices need real hard-reset by cutting the power. During power sequence turn off and on all of provided regulators. Additionally add support for instantiating the pwrseq-simple device on a generic property 'power-sequence'. The device will attach itself to the node containing the property and parse the node's properties like reset-gpios, supplies etc. Signed-off-by: Krzysztof Kozlowski --- .../bindings/power/pwrseq/pwrseq-simple.txt | 30 +++++- drivers/power/pwrseq/pwrseq_simple.c | 113 ++++++++++++++++++++- 2 files changed, 136 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt index ce0e76749671..7e5a414a67fc 100644 --- a/Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt +++ b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-simple.txt @@ -1,11 +1,18 @@ -* The simple MMC power sequence provider +* The simple power sequence provider -The purpose of the simple MMC power sequence provider is to supports a set of +The purpose of the simple power sequence provider is to supports a set of common properties between various SOC designs. It thus enables us to use the same provider for several SOC designs. -Required properties: -- compatible : contains "mmc-pwrseq-simple". +The driver supports two types of bindings: +1. Property for any node + Required properties: + - power-sequence + +2. Separate node (not recommended for new users) + Required properties: + - compatible : contains "mmc-pwrseq-simple". + Optional properties: - reset-gpios : contains a list of GPIO specifiers. The reset GPIOs are asserted @@ -16,6 +23,8 @@ Optional properties: See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entry: "ext_clock" (External clock provided to the card). +- *-supply : If supplies are provided, the driver will enable and disable + them during power sequence. Example: @@ -25,3 +34,16 @@ Example: clocks = <&clk_32768_ck>; clock-names = "ext_clock"; } + + usb3503@08 { + compatible = "smsc,usb3503"; + reg = <0x08>; + + intn-gpios = <&gpx3 0 GPIO_ACTIVE_HIGH>; + connect-gpios = <&gpx3 4 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpx3 5 GPIO_ACTIVE_HIGH>; + initial-mode = <1>; + + power-sequence; + vdd-supply = <&buck8_reg>; + }; diff --git a/drivers/power/pwrseq/pwrseq_simple.c b/drivers/power/pwrseq/pwrseq_simple.c index 93807a6ef162..f70e207f994b 100644 --- a/drivers/power/pwrseq/pwrseq_simple.c +++ b/drivers/power/pwrseq/pwrseq_simple.c @@ -1,12 +1,15 @@ /* - * Copyright (C) 2014 Linaro Ltd + * Copyright (C) 2014 Linaro Ltd + * Copyright (C) 2016 Samsung Electronics * * Author: Ulf Hansson + * Krzysztof Kozlowski * * License terms: GNU General Public License (GPL) version 2 * * Simple MMC power sequence management */ +#include #include #include #include @@ -16,13 +19,25 @@ #include #include #include +#include +#include #include +#include + +static LIST_HEAD(mmc_pwrseq_devs); + +struct mmc_pwrseq_dev { + struct platform_device *pdev; + struct list_head entry; +}; struct mmc_pwrseq_simple { struct pwrseq pwrseq; bool clk_enabled; struct clk *ext_clk; struct gpio_descs *reset_gpios; + unsigned int regulator_count; + struct regulator_bulk_data *regulators; }; #define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq) @@ -60,6 +75,14 @@ static void mmc_pwrseq_simple_post_power_on(struct pwrseq *_pwrseq) { struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(_pwrseq); + if (pwrseq->regulators) { + int err; + + err = regulator_bulk_enable(pwrseq->regulator_count, + pwrseq->regulators); + WARN_ON_ONCE(err); + } + mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); } @@ -73,6 +96,14 @@ static void mmc_pwrseq_simple_power_off(struct pwrseq *_pwrseq) clk_disable_unprepare(pwrseq->ext_clk); pwrseq->clk_enabled = false; } + + if (pwrseq->regulators) { + int err; + + err = regulator_bulk_disable(pwrseq->regulator_count, + pwrseq->regulators); + WARN_ON_ONCE(err); + } } static const struct pwrseq_ops mmc_pwrseq_simple_ops = { @@ -91,6 +122,7 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev) { struct mmc_pwrseq_simple *pwrseq; struct device *dev = &pdev->dev; + int err; pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); if (!pwrseq) @@ -100,12 +132,39 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev) if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT) return PTR_ERR(pwrseq->ext_clk); + err = devm_of_regulator_all_get(dev, &pwrseq->regulator_count, + &pwrseq->regulators); + if (err) + return err; + + if (pwrseq->regulators) { + /* + * Be sure that regulator is off, before the driver will start + * power sequence. It is likely that regulator is on by default + * and it without toggling it here, it would be disabled much + * later by the core. + */ + err = regulator_bulk_enable(pwrseq->regulator_count, + pwrseq->regulators); + WARN_ON_ONCE(err); + + err = regulator_bulk_disable(pwrseq->regulator_count, + pwrseq->regulators); + WARN_ON_ONCE(err); + } + pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(pwrseq->reset_gpios) && PTR_ERR(pwrseq->reset_gpios) != -ENOENT && PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) { - return PTR_ERR(pwrseq->reset_gpios); + /* + * Don't care about errors. If this pwrseq device was added + * to node with existing reset-gpios, then the GPIO reset will + * be handled by other device. + */ + dev_warn(dev, "Cannot get reset gpio: %ld\n", + PTR_ERR(pwrseq->reset_gpios)); } pwrseq->pwrseq.dev = dev; @@ -122,6 +181,14 @@ static int mmc_pwrseq_simple_remove(struct platform_device *pdev) pwrseq_unregister(&pwrseq->pwrseq); + if (pwrseq->regulators) { + int err; + + err = regulator_bulk_disable(pwrseq->regulator_count, + pwrseq->regulators); + WARN_ON_ONCE(err); + } + return 0; } @@ -134,5 +201,45 @@ static struct platform_driver mmc_pwrseq_simple_driver = { }, }; -module_platform_driver(mmc_pwrseq_simple_driver); +static int __init mmc_pwrseq_simple_driver_init(void) +{ + struct mmc_pwrseq_dev *pwrseq_dev; + struct platform_device *pdev; + struct device_node *np; + + for_each_node_with_property(np, "power-sequence") { + pdev = platform_device_register_simple("pwrseq_simple", + PLATFORM_DEVID_AUTO, + NULL, 0); + if (IS_ERR(pdev)) + continue; + + pwrseq_dev = kzalloc(sizeof(*pwrseq_dev), GFP_KERNEL); + if (!pwrseq_dev) + continue; + + of_node_get(np); + pdev->dev.of_node = np; + pwrseq_dev->pdev = pdev; + list_add(&pwrseq_dev->entry, &mmc_pwrseq_devs); + } + + return platform_driver_register(&mmc_pwrseq_simple_driver); +} +module_init(mmc_pwrseq_simple_driver_init); + +static void __exit mmc_pwrseq_simple_driver_exit(void) +{ + struct mmc_pwrseq_dev *pwrseq_dev, *tmp; + + list_for_each_entry_safe(pwrseq_dev, tmp, &mmc_pwrseq_devs, entry) { + list_del(&pwrseq_dev->entry); + of_node_put(pwrseq_dev->pdev->dev.of_node); + platform_device_unregister(pwrseq_dev->pdev); + kfree(pwrseq_dev); + } + + platform_driver_unregister(&mmc_pwrseq_simple_driver); +} +module_exit(mmc_pwrseq_simple_driver_exit); MODULE_LICENSE("GPL v2");