From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752173AbcKRBZG (ORCPT ); Thu, 17 Nov 2016 20:25:06 -0500 Received: from mail-db5eur01on0135.outbound.protection.outlook.com ([104.47.2.135]:18275 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750866AbcKRBZD (ORCPT ); Thu, 17 Nov 2016 20:25:03 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=peda@axentia.se; From: Peter Rosin To: CC: Peter Rosin , Wolfram Sang , "Rob Herring" , Mark Rutland , "Jonathan Cameron" , Hartmut Knaack , "Lars-Peter Clausen" , Peter Meerwald-Stadler , "Arnd Bergmann" , Greg Kroah-Hartman , , , Subject: [RFC PATCH v2 7/7] i2c: i2c-mux-simple: new driver Date: Thu, 17 Nov 2016 22:48:09 +0100 Message-ID: <1479419289-17553-8-git-send-email-peda@axentia.se> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1479419289-17553-1-git-send-email-peda@axentia.se> References: <1479419289-17553-1-git-send-email-peda@axentia.se> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [217.210.101.82] X-ClientProxiedBy: DB5PR03CA0075.eurprd03.prod.outlook.com (10.164.34.43) To DB6PR0201MB2311.eurprd02.prod.outlook.com (10.169.222.150) X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2311;2:UVEZciTQyS1XEoDrgMWbvptm/QnB0wZXkeKSq4qEhTWXd//xlyQHkl7EFLvBIcpJeS6RB6pWxotNJ7FhetJfrOJuJpaarFLoP/UpScC1qnUS71EOGaZTYEU/6qCEFgHIlOYLHEA2jjJ4eKZDrbNoEP/oDYWTaUpw4URxk6WrdRQ=;3:vYZjQskR8H454gPXHynjeMS9C2pxt+pinyNfY3SejSvP3vuocSik7d1gvEI+aDC/D4y3xmchFgUtWAXFrYDTv/dKUVnxZGqC8YJRAsAf+jwNFkcuJaoIBsFyeOTiBNtNFnPO6zQdu9nn6EXbfAZ3A/Gi478YZQEvFoY/B3fuv0c=;25:GASE3vCxDtwnEE1zJKfLeVSTWAWgIGk92MTDAp+coAIRtekiV/lEgeieaPH4rLelpHAe6AigYNKt/KZ1xbK460kyU3KLBkL9rFow241Yv+3i+G6olP3hxkGu+/XLreU498CRGTF/T/Fawy32KLEjqjwKtiVeQZN5nTRh+IhjiO5bIWm4oRZDVNy/g32zXdF1mzcAiVaU2opzSYrv3m7CxM8QhZpwJbHuXANnCsq/MI2fVUEMUso6vpgFGyl88ex+fKSEJy4cOi2rv0wWpfL2CQ2souFsdqWsDd3HedClNywofwdOfKR1JNxCnvoUGS8t2VX2MC+TtwoGZJ2hdqU9hm8NQQAmqD+/j7pWI3NB4/7ACBl8deOnLcB/TQZYvGwEcL6DDo0Hmji5a1bCDp2OdMx/xJCC0ra0fQcgWWk5PEZdPUvxd7tb5NXDe2JajnEFEmN4uE4Uz6Jss+czT5U2dQ== X-MS-Office365-Filtering-Correlation-Id: 09842aae-7b9f-406a-3f01-08d40f339b72 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001);SRVR:DB6PR0201MB2311; X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2311;31:7Cv3ieBd63+WKD7CTNz+bgtFnLftnDirNlch6CozMVSNFOKZCUuKngd8tvcNwVonXdraRLv8GdXHiunKymNfzJ/9KABgzBBVBsd5aoKDgcnAKKfT2EN4lddh/Egkmmcy1wms0yECnjdpsPKBDUDZM4W9Yx0oixIt82Z+6eS2KUMir+FvO1knQwgsFKHSgVlNC7egmXlRoFGAxCVsQR5UgVk0PSql4y1qfKoRuE5CQfebyx9V0NlFgnsO7U1pL9qTTlWHGfVs3GHIx0IXMPi8k26hjGleSBjgMxndujLv1cM=;4:PSBuiVE8FLTNBqV+cWuPuJ6NDSEpYiepyzCYZoJs69ZMFGkNVF6k3u5/w89+OEkJotu5zxqFuhBbB6bTfjIksB2XPO7r+ijFvece9DktLg8fzciOVeE6p/CFsn3R8oTz4HMMSjFtXF7yJoZ/j8yBZlbvlN01H8py+lCqx39g2j1gmpjat4GCfEb9NGOiPGY3SiIIVOZFWUh0KQeo8f2FgLTShyfP4nfSjVXYN4XVtSbetzPVH4I1m2pJ6Cg1w7x2rwkoWS5zLCtHiEkYIxFtOhMNTAGK1jpZx7yc4uzvPA8a6pkxfCDhJH9B53BY1tTtIQ2gu5td0jM35C5HlTxMFNUAZgovK/GzFlT0m6j+AbZxelK1fKJ7SZI4FqYa8VR+Wx/7l9/DeRzOeUwskslXr31wS/Wmqkx0bxAIUN6rlm/P8VZDgB0v3WUXqzb7AMNUu/TivtCVB2ypI2uGt1HJy0KT7uT2cndhUuyijPjdmZo= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040281)(6060326)(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6061324)(6041223)(6043046);SRVR:DB6PR0201MB2311;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0201MB2311; X-Forefront-PRVS: 01294F875B X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(6069001)(7916002)(189002)(199003)(305945005)(8676002)(101416001)(7416002)(8666005)(7736002)(7846002)(50466002)(48376002)(92566002)(50986999)(76176999)(105586002)(106356001)(2351001)(230783001)(36756003)(33646002)(42186005)(74482002)(6116002)(3846002)(2906002)(4326007)(81166006)(5003940100001)(81156014)(50226002)(110136003)(5660300001)(6666003)(2950100002)(6916009)(47776003)(66066001)(68736007)(77096005)(86362001)(189998001)(575784001)(97736004)(7059030)(2004002)(217873001)(42262002)(309714004);DIR:OUT;SFP:1102;SCL:1;SRVR:DB6PR0201MB2311;H:localhost.localdomain;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;DB6PR0201MB2311;23:PCFapSFT5NKUfwcYY+nBQf+I9wCq4r3VSWWEmK1?= =?us-ascii?Q?hraGst1dycKSGZqbXLC4h7xhFbfGpK/5WOl82DEdiydliFMx8v6dvxDdbPh1?= =?us-ascii?Q?5JDrKrS2RXXV4vHP/l2GXw78St8PSJ/mcZKF7l5oNXs2ynfo3yr7k0GK/s4f?= =?us-ascii?Q?k6O6Khh70YZHT9MeVlF9Uw04MPwVZnvh0fGaajpoLn/nZHUunJT7amvnZ6w7?= =?us-ascii?Q?zDCWXXF8L157GSqR5lFF9GiubzUy0llXYGMOxD7aOwluyQCOM+TXfPbdG3bq?= =?us-ascii?Q?tc9CVZg+O5jj6C9z2RLh9bK33fwPu7D6il0ahuT2/G3C88jTVHNhxWTGnK7U?= =?us-ascii?Q?sZbossmvD5qkldbGoFyL/cPRdw2R3J1EAmU/AnxsUVD6cxU8pF6SAAF18rQN?= =?us-ascii?Q?TArdytdVh0O2Mt5zjhKS/3an08v7yvI/J0YIyi1SnnnP/bN6spzsphAp+zUT?= =?us-ascii?Q?LcF1kJ7CneVIniMd2lP8T7qSWxTh+DkSPmWl5RvMEvvkrn8AKGscvHI8sOrJ?= =?us-ascii?Q?k/wmb6rBe8MDOQn8OMC92ROQGZl8BCs8Legn8zrjyUTQIclCuPbuKtTALjec?= =?us-ascii?Q?VoXDmhL/3b7dZFPlwgjDEpFR2b58OK3EjCVdnz9y6p8bCYKswnvDJPO2W+gK?= =?us-ascii?Q?nczgppllBbNVvvpoHodptaw+Euht3vse4z7dt6C4ztcyuvFLwe6VlHo1Gfgc?= =?us-ascii?Q?WXm4DR5AmZKahLSzfN1SLelwJBp8dGLAXHARzt3htT7lNnwATwnwwE8FwdGs?= =?us-ascii?Q?Z2A1rPnkdjoWkxsUNxNQ+1v4DK1vWpi+aGyRXphOpBcpx5JmVGgm/NLJ7s4r?= =?us-ascii?Q?8d/TNcTUZ1MJ0VRalMfHnpIGTKnb2ac2wLUolyw+B4fN/Bld0JykLpAi7/20?= =?us-ascii?Q?RkgkcK6U+6vHZpv+zzQi9bCiIyw2DPxxMBPM73qSQXQOYA/08j9baHODHmtb?= =?us-ascii?Q?45zX5hnJ6F6R2E8MkM82BrWmeJOYdWBodlST2iBwZGeWtxmiQg8awvBdcRtu?= =?us-ascii?Q?vuS4b/K7TC8FguJSeBpzk5gyNIDNA9RD184qP1WIzjlVKtmVu0fSEkYetc64?= =?us-ascii?Q?E0kSZOc9cpykjAUIXTAz/hSHyJpWAZRJSj/k4MS7XA2N4R0Rm+miPBi0nujv?= =?us-ascii?Q?jjPJOvEpuJoMlY4B0EPXj20zFf3MCoPX5s2VyDqHgNRCyAKugZ4zFeg4xioU?= =?us-ascii?Q?zFejbdDBKMMPugg+1R3JcwOWZ814/y10INE5zJ8YyJVMjVuidwWuZHwNl/A?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2311;6:+LBaYUaDzTiOizlb4B+nKFyCxNR21gR7LkjJQuoQInCSC4MJINlblqk32LdU7ktGq6kglZmabTXr3q6YaV3kxvPFO2/1eegsqX9y0yZFTN0ils7jasezJVocD7AzLMcepSr5lz3Xh0PrhxJtdbKbQnXKyX6H0bjmBmYpPWXMlWsPUpWRw2Sc8KX/MtyxOSHHFVSLACkmCs+7TLHiro4xPbwDwFX9Ib2Vqr1rpIjh2PYXl0LuIObdoiBzAGrkvu27YLkoq4OsQFBLvXJHPukc0+GCysxHnI6/QDjuhgrhfnWeb7XVIRyxgLoAtVzTQXjWdb8YcTmbfIJOuccRr/pfkrektt0NeHJVNlKuLZNNhG1tdWEwd7+gY/mCBuzI2hdE;5:JVsfWQKTPJ10cV15ymbd8f4xD9vrUyWpqdLNQOYzKK6qBpwYDrkjXlTP6VIvQISVrDtdOtBGCRGDDvh/7W41bK8Z9FtM455x0xSk9lxPhpsm2oM1/z4tbywx8kUtp4WJp+VzGq9gPJ8XM7m5eh5aF5unygLblhFd4Xzc/TKkuoA=;24:muoVlIbLW36zDJWYcsLYcJHztp/9LYHeAh/IDsdPvwNoDGMqU9gbq3oGY8jRSkTyYVQ9Y/EEqlsCeZLBqAuTQAClhbpxAQlVDkUqAFIXZPI= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;DB6PR0201MB2311;7:xe5owLxA3+JUXySYZDRBjWtnT2X47e3i/LzJODhRaBXmAUFa+6W20ciynj/fgzaFiiaFt/OBuNDr86xvl8sfqA+0z1GmmE7c1OsGjFRtOPcofnEl552+gu2oiTsupAcMNnZm60zrH4yajGjbtk2Ewn1q0Ux3JxJMkJGWXLUJpmfRW126EzojpoSlC7wNurKyLtw3z0lrA1hKVPD2SJCbkl0lSxOJ//dSZ2p94M74qVOYlHMuRPq1ZCyvd2davves8HihV4uTM51aH+/lD+uyy6RwWUut9aH1Ptv1WCB1sBbG8SBpicg+AzuwNfH6VbaOxslN83a84u6rc0INSXIn8Tu57hr2BJx5RUKOSC8H6UY= X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Nov 2016 21:49:27.7845 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0201MB2311 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This is a generic simple i2c mux that uses the generic multiplexer subsystem to do the muxing. The user can select if the mux is to be mux-locked and parent-locked as described in Documentation/i2c/i2c-topology. --- drivers/i2c/muxes/Kconfig | 12 +++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/i2c-mux-simple.c | 168 +++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index e280c8ecc0b5..45e80ad2d4ab 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -72,6 +72,18 @@ config I2C_MUX_REG This driver can also be built as a module. If so, the module will be called i2c-mux-reg. +config I2C_MUX_SIMPLE + tristate "Simple I2C multiplexer" + depends on OF + help + If you say yes to this option, support will be included for a + simple generic I2C multiplexer. This driver provides access to + I2C busses connected through a MUX, which is controlled + by a generic MUX controller. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-simple. + config I2C_DEMUX_PINCTRL tristate "pinctrl-based I2C demultiplexer" depends on PINCTRL && OF diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 7c267c29b191..eea1fb9e6466 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_SIMPLE) += i2c-mux-simple.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/drivers/i2c/muxes/i2c-mux-simple.c b/drivers/i2c/muxes/i2c-mux-simple.c new file mode 100644 index 000000000000..6d8ddbc94ecc --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-simple.c @@ -0,0 +1,168 @@ +/* + * Generic simple I2C multiplexer + * + * Peter Rosin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +struct mux { + struct mux_control *control; + + bool do_not_deselect; +}; + +static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct mux *mux = i2c_mux_priv(muxc); + int ret; + + ret = mux_control_select(mux->control, chan); + mux->do_not_deselect = ret < 0; + + return ret; +} + +static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct mux *mux = i2c_mux_priv(muxc); + + if (mux->do_not_deselect) + return 0; + + return mux_control_deselect(mux->control); +} + +static struct i2c_adapter *mux_parent_adapter(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *parent_np; + struct i2c_adapter *parent; + + parent_np = of_parse_phandle(np, "i2c-parent", 0); + if (!parent_np) { + dev_err(dev, "Cannot parse i2c-parent\n"); + return ERR_PTR(-ENODEV); + } + parent = of_find_i2c_adapter_by_node(parent_np); + of_node_put(parent_np); + if (!parent) + return ERR_PTR(-EPROBE_DEFER); + + return parent; +} + +static const struct of_device_id i2c_mux_of_match[] = { + { .compatible = "i2c-mux-simple,parent-locked", + .data = (void *)0, }, + { .compatible = "i2c-mux-simple,mux-locked", + .data = (void *)1, }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_of_match); + +static int i2c_mux_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + const struct of_device_id *match; + struct i2c_mux_core *muxc; + struct mux *mux; + struct i2c_adapter *parent; + int children; + int ret; + + if (!np) + return -ENODEV; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + mux->control = devm_mux_control_get(dev, "mux"); + if (IS_ERR(mux->control)) { + if (PTR_ERR(mux->control) != -EPROBE_DEFER) + dev_err(dev, "failed to get control-mux\n"); + return PTR_ERR(mux->control); + } + + parent = mux_parent_adapter(dev); + if (IS_ERR(parent)) { + if (PTR_ERR(parent) != -EPROBE_DEFER) + dev_err(dev, "failed to get i2c-parent adapter\n"); + return PTR_ERR(parent); + } + + children = of_get_child_count(np); + + muxc = i2c_mux_alloc(parent, dev, children, 0, 0, + i2c_mux_select, i2c_mux_deselect); + if (!muxc) { + ret = -ENOMEM; + goto err_parent; + } + muxc->priv = mux; + + platform_set_drvdata(pdev, muxc); + + match = of_match_device(of_match_ptr(i2c_mux_of_match), dev); + if (match) + muxc->mux_locked = !!of_device_get_match_data(dev); + + for_each_child_of_node(np, child) { + u32 chan; + + ret = of_property_read_u32(child, "reg", &chan); + if (ret < 0) + goto err_children; + + ret = i2c_mux_add_adapter(muxc, 0, chan, 0); + if (ret) + goto err_children; + } + + dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name); + + return 0; + +err_children: + i2c_mux_del_adapters(muxc); +err_parent: + i2c_put_adapter(parent); + + return ret; +} + +static int i2c_mux_remove(struct platform_device *pdev) +{ + struct i2c_mux_core *muxc = platform_get_drvdata(pdev); + + i2c_mux_del_adapters(muxc); + i2c_put_adapter(muxc->parent); + + return 0; +} + +static struct platform_driver i2c_mux_driver = { + .probe = i2c_mux_probe, + .remove = i2c_mux_remove, + .driver = { + .name = "i2c-mux-simple", + .of_match_table = i2c_mux_of_match, + }, +}; +module_platform_driver(i2c_mux_driver); + +MODULE_DESCRIPTION("Simple I2C multiplexer driver"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL v2"); -- 2.1.4