From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753217AbdARQDr (ORCPT ); Wed, 18 Jan 2017 11:03:47 -0500 Received: from mail-db5eur01on0092.outbound.protection.outlook.com ([104.47.2.92]:7097 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753183AbdARQDl (ORCPT ); Wed, 18 Jan 2017 11:03:41 -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 , Jonathan Corbet , Andrew Morton , , , , Subject: [PATCH v8 08/12] i2c: i2c-mux-simple: new driver Date: Wed, 18 Jan 2017 16:57:11 +0100 Message-ID: <1484755035-25927-9-git-send-email-peda@axentia.se> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1484755035-25927-1-git-send-email-peda@axentia.se> References: <1484755035-25927-1-git-send-email-peda@axentia.se> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [217.210.101.82] X-ClientProxiedBy: HE1PR0801CA0032.eurprd08.prod.outlook.com (10.167.184.42) To VI1PR0202MB2558.eurprd02.prod.outlook.com (10.173.79.137) X-MS-Office365-Filtering-Correlation-Id: bae97312-14ca-4a67-eb0a-08d43fbae310 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001);SRVR:VI1PR0202MB2558; X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2558;3:ioycSgpxYUbO4hzwZfMbJV1E9dNHQC3IN+3SoMchV1wckZPnGf2XfGVUtngb2Zv59SFL7pZC5lhVj/KPFyFz85Q9Snv+77pwfq/FF8gHm9/HkX4OIADmVHG5ApSfUPRdquAXGWn6IgZXGDxa6FLTiTAPS01VelYgiCB61pT6w0sVnDPvvq6AvVi4rHtS0D2Kp/CKb458wwwg6bT0mHO/XLjfMug5sxtIz8iLKE/b/qYMzXx+OBztmkm492mDeEHxIKn5PeKNHK/37p9T5Vo0iQ==;25:Vfc+QQfiKCieWBjSrE1DBILqjN7a2pFWbkqPD/4VwEJ/qUDh/JiWXKsAiCmF3H00hLb6y5V/bncD0O0/r5j8eoZ5JyUBjsVmfr/2J+Sigj/hzvBjvouMAbJvDtT9ej0D7Y2/1dvd8UjHdpRn5Ojt3Fz2b0Wr4QQp9dmnhA6v63IMHJHKfdTRAmGX/82YmRttSTeClO36RkaUsM1k2YETi9Ui1sHUUwB2zxMTHNINoXijaHziJ6qY88OV00rHY9doJpT6+MZy0QN55Y1Is3r4umhYMny3gwsTpCXRQJiDH6Lz9DpdkjV9yDM417WcT5CloDC/kSWKkdrYmaqjd4cBDZ3JTQm0OxpJkluzQr9Epuv49JcPgeqc5dz6ub5YYqEtQq5W6UM1PP2FWwe2Hd0eyLOIy/e1RJma+t8X0466SX7sBCSoFleCtDkoV7v7W4rBVjL6KZxmNhL6/Di8Isumuw== X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2558;31:yMOvWdhL3reV3qSt4qRfBdLCovfcJbLkRl49JLOSXgozIhrOWgrqbQPeQooKhalqJ3rVG5E4efJ+aaPcwX8H7YAZLhcjhen42Fo3PVfLJ9SBiGZRcQsFEj7NDQKzZs+QM7p034kEaMQ9UJPJ6WB5brN5KWPWu8gcossx9QTJpNMfNcaYK7UuVi4nhvQLell82J38KYElL1ya77T4O3bbmO6YgDsid5Ff25tUWERxldLczR9RGO4BRVieEQtRT6SBh2g2bz/cZYABtS4Rc1DVTA==;4:jPwGF63R8IHX7HbxBqKFc73N8cvaAzqtWccWyFgzkHwbEEvSuuSlUGJ1/GBwcY5sdbKxX958548CLF2WOJkZycHt2qB/sYVmsCJzLRWczzkrCeglR/nGJxeUHEW7R5wJdhJfxmsIQuKUFDAqsBmTsTIdQ/iaQNHB4jDBYaMbt64MXvMaMVrKikY6mcJmyR1SQfc5MZRI6wIB+CMUNM+fHcWydwfRqx0rH6TvCswQPpPK5UbLa970ph8sif/w2DPBJYSZiNc5mIJEJBQ/Kkj9XQea9/SnqbxbTZFXjgIa68nYochUEA88YaXMLbxW1Fh8Gb3GnteNNFh4rIqXIo775ggkFSrs7xreGIypImfnHsCg1JQdgBTmYpLX2dtH1dBy3pY2K7aJJEBD8gm9PYEMvE65F5SxS17WXJAnUGxlGg7FSfx8VI+iQSvIPyuHG6WvqrjNJDNg/DUE6ZYYv0BzMUhFL5FTW0B3+0kl8ORJZAzDHPB44iPDFX2K+MNiWzpcub0N9Mt+Gk0DJWtXqQhG7zIwpxSQuQf5OWNQoWplmiIcHzEQjCgfVVSO3O9gLRs8zAatd1xpNp9lPp4sVT+Oj/6OSx8S1fVrYJeDj5QLOXBKjVAIqQ30wQtUB90kcsyX X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040375)(601004)(2401047)(8121501046)(5005006)(10201501046)(3002001)(6041248)(2016111802025)(20161123555025)(20161123564025)(20161123562025)(20161123560025)(6072148)(6043046);SRVR:VI1PR0202MB2558;BCL:0;PCL:0;RULEID:;SRVR:VI1PR0202MB2558; X-Forefront-PRVS: 01917B1794 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(6069001)(7916002)(39450400003)(39410400002)(39840400002)(189002)(199003)(3846002)(38730400001)(6512007)(5660300001)(50466002)(101416001)(47776003)(48376002)(54906002)(97736004)(76176999)(53936002)(189998001)(50986999)(305945005)(7416002)(4326007)(74482002)(106356001)(2950100002)(6666003)(86362001)(6116002)(81166006)(6916009)(68736007)(5003940100001)(36756003)(7736002)(2906002)(25786008)(8666007)(42186005)(2351001)(81156014)(33646002)(6486002)(110136003)(6506006)(66066001)(92566002)(105586002)(50226002)(8676002)(230783001)(2004002)(42262002)(309714004);DIR:OUT;SFP:1102;SCL:1;SRVR:VI1PR0202MB2558;H:localhost.localdomain;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;VI1PR0202MB2558;23:4I0Orhy1ekol4nIlt1P/vJSA4zDZ0H6fBQeXe9R?= =?us-ascii?Q?Qsrxgar2dlxjVbV3ItbwmLVTnLmW8ABF9CDaswgfwbD72g3INFYeTCUBSbyy?= =?us-ascii?Q?q1qruDQV63I//DZ4Foch04tcNSKDradOYs0Sa7C94spM9yMZjlx/ccVN4nN2?= =?us-ascii?Q?xh4tn+2ItyZv6wGGJzW11QcRF5OZF1upsMzGi961QLod6jqS7pK0IJ1OxrT8?= =?us-ascii?Q?JKwOmnAuxyHpdznyXLLMDaIWsLFsFO7z92EAtMy2oyaSaw5nXdwlfTqvxgDZ?= =?us-ascii?Q?UwNACVDvomFHMDBY1+xa1Ty+6XFZwaCinhAn5s4SYQj+pZFTxnFmmJItTAGo?= =?us-ascii?Q?GlDwwl6t2cwKGHC/jc/C4UqRNoJOsPUvr6NgCB5XvLodmMOwCh4tx+K7OqmM?= =?us-ascii?Q?3gCMomOuKJzQX+YXyji6EZBfhKlO+8Q/f4aRPn0j5DwsRXJoP1x5uPRWWc8Y?= =?us-ascii?Q?yg0BvHQQ+tDwOErHGLVgZr36jOhaC0Pl4PLWuAP/MYIUPJgplF/c1W0sHk9s?= =?us-ascii?Q?t2ZL9X0OYuzb1NBEZhscsI5ZnfNI/G1nTY5YRl2BCNhVXmp1HWJkzynrIzTE?= =?us-ascii?Q?2U8bedi6txxSqZX8iB4zxzii8f77rdW0u5rb3aIgdxOOiB/kfJWdfPHFp0iv?= =?us-ascii?Q?WGH+/rHjaPbEeM2+Ti5avHSZMv8dcPlzOJ2xNzrI19qJ7BjeaxH1DGzPFbu6?= =?us-ascii?Q?YWyg+OL3kwcoc8B5RvP56miNp4aYsyv3bhcELichVz0+GANoKoIcUvc9zZ6l?= =?us-ascii?Q?aXhS6TjteDpQ5d7o3npakF5IcgDj6L5kuhKxHizEskdbdkX63LsIjmhzzi17?= =?us-ascii?Q?TSZUB/cAcehaAoSa5UstF0rYygdBGSZ8k8Mi5XxHbrfLHL/iRQugDMW0gR93?= =?us-ascii?Q?kypbqXtw+Abv/7Vf7uYHTv64AJjHxBM5LuRh4RwhqpZ+T6IWUqYw4/iLTUnW?= =?us-ascii?Q?dfJ5wb3jRjlvqH5OxJ22Ov2jzbQP8i3L04vvKlMP5u1gQolvF6w8OJDcjHH4?= =?us-ascii?Q?2LSkqh9UU626fi/zgcQ1i9TFhvDLrCLC5V/NlEmohSr4ubBi9xYRE45vb4Di?= =?us-ascii?Q?WYWdbMQYeDiuLbalhqedG69vHAqBT6fw6Il2vqLYMT3AW11oIlQ+/WOGxjVb?= =?us-ascii?Q?KT2GnbfGiot65nlby3d9CMwS38Q1B+MGjVMNOSyl4hCCw4Ban2v/HaDMAAbH?= =?us-ascii?Q?pfr95Ji5UBuBLPI1C8rrTCJ5Vs3zVv2VhD18Kr28FuFpCrlHkErDwFbhG8dj?= =?us-ascii?Q?GsH8/ITM7GUHJ4Ul/BUKhiRLtNxAXr3Orva+nc+Jakwl2mbJPpWHWJGlaTQB?= =?us-ascii?Q?hlgayXw6Y2FeiSjpnKCiXl3Rxwrz++CRr4yBNBRHP8T/pVJ6j698b4gSa6oy?= =?us-ascii?Q?MnKtL5A=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2558;6:dN7u3WA3M39Pd3rvUKA7CEnkzK7fBxcjQC8uiSuqoRlRB7wEUzUj+2cz+Rwc7o2mxXv33y6XJDCS5LF9rMMTqWb3GxMNpxTELef6b5v44IMTdUOC93G3N1IIbMbqakDwOKjF73fFcM8p1z/L11fzYwabDgk8vcse1hro4Syqb/TSX2wvGo6KPM1KhSLLZT+Eh5cuOOjJwYY/VuLooCyKLsIVl9uJMEmEFs72WWfzf/DiqTkM8JEZ+aOXImfUqiX3hhJVL18kRLtSOY4ziM7bVXTdAct62XWZnNiudW8Qw4XiilGlPyJ60AihIJ+/eQKwZlqzCndfOsbsgSejBi20hXq4fBk4DCVVWAQt/9KHyfrESbHzPC8jHDMQVMa0A4Y8pBCQQxqv3UOL5UySaXe/llPlJyqmyzlhdTpy90rWGDEpKeWwoPz+ncMc9Zemc5lR;5:V5XGKU0agPYy6n4HjXs2rFnP5wRuSBwGP8iAhDj9i+TwwCULeht/99UC0zULrHtApAS1jj1uYDL/CK2SsLiUrmgYUXpYBqiiH94htYTQmhr9Z2E9G5o+JhKF8RMUoQQJMTWmqbzS2F3dMu/y+jnkRA==;24:btJ7UgY1cLBq+fGlcjogkHauonbG2SPeUEvOzZhBnBqotTDfeD1S9WiG4ArveCLPq3JUrFV6RDp5/V5wRYQ159cSBcTCp54uumBOKQ44CVk= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;VI1PR0202MB2558;7:BJ7SCOcI+EtuIiD/4cq+ThtiZSfxpEOuMkbfCSTd7oJM6GKIllXTslehIrVMQy/C4Tjs6QDdL0juONJFXKjE12yzrp19KwPsPb82unq2f4xzBPsAyB6m6w32mDUB6Xs1gAf0ns8XgUlNCnSlxDv2ybevrImDl06rrsnw0A45O24QQo/AIqSjiek2puBO2v7kZzbESTc9/YzeW5/IAlvXY9untPzyY2t/PRKXeLYc6np3ant/cYO/zQaoiJPw8eoEcMx9aXd5eLb1JPoKActk51xH6qEPPxchqnTbTXuNA7H/QrAs0i0GAZuxCQc60KYCy8cs/ElckQrd0fg25AovZrW1HL+zC8JEkvvJ9ke6B+Q7VFgUdSatFbA+A7V8K0NL7gILzpnF2cjc8yh/R0q4dBbjdypGIl7oVqVY0IfEl6aNieZQpQNJ4BoHo9aP0EtyWrv/hrmIVfUtj7NH9Hyvcg== X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jan 2017 15:58:45.5081 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0202MB2558 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. 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-simple.c | 182 +++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 drivers/i2c/muxes/i2c-mux-simple.c diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 10b3d17ae3ea..565921e09a96 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -73,6 +73,19 @@ 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" + select 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 9948fa45037f..6821d95c92a3 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -11,5 +11,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..6a7de6e91ae3 --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-simple.c @@ -0,0 +1,182 @@ +/* + * Generic simple 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 + +#define SIMPLE_PARENT_LOCKED (0) +#define SIMPLE_MUX_LOCKED (1) + +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 *)SIMPLE_PARENT_LOCKED, }, + { .compatible = "i2c-mux-simple,mux-locked", + .data = (void *)SIMPLE_MUX_LOCKED, }, + {}, +}; +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, 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); + + 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) { + 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-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