From patchwork Fri Jun 17 10:09:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Chen X-Patchwork-Id: 9183279 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 72E276075F for ; Fri, 17 Jun 2016 10:20:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5FA561FF60 for ; Fri, 17 Jun 2016 10:20:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 53F4728399; Fri, 17 Jun 2016 10:20:52 +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=-4.2 required=2.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A93B11FF60 for ; Fri, 17 Jun 2016 10:20:51 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1bDqrx-0000ah-R9; Fri, 17 Jun 2016 10:19:21 +0000 Received: from mail-by2on0097.outbound.protection.outlook.com ([207.46.100.97] helo=na01-by2-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1bDqpq-0006ES-EJ for linux-arm-kernel@lists.infradead.org; Fri, 17 Jun 2016 10:17:18 +0000 Received: from BLUPR0301CA0027.namprd03.prod.outlook.com (10.162.113.165) by CY1PR03MB2377.namprd03.prod.outlook.com (10.166.207.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.517.8; Fri, 17 Jun 2016 10:16:48 +0000 Received: from BL2FFO11FD008.protection.gbl (2a01:111:f400:7c09::190) by BLUPR0301CA0027.outlook.office365.com (2a01:111:e400:5259::37) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.523.12 via Frontend Transport; Fri, 17 Jun 2016 10:16:48 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none; nxp.com; dmarc=none action=none header.from=nxp.com; nxp.com; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BL2FFO11FD008.mail.protection.outlook.com (10.173.161.4) with Microsoft SMTP Server (TLS) id 15.1.511.7 via Frontend Transport; Fri, 17 Jun 2016 10:16:48 +0000 Received: from shlinux2.ap.freescale.net (shlinux2.ap.freescale.net [10.192.224.44]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id u5HAFbSv029984; Fri, 17 Jun 2016 03:16:41 -0700 From: Peter Chen To: , , , , , Subject: [PATCH 09/12] power: pwrseq: pwrseq_usb_generic: add generic power sequence support for USB deivces Date: Fri, 17 Jun 2016 18:09:22 +0800 Message-ID: <1466158165-9380-10-git-send-email-peter.chen@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1466158165-9380-1-git-send-email-peter.chen@nxp.com> References: <1466158165-9380-1-git-send-email-peter.chen@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131106322087743932; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(1110001)(1109001)(339900001)(189002)(199003)(5003940100001)(50226002)(2950100001)(50466002)(106466001)(11100500001)(2906002)(8936002)(8666005)(4326007)(8676002)(81166006)(2201001)(77096005)(5008740100001)(15975445007)(356003)(5001770100001)(36756003)(87936001)(47776003)(19580395003)(2171001)(48376002)(229853001)(19580405001)(76176999)(104016004)(33646002)(50986999)(86362001)(6806005)(85426001)(105606002)(81156014)(586003)(189998001)(97736004)(92566002)(68736007)(41533002)(7059030)(2004002); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1PR03MB2377; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; MX:1; A:1; CAT:NONE; LANG:en; CAT:NONE; X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11FD008; 1:oXuqVW/kjHK6TbQG3bq/F89SO9/rzKNYesvfo94/JtFrHts2U8nsO0X1hQzAZ7H9h3jYJ30yY3sDtWPXJ3m3XjLsO1JJcoJr/lsc2zUoZ9+Mn//HUItAzgUoPITAW3meJRge72t5XUIGiNq1TQPiUB30Q9lxERhntFXPDTXQecfu5oIDxegWNgGQJxKc/6uO/DfWVPsQAfiUW5x8RojiFH9ZODdjTTETFfmuFwyPqJJwoiQY/U/BDmMIQDHQjAVYz/JW7/UY6Om7LK5wp+72OnlcihOYY4MTzdt8niS8lZAFohIGr7NY2MrRUaobZjPl+fEhqGs3cYgfxMJ5/LBLTcXaO9Ri3k25sxhSmOM6MIAgo1hmTjYJPbR7j4CR8oBXMmZH04YKYaGZqXANGM5qWV1g59UMauIveaay8V9/q7HxUrheFwgokEHVuIoZx8z9jq963KTX3LXcIqufjKgysC399D3EGIsUlh/VeP8h52M9mKceUepnGFuDiRQuAxKtDf/nGRW7pRdggHQxbek7a13/yq/6rRdtYYWGI7ZvuOTop60+Y3Dte0h3O+tSicpqYGsSXLoFn3KYAyA6QtKyARoret+BurDE/0t70owCQRqfJIUVfURV6EzfoGtwdaT3J0kt64Uyq/IH/kwpqx1qrzwAQMZ1jHrK372+BKQnNrSHCMYvQO8k3FtOAPHTQFYUpUo1WCSupmPF4F73qkTIkvDzmUATaSmxCR0gzO+Qs7Y= MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: b4a4b375-b793-4acd-b05b-08d396987e4d X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB2377; 2:7gdEepfqFFgW+7zNJuFd4guiopMGuMnGMeC1cTxXzfME7VKbwcqYoc+iOxrepsG4iuW6BQpVe8ImQSVzxQ+VYMarEojrS3AYzFfcAShAc3O1UNMWatyupyTfMqUHbgwXnDKkTQm2b1JckF1TYWDmaaMpBWO2wMexswJroWY5PjZLvPTWF2Aqo+XswcM4mSHG; 3:bpakZNvM455fhm+YhhASF4B4G39YMBYQxaRkkXBLv5uOPtTti19RBC+YRnqZeRzmmRMlfL9dP3iZX8re/UxCDK84MfEpJYwI2jqUP0GIM5zoU0MGSbYMdGtE/tVh/A7p+z0b76KRyyd5WTSXJ6rddTgmQpr/s6P4B0JNGzP/c9/MWnH9ds8iHw3zaBbFtek2Ac7LrVT6ygVHTdvMBBQKi3Rdatujl7cT5d7s7i5uCSQ=; 25:ZwcN4c4Fw8mMlJF3xg3CQk0i5fhkqy5EGnwctrG7dTYoy9yJ38803/JH19srhvPT/YDycT52P+e0nbs6jXbXR2NDN0DHnY+pzR0tj7GPPNitX3L3C7E2AVz9ChQ0+iq9DZ6x5Cvzk3EIk4lRN6Mrl0eDTxI7y6vUsn35+Ggx6egQpMRLZcnpXfmyiUPKAPvF/us1KYtBltyZcMRZszoQBRMsW8usgYe8aGXks79K8q21aXDOCyQKli4a+gkNOHc+5JZC7DSbMn0oqzNHmomOEsXiUcBAGAKbDjr6dXNx4hmCfhYDRek0DG7y644jWp7R90+UyaOxVg7Y4dzcaYdduNhMod2sQPcG7+ej6w3/Uj9YyRPNQzE+nKjtvYLEf/77PXAMovEn7Gp3LLMwfSJ0GrWIiXh0nZITAo4yER/8+yc= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR03MB2377; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(250305191791016)(22074186197030)(185117386973197); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(8121501046)(13015025)(13018025)(13024025)(13023025)(13017025)(10201501046)(3002001)(6055026); SRVR:CY1PR03MB2377; BCL:0; PCL:0; RULEID:(400006); SRVR:CY1PR03MB2377; X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB2377; 4:MmLBk+wsUTfmKIaljijnfLyZphbBoEhrTDu0vPdeRtXrC5VYstNiZVQPc6diDUeCfWmgeUNq/qiguRDKcoGtFIicjIlxSzBEVldjFYudfCwwX6zqmbFrUoo3SevdbBnQKlWXQFTUi39NyHX0A++b2tUYZh+DbW35opsYYuTYjRJGkZvhFqUMhiScGVm51YR4jUpfKfLx2lXe8dbcjuQK5ttyBvsbonK2BvecjsE1KKHPMOusNPE1h0ft0dBUh+EzqognxEokyRpM4B762GWZdF5rUvzxZ/5pWdItETftB+GxL8hCsgzV1d84+y6ALnCKGRrwQ+Nn1F7UbKrX0tFb4sm3mI+1H3UGqYHYYx5g+moAciv1YiClwKVbJMbVXAZAtlB1Irb4hPL/Umi3h8coZKULyNL183N0t4739mep0Z4z2LcS/89RiiEGBtYoEGiQU1Ed6kQd37guTeSj+JrnfifDdyHleKwdeVkmE1IOqMt85qVC7IQG/xGCVlmiFCCP3BhrytQuKt6B/rnxwDQdcWYj/Rqkf6W0rySpfo5xvYQbnbc1JPvtRc073mTOwxQzSh0Wh42WX/9lJp6BqEsoug== X-Forefront-PRVS: 09760A0505 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR03MB2377; 23:p8cvnRtKjG875exuf4k1ppB2ovTTcesfB4pOnq+yK?= =?us-ascii?Q?RnNrVWrynj44jfX+rjz+7bDHHgwBYwOmxrtBo2OeEdQYGAehaypLpZZRCaOP?= =?us-ascii?Q?EwqOAKjlhVTseMLff2LQPMSpzNxOI0RmYGY622exW7mxEYMfkKj/lZPGp87N?= =?us-ascii?Q?AAG41/dBdkapccUmD1LskbYzEo68YQt3NjE4zdOl8j8ScYecMBnuMNA5iY4W?= =?us-ascii?Q?1rFcUCDAyRznaj649yv5yqLFBKAzY1ALaiPIM2B1lDOl2AV0JNbuhzMwzUHf?= =?us-ascii?Q?F1DsoA08N4NmfQYC3McaJtdA0BFzEGVycDh8IkUQf7me+oe3lVccG+KJg88+?= =?us-ascii?Q?UxVD0ne/s1Xlq+LMPXoEogsIGUH9nTwPZwLK+gSHQVMDCRuCHovnMb72lbxR?= =?us-ascii?Q?W+1pQDoxDyoUaqsfwqUGBTcZzy5Ej2SDZ03m2/vyP3KRvpRLYEjqKam2nWei?= =?us-ascii?Q?xwMvtP3HxiOjDNA1kUJNMdK/nAky4iP5KNf31pFDKaAYym5eohsHI4ViW1Gu?= =?us-ascii?Q?9EuZVRWXBk5TXB3AGrUPutr0bd5lbxVzw9/3pHsKdCjouOuOpgiV0dFyV3CX?= =?us-ascii?Q?jkKM2Ek8YqnJznznVhTnUxCkn0did4sleQoRZhTugyrKsmF4NgMobVMYj+Zk?= =?us-ascii?Q?GSop6q97GIuDvw1HDgd9zD6oRlxhZZdckmUz6pSgSw5kAERxgSBMdhj3B0VE?= =?us-ascii?Q?+cVFtoB8HEzuk5YRrpVDaJ/iJnBLZnc5pFqnAoBfCUX0lm8OeqJt9Nq9bdnq?= =?us-ascii?Q?Y5/X9qw18E9HoM/gREGuWYShkGjR3PG5FyGXH/bgNiBrEZyZMw2xtsILYXb4?= =?us-ascii?Q?A33Bnesc6oVFc40aHF5tqixncTren4Az0M1RbVKGMPB5a6V7Bv4k0KRv9UpW?= =?us-ascii?Q?NK1DNpL2kAjNdsn1tW8BSFXV+3Pr3YgKZCRYDSw7zAGzN4Wq/wWMEO5O4f0a?= =?us-ascii?Q?3EujrTEea8irgaBXDVTLZ1y4cwHt4VjZS7mmn0Cu6DAyIjQvtAUm/Se2wvRP?= =?us-ascii?Q?q6gcnt/4+o4dsGlubkpM7XZVATyOMT3iHSuvzRKYtC3HJxnKKDoEJxGOphQe?= =?us-ascii?Q?cJ9fPnR7jeJ8NTJUK7xnpGcJATJno/U1UxgFPIiYgs0BsfyEw+KcI9Tqp0e0?= =?us-ascii?Q?kykX1BcAj55jlbyFaSLIE1AIff3fve9dG3dU+xHlknavO+jPcGuuBTTmqLpA?= =?us-ascii?Q?eerkJmfJCngQsGTmhjbZKz1nhWKvqjmoO4NI62IhivPSfTx7fhYHGh9DpRKS?= =?us-ascii?Q?b+Ig4KSZ3H2tGOB/t4ysqWxbYt+vnxBX5kboqK0?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB2377; 6:ItJPaVOx+YhiM6q0zROoLpdjSHHkb2dM+GwEub7yTdBCK+LlFyhOashuVV2K2VoWjo1nzhEVR8HwhgU1LLJQCM7VnS0clMRXWH8MvrRgpi5rdTI0jAhsW1ni1vgKSeG3yCDBVMXuVX+tKNPIAvJ0iMrE9wXgtR7mcwD7f0WXyxI4PNyL5ufWBDomFakSi+P441G86F1bRuWaRaVhv5k4mnxcONMYW+MhPyvTvmsnHsRpM8rzHvLtzrHt5byjmc6C5z/41PTGbczi3tBJpyGRIxjZP4yWfbBy5wV04tKv8CI=; 5:6Is4nMTtkVBo7pYoxgaWwi3TVpU5lJWV55PHCuLOIv1Wg1Deqa65ebWn0/IpyF0038DV++YF9tK+sUmEQ37HfXYEttjFSSalpGl3mvyXlkpuU/hMQbUXcquVe3+Bd+c7zBkmhPInYniHyIH8c5QjpFlOeyXFd/XVUXq5RjmODso=; 24:kJm8AMGCi4OuM91+kjHkq8tJ74URbnk976qncAyjSOf3kcMrUCKpNpRZ+kbiVRwT8jHxvDFMCS7Yf+mjBFPUeGG7ynDeyj9Y0zmSvO7gGew=; 7:/wSybn/PVbzxt5oDoWkjvzNId4xMsJdqHey04tgyed5wu6+dNiSzvXm5DBUmhXzijZlk4W/4XkUXq5p0QY6komY4sXJGhkO8ptWFW8aCV0BUfT1O8AlzGXzvnS6JaQBN1N1CORa7mAIOVqshZkegxTj/16C2CTK1QzuoWevJhOk0RDpyDNAHrV1nZtmw3VJa8iGKu3i7UvmMvif89CYloA== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Jun 2016 10:16:48.3531 (UTC) X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR03MB2377 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160617_031710_922295_CFD0128A X-CRM114-Status: GOOD ( 23.06 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, k.kozlowski@samsung.com, stephen.boyd@linaro.org, oscar@naiandei.net, arnd@arndb.de, pawel.moll@arm.com, linux-pm@vger.kernel.org, s.hauer@pengutronix.de, linux-usb@vger.kernel.org, linux-mmc@vger.kernel.org, mail@maciej.szmigiero.name, troy.kisky@boundarydevices.com, javier@osg.samsung.com, Peter Chen , p.zabel@pengutronix.de, festevam@gmail.com, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Add driver for generic power sequence support for USB deivces which handles below things: - Clock and its frequencies - GPIO for reset and the duration time - GPIO for enable - Regulator for power Signed-off-by: Peter Chen --- drivers/power/pwrseq/Kconfig | 11 ++ drivers/power/pwrseq/Makefile | 1 + drivers/power/pwrseq/pwrseq_usb_generic.c | 202 ++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 drivers/power/pwrseq/pwrseq_usb_generic.c diff --git a/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig index c7e9271..9749c6d 100644 --- a/drivers/power/pwrseq/Kconfig +++ b/drivers/power/pwrseq/Kconfig @@ -29,4 +29,15 @@ config POWER_SEQ_SIMPLE This driver can also be built as a module. If so, the module will be called pwrseq_simple. +config POWER_SEQ_USB_GENERIC + tristate "Generic power sequence support for USB devices" + default y + depends on OF || COMPILE_TEST + help + This selects generic power sequence support for USB devices. + By default this option is set to y. + + This driver can also be built as a module. If so, the module + will be called pwrseq_usb_generic. + endif diff --git a/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile index d475e01..230bb45 100644 --- a/drivers/power/pwrseq/Makefile +++ b/drivers/power/pwrseq/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_POWER_SEQ) += core.o obj-$(CONFIG_POWER_SEQ_SIMPLE) += pwrseq_mmc_simple.o obj-$(CONFIG_POWER_SEQ_EMMC) += pwrseq_emmc.o +obj-$(CONFIG_POWER_SEQ_USB_GENERIC) += pwrseq_usb_generic.o diff --git a/drivers/power/pwrseq/pwrseq_usb_generic.c b/drivers/power/pwrseq/pwrseq_usb_generic.c new file mode 100644 index 0000000..6017636 --- /dev/null +++ b/drivers/power/pwrseq/pwrseq_usb_generic.c @@ -0,0 +1,202 @@ +/* + * usb_generic.c The generic power sequence driver for USB device + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Author: Peter Chen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct usb_pwrseq_generic { + struct pwrseq pwrseq; + struct gpio_desc *gpiod_reset; + struct gpio_desc *gpiod_enable; + struct clk *clk; + struct regulator *reg_power; +}; + +#define to_pwrseq_generic(p) container_of(p, struct usb_pwrseq_generic, pwrseq) + +static void usb_pwrseq_power_off(struct pwrseq *_pwrseq) +{ + struct usb_pwrseq_generic *pwrseq = to_pwrseq_generic(_pwrseq); + + if (pwrseq->clk) + clk_disable_unprepare(pwrseq->clk); + + if (pwrseq->gpiod_enable) + gpiod_set_value(pwrseq->gpiod_enable, 0); + + if (pwrseq->reg_power) + regulator_disable(pwrseq->reg_power); +} + +static int usb_pwrseq_power_on(struct pwrseq *_pwrseq) +{ + struct usb_pwrseq_generic *pwrseq = to_pwrseq_generic(_pwrseq); + struct gpio_desc *gpiod_reset = pwrseq->gpiod_reset; + struct gpio_desc *gpiod_enable = pwrseq->gpiod_enable; + struct device *dev = _pwrseq->dev; + struct device_node *node = dev->of_node; + u32 duration_us = 50, clk_rate = 0; + int ret; + + if (pwrseq->clk) { + ret = clk_prepare_enable(pwrseq->clk); + if (ret) { + dev_err(dev, + "Can't enable external clock: %d\n", + ret); + return ret; + } + + of_property_read_u32(node, "clock-frequency", &clk_rate); + if (clk_rate) { + ret = clk_set_rate(pwrseq->clk, clk_rate); + if (ret) { + dev_err(dev, "Error setting clock rate\n"); + goto disable_clk; + } + } + } + + if (gpiod_reset) { + of_property_read_u32(node, "reset-duration-us", &duration_us); + gpiod_direction_output(gpiod_reset, 1); + + gpiod_set_value(gpiod_reset, 1); + usleep_range(duration_us, duration_us + 10); + gpiod_set_value(gpiod_reset, 0); + } + + if (gpiod_enable) { + gpiod_direction_output(gpiod_enable, 1); + gpiod_set_value(gpiod_enable, 1); + } + + if (pwrseq->reg_power) { + ret = regulator_enable(pwrseq->reg_power); + if (ret) { + dev_err(dev, "Failed to power regulator, ret=%d\n", + ret); + goto disable_gpio; + } + } + + return 0; + +disable_gpio: + if (gpiod_enable) + gpiod_set_value(gpiod_enable, 0); + +disable_clk: + if (pwrseq->clk) + clk_disable_unprepare(pwrseq->clk); + return ret; +} + +static const struct pwrseq_ops usb_pwrseq_generic_ops = { + .pre_power_on = usb_pwrseq_power_on, + .power_off = usb_pwrseq_power_off, +}; + +static const struct of_device_id usb_pwrseq_generic_of_match[] = { + { .compatible = "usb-pwrseq-generic",}, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, usb_pwrseq_generic_of_match); + +static int usb_pwrseq_generic_probe(struct platform_device *pdev) +{ + struct usb_pwrseq_generic *pwrseq; + struct device *dev = &pdev->dev; + struct regulator *reg; + int ret; + + pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); + if (!pwrseq) + return -ENOMEM; + + pwrseq->clk = devm_clk_get(dev, NULL); + if (IS_ERR(pwrseq->clk)) { + dev_dbg(dev, "Can't get clock: %ld\n", + PTR_ERR(pwrseq->clk)); + pwrseq->clk = NULL; + } + + pwrseq->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(pwrseq->gpiod_reset); + if (ret) { + dev_err(dev, "Failed to get reset gpio, err = %d\n", ret); + return ret; + } + + pwrseq->gpiod_enable = devm_gpiod_get_optional(dev, "enable", + GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(pwrseq->gpiod_enable); + if (ret) { + dev_err(dev, "Failed to get enable gpio, err = %d\n", ret); + return ret; + } + + reg = devm_regulator_get(dev, "power"); + if (PTR_ERR(reg) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (PTR_ERR(reg) == -ENODEV) + /* no power regulator is needed */ + reg = NULL; + else if (IS_ERR(reg)) + return PTR_ERR(reg); + pwrseq->reg_power = reg; + + pwrseq->pwrseq.dev = dev; + pwrseq->pwrseq.ops = &usb_pwrseq_generic_ops; + pwrseq->pwrseq.owner = THIS_MODULE; + platform_set_drvdata(pdev, pwrseq); + + return pwrseq_register(&pwrseq->pwrseq); +} + +static int usb_pwrseq_generic_remove(struct platform_device *pdev) +{ + struct usb_pwrseq_generic *pwrseq = platform_get_drvdata(pdev); + + pwrseq_unregister(&pwrseq->pwrseq); + + return 0; +} + +static struct platform_driver usb_pwrseq_generic_driver = { + .probe = usb_pwrseq_generic_probe, + .remove = usb_pwrseq_generic_remove, + .driver = { + .name = "usb_pwrseq_generic", + .of_match_table = usb_pwrseq_generic_of_match, + }, +}; + +module_platform_driver(usb_pwrseq_generic_driver); +MODULE_LICENSE("GPL v2");