From patchwork Fri Mar 10 11:10:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Rosin X-Patchwork-Id: 737362 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3vfl4J4kgWz9s76 for ; Fri, 10 Mar 2017 22:13:20 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=axentiatech.onmicrosoft.com header.i=@axentiatech.onmicrosoft.com header.b="Xq7DgkQl"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934606AbdCJLNQ (ORCPT ); Fri, 10 Mar 2017 06:13:16 -0500 Received: from mail-db5eur01on0139.outbound.protection.outlook.com ([104.47.2.139]:2624 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S934603AbdCJLLh (ORCPT ); Fri, 10 Mar 2017 06:11:37 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axentiatech.onmicrosoft.com; s=selector1-axentia-se; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=0OpktnT9lYdtQ9JwlORO8UFTNitiixWHABbiQkTAfFE=; b=Xq7DgkQliDpG32YdM8CNtDdnV+P/NKFEOKv4ZN+5on/dHtEN1matt15LqC2eCx1laLkov9B7bYcXvrGCyjZ44MJpDFB4+tw8ZvntEkqA21wDy1mlO/0wNS66e7e55ZGkoQMh1AiNievCgWojs7B3mWKkXP0fbJlm17ebOil16fc= Authentication-Results: vger.kernel.org; dkim=none (message not signed) header.d=none; vger.kernel.org; dmarc=none action=none header.from=axentia.se; Received: from localhost.localdomain (81.224.171.159) by VI1PR0202MB2560.eurprd02.prod.outlook.com (10.173.79.139) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.947.12; Fri, 10 Mar 2017 11:10:51 +0000 From: Peter Rosin To: CC: Peter Rosin , Wolfram Sang , Rob Herring , Mark Rutland , Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Jonathan Corbet , , , , , Andrew Morton , Colin Ian King , Paul Gortmaker Subject: [PATCH v10 08/11] i2c: i2c-mux-gpmux: new driver Date: Fri, 10 Mar 2017 12:10:02 +0100 Message-ID: <1489144205-17427-9-git-send-email-peda@axentia.se> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1489144205-17427-1-git-send-email-peda@axentia.se> References: <1489144205-17427-1-git-send-email-peda@axentia.se> MIME-Version: 1.0 X-Originating-IP: [81.224.171.159] X-ClientProxiedBy: HE1PR02CA0050.eurprd02.prod.outlook.com (10.163.170.18) To VI1PR0202MB2560.eurprd02.prod.outlook.com (10.173.79.139) X-MS-Office365-Filtering-Correlation-Id: 15dede04-8898-46e8-7ec2-08d467a61e56 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:VI1PR0202MB2560; X-Microsoft-Exchange-Diagnostics: 1; VI1PR0202MB2560; 3:2/YAEfVLasRnzfM6htt7Vf1E6OCmrF2KC+oh7aceJWrV1xku2PcTti64y+jECw0qb16d9r1WY5k9zGJyeqT6VkJ0mIWYcKD1xx4cdUxyCq/Mj7e+DbtDOcWq1gAmGqvuOiMecj6RGvYunuft0WtmM8+cvbHDozPdF0pU2QOFDe8gytcxwqWr93sckoT8S9M1nkCBcHdQEuWkYOM+k9PKuLYa9OEz7Wde+Q7MpD580S65ad+fq6X9svlWgLj4UevTma4/xD4etRvUy4mtxHCc7w==; 25:0J3jK2GjwQ46iLYOaTk4TVfS0CsR3/u2sBwW7j2QnuzPywQEo1jbQKRek4D6PbVjQ6kZ6sXXCZHSadvoFUdzWxts70XMdRaa7SPswvKkIOnlTvHf9+IhCHxbV43RCrnXME9OrLbG+YWznLSCe824mOi131BCOugaulvMWr6ZAOG1qoUW5TrnlIzefbGyc1/TPthA5b6x1xqZSKx/mKJqO575m/dQioTfIyTGoi/VsDuMCBM5PxjYmjjtfgBYlIHV0N1bwHwH4OEgZft28/rJJRn27zdycffIRJuJjflOmUYyGzrBeihxlAoo0lyR4HmZ+hhDkmAIXUYVFv9cYWA3Mgk3R8bFKm41gwZh+gj4G8pJqCadTlG5cPVMxC2YJsjBIEYLKLlbK2hCxm5d2otbGoA9d0lxPVEf965IS8vURastzajF37rU4pU/uoUe1qaNqQk59YElSvJKc9EUTwjI5A== X-Microsoft-Exchange-Diagnostics: 1; VI1PR0202MB2560; 31:3wWMd/7oIkHtf5CdbLLWO1dERW6HwqDgn7U/B81TRdIRLfJFs/S7EUfyPljkwGPUAXJIfSjPrrhk2LBzPEpcpMDedTwrop8vI06DlBnjJivgR9SRX66jWz46uXq09kC6hNdOgrCad1/ugtI30mmLQlmX1mYLkX8BRlHi1yER0e++XGKD4ueBA367GOp2GBsoM7Q/tVz6aRPHQ6ZBJa0hSSKrILTRaZD83L/dupxfwQTYwBUl5XqHIQSyxh9QdIPu; 4:fRbt6l0l7xA2Iop/MPl+Sv/vUku0E9raS/LS/VRgzHHV+Ddq3qMmZpMCNdDz2ud9svklq7XRr8iqkmk+mIrUFjCzBcQ5UCuMHNi0iCpTX7sXHTP5hhtsSHlXUloyeLlP1eCL0HwwSxbQodvhUy/axpUw8FOiw04vlV4+R71ol63j08zQNKUr8dFrDIcfIEwjTAgG+NhdvdoNbMNa7dP78/35+8ieJ+6OoMJZBjQFEpApSxtgbqs26JlGn71Mjq3PwdrrXwR0G0Cx5MjhI8g4d/SHGvTvaut2kJSKtaBEqD5vD8/9CD1Cq8g/SpuFH8YZNPFlqbU0iZ7WRruRGtljZguqE1D+HRm1ee6dU3fWXQ57uifn7CYzva/IZbmbT682sMrcOxIXmx+nhC0nSiAyVztgIbwG3LbRkGCt1XCWlcO0gJR/F3CGXHrQUF3RJh0ikStlEOXq1XNBARIaZX4Y6i6zkAY6iSJS/2oo0AbqMs5Pdk8MYfVM2g0WYH5tnpYt6Ms7lXA1aLUioNL+13UPKMvdzFgxsIKGwJbM0GvZjoBI90z3mETZoiNwII30AxR0gqEv6nH4MPQ45QV8ugeI4NhB83CJ4blrOSwTDDk3C6YC3a0K+LMUyDpfFqz3dYC5UyZuQcF+xxXjvABPF3qaiAVaH9pHn6oXCiDm/35yZ+w= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6041248)(2016111802025)(20161123560025)(20161123558025)(20161123555025)(20161123564025)(20161123562025)(6043046)(6072148); SRVR:VI1PR0202MB2560; BCL:0; PCL:0; RULEID:; SRVR:VI1PR0202MB2560; X-Forefront-PRVS: 02426D11FE X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(39840400002)(39450400003)(39410400002)(5660300001)(6506006)(8666007)(6486002)(25786008)(42186005)(2351001)(2950100002)(6512007)(2906002)(6666003)(38730400002)(6916009)(7736002)(50466002)(110136004)(54906002)(50226002)(4326008)(86362001)(48376002)(53936002)(66066001)(47776003)(74482002)(81166006)(50986999)(76176999)(5003940100001)(189998001)(305945005)(8676002)(230783001)(3846002)(36756003)(6116002)(33646002)(42262002); DIR:OUT; SFP:1102; SCL:1; SRVR:VI1PR0202MB2560; H:localhost.localdomain; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR0202MB2560; 23:BAfU2U3yc7Oxb4rkUUsrUMpZplNqukuGaZIFt3t?= =?us-ascii?Q?qtsHNSr7u4LX0wbha5T/praOJ4iwv3a+dpzEy0feVZOzoMG+skr/+w1tu8RP?= =?us-ascii?Q?WX98eNUgSZkj7GVNzICtCUnzHrfgAZjL9Hr9JMfcN0PQsxTbd4DjlqfQ0pYi?= =?us-ascii?Q?Byv8jp5A24DmBA4lWOlsgtUa8cRHrLvIZoL3D/CjumEYPqTP1qN+DmaXIOHV?= =?us-ascii?Q?9K5mjb/fsudcgeQgtZ843ZfxhDN2yURIYYtO6/O7b2KtlB4Ira5fqBDlNYmY?= =?us-ascii?Q?KgqMv1pbz+t2eYwJ9kuEnG0H/0cw4QSY+OruSyXAMuvrg14j5rP6r08Jd42W?= =?us-ascii?Q?0lgAqpzwzTgjTWAnvhT5NlgUVeAxT/RC9NGtzTzAcLnhM9CHmbJKpqhC5ohr?= =?us-ascii?Q?07j39+jovRhD0r8ySbrxaCYtlaD9/PP36qFK1StmHaeqd/ndFkYneF3sdGuS?= =?us-ascii?Q?FWkWvF1SjvXbvvlO0TJYRdOFvLch3XGgfspbFnVTpl6nAy1gJQ+Y86hMjMlF?= =?us-ascii?Q?Tof5GR5HqmPkZwudUk0Qns4LhzVj85kHB8yzPcDbGmh0fWlMDfb/kAJlryrc?= =?us-ascii?Q?u7I9x0KKTJsnnoDIPX9roTJfVsBGT446iuSbytpQaEW85eCtjGZMwGusoTac?= =?us-ascii?Q?zY/1xtodm1+vX4O8+jwOKgVCWlbT+/DSpiM+n+FaE9NSmAd3iIPSibzKF6j+?= =?us-ascii?Q?iI/gxpIcWdmQ2Sgrz9/XoarxamRl8B97tLiYH6xginfg2zDyFyPH3iof/3su?= =?us-ascii?Q?uXzWPoWgcZFXCbhrwpDtxtJdK4AHb/hB7MDGumzAxMB7pJc1oNC4HssCr7io?= =?us-ascii?Q?z8pJ8HDPBZIAPzWYL80pHv6q77lbIEXEhaLi0ddvkx2ohUmZFfmT3pPMQPHE?= =?us-ascii?Q?84G2PhDuKN6ecW20PyEq8sYTyKPjhUknsf7cSvNJPfvSyLEWhPomjPVqsVTB?= =?us-ascii?Q?y/TLKrbhjVr9XnZRoXfy+FWoxWxqd9WpbjtU+r8Wql1s21DIg9lDoYbrmPP2?= =?us-ascii?Q?YSIkXVfxOJe/EiJDgdIfU3scy76YvxW3FUBatcJ8rxLM55qlclMtRk3ThWqs?= =?us-ascii?Q?RUIvmcdw0USbkXCckljj3nVLcFkgX?= X-Microsoft-Exchange-Diagnostics: 1; VI1PR0202MB2560; 6:PUVFjCqVBFsnKwnlztP43yeiqKFUE/DgSMDgV1y8A/oBdl4Vp/0rIeRZicmkkAN5EGAaAluBOsFMFpBa/jTyXYsxR+cNAvbQI6iMEeys90lJi0BYohZquXqGe9Io74NkdCCVTgGzLIJn+/cMVEAx4TT2Vu5ivxooxtC+7zNZDgU2B7dUFsRTovSVZs7GAV2QCS+M6s2udFq35ZE50e0vi7ijZIBMv+ifFA6xuoa+JBT2THAb/OjlwxIGC+z+TedJncrVnf3kh/uIdb1GUF8EipJ2ZD0hnYUtLkjEIbL9+LnbHry3ItAeDv8wXm+taGKY9vuAAYUcsmnDf7XEw92T9GYrr/mQ1yGB4Sav7jwOP11C2VLOVNoHYc+Fnew2TQtsC7qouqiwDi29ABhmb83MEg==; 5:ymo0k+6wMWpgYIIYQxZlebtCtsZmOZk5PE87zfReondDxhwvk9BlewCne2yRhRVsNSdQsekT2pDDah9Xe2VjIZgrnass7pZTIBULzlq308sjA+YQEzF6IQTHBrwsDaQw19gilKKiH2izqg/pCUhHCZyYp6wkBd9RWS3aX6xUVpU=; 24:CYIgiKnKdw+5Y+ALW3gcpGGJ9zq9iD6czp48X1H1KXULPv5/M68Csp/YZhxSWfzoLSR84MWhRLPW9stHspaPjKzqq83y7GiHcMBQwx+Hzr4= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; VI1PR0202MB2560; 7:D3+UTE0MHdgGoEUdk0XO1tPZm3Fv0p8zGHsSXeGQNpaUWX10aD9F/RgdNAXB/H5AJ/sp2qlM69Wm69HZxfxNl957Q0mZSsEsm/lukvCemLBfhnk3Md9yFMGJ73eGMJl7Qif/l4cjH2lTIUqVQYCNwjJCMsB0eLeb60mNBoMOLUzqAOC9ZLLRbbaKjvG26MQ0Ok+GaWyKy2eBKIiquHTdSIHXsnHOS/juot/EucAzLe7f0aOXpT4EhSNt3oF1WOI9TEZJoBh7uJ8LnvgUODzhT22wNTyug0dHxMmiBbWoYOmB6mg+vuNn8CgcLC/pMasV7Wiudkpop4Mm5zavc4is+w== X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Mar 2017 11:10:51.7143 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0202MB2560 Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org This is a general purpose i2c mux that uses a multiplexer controlled by the 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. Acked-by: Jonathan Cameron Acked-by: Wolfram Sang Signed-off-by: Peter Rosin --- drivers/i2c/muxes/Kconfig | 13 +++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/i2c-mux-gpmux.c | 173 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 drivers/i2c/muxes/i2c-mux-gpmux.c diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 10b3d17ae3ea..11115fb34f24 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -30,6 +30,19 @@ config I2C_MUX_GPIO This driver can also be built as a module. If so, the module will be called i2c-mux-gpio. +config I2C_MUX_GPMUX + tristate "General Purpose I2C multiplexer" + select MULTIPLEXER + depends on OF + help + If you say yes to this option, support will be included for a + general purpose I2C multiplexer. This driver provides access to + I2C busses connected through a MUX, which in turn is controlled + by a MUX-controller from the MUX subsystem. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-gpmux. + config I2C_MUX_PCA9541 tristate "NXP PCA9541 I2C Master Selector" help diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 9948fa45037f..af43c6c3e861 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o +obj-$(CONFIG_I2C_MUX_GPMUX) += i2c-mux-gpmux.o obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c new file mode 100644 index 000000000000..fb23b2278462 --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -0,0 +1,173 @@ +/* + * General Purpose I2C multiplexer + * + * Copyright (C) 2017 Axentia Technologies AB + * + * Author: 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", }, + {}, +}; +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; + 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, NULL); + 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); + + muxc->mux_locked = of_property_read_bool(np, "mux-locked"); + + for_each_child_of_node(np, child) { + u32 chan; + + ret = of_property_read_u32(child, "reg", &chan); + if (ret < 0) { + dev_err(dev, "no reg property for node '%s'\n", + child->name); + goto err_children; + } + + if (chan >= mux->control->states) { + dev_err(dev, "invalid reg %u\n", chan); + ret = -EINVAL; + 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-gpmux", + .of_match_table = i2c_mux_of_match, + }, +}; +module_platform_driver(i2c_mux_driver); + +MODULE_DESCRIPTION("General Purpose I2C multiplexer driver"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL v2");