From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754250AbcIBUtA (ORCPT ); Fri, 2 Sep 2016 16:49:00 -0400 Received: from mail-db5eur01on0138.outbound.protection.outlook.com ([104.47.2.138]:30502 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753925AbcIBUs4 (ORCPT ); Fri, 2 Sep 2016 16:48:56 -0400 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=peda@axentia.se; Subject: Re: [patch 2/2] i2c: mux: mellanox: add driver To: , References: <1472492176-195844-1-git-send-email-vadimp@mellanox.com> CC: , , , Michael Shych From: Peter Rosin Organization: Axentia Technologies AB Message-ID: <96dbc894-0c25-9d41-29ce-949e733781e5@axentia.se> Date: Fri, 2 Sep 2016 14:16:51 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: <1472492176-195844-1-git-send-email-vadimp@mellanox.com> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit X-Originating-IP: [217.210.101.82] X-ClientProxiedBy: DB4PR05CA0036.eurprd05.prod.outlook.com (10.160.40.46) To DB6PR0201MB2309.eurprd02.prod.outlook.com (10.169.222.148) X-MS-Office365-Filtering-Correlation-Id: 81ab7aca-3069-4ff6-5860-08d3d32b084d X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2309;2:6hAae5HDJAUI5Ys3oaKfQXrcI5yfGHYUeGesKd2ySCaK7p/c2GB3Qo0rO7B1xNS73pSdrxod7OO8iTkEYt8hfel5gL8+YDXih5bAqGoJc87Kby3lJ8g9zvVkqe4m1Bm9y8lctZCcpZFYcXm9OK7oZD7JuomN28zqv5LaocT5B64TmySqAfdVm4uCSwqzSILj;3:b9KO4nW/VbVRHqND3K2YR5cY3CWuJucnUH0lMvOfBAxacZYwFb2tp2IPE7gJa3fF+MoxSvVRUoleNQjZccuWd8L6252MatSwud0fLhdxq0SnWbPAoWmQcJUO2PpVjhXV X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0201MB2309; X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2309;25:3yF1wOC15yeNvjAaaqKc4qRE4WydLV+9ZpvlTsHHCylQDeDDLuBWfpxomeh/5ctivNRrwVa2rZx8+KTAATa10Whks4Kb8g595VdRz5wB5LxnF0DvM0kw5iPZ2pn1BZh5QSv85mCYlUwpyiHMx14LGn+Zow6jiLOwBhBVw32f+tqxrtS3MDKQ1teATXv6iaO3jxuPUGOcguOIirtHVJFfIPgVDQm+vKjh7TC7hbkqmX9c2dNOxjKFbNV4cTVt3oSjARtKNydU/f7TOCvR08OOocnqnd9E2/GKx3Csnt4+1j7cE87BwpylfYQsQJQPS+fgPnroqi4QJt+JufAoSE6yMBFndJyQICDBK0Q8tFFXYCQp8cugMQMDBYSwMATmDdEDUdQek/3nXzVrqy/eBho0FKM8t7u/KCL2jl0OBO6NWK+sa4i9a204qVdtBca9zj2rBxMnAt1NqZmO7RIdEg0kyropPpG8FX3Yuj4W4GEgsFgOgup+P7qIkEZw07p7FOb15+ZCCK5It7Xorbjzel6l9FPdgJtC4TU1RKgxS8nqBFOgQ544/sebcuU5anag+3WF/m3YBjmU5I93RZwwNPuOceCD8yspdycV4wAJZ4cnyGjNWfihLRletw4NvB4P423Ig+q4j0VTIgENpNtmwB4NeaE9nyJus+SkYE2R/M8A428SfF6XAqAPcrUJr5PeE2Mm9TovlFo3N2EGXxrKiBWLg6JNPP1VIaDjEFy/Ltx4mcK0j7RF+hWLz3KtGab9K3hr7109T8wqYN7/l4p9Cqqel/gbg5HqpLSBH/DOeboqxaU= X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2309;31:bcgW/6Qzc58A8MV+XClBfSw0ZbkGivro67HC2AGLXMkdfCCZyqND6DvG7PPidED3L5mCJWivwc9t0pxBQxHwpgtqc75C711zKrmRl8/l+BxhWg5Zj3LQZiyxmNkpkqg18rrY4L/X/fzOAU4lwKihzFK0US+shE+5yKmsKVEC1A+nlY2k8e7+BlMpaucduyM7dYO+LhHYdmMynk5EyTyul0ZPU1nUedyq2i+doGO4JUU=;4:UAx7HWvwkv2118UxcUsBgVRoi4AFeLN/Rp+QnrThNy/8PXrrtTxjpjrK/9wLQ5CnfrmHEYGFLGKy4G2WyPbl3lz0uAoup4sducZkd4A7769M5TkMtg7Pon9KLaNJVt5MIZTqJmni5H7aPpsf5RiPBTYScG4/6LBpozNuay8LraktD1fzdr0cxU+8Z10lmk0Kk0rvYjrmCnmw1W7Li3J0TfT5exF4Lu0cgC51AG1OQJkQbY/neDcT4Xi/QrIpeR28A+qCtXg3KerSwkJGMDfT1a0Ec4FU2RZRAbgHGShwdPl9rfICknp4tRRV3Bmcoq1JnwYkPCvPb4MUBsiS/kaHWT8vUobQ1fY5mZ6s549apYV977Bk23JIE8GH1wQttmxNwDU1ugwDnVW2BDwTUqz5H/M1X90nFtwyBIY/A6wI3kjKtJQXQaVCYKvxJmV7mPGBONcft35wiLofA4GnACTkZ1si7IDmfNlUUJj+fWGoQuqgsjxAeGTpw++X9jqBu0AR X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(9452136761055)(171992500451332); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6043046)(6042046);SRVR:DB6PR0201MB2309;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0201MB2309; X-Forefront-PRVS: 00531FAC2C X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(6049001)(7916002)(189002)(199003)(377424004)(54534003)(24454002)(23746002)(66066001)(15975445007)(65956001)(54356999)(65806001)(97736004)(189998001)(83506001)(4001350100001)(86362001)(50466002)(5890100001)(5660300001)(19580395003)(2950100001)(77096005)(4326007)(31696002)(230700001)(19580405001)(65826007)(5001770100001)(105586002)(92566002)(68736007)(47776003)(16601075003)(50986999)(106356001)(101416001)(305945005)(6116002)(33646002)(586003)(31686004)(76176999)(74482002)(2906002)(8676002)(3846002)(81166006)(117156001)(81156014)(7736002)(36756003)(7846002)(64126003)(42186005)(42262002);DIR:OUT;SFP:1102;SCL:1;SRVR:DB6PR0201MB2309;H:[192.168.0.125];FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?Windows-1252?Q?1;DB6PR0201MB2309;23:/Oi8tL4z3UWdwO9mTC2O2GdivQ+K0hhSjdE?= =?Windows-1252?Q?2adIN+cTMelEGr090SE+0jnmXdbhpIG/v4YWsoaJTJe4icyGf1Do21f6?= =?Windows-1252?Q?eVu7wvoUpVuQWLscLIn4mYHjjxHGA7+pYNaZbA4+eX57KCQaaal124Gw?= =?Windows-1252?Q?7Xzt0f9L5BnCwhqrHTFtvIXee97dSta0W6+WUvmao4fib3BBQ2FwMK7J?= =?Windows-1252?Q?yL/AtOM01RPwBWmtRVozIDwCBj+SvFA2yyfHLw+gvlb0EBF2v5uqyr/e?= =?Windows-1252?Q?+yHg/MXZbSEIOTRj+/bZh/oTXA25/cI1TEJmZ0XYucG5vck1Sq26nfzB?= =?Windows-1252?Q?Qj+dlgXpQ7WfwcKfPyib3wmZGuz+EvP00dkazPTK2dzy8RFTOezzfucY?= =?Windows-1252?Q?ei3UXlFVvn7ayhnplcZfbbrR7DGTqaYjmMj2VaPOROdfKm0Q05JKJyYk?= =?Windows-1252?Q?SYrFKxmMrX8pRCttA7Z0HkNAR9Y64F4QSzRDJVPJZga9zMTfD5pCGpHb?= =?Windows-1252?Q?cx+Y3NHULMlWaiBt4saTvpsPtFRNOFMLhq9DMILF6eNMkQqd9QvxRK2q?= =?Windows-1252?Q?9JCh14fxTv4Wd1cN4lN2VDPFeGaiI1dhuQ5iN0hZcR1gxZawUowO7BKo?= =?Windows-1252?Q?xhXiFvkbhUJB5x4+DqcdCjXOr5nkzj53bCRM6OA6XXJVl+/11WMnjJ5j?= =?Windows-1252?Q?JgUI+/jdPtg561EnjJFyYJaDHcmg9ZreczaY0joHqwAqSRhIX1T43rie?= =?Windows-1252?Q?pwRg/jZRt57K6/Fs1cFanuJpTfZxCqCABTNpIjLE+9Wo9LWIVJO2azPw?= =?Windows-1252?Q?uhkytXEi99v/sdjMXFZJT4azBlIJ3teO6ctOPGpg/Zmqh07nWwUEQff9?= =?Windows-1252?Q?K2on3vGZN77YjcLWWeXSJl632gSDCdi2gOhTJewOVe91NwUiVlqS+Hcv?= =?Windows-1252?Q?14WMsLDWqYXja9wjNOF5CyeiCWQJXlLlkdqEKeAm98cAlA5Mf1eiNv7u?= =?Windows-1252?Q?uUnzcoXRF0hjIdLJ27cpNghtWFFDt2lplTKtFLNI1YqtEczEY+x3XnVN?= =?Windows-1252?Q?ix3ddslZnb80WREIepWV+FSeeepiy9fRjkA4aYarF050g+w4LmK8z2ZU?= =?Windows-1252?Q?pKqJuh/aLMCPYpR1KZ9/On5oSL9vFKu9DbelagMgU7tH6YWaPoxVWA8h?= =?Windows-1252?Q?T9ZCfVOFDJPNF4tOofAweeEr6DUi17xvZyL6L7XZ65tdBoGeOPjUxiqT?= =?Windows-1252?Q?dZqlm9X2hi99/6TFTRGgFeRzEXpJFlrZG4qFxeUFhuFhIUUuH+OyNlWo?= =?Windows-1252?Q?gktt6+L816eD4uijQ5VClBWvuvUpjk0RsQVQnBvCQiO9EpkHPdvGS0uR?= =?Windows-1252?Q?7q3UolqBelO0F+HcbRYy6UP9fdVowPIJrhRrNFkX5S8L/QAbHoyHmSOo?= =?Windows-1252?Q?oWZ1ffOQem5v2s4rMzwLeQkl3487+cYcDViDD8TivhMkk2G3pM0ELc2A?= =?Windows-1252?Q?DisxLPODZLd/V0Srk09JHt9lwnronuu4MSKjJtpskiTUdQlklPy/IIKo?= =?Windows-1252?Q?RtvTNsd14qVia4xs=3D?= X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2309;6:JA3PvyJ4ugNJTT3ci59YZ6+4u6thpT/8hGhSOp+YJOqK904Kaw2BiZj+Yd0giDDZpFTmvvBw3qMg7tgBvClByc1en+pdO2lYErFwLk/rwNU6ee6CrRZykXsloOT3UBcpUll3xahXF1dcQS+P010V2TG+a42ZN2xY6vNHQp91Ku3LyHDGNYJbLBnF7NuhdWReJ5ZGfKhADcw/dyvgxWykDjrDxPXtILWKuKawKqjwUQOThzx2pl4WGMRlqKbNoTvYpU9ZTqZHFa4BN9Hi4madf42xhH6mxH3/m91Nw33m3cSEAqTkZYw62ow6/7qym8XD;5:sEuAe7OCH3NiP9TmQCxcKLeIsSTzMRr3llXNJeyBUtDadHUTg/wPZPIr0yWZSrVH3t37tR4Cfe9mjnQpQl4x/mzie0mhJQBi779rN75iOqadRxjkyMU5SEiBO6E47maMWRvQM60EwWaMctswMWbsEQ==;24:UMvnB32uiBJbswGz0TmK3u0+JRKSankHilmcSY8G6lrU3pkg7aKilhpiNEEs6yy88vzfHhdY1fFLKJ4/EyDJuaWZrjpAgLoKfbwWE6Ipq9A=;7:1blXu1uleWKSzzAwI9nRpJMOCxMN8y96Rycv88QsUhVdRgSXHq+3mDPqSuyc0vpzhrzwtOyjHuXOmWaOKGXNeU6Q6Jp/Inzy+yy+jWkwmAcwnUrXxCpt27nTYuZfP3z4Oj2ZVNH2jkeq64InSd+v0aa7aPKQiO+8HKF3YwK9yu/091i3yL5D8obdgZ9e0iLEWQVREAXor63+sJ8jJRQ/J3lHXpBLNIeMrFIkhDxee0aAAc7Fu7md2lSEWm9SZ62H SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Sep 2016 12:16:55.8486 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0201MB2309 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 2016-08-29 19:36, vadimp@mellanox.com wrote: > From: Vadim Pasternak > > This driver allows I2C routing controlled through CPLD select registers on > wide range of Mellanox systems (CPLD Lattice device). > MUX selection is provided by digital and analog HW. Analog part is not > under SW control. > Digital part is under CPLD control (channel selection/de-selection). > > Connectivity schema. > i2c-mlxcpld Digital Analog > driver > *--------* * -> mux1 (virt bus2) -> mux ->| > | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux ->| > | bridge | bus 1 *---------* | > | logic |---------------------> * mux reg * | > | in CPLD| *---------* | > *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux ->| > | driver | | > | *---------------* | Devices > | * CPLD (LPC bus)* select | > | * registers for *--------* > | * mux selection * deselect > | *---------------* > | | > <--------> <-----------> > i2c cntrl Board cntrl reg > reg space space (mux select, > | IO, LED, WD, info) > | | *-----* *-----* > *------------- LPC bus --------------| PCH |---| CPU | > *-----* *-----* > > i2c-mux-mlxpcld does not necessary required i2c-mlxcpld. It can be use s/necessary required/necessarily require a/ > along with another bus driver, and still control i2c routing through CPLD > mux selection, in case the system is equipped with CPLD capable of mux > selection control. > > The Kconfig currently controlling compilation of this code is: > drivers/i2c/muxes/Kconfig:config I2C_MUX_MLXCPLD > > Signed-off-by: Michael Shych > Signed-off-by: Vadim Pasternak > Reviewed-by: Jiri Pirko > --- > MAINTAINERS | 8 + > drivers/i2c/muxes/Kconfig | 11 ++ > drivers/i2c/muxes/Makefile | 1 + > drivers/i2c/muxes/i2c-mux-mlxcpld.c | 326 ++++++++++++++++++++++++++++++++++++ > include/linux/i2c/mlxcpld.h | 57 +++++++ > 5 files changed, 403 insertions(+) > create mode 100644 drivers/i2c/muxes/i2c-mux-mlxcpld.c > create mode 100644 include/linux/i2c/mlxcpld.h It is customary to mark updated patches with v2, v3 etc in the subject and to include a short changelog right here in this space (or perhaps in a cover letter if it is a patch series). Please do so going forward. > > diff --git a/MAINTAINERS b/MAINTAINERS > index 8b3f8d7..a994455 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -7664,6 +7664,14 @@ W: http://www.mellanox.com > F: drivers/i2c/busses/i2c-mlxcpld.c > F: Documentation/i2c/busses/i2c-mlxcpld > > +MELLANOX MLXCPLD I2C MUX DRIVER > +M: Vadim Pasternak > +M: Michael Shych > +L: linux-kernel@vger.kernel.org Isn't the linux-i2c list a narrower and therefore better fit? > +S: Supported > +W: http://www.mellanox.com > +F: drivers/i2c/muxes/i2c-mux-mlxcpld.c > + > SOFT-ROCE DRIVER (rxe) > M: Moni Shoua > L: linux-rdma@vger.kernel.org > diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig > index e280c8e..b7ab144 100644 > --- a/drivers/i2c/muxes/Kconfig > +++ b/drivers/i2c/muxes/Kconfig > @@ -81,4 +81,15 @@ config I2C_DEMUX_PINCTRL > demultiplexer that uses the pinctrl subsystem. This is useful if you > want to change the I2C master at run-time depending on features. > > +config I2C_MUX_MLXCPLD > + tristate "Mellanox CPLD based I2C multiplexer" > + help > + If you say yes to this option, support will be included for a > + CPLD based I2C multiplexer. This driver provides access to > + I2C busses connected through a MUX, which is controlled > + by a CPLD registers. > + > + This driver can also be built as a module. If so, the module > + will be called i2c-mux-mlxcpld. > + > endmenu > diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile > index 7c267c2..e5c990e 100644 > --- a/drivers/i2c/muxes/Makefile > +++ b/drivers/i2c/muxes/Makefile > @@ -10,5 +10,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o > obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o > obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o > obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o > +obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o > > ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG > diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c > new file mode 100644 > index 0000000..9624613 > --- /dev/null > +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c > @@ -0,0 +1,326 @@ > +/* > + * drivers/i2c/muxes/i2c-mux-mlxcpld.c > + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. > + * Copyright (c) 2016 Michael Shych > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * 3. Neither the names of the copyright holders nor the names of its > + * contributors may be used to endorse or promote products derived from > + * this software without specific prior written permission. > + * > + * Alternatively, this software may be distributed under the terms of the > + * GNU General Public License ("GPL") version 2 as published by the Free > + * Software Foundation. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Please sort the includes. > + > +#define CPLD_MUX_MAX_NCHANS 8 > +#define CPLD_MUX_EXT_MAX_NCHANS 24 > + > +/* > + * mlxcpld_mux types - kind of mux supported by driver: > + * @mlxcpld_mux_tor - LPC access; 8 channels. > + * @mlxcpld_mux_mgmt - LPC access; 8 channels. > + * @mlxcpld_mux_mgmt_ext - LPC access; 24 channels. > + * @mlxcpld_mux_module - I2C access; 8 channels/legs. > + */ > +enum mlxcpld_mux_type { > + mlxcpld_mux_tor, > + mlxcpld_mux_mgmt, > + mlxcpld_mux_mgmt_ext, > + mlxcpld_mux_module, > +}; > + > +/* mlxcpld_mux_type - underlying physical bus, to which device is connected: > + * @lpc_access - LPC connected CPLD device > + * @i2c_access - I2C connected CPLD device > + */ > +enum mlxcpld_mux_access_type { > + lpc_access, > + i2c_access, > +}; > + > +/* mlxcpld_mux - mux control structure: > + * @type - mux type > + * @last_chan - last register value > + * @client - I2C device client > + */ > +struct mlxcpld_mux { > + enum mlxcpld_mux_type type; > + u8 last_chan; > + struct i2c_client *client; > +}; > + > +/* mlxcpld_mux_desc - mux descriptor structure: > + * @nchans - number of channels > + * @muxtype - physical mux type (LPC or I2C) > + */ > +struct mlxcpld_mux_desc { > + u8 nchans; > + enum mlxcpld_mux_access_type muxtype; > +}; > + > +/* MUX logic description. > + * This logic can be applied for LPC attached CPLD and fro I2C attached CPLD. > + * Driver can support different mux control logic, according to CPLD > + * implementation. > + * > + * Connectivity schema. > + * > + * i2c-mlxcpld Digital Analog > + * driver > + * *--------* * -> mux1 (virt bus2) -> mux -> | > + * | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux -> | > + * | bridge | bus 1 *---------* | > + * | logic |---------------------> * mux reg * | > + * | in CPLD| *---------* | > + * *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux -> | > + * | driver | | > + * | *---------------* | Devices > + * | * CPLD (LPC bus)* select | > + * | * registers for *--------* > + * | * mux selection * deselect > + * | *---------------* > + * | | > + * <--------> <-----------> > + * i2c cntrl Board cntrl reg > + * reg space space (mux select, > + * | IO, LED, WD, info) > + * | | *-----* *-----* > + * *------------- LPC bus --------------| PCH |---| CPU | > + * *-----* *-----* > + * > + */ > +static const struct mlxcpld_mux_desc muxes[] = { > + [mlxcpld_mux_tor] = { > + .nchans = CPLD_MUX_MAX_NCHANS, > + .muxtype = lpc_access, > + }, > + [mlxcpld_mux_mgmt] = { > + .nchans = CPLD_MUX_MAX_NCHANS, > + .muxtype = lpc_access, > + }, > + [mlxcpld_mux_mgmt_ext] = { > + .nchans = CPLD_MUX_EXT_MAX_NCHANS, > + .muxtype = lpc_access, > + }, > + [mlxcpld_mux_module] = { > + .nchans = CPLD_MUX_MAX_NCHANS, > + .muxtype = i2c_access, > + }, > +}; > + > +static const struct i2c_device_id mlxcpld_mux_id[] = { > + { "mlxcpld_mux_tor", mlxcpld_mux_tor }, > + { "mlxcpld_mux_mgmt", mlxcpld_mux_mgmt }, > + { "mlxcpld_mux_mgmt_ext", mlxcpld_mux_mgmt_ext }, > + { "mlxcpld_mux_module", mlxcpld_mux_module }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id); > + > +/* Write to mux register. Don't use i2c_transfer() and > + * i2c_smbus_xfer() for this as they will try to lock adapter a second time > + */ > +static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, > + struct i2c_client *client, u8 val, > + enum mlxcpld_mux_access_type muxtype) > +{ > + struct mlxcpld_mux_platform_data *pdata = > + dev_get_platdata(&client->dev); This looks weird (several instances). Use shorter names, assign after the declaration or just ignore the line length "rule". > + int ret = -ENODEV; > + > + switch (muxtype) { > + case lpc_access: > + outb(val, pdata->addr); /* addr = CPLD base + offset */ > + ret = 1; > + break; > + > + case i2c_access: > + if (adap->algo->master_xfer) { > + struct i2c_msg msg; > + u8 msgbuf[] = {pdata->sel_reg_addr, val}; > + > + msg.addr = pdata->addr; > + msg.flags = 0; > + msg.len = 2; > + msg.buf = msgbuf; > + return __i2c_transfer(adap, &msg, 1); > + } > + dev_err(&client->dev, "SMBus isn't supported on this adapter\n"); > + break; > + > + default: > + dev_err(&client->dev, "Incorrect muxtype %d\n", muxtype); > + } > + > + return ret; > +} > + > +static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) > +{ > + struct mlxcpld_mux *data = i2c_mux_priv(muxc); > + struct i2c_client *client = data->client; > + struct mlxcpld_mux_platform_data *pdata = > + dev_get_platdata(&client->dev); > + const struct mlxcpld_mux_desc *mux = &muxes[data->type]; > + u8 regval; > + int err = 0; > + > + switch (data->type) { > + case mlxcpld_mux_tor: > + regval = pdata->first_channel + chan; > + break; > + > + case mlxcpld_mux_mgmt: > + case mlxcpld_mux_mgmt_ext: > + case mlxcpld_mux_module: > + regval = chan + 1; > + break; > + > + default: > + return -ENXIO; > + } > + > + /* Only select the channel if its different from the last channel */ > + if (data->last_chan != regval) { > + err = mlxcpld_mux_reg_write(muxc->parent, client, regval, > + mux->muxtype); > + data->last_chan = regval; As I said for v2, if the reg write fails, you ignore the error when setting last_chan. That means the reg write is not retried next time around and the i2c traffic may end up on the wrong segment. I suggest that you set last_chan to some "illegal" value on error (zero looks like a good candidate if you look at deselect), so that the reg write is always done on a select following an error. > + } > + > + return err; > +} > + > +static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) > +{ > + struct mlxcpld_mux *data = i2c_mux_priv(muxc); > + struct i2c_client *client = data->client; > + const struct mlxcpld_mux_desc *mux = &muxes[data->type]; > + > + /* Deselect active channel */ > + data->last_chan = 0; > + > + return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan, > + mux->muxtype); > +} > + > +/* I2C init/probing/exit functions */ > +static int mlxcpld_mux_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); > + struct mlxcpld_mux_platform_data *pdata = > + dev_get_platdata(&client->dev); > + struct i2c_mux_core *muxc; > + int num, force; > + u8 nchans; > + struct mlxcpld_mux *data; > + int err; > + > + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) > + return -ENODEV; > + > + switch (id->driver_data) { > + case mlxcpld_mux_tor: > + case mlxcpld_mux_mgmt: > + case mlxcpld_mux_mgmt_ext: > + case mlxcpld_mux_module: > + nchans = muxes[id->driver_data].nchans; > + break; > + default: > + return -EINVAL; > + } > + > + muxc = i2c_mux_alloc(adap, &client->dev, nchans, sizeof(*data), 0, > + mlxcpld_mux_select_chan, mlxcpld_mux_deselect); > + if (!muxc) > + return -ENOMEM; > + > + data = i2c_mux_priv(muxc); > + i2c_set_clientdata(client, muxc); > + data->client = client; > + data->type = id->driver_data; > + data->last_chan = 0; /* force the first selection */ > + > + /* Only in mlxcpld_mux_tor first_channel can be different. > + * In other mlxcpld_mux types channel numbering begin from 1 > + * Now create an adapter for each channel > + */ > + for (num = 0; num < muxes[data->type].nchans; num++) { > + force = 0; /* dynamic adap number */ > + if (pdata) { Here, you check if you have pdata, but in other places you assume pdata is there. Maybe the probe should error out if there is no pdata? > + if (num < pdata->num_adaps) > + force = pdata->adap_ids[num]; > + else > + /* discard unconfigured channels */ > + break; > + } > + > + err = i2c_mux_add_adapter(muxc, force, num, 0); > + if (err) { > + dev_err(&client->dev, "failed to register multiplexed adapter %d as bus %d\n", > + num, force); > + goto virt_reg_failed; > + } > + } > + > + return 0; > + > +virt_reg_failed: > + i2c_mux_del_adapters(muxc); > + return err; > +} > + > +static int mlxcpld_mux_remove(struct i2c_client *client) > +{ > + struct i2c_mux_core *muxc = i2c_get_clientdata(client); > + > + i2c_mux_del_adapters(muxc); > + return 0; > +} > + > +static struct i2c_driver mlxcpld_mux_driver = { > + .driver = { > + .name = "mlxcpld-mux", > + }, > + .probe = mlxcpld_mux_probe, > + .remove = mlxcpld_mux_remove, > + .id_table = mlxcpld_mux_id, > +}; > + > +module_i2c_driver(mlxcpld_mux_driver); > + > +MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); > +MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); > +MODULE_LICENSE("GPL v2"); > +MODULE_ALIAS("platform:i2c-mux-mlxcpld"); > diff --git a/include/linux/i2c/mlxcpld.h b/include/linux/i2c/mlxcpld.h > new file mode 100644 > index 0000000..ceb31da > --- /dev/null > +++ b/include/linux/i2c/mlxcpld.h > @@ -0,0 +1,57 @@ > +/* > + * mlxcpld.h - Mellanox I2C multiplexer support in CPLD > + * > + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. > + * Copyright (c) 2016 Michael Shych > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * 3. Neither the names of the copyright holders nor the names of its > + * contributors may be used to endorse or promote products derived from > + * this software without specific prior written permission. > + * > + * Alternatively, this software may be distributed under the terms of the > + * GNU General Public License ("GPL") version 2 as published by the Free > + * Software Foundation. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#ifndef _LINUX_I2C_MLXCPLD_H > +#define _LINUX_I2C_MLXCPLD_H > + > +/* Platform data for the CPLD I2C multiplexers */ > + > +/* mlxcpld_mux_platform_data - per mux data, used with i2c_register_board_info > + * @adap_ids - adapter array This description is a bit misleading, it's an adapter *id* array. And there is a special value (0) for dynamic numbering. > + * @num_adaps - number of adapters > + * @sel_reg_addr - mux select register offset in CPLD space > + * @first_channel - first channel to start virtual busses vector > + * @addr - address of mux device - set to mux select register offset on LPC > + * connected CPLDs or to I2C address on I2C conncted CPLDs > + */ > +struct mlxcpld_mux_platform_data { > + int *adap_ids; > + int num_adaps; > + int sel_reg_addr; > + int first_channel; > + int addr; > +}; > + > +#endif /* _LINUX_I2C_MLXCPLD_H */ > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter Rosin Subject: Re: [patch 2/2] i2c: mux: mellanox: add driver Date: Fri, 2 Sep 2016 14:16:51 +0200 Message-ID: <96dbc894-0c25-9d41-29ce-949e733781e5@axentia.se> References: <1472492176-195844-1-git-send-email-vadimp@mellanox.com> Mime-Version: 1.0 Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit Return-path: Received: from mail-db5eur01on0138.outbound.protection.outlook.com ([104.47.2.138]:30502 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753925AbcIBUs4 (ORCPT ); Fri, 2 Sep 2016 16:48:56 -0400 In-Reply-To: <1472492176-195844-1-git-send-email-vadimp@mellanox.com> Sender: linux-i2c-owner@vger.kernel.org List-Id: linux-i2c@vger.kernel.org To: vadimp@mellanox.com, wsa@the-dreams.de Cc: linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org, jiri@resnulli.us, Michael Shych On 2016-08-29 19:36, vadimp@mellanox.com wrote: > From: Vadim Pasternak > > This driver allows I2C routing controlled through CPLD select registers on > wide range of Mellanox systems (CPLD Lattice device). > MUX selection is provided by digital and analog HW. Analog part is not > under SW control. > Digital part is under CPLD control (channel selection/de-selection). > > Connectivity schema. > i2c-mlxcpld Digital Analog > driver > *--------* * -> mux1 (virt bus2) -> mux ->| > | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux ->| > | bridge | bus 1 *---------* | > | logic |---------------------> * mux reg * | > | in CPLD| *---------* | > *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux ->| > | driver | | > | *---------------* | Devices > | * CPLD (LPC bus)* select | > | * registers for *--------* > | * mux selection * deselect > | *---------------* > | | > <--------> <-----------> > i2c cntrl Board cntrl reg > reg space space (mux select, > | IO, LED, WD, info) > | | *-----* *-----* > *------------- LPC bus --------------| PCH |---| CPU | > *-----* *-----* > > i2c-mux-mlxpcld does not necessary required i2c-mlxcpld. It can be use s/necessary required/necessarily require a/ > along with another bus driver, and still control i2c routing through CPLD > mux selection, in case the system is equipped with CPLD capable of mux > selection control. > > The Kconfig currently controlling compilation of this code is: > drivers/i2c/muxes/Kconfig:config I2C_MUX_MLXCPLD > > Signed-off-by: Michael Shych > Signed-off-by: Vadim Pasternak > Reviewed-by: Jiri Pirko > --- > MAINTAINERS | 8 + > drivers/i2c/muxes/Kconfig | 11 ++ > drivers/i2c/muxes/Makefile | 1 + > drivers/i2c/muxes/i2c-mux-mlxcpld.c | 326 ++++++++++++++++++++++++++++++++++++ > include/linux/i2c/mlxcpld.h | 57 +++++++ > 5 files changed, 403 insertions(+) > create mode 100644 drivers/i2c/muxes/i2c-mux-mlxcpld.c > create mode 100644 include/linux/i2c/mlxcpld.h It is customary to mark updated patches with v2, v3 etc in the subject and to include a short changelog right here in this space (or perhaps in a cover letter if it is a patch series). Please do so going forward. > > diff --git a/MAINTAINERS b/MAINTAINERS > index 8b3f8d7..a994455 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -7664,6 +7664,14 @@ W: http://www.mellanox.com > F: drivers/i2c/busses/i2c-mlxcpld.c > F: Documentation/i2c/busses/i2c-mlxcpld > > +MELLANOX MLXCPLD I2C MUX DRIVER > +M: Vadim Pasternak > +M: Michael Shych > +L: linux-kernel@vger.kernel.org Isn't the linux-i2c list a narrower and therefore better fit? > +S: Supported > +W: http://www.mellanox.com > +F: drivers/i2c/muxes/i2c-mux-mlxcpld.c > + > SOFT-ROCE DRIVER (rxe) > M: Moni Shoua > L: linux-rdma@vger.kernel.org > diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig > index e280c8e..b7ab144 100644 > --- a/drivers/i2c/muxes/Kconfig > +++ b/drivers/i2c/muxes/Kconfig > @@ -81,4 +81,15 @@ config I2C_DEMUX_PINCTRL > demultiplexer that uses the pinctrl subsystem. This is useful if you > want to change the I2C master at run-time depending on features. > > +config I2C_MUX_MLXCPLD > + tristate "Mellanox CPLD based I2C multiplexer" > + help > + If you say yes to this option, support will be included for a > + CPLD based I2C multiplexer. This driver provides access to > + I2C busses connected through a MUX, which is controlled > + by a CPLD registers. > + > + This driver can also be built as a module. If so, the module > + will be called i2c-mux-mlxcpld. > + > endmenu > diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile > index 7c267c2..e5c990e 100644 > --- a/drivers/i2c/muxes/Makefile > +++ b/drivers/i2c/muxes/Makefile > @@ -10,5 +10,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o > obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o > obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o > obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o > +obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o > > ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG > diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c > new file mode 100644 > index 0000000..9624613 > --- /dev/null > +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c > @@ -0,0 +1,326 @@ > +/* > + * drivers/i2c/muxes/i2c-mux-mlxcpld.c > + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. > + * Copyright (c) 2016 Michael Shych > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * 3. Neither the names of the copyright holders nor the names of its > + * contributors may be used to endorse or promote products derived from > + * this software without specific prior written permission. > + * > + * Alternatively, this software may be distributed under the terms of the > + * GNU General Public License ("GPL") version 2 as published by the Free > + * Software Foundation. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Please sort the includes. > + > +#define CPLD_MUX_MAX_NCHANS 8 > +#define CPLD_MUX_EXT_MAX_NCHANS 24 > + > +/* > + * mlxcpld_mux types - kind of mux supported by driver: > + * @mlxcpld_mux_tor - LPC access; 8 channels. > + * @mlxcpld_mux_mgmt - LPC access; 8 channels. > + * @mlxcpld_mux_mgmt_ext - LPC access; 24 channels. > + * @mlxcpld_mux_module - I2C access; 8 channels/legs. > + */ > +enum mlxcpld_mux_type { > + mlxcpld_mux_tor, > + mlxcpld_mux_mgmt, > + mlxcpld_mux_mgmt_ext, > + mlxcpld_mux_module, > +}; > + > +/* mlxcpld_mux_type - underlying physical bus, to which device is connected: > + * @lpc_access - LPC connected CPLD device > + * @i2c_access - I2C connected CPLD device > + */ > +enum mlxcpld_mux_access_type { > + lpc_access, > + i2c_access, > +}; > + > +/* mlxcpld_mux - mux control structure: > + * @type - mux type > + * @last_chan - last register value > + * @client - I2C device client > + */ > +struct mlxcpld_mux { > + enum mlxcpld_mux_type type; > + u8 last_chan; > + struct i2c_client *client; > +}; > + > +/* mlxcpld_mux_desc - mux descriptor structure: > + * @nchans - number of channels > + * @muxtype - physical mux type (LPC or I2C) > + */ > +struct mlxcpld_mux_desc { > + u8 nchans; > + enum mlxcpld_mux_access_type muxtype; > +}; > + > +/* MUX logic description. > + * This logic can be applied for LPC attached CPLD and fro I2C attached CPLD. > + * Driver can support different mux control logic, according to CPLD > + * implementation. > + * > + * Connectivity schema. > + * > + * i2c-mlxcpld Digital Analog > + * driver > + * *--------* * -> mux1 (virt bus2) -> mux -> | > + * | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux -> | > + * | bridge | bus 1 *---------* | > + * | logic |---------------------> * mux reg * | > + * | in CPLD| *---------* | > + * *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux -> | > + * | driver | | > + * | *---------------* | Devices > + * | * CPLD (LPC bus)* select | > + * | * registers for *--------* > + * | * mux selection * deselect > + * | *---------------* > + * | | > + * <--------> <-----------> > + * i2c cntrl Board cntrl reg > + * reg space space (mux select, > + * | IO, LED, WD, info) > + * | | *-----* *-----* > + * *------------- LPC bus --------------| PCH |---| CPU | > + * *-----* *-----* > + * > + */ > +static const struct mlxcpld_mux_desc muxes[] = { > + [mlxcpld_mux_tor] = { > + .nchans = CPLD_MUX_MAX_NCHANS, > + .muxtype = lpc_access, > + }, > + [mlxcpld_mux_mgmt] = { > + .nchans = CPLD_MUX_MAX_NCHANS, > + .muxtype = lpc_access, > + }, > + [mlxcpld_mux_mgmt_ext] = { > + .nchans = CPLD_MUX_EXT_MAX_NCHANS, > + .muxtype = lpc_access, > + }, > + [mlxcpld_mux_module] = { > + .nchans = CPLD_MUX_MAX_NCHANS, > + .muxtype = i2c_access, > + }, > +}; > + > +static const struct i2c_device_id mlxcpld_mux_id[] = { > + { "mlxcpld_mux_tor", mlxcpld_mux_tor }, > + { "mlxcpld_mux_mgmt", mlxcpld_mux_mgmt }, > + { "mlxcpld_mux_mgmt_ext", mlxcpld_mux_mgmt_ext }, > + { "mlxcpld_mux_module", mlxcpld_mux_module }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id); > + > +/* Write to mux register. Don't use i2c_transfer() and > + * i2c_smbus_xfer() for this as they will try to lock adapter a second time > + */ > +static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, > + struct i2c_client *client, u8 val, > + enum mlxcpld_mux_access_type muxtype) > +{ > + struct mlxcpld_mux_platform_data *pdata = > + dev_get_platdata(&client->dev); This looks weird (several instances). Use shorter names, assign after the declaration or just ignore the line length "rule". > + int ret = -ENODEV; > + > + switch (muxtype) { > + case lpc_access: > + outb(val, pdata->addr); /* addr = CPLD base + offset */ > + ret = 1; > + break; > + > + case i2c_access: > + if (adap->algo->master_xfer) { > + struct i2c_msg msg; > + u8 msgbuf[] = {pdata->sel_reg_addr, val}; > + > + msg.addr = pdata->addr; > + msg.flags = 0; > + msg.len = 2; > + msg.buf = msgbuf; > + return __i2c_transfer(adap, &msg, 1); > + } > + dev_err(&client->dev, "SMBus isn't supported on this adapter\n"); > + break; > + > + default: > + dev_err(&client->dev, "Incorrect muxtype %d\n", muxtype); > + } > + > + return ret; > +} > + > +static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) > +{ > + struct mlxcpld_mux *data = i2c_mux_priv(muxc); > + struct i2c_client *client = data->client; > + struct mlxcpld_mux_platform_data *pdata = > + dev_get_platdata(&client->dev); > + const struct mlxcpld_mux_desc *mux = &muxes[data->type]; > + u8 regval; > + int err = 0; > + > + switch (data->type) { > + case mlxcpld_mux_tor: > + regval = pdata->first_channel + chan; > + break; > + > + case mlxcpld_mux_mgmt: > + case mlxcpld_mux_mgmt_ext: > + case mlxcpld_mux_module: > + regval = chan + 1; > + break; > + > + default: > + return -ENXIO; > + } > + > + /* Only select the channel if its different from the last channel */ > + if (data->last_chan != regval) { > + err = mlxcpld_mux_reg_write(muxc->parent, client, regval, > + mux->muxtype); > + data->last_chan = regval; As I said for v2, if the reg write fails, you ignore the error when setting last_chan. That means the reg write is not retried next time around and the i2c traffic may end up on the wrong segment. I suggest that you set last_chan to some "illegal" value on error (zero looks like a good candidate if you look at deselect), so that the reg write is always done on a select following an error. > + } > + > + return err; > +} > + > +static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) > +{ > + struct mlxcpld_mux *data = i2c_mux_priv(muxc); > + struct i2c_client *client = data->client; > + const struct mlxcpld_mux_desc *mux = &muxes[data->type]; > + > + /* Deselect active channel */ > + data->last_chan = 0; > + > + return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan, > + mux->muxtype); > +} > + > +/* I2C init/probing/exit functions */ > +static int mlxcpld_mux_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); > + struct mlxcpld_mux_platform_data *pdata = > + dev_get_platdata(&client->dev); > + struct i2c_mux_core *muxc; > + int num, force; > + u8 nchans; > + struct mlxcpld_mux *data; > + int err; > + > + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) > + return -ENODEV; > + > + switch (id->driver_data) { > + case mlxcpld_mux_tor: > + case mlxcpld_mux_mgmt: > + case mlxcpld_mux_mgmt_ext: > + case mlxcpld_mux_module: > + nchans = muxes[id->driver_data].nchans; > + break; > + default: > + return -EINVAL; > + } > + > + muxc = i2c_mux_alloc(adap, &client->dev, nchans, sizeof(*data), 0, > + mlxcpld_mux_select_chan, mlxcpld_mux_deselect); > + if (!muxc) > + return -ENOMEM; > + > + data = i2c_mux_priv(muxc); > + i2c_set_clientdata(client, muxc); > + data->client = client; > + data->type = id->driver_data; > + data->last_chan = 0; /* force the first selection */ > + > + /* Only in mlxcpld_mux_tor first_channel can be different. > + * In other mlxcpld_mux types channel numbering begin from 1 > + * Now create an adapter for each channel > + */ > + for (num = 0; num < muxes[data->type].nchans; num++) { > + force = 0; /* dynamic adap number */ > + if (pdata) { Here, you check if you have pdata, but in other places you assume pdata is there. Maybe the probe should error out if there is no pdata? > + if (num < pdata->num_adaps) > + force = pdata->adap_ids[num]; > + else > + /* discard unconfigured channels */ > + break; > + } > + > + err = i2c_mux_add_adapter(muxc, force, num, 0); > + if (err) { > + dev_err(&client->dev, "failed to register multiplexed adapter %d as bus %d\n", > + num, force); > + goto virt_reg_failed; > + } > + } > + > + return 0; > + > +virt_reg_failed: > + i2c_mux_del_adapters(muxc); > + return err; > +} > + > +static int mlxcpld_mux_remove(struct i2c_client *client) > +{ > + struct i2c_mux_core *muxc = i2c_get_clientdata(client); > + > + i2c_mux_del_adapters(muxc); > + return 0; > +} > + > +static struct i2c_driver mlxcpld_mux_driver = { > + .driver = { > + .name = "mlxcpld-mux", > + }, > + .probe = mlxcpld_mux_probe, > + .remove = mlxcpld_mux_remove, > + .id_table = mlxcpld_mux_id, > +}; > + > +module_i2c_driver(mlxcpld_mux_driver); > + > +MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); > +MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); > +MODULE_LICENSE("GPL v2"); > +MODULE_ALIAS("platform:i2c-mux-mlxcpld"); > diff --git a/include/linux/i2c/mlxcpld.h b/include/linux/i2c/mlxcpld.h > new file mode 100644 > index 0000000..ceb31da > --- /dev/null > +++ b/include/linux/i2c/mlxcpld.h > @@ -0,0 +1,57 @@ > +/* > + * mlxcpld.h - Mellanox I2C multiplexer support in CPLD > + * > + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. > + * Copyright (c) 2016 Michael Shych > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are met: > + * > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * 3. Neither the names of the copyright holders nor the names of its > + * contributors may be used to endorse or promote products derived from > + * this software without specific prior written permission. > + * > + * Alternatively, this software may be distributed under the terms of the > + * GNU General Public License ("GPL") version 2 as published by the Free > + * Software Foundation. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" > + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE > + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#ifndef _LINUX_I2C_MLXCPLD_H > +#define _LINUX_I2C_MLXCPLD_H > + > +/* Platform data for the CPLD I2C multiplexers */ > + > +/* mlxcpld_mux_platform_data - per mux data, used with i2c_register_board_info > + * @adap_ids - adapter array This description is a bit misleading, it's an adapter *id* array. And there is a special value (0) for dynamic numbering. > + * @num_adaps - number of adapters > + * @sel_reg_addr - mux select register offset in CPLD space > + * @first_channel - first channel to start virtual busses vector > + * @addr - address of mux device - set to mux select register offset on LPC > + * connected CPLDs or to I2C address on I2C conncted CPLDs > + */ > +struct mlxcpld_mux_platform_data { > + int *adap_ids; > + int num_adaps; > + int sel_reg_addr; > + int first_channel; > + int addr; > +}; > + > +#endif /* _LINUX_I2C_MLXCPLD_H */ >