Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753479AbdIHPqd (ORCPT ); Fri, 8 Sep 2017 11:46:33 -0400 Received: from mail-ve1eur01on0119.outbound.protection.outlook.com ([104.47.1.119]:29792 "EHLO EUR01-VE1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751548AbdIHPqa (ORCPT ); Fri, 8 Sep 2017 11:46:30 -0400 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=peda@axentia.se; From: Peter Rosin To: Hans de Goede Cc: Stephen Boyd , MyungJoo Ham , Chanwoo Choi , Guenter Roeck , Heikki Krogerus , Darren Hart , Andy Shevchenko , Mathias Nyman , linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, devel@driverdev.osuosl.org, Kuppuswamy Sathyanarayanan , Sathyanarayanan Kuppuswamy Natarajan , Greg Kroah-Hartman , linux-usb@vger.kernel.org, Peter Rosin Subject: [PATCH 1/2] mux: add mux_control_get_optional() API Date: Fri, 8 Sep 2017 17:45:13 +0200 Message-Id: <20170908154514.4463-2-peda@axentia.se> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170908154514.4463-1-peda@axentia.se> References: <20170905164221.11266-6-hdegoede@redhat.com> <20170908154514.4463-1-peda@axentia.se> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [81.224.168.30] X-ClientProxiedBy: HE1PR0301CA0017.eurprd03.prod.outlook.com (2603:10a6:3:76::27) To VI1PR0202MB2557.eurprd02.prod.outlook.com (2603:10a6:801:6::8) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: a05a6cd1-c116-4a1d-4eca-08d4f6d0c40c X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(2017030254152)(2017082002075)(300000503095)(300135400095)(201703131423075)(201702281549075)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095);SRVR:VI1PR0202MB2557; X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2557;3:YDidEb+Hjynbczky2lIceQk//9d2mgNrcHXV3P3rm8VpacyH5FwrbePChVuzLG4+iT2CIsXoH5/TzqipCJYPC880Z2lMA4EivWWcZa9XUWmSEQaeIo1xC5IndPb6xN1j4buJ1KmFQwapuRbDZGfE69NTwvyRLhxNgBrx3Y4A3QOKYuw4V+s3COCGktyWfviNo20hle29SDKwtx5Ls7KrTS/NAEmmEVQCc7IeBr1uNsXX9mKU1fdyTO8ZQNN6Rzlm;25:qVTUDQaN+92d2KmhQ0U6jj+wG0rVTezbXJmR4kVDa0nTP+us1H5h2mfEi54WB+JTXwDJ8vJ9OpU3QPiQWXm/5Zo+OSVnuxs8oDYeq53n1gktebSleaZd9NcUi+HjMGJdbLB7Ypa2AsGbcKaJ7Da3vF9ccFb50UVTvaS9tAUSXubE+YXWJCKzD7SP8yCAE0H2Tq12POghrVXs0AhGaOdwEHFARzQd6AL+Hb7AY4rrxrB//duAsXbAtVRJnmc5ldeOiTmvV8dVwMSdk6joHc8nHnpy4LRvVbUMIB0Dt0oSWQZw1HlSGlUTv0vyU8Rz3QGtWcRJm6xcGi9IMXCwdLWxNg==;31:PPolN9irltq+D92mCvwzemXa/+rQ8fak54X07LrZ93CytKsG5bO9Bx+ebYefnFGTFje6XI9dL5oXiktxyGUUDbumtAbqoIE0iPtFRhIFx4pIU0BhxWf8QQgbrlpbKxBHMFGqt7eXOEwuMgy18QKVhOs2hbJKbOwpL+FlVS9NHTS05FMAYtqLl+VVvqkTDHPPmnc+H6QrEliXNJLMU3exs1+ZggNSmN5pLOglFNfaoCc= X-MS-TrafficTypeDiagnostic: VI1PR0202MB2557: X-Exchange-Antispam-Report-Test: UriScan:; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(93006095)(93001095)(3002001)(10201501046)(100000703101)(100105400095)(6041248)(20161123558100)(20161123560025)(20161123555025)(2016111802025)(20161123564025)(201703131423075)(201703061421075)(20161123562025)(6042181)(6043046)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);SRVR:VI1PR0202MB2557;BCL:0;PCL:0;RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);SRVR:VI1PR0202MB2557; X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2557;4:E/No935IwpCsiqhCisYTH3qY7NXQmAahiDp9QEebfCgwNHY2lBLMQxGeGIddsXYeiC01azL4Qq/oPkD+k/AewmJqKzu7jZjPgCZh0iQY51Zummz40nw4jeQQoLrIuoyZlzGWZLusbwpT4y7VfW2plrU4yhYjDLyd3R10SRwqFUl8jt6L/Rt7pAMkUPRO/LOxbQcQoq1ks6lL5l8smwJtALAEgAD2S7Oo529KwnGLlOVanvkOIj/rQeP4hFtKNcls X-Forefront-PRVS: 04244E0DC5 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(7370300001)(6009001)(199003)(189002)(575784001)(6116002)(68736007)(86362001)(189998001)(3846002)(2906002)(6916009)(6666003)(2950100002)(107886003)(50986999)(1076002)(110136004)(76176999)(4326008)(53936002)(36756003)(54906002)(7350300001)(97736004)(6512007)(5003940100001)(81156014)(81166006)(8676002)(7736002)(66066001)(6506006)(305945005)(50226002)(508600001)(50466002)(7416002)(101416001)(74482002)(105586002)(47776003)(48376002)(42186005)(5660300001)(33646002)(106356001)(25786009)(6486002)(42262002);DIR:OUT;SFP:1102;SCL:1;SRVR:VI1PR0202MB2557;H:orc.pedanet;FPR:;SPF:None;PTR:InfoNoRecords;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;VI1PR0202MB2557;23:gGYGO+jSXPOXQxMX+Ub+3k9OcCKJbIrnMUTZXH9?= =?us-ascii?Q?jikvVl2gTFL2R7X/VWUz0GTQFB5QHtkNsu8GXzGepSrEekGrE+3D/Xd8isy4?= =?us-ascii?Q?yyWE/JOMbWCs4FxqRhDNmjyoZNgFriVcMBb07Yhqz459LdnZXBl8Ox3b75p7?= =?us-ascii?Q?GIfAKGjdfYEOzPM30XudH11IkmrWNcjAdT6dxkLcJM4P3+Baxm/xkx3wR7Ac?= =?us-ascii?Q?R45cecNZXR6nqQuOklYzfqbOZjU0FUVynCNDQyjTqgjmkvsLXVCFUVLVgt6h?= =?us-ascii?Q?FgoHf1su9XnTxUsG6gPfLQJUXVJziYyQaX8s6/H2g8DV7c/JzG+w1Mh6gH6P?= =?us-ascii?Q?4RRxjtPpeJlCYgqEqqzFgMzbW7S7Z5USAe4dlEDPHK1343yWRvdGpU+SXTb+?= =?us-ascii?Q?uD5ymnp1HQDnxYkZrKCKVIuPw7A/omBdTz2uNaY/fXHyxmO2WlhCcfvDUqk8?= =?us-ascii?Q?XGHUxG8pEmvzscsyV8/LCkTgXOjo8mTwzpwI3Ggyz5SQClro2AkP3ZhcCzTJ?= =?us-ascii?Q?zbXkjtoPbHWtzu5Fv1yEZ7CMiqYeU9lVQHO/P0I1OPsOaZ0B0fe7Hc9wh78F?= =?us-ascii?Q?fZXQTCuugz8xKpXvlmZtEAx/yL0Sz0jTUzIQYnmZ6EGirn2ksqxs4muD3AzD?= =?us-ascii?Q?8xX/k1usaZFbKBhop10UoIwhqLgG64ziM5DYZrlvJPrfqMkvZXtLygHyqj49?= =?us-ascii?Q?m5r+MNZ8LlIyLYhdWIiU9+Kq2CUkhmDzllU+jKUU+3h4xCPYnvSDs/IP1CCj?= =?us-ascii?Q?7tFR706es3mOpLFii1EsBXNEph5a154upYTYUrIkwMAvJ3Q4ZxpY/Z3EoeYH?= =?us-ascii?Q?+AAU5sguXyb8JLeEihDTEeMiMjJ+hukzfMKD01EqLo1plxNL/TsMikBxQPFJ?= =?us-ascii?Q?jhIluFvQOa1x3tdWSJn45k8UDZz29sZfU2Nuk1M1pVe3tIBGU+oDkoNxX5e0?= =?us-ascii?Q?xgWc9UZE1xYXzoWin2tX/8bfD/C3p5lXsOI+ivBPqN1HpwIarUl07VslIjPS?= =?us-ascii?Q?mwaC7bmHH7sdmxeDblAMOAx+aPcOZNkn/laPta6y4qSp9X2rucZ0ZPFsYRbD?= =?us-ascii?Q?A+E4hNVShM2n15OD/5JEl1oKPpokLRg33JTdZOkrPUR/xz7ywi3g6gU8ECVL?= =?us-ascii?Q?t9Ux4Kg5VbRD/BdzJ2D4zTZJPnIR3K4l0Cpt0t2j3SnZ/uopEiJRHFksVoT0?= =?us-ascii?Q?0yeH3GRLgA+4Gj3sgfz3H9T9N39buJczi1qYetepTeSitZqbvcWr1oEUqbw?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2557;6:8iXctzpxXdbwGl5coZCiacGHdi2wM7xS+miJCn46tPNv9QoU1kOzW9pe1Cbn+uO3tg3zoBnGLOk0zOPQlBiw3JyG/5NOrBOvOauLopH0y1ZkqyFNZHEdX074SflMPUAU0lSAzkAokqwAgL6bjJ2429DO6j4y83z47jKwhWwxxdiBnecuwcJrY353KCk9sWF4Blz3CZW5gCFkP640hj9xG9tsAydFHb5e7fmnMwN3nAce3jDQnZPQRT+dsOcbNou9MHXW/x7uZ7guhz5/cNkW8Se2BZECJlsUOF06NTwBWLUJnMzQuasb0JFWAR0KhghfCbnCpYxgKlMEpA+X/aoMWA==;5:Oy7gFmp5pvJHPzI1Q84PrE989VjT6l9EOsjW9lHg/xKvWtrJSPNG0xa4IKnOdnsOExkCGGzc3XI4r95Ud++ASPzTG92jUcQaOw02iiUVY+j70dccJGlryhK1iaIDoF92aZGSJwBDRZz7CDerXt+V4A==;24:SzqUsRR73t6AYJAM8TULVCpGsYkMhrCftQSOZtUSk4j1qmvoBKelL9lPUWnkkFIaK3U4wJakNl82sVMl1atS5gDyzyVekVCBf6fl0MPNnYY=;7:7eHTBDQe5D2+cFBcCaQiPrPtSLTi6n6cZb7xOEl9RZAVfGtm3jKdVq99K/w83yRK5VVYKmFpnowPO0kbSJp8Tk4aBHyA6deSkK4ivWDc1Ku11AtP4sYoOXTZECpnPYk+G2en53gvd9gjekuhpcM47bdQOMNQeNlYSGz4EDlK/vY/Xs7RXYQhG9n/g9ejmwknMvtBRdE8xvVxLFKILKqIN4LsjLQ+3o6fChGcVMQ+ZRE= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Sep 2017 15:46:24.9166 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0202MB2557 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8096 Lines: 253 From: Stephen Boyd Sometimes drivers only use muxes under certain scenarios. For example, the chipidea usb controller may be connected to a usb switch on some platforms, and connected directly to a usb port on others. The driver won't know one way or the other though, so add a mux_control_get_optional() API that allows the driver to differentiate errors getting the mux from there not being a mux for the driver to use at all. --- Documentation/driver-model/devres.txt | 1 + drivers/mux/core.c | 104 +++++++++++++++++++++++++++------- include/linux/mux/consumer.h | 4 ++ 3 files changed, 89 insertions(+), 20 deletions(-) I haven't tested this patch, and hence I have not signed it and I also removed the sign-off from Stephen... Cheers, peda diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 30e04f7a690d..4fdd3e63ff8b 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -342,6 +342,7 @@ MUX devm_mux_chip_alloc() devm_mux_chip_register() devm_mux_control_get() + devm_mux_control_get_optional() PER-CPU MEM devm_alloc_percpu() diff --git a/drivers/mux/core.c b/drivers/mux/core.c index 2260063b0ea8..2eb234300669 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -289,6 +289,9 @@ EXPORT_SYMBOL_GPL(devm_mux_chip_register); */ unsigned int mux_control_states(struct mux_control *mux) { + if (!mux) + return 0; + return mux->states; } EXPORT_SYMBOL_GPL(mux_control_states); @@ -338,6 +341,9 @@ int mux_control_select(struct mux_control *mux, unsigned int state) { int ret; + if (!mux) + return 0; + ret = down_killable(&mux->lock); if (ret < 0) return ret; @@ -370,6 +376,9 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state) { int ret; + if (!mux) + return 0; + if (down_trylock(&mux->lock)) return -EBUSY; @@ -398,6 +407,9 @@ int mux_control_deselect(struct mux_control *mux) { int ret = 0; + if (!mux) + return 0; + if (mux->idle_state != MUX_IDLE_AS_IS && mux->idle_state != mux->cached_state) ret = mux_control_set(mux, mux->idle_state); @@ -422,14 +434,8 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np) return dev ? to_mux_chip(dev) : NULL; } -/** - * mux_control_get() - Get the mux-control for a device. - * @dev: The device that needs a mux-control. - * @mux_name: The name identifying the mux-control. - * - * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno. - */ -struct mux_control *mux_control_get(struct device *dev, const char *mux_name) +static struct mux_control * +__mux_control_get(struct device *dev, const char *mux_name, bool optional) { struct device_node *np = dev->of_node; struct of_phandle_args args; @@ -441,16 +447,22 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) if (mux_name) { index = of_property_match_string(np, "mux-control-names", mux_name); + if ((index == -EINVAL || index == -ENODATA) && optional) + return NULL; if (index < 0) { dev_err(dev, "mux controller '%s' not found\n", mux_name); return ERR_PTR(index); } + /* OF does point to a mux, so it's no longer optional */ + optional = false; } ret = of_parse_phandle_with_args(np, "mux-controls", "#mux-control-cells", index, &args); + if (ret == -ENOENT && optional) + return NULL; if (ret) { dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n", np, mux_name ?: "", index); @@ -482,9 +494,36 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) get_device(&mux_chip->dev); return &mux_chip->mux[controller]; } + +/** + * mux_control_get() - Get the mux-control for a device. + * @dev: The device that needs a mux-control. + * @mux_name: The name identifying the mux-control. + * + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno. + */ +struct mux_control *mux_control_get(struct device *dev, const char *mux_name) +{ + return __mux_control_get(dev, mux_name, false); +} EXPORT_SYMBOL_GPL(mux_control_get); /** + * mux_control_get_optional() - Get the optional mux-control for a device. + * @dev: The device that needs a mux-control. + * @mux_name: The name identifying the mux-control. + * + * Return: NULL if no mux with the provided name is found, a pointer to + * the named mux-control or an ERR_PTR with a negative errno. + */ +struct mux_control * +mux_control_get_optional(struct device *dev, const char *mux_name) +{ + return __mux_control_get(dev, mux_name, true); +} +EXPORT_SYMBOL_GPL(mux_control_get_optional); + +/** * mux_control_put() - Put away the mux-control for good. * @mux: The mux-control to put away. * @@ -492,6 +531,9 @@ EXPORT_SYMBOL_GPL(mux_control_get); */ void mux_control_put(struct mux_control *mux) { + if (!mux) + return; + put_device(&mux->chip->dev); } EXPORT_SYMBOL_GPL(mux_control_put); @@ -503,16 +545,8 @@ static void devm_mux_control_release(struct device *dev, void *res) mux_control_put(mux); } -/** - * devm_mux_control_get() - Get the mux-control for a device, with resource - * management. - * @dev: The device that needs a mux-control. - * @mux_name: The name identifying the mux-control. - * - * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno. - */ -struct mux_control *devm_mux_control_get(struct device *dev, - const char *mux_name) +static struct mux_control * +__devm_mux_control_get(struct device *dev, const char *mux_name, bool optional) { struct mux_control **ptr, *mux; @@ -520,8 +554,8 @@ struct mux_control *devm_mux_control_get(struct device *dev, if (!ptr) return ERR_PTR(-ENOMEM); - mux = mux_control_get(dev, mux_name); - if (IS_ERR(mux)) { + mux = __mux_control_get(dev, mux_name, optional); + if (IS_ERR_OR_NULL(mux)) { devres_free(ptr); return mux; } @@ -531,8 +565,38 @@ struct mux_control *devm_mux_control_get(struct device *dev, return mux; } + +/** + * devm_mux_control_get() - Get the mux-control for a device, with resource + * management. + * @dev: The device that needs a mux-control. + * @mux_name: The name identifying the mux-control. + * + * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno. + */ +struct mux_control * +devm_mux_control_get(struct device *dev, const char *mux_name) +{ + return __devm_mux_control_get(dev, mux_name, false); +} EXPORT_SYMBOL_GPL(devm_mux_control_get); +/** + * devm_mux_control_get_optional() - Get the optional mux-control for a device, + * with resource management. + * @dev: The device that needs a mux-control. + * @mux_name: The name identifying the mux-control. + * + * Return: NULL if no mux with the provided name is found, a pointer to + * the named mux-control or an ERR_PTR with a negative errno. + */ +struct mux_control * +devm_mux_control_get_optional(struct device *dev, const char *mux_name) +{ + return __devm_mux_control_get(dev, mux_name, true); +} +EXPORT_SYMBOL_GPL(devm_mux_control_get_optional); + /* * Using subsys_initcall instead of module_init here to try to ensure - for * the non-modular case - that the subsystem is initialized when mux consumers diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h index ea96d4c82be7..fc98547bf494 100644 --- a/include/linux/mux/consumer.h +++ b/include/linux/mux/consumer.h @@ -26,9 +26,13 @@ int __must_check mux_control_try_select(struct mux_control *mux, int mux_control_deselect(struct mux_control *mux); struct mux_control *mux_control_get(struct device *dev, const char *mux_name); +struct mux_control *mux_control_get_optional(struct device *dev, + const char *mux_name); void mux_control_put(struct mux_control *mux); struct mux_control *devm_mux_control_get(struct device *dev, const char *mux_name); +struct mux_control *devm_mux_control_get_optional(struct device *dev, + const char *mux_name); #endif /* _LINUX_MUX_CONSUMER_H */ -- 2.11.0