Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751357AbdFEGvh (ORCPT ); Mon, 5 Jun 2017 02:51:37 -0400 Received: from mail-dm3nam03on0042.outbound.protection.outlook.com ([104.47.41.42]:14748 "EHLO NAM03-DM3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751295AbdFEGvd (ORCPT ); Mon, 5 Jun 2017 02:51:33 -0400 Authentication-Results: spf=softfail (sender IP is 192.88.168.50) smtp.mailfrom=gmail.com; nxp.com; dkim=none (message not signed) header.d=none;nxp.com; dmarc=fail action=none header.from=gmail.com; Date: Mon, 5 Jun 2017 14:51:23 +0800 From: Peter Chen To: Peter Chen , CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Subject: Re: [PATCH v14 2/7] power: add power sequence library Message-ID: <20170605065122.GD20014@b29397-desktop> References: <1495068543-6938-1-git-send-email-peter.chen@nxp.com> <1495068543-6938-3-git-send-email-peter.chen@nxp.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline In-Reply-To: <1495068543-6938-3-git-send-email-peter.chen@nxp.com> User-Agent: Mutt/1.5.24 (2015-08-30) X-EOPAttributedMessage: 0 X-Matching-Connectors: 131411190898370563;(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)(336005)(39410400002)(39380400002)(39860400002)(39840400002)(39850400002)(39400400002)(39450400003)(2980300002)(199003)(24454002)(189002)(9170700003)(4001350100001)(6246003)(1076002)(77096006)(73392002)(189998001)(966005)(50466002)(23726003)(356003)(5660300001)(82202002)(33656002)(76482006)(104016004)(81166006)(46406003)(38730400002)(8936002)(229853002)(83322999)(2906002)(83506001)(2950100002)(305945005)(4326008)(8676002)(39060400002)(81442002)(86362001)(7406005)(7416002)(53936002)(9686003)(6306002)(97756001)(498600001)(33716001)(73972006)(50986999)(105596002)(106466001)(54356999)(76176999)(6666003)(8656002)(6260500002)(87572001)(47776003)(55016002)(54906002)(18370500001)(2004002);DIR:OUT;SFP:1101;SCL:1;SRVR:BN6PR03MB2803;H:tx30smr01.am.freescale.net;FPR:;SPF:SoftFail;MLV:ovrnspm;A:1;MX:1;PTR:InfoDomainNonexistent;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BN1AFFO11FD017;1:fDZKbadSzscEB/3t5rTiBgVOfAkIF9QOlFaUo9LKGF31IZP5ToEObMllhhZhHup/AZ6nwEvlb8oqtXM5y4Y/eCbjkN+5mVjzLRfPCAbOtFqDXR5YBGKPsXEsLpzVfu5STdzx421zmeF1bIitc3/UNDWk04H8Oa/XPsDJHElknzOeXq4W5A4nd4vY+SK+17UhTB6fYMWqOQNNm5ZcFL4tnbyX8zkXqPLgeILJW2yZgyy8enMDs291Yv9/0+hPpm18EPukFFOrvIBucHK1nCBheE93RdQhqijtuMiAznW35SV9EKR9K5i0sV2xSpuBVNRsYERDyTlQ8zAing7LjSO/6mSW/EshUb3DRdgRFtsoxlX23adDSE9KucfqQDHM7nj4G5rJE37sauNzR3rnQf0u3RgNwRDP5wNfQTtNkLEFdlvluTshpcaGS4xuMqMmM5hNCXLMGImwUwjzuY23uOYYkR5uhE87D/U80cn2Rh+XDP0Wn90IEFy6DJKpjj0bbvC2IQwBpan5K/Y6/8GwTAdPtgBal8mG/iV3SnH2Ds0ZijeVqxccqItQpd2NyX4Xx02l X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN6PR03MB2803: X-MS-Office365-Filtering-Correlation-Id: bb6484fc-6b1d-4404-c6a4-08d4abdf4b76 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001)(201703131430075)(201703131517081);SRVR:BN6PR03MB2803; X-Microsoft-Exchange-Diagnostics: 1;BN6PR03MB2803;3:NpLILhF1Prilbko5SKsFfgTTid3T8n4U6nexw+/5tomPoYLcmEhR4rxg8c8QabnKv6v6SGVYQkRvPHsJIxEGtjmX7yXToAHbbITzsla+QOKgJiysbbYjPsvXgf6odLzAzvDBhVgfRw3ACsiU7ekSchOY5krZeg2z7ufZxpTUIcmRPBiOZnHYuDepCJvbRY7tnL/ccH0hdZ/QYV7iLZdUsrV7Z5AwRGnCX3NbFzdZFXSBzJwfHbD199YL0PJFNPqAWQqPPdzgef+P2mlkbLLYWvFK89Wt9wB8idTsYWn3ZP4e4FmmJT1SYWc3tOxRFXx9o6AWAzKPN9y4Zg0QYsYAkmY1j+S2LpB+hEv3zjUQi8dAvUYs80jUhB2LR5efNgLvCOD7itc3HdeTxp04a37QnmQLKOrKpmZmYR3y/zjhzbyexf5BjZMV6hzFPVknMfGv;25:JdJrq+Y2IVI69Ey6xD2WpsvxZtO4UBFp+duVJEboNVBc7qwQwaI8zhFNgjSIE7xkVY8LwOZahzdU/GTpkTih3tdZApsJO5MRWBsZIrmYPqXzq9B3TlK5R11adPbD7EicpC9qtumTqbyo2WgitObG3xUH0hL7lWzXH4BgRAayvRWjwX4DWceoGvivNR+5E/VVdsW3mZWOKNdpvvtVkojDy3YzggaMCX7Ogb0ScvIitE1l2zIQRAaMpuXDx09YSZaKXOELcea7R91lUqqvHMISGiGIQSQygE+LhcG5lIHQe3v6tLinjvopJgN4DPetat4srGsrTBdbZ4qr/mputXsaUTEmBB0RBIWwld3Q5A4Asv1b5Bq9eRaCdVvreYVqEF/Xik8BQXWSkDOxxR03agFVfm+9QDCpG2xI54A/bdqJhFuLNrCF8eV6u7VXUwdnNm25AskTAZb7HGD3bSaVukLwUhl9uQ9WU0C/a5kx5tYCbbk= X-Microsoft-Exchange-Diagnostics: 1;BN6PR03MB2803;31:z9pS7grNuvJhHlze5ghY0TjNd6hk3/A+tO+lJG8b6E+rkknXWVoORLYi3GCjGFOfqRM0/sT2wEkW+Xn3s7y3uEwKI6mpQI7syHbnKrWy9rsIJ8DIdMIY/CqCOeHPk9zEk/2JSMOLZO0+hzuRR8ZBfDxguFBmdqC8MiRslEYaXrwqB8OjJWD/PFI5jJt3RtOE9RIWjb+lwljF6KeLQ1xhvx3giyhc82nUVzRWvlBm9vl95VSG3kHbq6TFv86BspK1bJKFX26UC5I3BleDXUHEYg== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(9452136761055)(185117386973197)(84791874153150); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6095135)(601004)(2401047)(8121501046)(5005006)(13016025)(13018025)(93006095)(93001095)(10201501046)(3002001)(100000703101)(100105400095)(6055026)(6096035)(201703131430075)(201703131448075)(201703131433075)(201703161259150)(201703151042153)(20161123556025)(20161123561025)(20161123563025)(20161123559100)(20161123565025)(100000704101)(100105200095)(100000705101)(100105500095);SRVR:BN6PR03MB2803;BCL:0;PCL:0;RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(400006)(100000804101)(100110200095)(100000805101)(100110500095);SRVR:BN6PR03MB2803; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BN6PR03MB2803;4:vvS+rlEm4YBgxKyfve04gjXSFi5gac4vQcp3/l/MFS?= =?us-ascii?Q?LNxJDdgvRFFERU91jm6yK+1DBqo4oJ1NvCecNMuxilsfvAPalQ7r6oCSwSLR?= =?us-ascii?Q?mUN4waSchPTEesi6/dQb7H6I49Ns/Yk/HxlrLk3h4/g3kM4pO1XcRJ8gFTg3?= =?us-ascii?Q?08yPWNGuI5r8ZJMj39iNB+/X3l20WFbgs/VWFzRRux5NFrLA0pvHtvu16c63?= =?us-ascii?Q?pmEYstJnjaCnalAijWVjLkim4F6tYHmQograNR0KiQLSsWXonjANDIYSBNwY?= =?us-ascii?Q?68RwWp/4jd2rDs6ZtXpGsTN0/zWbav+lXMMzV+R4Pay+pbVE9W4GDJSqOveY?= =?us-ascii?Q?VNrjOATw1ly28O7awxKYIPucZ6rghYc4Qi1u/SRx6wF3B9rBROftpisP/X6E?= =?us-ascii?Q?G4k6RxFXYG2QGxTnnk+dDM+ssUyOhQSx4sj58t9F/gur/XXCtpFuVSpssW2a?= =?us-ascii?Q?ePg+wkx0mciiA8buNg8cNk46IhKjVeetXRyWfD6YBwjarscI77MbCSVHmdxS?= =?us-ascii?Q?0/mp5/5zcEFIumM+xvu7pD7BFmu/RicfiffIxRaqtyRarWwzDNCfzQiDKuvj?= =?us-ascii?Q?9hNilooF+sECX1ahgrW+zlnFmKgyvoInSr+x9v7xyrM6TEmGUrTZZb1ICU/I?= =?us-ascii?Q?Ozm6uJZxCqgYVGAEJ/IN8bltmwWIkedl361GDN3v/+12F44V8xWPqfNtYH1J?= =?us-ascii?Q?nA0dIk6qXGSOvM4j8v3gTAwdOjVgWHbK9A4034aKxR92Tf3P0goOhc6IZLvj?= =?us-ascii?Q?eaDLV2/PRIkEm2onOKkA7sUiJa2AYvfkvqfhV0JyfeK7j7jGQ19IArkFedCu?= =?us-ascii?Q?CAaYi1mTTYLWXrP93nmwkfGGqdxcEZlfmc6KIb1yOE8H2yg+9aLJQVZI6gDZ?= =?us-ascii?Q?agX8tCeQdST2ZkuFVrfTLS/UeBHL++P5oq1om7vIyRc5xMGvT3mt4ojJTtsh?= =?us-ascii?Q?yyhXUEBHHk8r/zWKhiUu/sXlbggIItoeIMmDFr9r5ut60ODF19tfYOy81vZb?= =?us-ascii?Q?lZI9NnBQ3FU60CanKekRV8S6adfQtu+df95Aiv9SJ9TEznXZX4KZwoncPhRV?= =?us-ascii?Q?LfnlUgLTs3eQ9oWONK7a1GKYZ1AkVV8xSW/lzDxpaicEf2rCvZbgGvWPtRIj?= =?us-ascii?Q?/5KOIOq9f9wgxL6hvxY4mx/hnL33TEXIbV9s/BDpL6f0oWBuiEZBOIeOe0RJ?= =?us-ascii?Q?l1+7W+U0ll53qtv+zb2II3xf+/kTboQbCNp3Mx7qcdp17xknFHstBv05u6+3?= =?us-ascii?Q?54hIqk/e6gMnPx0FQ/jO3BwvAtrWCElj5L1acdbBlsNs28yYp03HY2r8nnO2?= =?us-ascii?Q?019Jo/0sp3Za274i7h78yg7zPBq8uzJxl4iRpFm+UJ?= X-Forefront-PRVS: 0329B15C8A X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BN6PR03MB2803;23:Q3UYKjVFMiYNi3AJr9I0k19FoBa3pIBrRCPfpZQrm?= =?us-ascii?Q?xlo9FszggSAWBEnx9Nu/OkaORV2wZbZ1S0aBUi4I4Q9WmNBs301IsfwOpsNr?= =?us-ascii?Q?cDiuBC/WqZNSm8R4o7oqpGu7HsaKe/TMxoCkmB+K6E+hPSjuLK1KDofljIfE?= =?us-ascii?Q?kolRiSJ2Eoz9jwxA0frX0HQM2FOl2FHx9kwYvx41uyDDRYWbf0iZQipe3Yh0?= =?us-ascii?Q?unb1k99xdDH02ElwD9o5cFtUoBZdAbOiaYkOqrlA38Y3JHpcmd60A9AuFHps?= =?us-ascii?Q?DCmmaTmp6YAy04lslDPSD1B3KIAM0Y/ZLQbGwqBpkVcYMWvj7JVsCE9rGx0t?= =?us-ascii?Q?kuw8S/e14Plx0MJ8gdoDQh3dZC5QRVU3LY0/eVG52KsemVWi7moGloK82Zkd?= =?us-ascii?Q?0Nq9PmuMnyt4zyLwVedJ9LfjuQafO5gYPi9Il4vpWe46Tb62wChGq3ISt5c+?= =?us-ascii?Q?ie26DF1j8RXG8gIX412NACYd+/7f+xmlwsb2ItIQrOQUJo7Ce1oryE4DLTc/?= =?us-ascii?Q?JIz+qW3GfPei0To4fk2XUqphNpQzbF25pc+Ri0zhzpfqeakAZ2jU75On1juO?= =?us-ascii?Q?y5o+rri6wzYTbJIzjUEjt7n5ARBYfP6gKcSl7ApAzzqiMJq/oNTcW7N4T2XX?= =?us-ascii?Q?Aale3sscIPWlq2Bnw3XFOmrhsfaqQNVRC3x4r19/qD01+xNvvAZRjh9cmFrH?= =?us-ascii?Q?wb90OBADbRq8ykNW8drQduDxM82f+mqtYmhMVoWqzAoZJFWJnF5kAqC0kiK+?= =?us-ascii?Q?52KDeNzC5i2hSuFVuItymK9im+HeWtd5+mpbCRDgpoC95fWWjj9z+mSrm8fj?= =?us-ascii?Q?uzG9gDibiXeTjMVZ2W5NYgS9Vk08Vx/pWytgsz7MZVK5MpZ+hQVYWIqThWmq?= =?us-ascii?Q?NfZ+TzjTlyJ9498PkYkzPAfa3RkNs4NntGEzW8iagahyUqK6tFcq63zgi9hT?= =?us-ascii?Q?D1E2RlCHbA3qLE1CHPI0gTmby//RuDmb2ZughoGd4qyXni1NB+Rt2xwn/3II?= =?us-ascii?Q?miK4f3AN4P9rHV2DcpfNuYpO57lrhrhX7b8OaNRh75OFjdFWi1KQa7oIlc7w?= =?us-ascii?Q?l1a9jjtXxpbVxWTHzkpNbMwtM/d2FxpcD8dJz2MbW3MHTS9wPW9fYQ0wG7nQ?= =?us-ascii?Q?IXuEPchgAsXp9puG7BQxSlHs2fgbFT6T76RfQRzEcTU2qrigzZXAu1w210B9?= =?us-ascii?Q?4cfrxJkQEggn+Nq+zS9m/wAvcdMQ5/KbVH1kBajjzaW5l8ycMEdcPE60pu8P?= =?us-ascii?Q?6/1E1GZ3Oj+rQCqQiF2lZPrrCT8o/oWKTzvlU8n2TrAAhPmdlVxl//etMf8d?= =?us-ascii?Q?JshxlfuBRYqwZmHWhHG8JMcV07JgBa/Fm/iwolySpnv7D2Fj5+bvmjEQegJ3?= =?us-ascii?Q?ojptYhJvFSUeb9JvpQKE0JzbIzWn6qBY4+cYTf4OxrvPQgUKLGEuaWHY7cVS?= =?us-ascii?Q?/rmG44qm+eRs33BW+B69W62lM6vhASWw5xbJQOysxg5sul5LWZO+whkaQNgT?= =?us-ascii?Q?kuqxciqER6w2Po9jZ4zsIuYDjx1lktUkF5w9dVt7XwYyrd2d9as0re08Xyqq?= =?us-ascii?Q?Nprva44UnRy5r54maaQu+1HdOX8Ar3bz8o44m+g9FGkyhn7uDNylq9bDI+mF?= =?us-ascii?Q?zTDRDL4ZxIimZL2xvdd0A=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;BN6PR03MB2803;6:SxlgCcthcoz7cYTTWkQytZsfZbYxqVFMIsAD8/n3laP1CDPaH7u7cFHwGEOV/s7coQ4CPD7DIdhfAHTJavTN2A0CrVY4E8i/SAs9q/3eVGAskkJyyD6QMLJ6CgOSTyalF9l8L49m3d7L4OcNkXPJ2PHEBXsr7IcbLwiIekzah/VMtXcTqa66wcwN+SZYzK8O0r6ZYXJpSK2EOa6oBkS/6cDVbR3k2rVY8DBjetCSy9ZXHrcOwvxs5bHjMlpDMtZt9e2KTj8FsOBxKHxy2bNLm0htsMaGTJiAu5RWI6F3M1TMqR/lvSDbCU+SqnJnErNgBPi7QjYO6tsMAmllTZuJ81cbrGPVQBiUK/QmlNMzv61Cl7z0OSDCLHGuf9OVhrRsasEsww6FVDPrXwPKRNvf7jLWnsHmYHTN+V6muv1ZIA6cyK2KLYBr3UObo2NOBJ1zIPeuNnMj680ukqDrY6ExMxdSNTBzpV/Rq36Fli6ApGImn3YHqtBx3r/xfvZ5rua2X/0DuigmgyAc6EocL/R24w== X-Microsoft-Exchange-Diagnostics: 1;BN6PR03MB2803;5:ZUPABYD50x15b0f3hBE1AWFFHNpZhlYgZhBxcV/YWvoDLJTnE0JxtDfgblAV5AMKIwCzXlV3ZBQGG3DuHq8CsrCEfq0AZTvJF53ow0ODDY2ETmhCywiw22WQq7z/O3cq9kQ3bmR/RRU9mIdWMznmfbBDChlslC0t5bYWJbD0xTAlxkGNrblZG58m5owr6C8ifOViaVr1Q8WW+SFa4jgLDEf9I5SMZY8g/8enSZvh97cmJgqUfAaylYt/cwtq2yFQvcC6aIWKTV1Ydqvr8z3IfXF+ItFSggV9F9vLpF8OvVK0V33UE2+wXSrZDh4oOqeOwH5y7DGd8hActknDqzPVMK+z+wyI/BPrUN92nIh4ZUjdp6X1d0sSq1cTMMQ7jtwR+ql6uSX9PffE+Y36vaRGz3Zh7oiH7JsKZ4rIafGAUNA7F8WzHFBT5T5KQh3hRUfLC/ymivNDRAhoDFuCyUXfZ3pj+/vitaUaArDsYAQMEVgGL7QsqkpeIMnhvveFf81jat2Di71yCFFPTBUTJ2YUhw==;24:xssQ8rXTneaHR+E4Uf6ZZLJSD+jMvFPJthBmM/r+4dkvRGAue9AS4OjxMzZZ/N67EnysMKyLRhoXNSIMkKPRndH0b+xKYCxFRfy21Fln81Q= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;BN6PR03MB2803;7:pTteVy8eg4SI70bsdZIKnwSAfk0eMF7xJOvN0KVSAoTPYo2nch14DNLxaFDJJ+WLhbT645M9CdqfUjFxneZRf2QXDIUct5128HC9NLMlK98G77NRv8PnThKRbmyGZL5fsQZJX/h6j6h/VKazXRSWqF1whMGdITP8UWczHnsv+KA8yyjtSAUqRgKBKQJPHeNAnfawlEwckg93tk89dW7O8niITLhS/SzAA1jIJyt7cHJ0OU3uWlOFWgFK75HkoWlwBduBQdYriFTCRsnidHojIMKL0VHwQikdxMZ6xBSl93wPZFHE+np9NWzwxJog4wI97qIxrAV+45dPnAmUjc4tCA== X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Jun 2017 06:51:29.4782 (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: BN6PR03MB2803 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 26725 Lines: 861 On Thu, May 18, 2017 at 08:48:58AM +0800, Peter Chen wrote: > We have an well-known problem that the device needs to do some power > sequence before it can be recognized by related host, the typical > example like hard-wired mmc devices and usb devices. > > This power sequence is hard to be described at device tree and handled by > related host driver, so we have created a common power sequence > library to cover this requirement. The core code has supplied > some common helpers for host driver, and individual power sequence > libraries handle kinds of power sequence for devices. The pwrseq > librares always need to allocate extra instance for compatible > string match. > > pwrseq_generic is intended for general purpose of power sequence, which > handles gpios and clocks currently, and can cover other controls in > future. The host driver just needs to call of_pwrseq_on/of_pwrseq_off > if only one power sequence is needed, else call of_pwrseq_on_list > /of_pwrseq_off_list instead (eg, USB hub driver). > > For new power sequence library, it can add its compatible string > to pwrseq_of_match_table, then the pwrseq core will match it with > DT's, and choose this library at runtime. Ping.... > > Signed-off-by: Peter Chen > Tested-by: Maciej S. Szmigiero > Tested-by Joshua Clayton > Reviewed-by: Matthias Kaehlcke > Tested-by: Matthias Kaehlcke > --- > Documentation/power/power-sequence/design.rst | 54 +++++ > MAINTAINERS | 9 + > drivers/power/Kconfig | 1 + > drivers/power/Makefile | 1 + > drivers/power/pwrseq/Kconfig | 20 ++ > drivers/power/pwrseq/Makefile | 2 + > drivers/power/pwrseq/core.c | 335 ++++++++++++++++++++++++++ > drivers/power/pwrseq/pwrseq_generic.c | 234 ++++++++++++++++++ > include/linux/power/pwrseq.h | 81 +++++++ > 9 files changed, 737 insertions(+) > create mode 100644 Documentation/power/power-sequence/design.rst > create mode 100644 drivers/power/pwrseq/Kconfig > create mode 100644 drivers/power/pwrseq/Makefile > create mode 100644 drivers/power/pwrseq/core.c > create mode 100644 drivers/power/pwrseq/pwrseq_generic.c > create mode 100644 include/linux/power/pwrseq.h > > diff --git a/Documentation/power/power-sequence/design.rst b/Documentation/power/power-sequence/design.rst > new file mode 100644 > index 0000000..554608e > --- /dev/null > +++ b/Documentation/power/power-sequence/design.rst > @@ -0,0 +1,54 @@ > +==================================== > +Power Sequence Library > +==================================== > + > +:Date: Feb, 2017 > +:Author: Peter Chen > + > + > +Introduction > +============ > + > +We have an well-known problem that the device needs to do a power > +sequence before it can be recognized by related host, the typical > +examples are hard-wired mmc devices and usb devices. The host controller > +can't know what kinds of this device is in its bus if the power > +sequence has not done, since the related devices driver's probe calling > +is determined by runtime according to eunumeration results. Besides, > +the devices may have custom power sequence, so the power sequence library > +which is independent with the devices is needed. > + > +Design > +============ > + > +The power sequence library includes the core file and customer power > +sequence library. The core file exports interfaces are called by > +host controller driver for power sequence and customer power sequence > +library files to register its power sequence instance to global > +power sequence list. The custom power sequence library creates power > +sequence instance and implement custom power sequence. > + > +Since the power sequence describes hardware design, the description is > +located at board description file, eg, device tree dts file. And > +a specific power sequence belongs to device, so its description > +is under the device node, please refer to: > +Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt > + > +Custom power sequence library allocates one power sequence instance at > +bootup periods using postcore_initcall, this static allocated instance is > +used to compare with device-tree (DT) node to see if this library can be > +used for the node or not. When the result is matched, the core API will > +try to get resourses (->get, implemented at each library) for power > +sequence, if all resources are got, it will try to allocate another > +instance for next possible request from host driver. > + > +Then, the host controller driver can carry out power sequence on for this > +DT node, the library will do corresponding operations, like open clocks, > +toggle gpio, etc. The power sequence off routine will close and free the > +resources, and is called when the parent is removed. And the power > +sequence suspend and resume routine can be called at host driver's > +suspend and resume routine if needed. > + > +The exported interfaces > +.. kernel-doc:: drivers/power/pwrseq/core.c > + :export: > diff --git a/MAINTAINERS b/MAINTAINERS > index f7d568b..93b07aa 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -10188,6 +10188,15 @@ F: include/linux/pm_* > F: include/linux/powercap.h > F: drivers/powercap/ > > +POWER SEQUENCE LIBRARY > +M: Peter Chen > +T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git > +L: linux-pm@vger.kernel.org > +S: Maintained > +F: Documentation/devicetree/bindings/power/pwrseq/ > +F: drivers/power/pwrseq/ > +F: include/linux/power/pwrseq.h > + > POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS > M: Sebastian Reichel > L: linux-pm@vger.kernel.org > diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig > index 63454b5..c1bb046 100644 > --- a/drivers/power/Kconfig > +++ b/drivers/power/Kconfig > @@ -1,3 +1,4 @@ > source "drivers/power/avs/Kconfig" > source "drivers/power/reset/Kconfig" > source "drivers/power/supply/Kconfig" > +source "drivers/power/pwrseq/Kconfig" > diff --git a/drivers/power/Makefile b/drivers/power/Makefile > index ff35c71..7db8035 100644 > --- a/drivers/power/Makefile > +++ b/drivers/power/Makefile > @@ -1,3 +1,4 @@ > obj-$(CONFIG_POWER_AVS) += avs/ > obj-$(CONFIG_POWER_RESET) += reset/ > obj-$(CONFIG_POWER_SUPPLY) += supply/ > +obj-$(CONFIG_POWER_SEQUENCE) += pwrseq/ > diff --git a/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig > new file mode 100644 > index 0000000..c6b3569 > --- /dev/null > +++ b/drivers/power/pwrseq/Kconfig > @@ -0,0 +1,20 @@ > +# > +# Power Sequence library > +# > + > +menuconfig POWER_SEQUENCE > + bool "Power sequence control" > + help > + It is used for drivers which needs to do power sequence > + (eg, turn on clock, toggle reset gpio) before the related > + devices can be found by hardware, eg, USB bus. > + > +if POWER_SEQUENCE > + > +config PWRSEQ_GENERIC > + bool "Generic power sequence control" > + depends on OF > + help > + This is the generic power sequence control library, and is > + supposed to support common power sequence usage. > +endif > diff --git a/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile > new file mode 100644 > index 0000000..ad82389 > --- /dev/null > +++ b/drivers/power/pwrseq/Makefile > @@ -0,0 +1,2 @@ > +obj-$(CONFIG_POWER_SEQUENCE) += core.o > +obj-$(CONFIG_PWRSEQ_GENERIC) += pwrseq_generic.o > diff --git a/drivers/power/pwrseq/core.c b/drivers/power/pwrseq/core.c > new file mode 100644 > index 0000000..3d19e62 > --- /dev/null > +++ b/drivers/power/pwrseq/core.c > @@ -0,0 +1,335 @@ > +/* > + * core.c power sequence core file > + * > + * 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. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +static DEFINE_MUTEX(pwrseq_list_mutex); > +static LIST_HEAD(pwrseq_list); > + > +static int pwrseq_get(struct device_node *np, struct pwrseq *p) > +{ > + if (p && p->get) > + return p->get(np, p); > + > + return -ENOTSUPP; > +} > + > +static int pwrseq_on(struct pwrseq *p) > +{ > + if (p && p->on) > + return p->on(p); > + > + return -ENOTSUPP; > +} > + > +static void pwrseq_off(struct pwrseq *p) > +{ > + if (p && p->off) > + p->off(p); > +} > + > +static void pwrseq_put(struct pwrseq *p) > +{ > + if (p && p->put) > + p->put(p); > +} > + > +/** > + * pwrseq_register - Add pwrseq instance to global pwrseq list > + * > + * @pwrseq: the pwrseq instance > + */ > +void pwrseq_register(struct pwrseq *pwrseq) > +{ > + mutex_lock(&pwrseq_list_mutex); > + list_add(&pwrseq->node, &pwrseq_list); > + mutex_unlock(&pwrseq_list_mutex); > +} > +EXPORT_SYMBOL_GPL(pwrseq_register); > + > +/** > + * pwrseq_unregister - Remove pwrseq instance from global pwrseq list > + * > + * @pwrseq: the pwrseq instance > + */ > +void pwrseq_unregister(struct pwrseq *pwrseq) > +{ > + mutex_lock(&pwrseq_list_mutex); > + list_del(&pwrseq->node); > + mutex_unlock(&pwrseq_list_mutex); > +} > +EXPORT_SYMBOL_GPL(pwrseq_unregister); > + > +static struct pwrseq *pwrseq_find_available_instance(struct device_node *np) > +{ > + struct pwrseq *pwrseq; > + > + mutex_lock(&pwrseq_list_mutex); > + list_for_each_entry(pwrseq, &pwrseq_list, node) { > + if (pwrseq->used) > + continue; > + > + /* compare compatible string for pwrseq node */ > + if (of_match_node(pwrseq->pwrseq_of_match_table, np)) { > + pwrseq->used = true; > + mutex_unlock(&pwrseq_list_mutex); > + return pwrseq; > + } > + > + /* return generic pwrseq instance */ > + if (!strcmp(pwrseq->pwrseq_of_match_table->compatible, > + "generic")) { > + pr_debug("using generic pwrseq instance for %s\n", > + np->full_name); > + pwrseq->used = true; > + mutex_unlock(&pwrseq_list_mutex); > + return pwrseq; > + } > + } > + mutex_unlock(&pwrseq_list_mutex); > + pr_debug("Can't find any pwrseq instances for %s\n", np->full_name); > + > + return NULL; > +} > + > +/** > + * of_pwrseq_on - Carry out power sequence on for device node > + * > + * @np: the device node would like to power on > + * > + * Carry out a single device power on. If multiple devices > + * need to be handled, use of_pwrseq_on_list() instead. > + * > + * Return a pointer to the power sequence instance on success, > + * or an error code otherwise. > + */ > +struct pwrseq *of_pwrseq_on(struct device_node *np) > +{ > + struct pwrseq *pwrseq; > + int ret; > + > + pwrseq = pwrseq_find_available_instance(np); > + if (!pwrseq) > + return ERR_PTR(-ENOENT); > + > + ret = pwrseq_get(np, pwrseq); > + if (ret) { > + /* Mark current pwrseq as unused */ > + pwrseq->used = false; > + return ERR_PTR(ret); > + } > + > + ret = pwrseq_on(pwrseq); > + if (ret) > + goto pwr_put; > + > + return pwrseq; > + > +pwr_put: > + pwrseq_put(pwrseq); > + return ERR_PTR(ret); > +} > +EXPORT_SYMBOL_GPL(of_pwrseq_on); > + > +/** > + * of_pwrseq_off - Carry out power sequence off for this pwrseq instance > + * > + * @pwrseq: the pwrseq instance which related device would like to be off > + * > + * This API is used to power off single device, it is the opposite > + * operation for of_pwrseq_on. > + */ > +void of_pwrseq_off(struct pwrseq *pwrseq) > +{ > + pwrseq_off(pwrseq); > + pwrseq_put(pwrseq); > +} > +EXPORT_SYMBOL_GPL(of_pwrseq_off); > + > +/** > + * of_pwrseq_on_list - Carry out power sequence on for list > + * > + * @np: the device node would like to power on > + * @head: the list head for pwrseq list on this bus > + * > + * This API is used to power on multiple devices at single bus. > + * If there are several devices on bus (eg, USB bus), uses this > + * this API. Otherwise, use of_pwrseq_on instead. After the device > + * is powered on successfully, it will be added to pwrseq list for > + * this bus. The caller needs to use mutex_lock for concurrent. > + * > + * Return 0 on success, or an error value otherwise. > + */ > +int of_pwrseq_on_list(struct device_node *np, struct list_head *head) > +{ > + struct pwrseq *pwrseq; > + struct pwrseq_list_per_dev *pwrseq_list_node; > + > + pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL); > + if (!pwrseq_list_node) > + return -ENOMEM; > + > + pwrseq = of_pwrseq_on(np); > + if (IS_ERR(pwrseq)) { > + kfree(pwrseq_list_node); > + return PTR_ERR(pwrseq); > + } > + > + pwrseq_list_node->pwrseq = pwrseq; > + list_add(&pwrseq_list_node->list, head); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(of_pwrseq_on_list); > + > +/** > + * of_pwrseq_off_list - Carry out power sequence off for the list > + * > + * @head: the list head for pwrseq instance list on this bus > + * > + * This API is used to power off all devices on this bus, it is > + * the opposite operation for of_pwrseq_on_list. > + * The caller needs to use mutex_lock for concurrent. > + */ > +void of_pwrseq_off_list(struct list_head *head) > +{ > + struct pwrseq *pwrseq; > + struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node; > + > + list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) { > + pwrseq = pwrseq_list_node->pwrseq; > + of_pwrseq_off(pwrseq); > + list_del(&pwrseq_list_node->list); > + kfree(pwrseq_list_node); > + } > +} > +EXPORT_SYMBOL_GPL(of_pwrseq_off_list); > + > +/** > + * pwrseq_suspend - Carry out power sequence suspend for this pwrseq instance > + * > + * @pwrseq: the pwrseq instance > + * > + * This API is used to do suspend operation on pwrseq instance. > + * > + * Return 0 on success, or an error value otherwise. > + */ > +int pwrseq_suspend(struct pwrseq *p) > +{ > + int ret = 0; > + > + if (p && p->suspend) > + ret = p->suspend(p); > + else > + return ret; > + > + if (!ret) > + p->suspended = true; > + else > + pr_err("%s failed\n", __func__); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pwrseq_suspend); > + > +/** > + * pwrseq_resume - Carry out power sequence resume for this pwrseq instance > + * > + * @pwrseq: the pwrseq instance > + * > + * This API is used to do resume operation on pwrseq instance. > + * > + * Return 0 on success, or an error value otherwise. > + */ > +int pwrseq_resume(struct pwrseq *p) > +{ > + int ret = 0; > + > + if (p && p->resume) > + ret = p->resume(p); > + else > + return ret; > + > + if (!ret) > + p->suspended = false; > + else > + pr_err("%s failed\n", __func__); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pwrseq_resume); > + > +/** > + * pwrseq_suspend_list - Carry out power sequence suspend for list > + * > + * @head: the list head for pwrseq instance list on this bus > + * > + * This API is used to do suspend on all power sequence instances on this bus. > + * The caller needs to use mutex_lock for concurrent. > + */ > +int pwrseq_suspend_list(struct list_head *head) > +{ > + struct pwrseq *pwrseq; > + struct pwrseq_list_per_dev *pwrseq_list_node; > + int ret = 0; > + > + list_for_each_entry(pwrseq_list_node, head, list) { > + ret = pwrseq_suspend(pwrseq_list_node->pwrseq); > + if (ret) > + break; > + } > + > + if (ret) { > + list_for_each_entry(pwrseq_list_node, head, list) { > + pwrseq = pwrseq_list_node->pwrseq; > + if (pwrseq->suspended) > + pwrseq_resume(pwrseq); > + } > + } > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pwrseq_suspend_list); > + > +/** > + * pwrseq_resume_list - Carry out power sequence resume for the list > + * > + * @head: the list head for pwrseq instance list on this bus > + * > + * This API is used to do resume on all power sequence instances on this bus. > + * The caller needs to use mutex_lock for concurrent. > + */ > +int pwrseq_resume_list(struct list_head *head) > +{ > + struct pwrseq_list_per_dev *pwrseq_list_node; > + int ret = 0; > + > + list_for_each_entry(pwrseq_list_node, head, list) { > + ret = pwrseq_resume(pwrseq_list_node->pwrseq); > + if (ret) > + break; > + } > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pwrseq_resume_list); > diff --git a/drivers/power/pwrseq/pwrseq_generic.c b/drivers/power/pwrseq/pwrseq_generic.c > new file mode 100644 > index 0000000..4e7c090 > --- /dev/null > +++ b/drivers/power/pwrseq/pwrseq_generic.c > @@ -0,0 +1,234 @@ > +/* > + * pwrseq_generic.c Generic power sequence handling > + * > + * 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. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct pwrseq_generic { > + struct pwrseq pwrseq; > + struct gpio_desc *gpiod_reset; > + struct clk *clks[PWRSEQ_MAX_CLKS]; > + u32 duration_us; > + bool suspended; > +}; > + > +#define to_generic_pwrseq(p) container_of(p, struct pwrseq_generic, pwrseq) > + > +static int pwrseq_generic_alloc_instance(void); > +static const struct of_device_id generic_id_table[] = { > + { .compatible = "generic",}, > + { /* sentinel */ } > +}; > + > +static int pwrseq_generic_suspend(struct pwrseq *pwrseq) > +{ > + struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq); > + int clk; > + > + for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--) > + clk_disable_unprepare(pwrseq_gen->clks[clk]); > + > + pwrseq_gen->suspended = true; > + return 0; > +} > + > +static int pwrseq_generic_resume(struct pwrseq *pwrseq) > +{ > + struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq); > + int clk, ret = 0; > + > + for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) { > + ret = clk_prepare_enable(pwrseq_gen->clks[clk]); > + if (ret) { > + pr_err("Can't enable clock, ret=%d\n", ret); > + goto err_disable_clks; > + } > + } > + > + pwrseq_gen->suspended = false; > + return ret; > + > +err_disable_clks: > + while (--clk >= 0) > + clk_disable_unprepare(pwrseq_gen->clks[clk]); > + > + return ret; > +} > + > +static void pwrseq_generic_put(struct pwrseq *pwrseq) > +{ > + struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq); > + int clk; > + > + if (pwrseq_gen->gpiod_reset) > + gpiod_put(pwrseq_gen->gpiod_reset); > + > + for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) > + clk_put(pwrseq_gen->clks[clk]); > + > + pwrseq_unregister(&pwrseq_gen->pwrseq); > + kfree(pwrseq_gen); > +} > + > +static void pwrseq_generic_off(struct pwrseq *pwrseq) > +{ > + struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq); > + int clk; > + > + if (pwrseq_gen->suspended) > + return; > + > + for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--) > + clk_disable_unprepare(pwrseq_gen->clks[clk]); > +} > + > +static int pwrseq_generic_on(struct pwrseq *pwrseq) > +{ > + struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq); > + int clk, ret = 0; > + struct gpio_desc *gpiod_reset = pwrseq_gen->gpiod_reset; > + > + for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) { > + ret = clk_prepare_enable(pwrseq_gen->clks[clk]); > + if (ret) { > + pr_err("Can't enable clock, ret=%d\n", ret); > + goto err_disable_clks; > + } > + } > + > + if (gpiod_reset) { > + u32 duration_us = pwrseq_gen->duration_us; > + > + if (duration_us <= 10) > + udelay(10); > + else > + usleep_range(duration_us, duration_us + 100); > + gpiod_set_value(gpiod_reset, 0); > + } > + > + return ret; > + > +err_disable_clks: > + while (--clk >= 0) > + clk_disable_unprepare(pwrseq_gen->clks[clk]); > + > + return ret; > +} > + > +static int pwrseq_generic_get(struct device_node *np, struct pwrseq *pwrseq) > +{ > + struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq); > + enum of_gpio_flags flags; > + int reset_gpio, clk, ret = 0; > + > + for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) { > + pwrseq_gen->clks[clk] = of_clk_get(np, clk); > + if (IS_ERR(pwrseq_gen->clks[clk])) { > + ret = PTR_ERR(pwrseq_gen->clks[clk]); > + if (ret != -ENOENT) > + goto err_put_clks; > + pwrseq_gen->clks[clk] = NULL; > + break; > + } > + } > + > + reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags); > + if (gpio_is_valid(reset_gpio)) { > + unsigned long gpio_flags; > + > + if (flags & OF_GPIO_ACTIVE_LOW) > + gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW; > + else > + gpio_flags = GPIOF_OUT_INIT_HIGH; > + > + ret = gpio_request_one(reset_gpio, gpio_flags, > + "pwrseq-reset-gpios"); > + if (ret) > + goto err_put_clks; > + > + pwrseq_gen->gpiod_reset = gpio_to_desc(reset_gpio); > + of_property_read_u32(np, "reset-duration-us", > + &pwrseq_gen->duration_us); > + } else if (reset_gpio == -ENOENT) { > + ; /* no such gpio */ > + } else { > + ret = reset_gpio; > + pr_err("Failed to get reset gpio on %s, err = %d\n", > + np->full_name, reset_gpio); > + goto err_put_clks; > + } > + > + /* allocate new one for later pwrseq instance request */ > + ret = pwrseq_generic_alloc_instance(); > + if (ret) > + goto err_put_gpio; > + > + return 0; > + > +err_put_gpio: > + if (pwrseq_gen->gpiod_reset) > + gpiod_put(pwrseq_gen->gpiod_reset); > +err_put_clks: > + while (--clk >= 0) > + clk_put(pwrseq_gen->clks[clk]); > + return ret; > +} > + > +/** > + * pwrseq_generic_alloc_instance - power sequence instance allocation > + * > + * This function is used to allocate one generic power sequence instance, > + * it is called when the system boots up and after one power sequence > + * instance is got successfully. > + * > + * Return zero on success or an error code otherwise. > + */ > +static int pwrseq_generic_alloc_instance(void) > +{ > + struct pwrseq_generic *pwrseq_gen; > + > + pwrseq_gen = kzalloc(sizeof(*pwrseq_gen), GFP_KERNEL); > + if (!pwrseq_gen) > + return -ENOMEM; > + > + pwrseq_gen->pwrseq.pwrseq_of_match_table = generic_id_table; > + pwrseq_gen->pwrseq.get = pwrseq_generic_get; > + pwrseq_gen->pwrseq.on = pwrseq_generic_on; > + pwrseq_gen->pwrseq.off = pwrseq_generic_off; > + pwrseq_gen->pwrseq.put = pwrseq_generic_put; > + pwrseq_gen->pwrseq.suspend = pwrseq_generic_suspend; > + pwrseq_gen->pwrseq.resume = pwrseq_generic_resume; > + > + pwrseq_register(&pwrseq_gen->pwrseq); > + return 0; > +} > + > +/* Allocate one pwrseq instance during boots up */ > +static int __init pwrseq_generic_register(void) > +{ > + return pwrseq_generic_alloc_instance(); > +} > +postcore_initcall(pwrseq_generic_register) > diff --git a/include/linux/power/pwrseq.h b/include/linux/power/pwrseq.h > new file mode 100644 > index 0000000..cbc344c > --- /dev/null > +++ b/include/linux/power/pwrseq.h > @@ -0,0 +1,81 @@ > +#ifndef __LINUX_PWRSEQ_H > +#define __LINUX_PWRSEQ_H > + > +#include > + > +#define PWRSEQ_MAX_CLKS 3 > + > +/** > + * struct pwrseq - the power sequence structure > + * @pwrseq_of_match_table: the OF device id table this pwrseq library supports > + * @node: the list pointer to be added to pwrseq list > + * @get: the API is used to get pwrseq instance from the device node > + * @on: do power on for this pwrseq instance > + * @off: do power off for this pwrseq instance > + * @put: release the resources on this pwrseq instance > + * @suspend: do suspend operation on this pwrseq instance > + * @resume: do resume operation on this pwrseq instance > + * @used: this pwrseq instance is used by device > + */ > +struct pwrseq { > + const struct of_device_id *pwrseq_of_match_table; > + struct list_head node; > + int (*get)(struct device_node *np, struct pwrseq *p); > + int (*on)(struct pwrseq *p); > + void (*off)(struct pwrseq *p); > + void (*put)(struct pwrseq *p); > + int (*suspend)(struct pwrseq *p); > + int (*resume)(struct pwrseq *p); > + bool used; > + bool suspended; > +}; > + > +/* used for power sequence instance list in one driver */ > +struct pwrseq_list_per_dev { > + struct pwrseq *pwrseq; > + struct list_head list; > +}; > + > +#if IS_ENABLED(CONFIG_POWER_SEQUENCE) > +void pwrseq_register(struct pwrseq *pwrseq); > +void pwrseq_unregister(struct pwrseq *pwrseq); > +struct pwrseq *of_pwrseq_on(struct device_node *np); > +void of_pwrseq_off(struct pwrseq *pwrseq); > +int of_pwrseq_on_list(struct device_node *np, struct list_head *head); > +void of_pwrseq_off_list(struct list_head *head); > +int pwrseq_suspend(struct pwrseq *p); > +int pwrseq_resume(struct pwrseq *p); > +int pwrseq_suspend_list(struct list_head *head); > +int pwrseq_resume_list(struct list_head *head); > +#else > +static inline void pwrseq_register(struct pwrseq *pwrseq) {} > +static inline void pwrseq_unregister(struct pwrseq *pwrseq) {} > +static inline struct pwrseq *of_pwrseq_on(struct device_node *np) > +{ > + return NULL; > +} > +static void of_pwrseq_off(struct pwrseq *pwrseq) {} > +static int of_pwrseq_on_list(struct device_node *np, struct list_head *head) > +{ > + return 0; > +} > +static void of_pwrseq_off_list(struct list_head *head) {} > +static int pwrseq_suspend(struct pwrseq *p) > +{ > + return 0; > +} > +static int pwrseq_resume(struct pwrseq *p) > +{ > + return 0; > +} > +static int pwrseq_suspend_list(struct list_head *head) > +{ > + return 0; > +} > +static int pwrseq_resume_list(struct list_head *head) > +{ > + return 0; > +} > +#endif /* CONFIG_POWER_SEQUENCE */ > + > +#endif /* __LINUX_PWRSEQ_H */ > -- > 2.7.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-usb" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Best Regards, Peter Chen