Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: Multiplexed I2C bus core support

Add multiplexed bus core support. I2C multiplexer and switches
like pca954x get instantiated as new adapters per port.

Signed-off-by: Michael Lawnick <ml.lawnick@gmx.de>
Acked-by: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Jean Delvare <khali@linux-fr.org>

authored by

Michael Lawnick and committed by
Jean Delvare
0826374b dafc50d1

+327 -8
+11
drivers/i2c/Kconfig
··· 47 47 This support is also available as a module. If so, the module 48 48 will be called i2c-dev. 49 49 50 + config I2C_MUX 51 + tristate "I2C bus multiplexing support" 52 + depends on EXPERIMENTAL 53 + help 54 + Say Y here if you want the I2C core to support the ability to 55 + handle multiplexed I2C bus topologies, by presenting each 56 + multiplexed segment as a I2C adapter. 57 + 58 + This support is also available as a module. If so, the module 59 + will be called i2c-mux. 60 + 50 61 config I2C_HELPER_AUTO 51 62 bool "Autoselect pertinent helper modules" 52 63 default y
+1
drivers/i2c/Makefile
··· 6 6 obj-$(CONFIG_I2C) += i2c-core.o 7 7 obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o 8 8 obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o 9 + obj-$(CONFIG_I2C_MUX) += i2c-mux.o 9 10 obj-y += algos/ busses/ 10 11 11 12 ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
+57 -7
drivers/i2c/i2c-core.c
··· 20 20 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>. 21 21 All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> 22 22 SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and 23 - Jean Delvare <khali@linux-fr.org> */ 23 + Jean Delvare <khali@linux-fr.org> 24 + Mux support by Rodolfo Giometti <giometti@enneenne.com> and 25 + Michael Lawnick <michael.lawnick.ext@nsn.com> */ 24 26 25 27 #include <linux/module.h> 26 28 #include <linux/kernel.h> ··· 425 423 return 0; 426 424 } 427 425 426 + /* walk up mux tree */ 427 + static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr) 428 + { 429 + int result; 430 + 431 + result = device_for_each_child(&adapter->dev, &addr, 432 + __i2c_check_addr_busy); 433 + 434 + if (!result && i2c_parent_is_i2c_adapter(adapter)) 435 + result = i2c_check_mux_parents( 436 + to_i2c_adapter(adapter->dev.parent), addr); 437 + 438 + return result; 439 + } 440 + 441 + /* recurse down mux tree */ 442 + static int i2c_check_mux_children(struct device *dev, void *addrp) 443 + { 444 + int result; 445 + 446 + if (dev->type == &i2c_adapter_type) 447 + result = device_for_each_child(dev, addrp, 448 + i2c_check_mux_children); 449 + else 450 + result = __i2c_check_addr_busy(dev, addrp); 451 + 452 + return result; 453 + } 454 + 428 455 static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) 429 456 { 430 - return device_for_each_child(&adapter->dev, &addr, 431 - __i2c_check_addr_busy); 457 + int result = 0; 458 + 459 + if (i2c_parent_is_i2c_adapter(adapter)) 460 + result = i2c_check_mux_parents( 461 + to_i2c_adapter(adapter->dev.parent), addr); 462 + 463 + if (!result) 464 + result = device_for_each_child(&adapter->dev, &addr, 465 + i2c_check_mux_children); 466 + 467 + return result; 432 468 } 433 469 434 470 /** ··· 475 435 */ 476 436 void i2c_lock_adapter(struct i2c_adapter *adapter) 477 437 { 478 - rt_mutex_lock(&adapter->bus_lock); 438 + if (i2c_parent_is_i2c_adapter(adapter)) 439 + i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent)); 440 + else 441 + rt_mutex_lock(&adapter->bus_lock); 479 442 } 480 443 EXPORT_SYMBOL_GPL(i2c_lock_adapter); 481 444 ··· 488 445 */ 489 446 static int i2c_trylock_adapter(struct i2c_adapter *adapter) 490 447 { 491 - return rt_mutex_trylock(&adapter->bus_lock); 448 + if (i2c_parent_is_i2c_adapter(adapter)) 449 + return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent)); 450 + else 451 + return rt_mutex_trylock(&adapter->bus_lock); 492 452 } 493 453 494 454 /** ··· 500 454 */ 501 455 void i2c_unlock_adapter(struct i2c_adapter *adapter) 502 456 { 503 - rt_mutex_unlock(&adapter->bus_lock); 457 + if (i2c_parent_is_i2c_adapter(adapter)) 458 + i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent)); 459 + else 460 + rt_mutex_unlock(&adapter->bus_lock); 504 461 } 505 462 EXPORT_SYMBOL_GPL(i2c_unlock_adapter); 506 463 ··· 792 743 NULL 793 744 }; 794 745 795 - static struct device_type i2c_adapter_type = { 746 + struct device_type i2c_adapter_type = { 796 747 .groups = i2c_adapter_attr_groups, 797 748 .release = i2c_adapter_dev_release, 798 749 }; 750 + EXPORT_SYMBOL_GPL(i2c_adapter_type); 799 751 800 752 #ifdef CONFIG_I2C_COMPAT 801 753 static struct class_compat *i2c_adapter_compat_class;
+39 -1
drivers/i2c/i2c-dev.c
··· 189 189 return dev->driver ? -EBUSY : 0; 190 190 } 191 191 192 + /* walk up mux tree */ 193 + static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr) 194 + { 195 + int result; 196 + 197 + result = device_for_each_child(&adapter->dev, &addr, i2cdev_check); 198 + 199 + if (!result && i2c_parent_is_i2c_adapter(adapter)) 200 + result = i2cdev_check_mux_parents( 201 + to_i2c_adapter(adapter->dev.parent), addr); 202 + 203 + return result; 204 + } 205 + 206 + /* recurse down mux tree */ 207 + static int i2cdev_check_mux_children(struct device *dev, void *addrp) 208 + { 209 + int result; 210 + 211 + if (dev->type == &i2c_adapter_type) 212 + result = device_for_each_child(dev, addrp, 213 + i2cdev_check_mux_children); 214 + else 215 + result = i2cdev_check(dev, addrp); 216 + 217 + return result; 218 + } 219 + 192 220 /* This address checking function differs from the one in i2c-core 193 221 in that it considers an address with a registered device, but no 194 222 driver bound to it, as NOT busy. */ 195 223 static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) 196 224 { 197 - return device_for_each_child(&adapter->dev, &addr, i2cdev_check); 225 + int result = 0; 226 + 227 + if (i2c_parent_is_i2c_adapter(adapter)) 228 + result = i2cdev_check_mux_parents( 229 + to_i2c_adapter(adapter->dev.parent), addr); 230 + 231 + if (!result) 232 + result = device_for_each_child(&adapter->dev, &addr, 233 + i2cdev_check_mux_children); 234 + 235 + return result; 198 236 } 199 237 200 238 static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+165
drivers/i2c/i2c-mux.c
··· 1 + /* 2 + * Multiplexed I2C bus driver. 3 + * 4 + * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it> 5 + * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it> 6 + * Copyright (c) 2009-2010 NSN GmbH & Co KG <michael.lawnick.ext@nsn.com> 7 + * 8 + * Simplifies access to complex multiplexed I2C bus topologies, by presenting 9 + * each multiplexed bus segment as an additional I2C adapter. 10 + * Supports multi-level mux'ing (mux behind a mux). 11 + * 12 + * Based on: 13 + * i2c-virt.c from Kumar Gala <galak@kernel.crashing.org> 14 + * i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc. 15 + * i2c-virtual.c from Brian Kuschak <bkuschak@yahoo.com> 16 + * 17 + * This file is licensed under the terms of the GNU General Public 18 + * License version 2. This program is licensed "as is" without any 19 + * warranty of any kind, whether express or implied. 20 + */ 21 + 22 + #include <linux/kernel.h> 23 + #include <linux/module.h> 24 + #include <linux/slab.h> 25 + #include <linux/i2c.h> 26 + #include <linux/i2c-mux.h> 27 + 28 + /* multiplexer per channel data */ 29 + struct i2c_mux_priv { 30 + struct i2c_adapter adap; 31 + struct i2c_algorithm algo; 32 + 33 + struct i2c_adapter *parent; 34 + void *mux_dev; /* the mux chip/device */ 35 + u32 chan_id; /* the channel id */ 36 + 37 + int (*select)(struct i2c_adapter *, void *mux_dev, u32 chan_id); 38 + int (*deselect)(struct i2c_adapter *, void *mux_dev, u32 chan_id); 39 + }; 40 + 41 + static int i2c_mux_master_xfer(struct i2c_adapter *adap, 42 + struct i2c_msg msgs[], int num) 43 + { 44 + struct i2c_mux_priv *priv = adap->algo_data; 45 + struct i2c_adapter *parent = priv->parent; 46 + int ret; 47 + 48 + /* Switch to the right mux port and perform the transfer. */ 49 + 50 + ret = priv->select(parent, priv->mux_dev, priv->chan_id); 51 + if (ret >= 0) 52 + ret = parent->algo->master_xfer(parent, msgs, num); 53 + if (priv->deselect) 54 + priv->deselect(parent, priv->mux_dev, priv->chan_id); 55 + 56 + return ret; 57 + } 58 + 59 + static int i2c_mux_smbus_xfer(struct i2c_adapter *adap, 60 + u16 addr, unsigned short flags, 61 + char read_write, u8 command, 62 + int size, union i2c_smbus_data *data) 63 + { 64 + struct i2c_mux_priv *priv = adap->algo_data; 65 + struct i2c_adapter *parent = priv->parent; 66 + int ret; 67 + 68 + /* Select the right mux port and perform the transfer. */ 69 + 70 + ret = priv->select(parent, priv->mux_dev, priv->chan_id); 71 + if (ret >= 0) 72 + ret = parent->algo->smbus_xfer(parent, addr, flags, 73 + read_write, command, size, data); 74 + if (priv->deselect) 75 + priv->deselect(parent, priv->mux_dev, priv->chan_id); 76 + 77 + return ret; 78 + } 79 + 80 + /* Return the parent's functionality */ 81 + static u32 i2c_mux_functionality(struct i2c_adapter *adap) 82 + { 83 + struct i2c_mux_priv *priv = adap->algo_data; 84 + struct i2c_adapter *parent = priv->parent; 85 + 86 + return parent->algo->functionality(parent); 87 + } 88 + 89 + struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, 90 + void *mux_dev, u32 force_nr, u32 chan_id, 91 + int (*select) (struct i2c_adapter *, 92 + void *, u32), 93 + int (*deselect) (struct i2c_adapter *, 94 + void *, u32)) 95 + { 96 + struct i2c_mux_priv *priv; 97 + int ret; 98 + 99 + priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL); 100 + if (!priv) 101 + return NULL; 102 + 103 + /* Set up private adapter data */ 104 + priv->parent = parent; 105 + priv->mux_dev = mux_dev; 106 + priv->chan_id = chan_id; 107 + priv->select = select; 108 + priv->deselect = deselect; 109 + 110 + /* Need to do algo dynamically because we don't know ahead 111 + * of time what sort of physical adapter we'll be dealing with. 112 + */ 113 + if (parent->algo->master_xfer) 114 + priv->algo.master_xfer = i2c_mux_master_xfer; 115 + if (parent->algo->smbus_xfer) 116 + priv->algo.smbus_xfer = i2c_mux_smbus_xfer; 117 + priv->algo.functionality = i2c_mux_functionality; 118 + 119 + /* Now fill out new adapter structure */ 120 + snprintf(priv->adap.name, sizeof(priv->adap.name), 121 + "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id); 122 + priv->adap.owner = THIS_MODULE; 123 + priv->adap.id = parent->id; 124 + priv->adap.algo = &priv->algo; 125 + priv->adap.algo_data = priv; 126 + priv->adap.dev.parent = &parent->dev; 127 + 128 + if (force_nr) { 129 + priv->adap.nr = force_nr; 130 + ret = i2c_add_numbered_adapter(&priv->adap); 131 + } else { 132 + ret = i2c_add_adapter(&priv->adap); 133 + } 134 + if (ret < 0) { 135 + dev_err(&parent->dev, 136 + "failed to add mux-adapter (error=%d)\n", 137 + ret); 138 + kfree(priv); 139 + return NULL; 140 + } 141 + 142 + dev_info(&parent->dev, "Added multiplexed i2c bus %d\n", 143 + i2c_adapter_id(&priv->adap)); 144 + 145 + return &priv->adap; 146 + } 147 + EXPORT_SYMBOL_GPL(i2c_add_mux_adapter); 148 + 149 + int i2c_del_mux_adapter(struct i2c_adapter *adap) 150 + { 151 + struct i2c_mux_priv *priv = adap->algo_data; 152 + int ret; 153 + 154 + ret = i2c_del_adapter(adap); 155 + if (ret < 0) 156 + return ret; 157 + kfree(priv); 158 + 159 + return 0; 160 + } 161 + EXPORT_SYMBOL_GPL(i2c_del_mux_adapter); 162 + 163 + MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 164 + MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses"); 165 + MODULE_LICENSE("GPL v2");
+46
include/linux/i2c-mux.h
··· 1 + /* 2 + * 3 + * i2c-mux.h - functions for the i2c-bus mux support 4 + * 5 + * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it> 6 + * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it> 7 + * Michael Lawnick <michael.lawnick.ext@nsn.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with this program; if not, write to the Free Software 21 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 + */ 23 + 24 + #ifndef _LINUX_I2C_MUX_H 25 + #define _LINUX_I2C_MUX_H 26 + 27 + #ifdef __KERNEL__ 28 + 29 + /* 30 + * Called to create a i2c bus on a multiplexed bus segment. 31 + * The mux_dev and chan_id parameters are passed to the select 32 + * and deselect callback functions to perform hardware-specific 33 + * mux control. 34 + */ 35 + struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, 36 + void *mux_dev, u32 force_nr, u32 chan_id, 37 + int (*select) (struct i2c_adapter *, 38 + void *mux_dev, u32 chan_id), 39 + int (*deselect) (struct i2c_adapter *, 40 + void *mux_dev, u32 chan_id)); 41 + 42 + int i2c_del_mux_adapter(struct i2c_adapter *adap); 43 + 44 + #endif /* __KERNEL__ */ 45 + 46 + #endif /* _LINUX_I2C_MUX_H */
+8
include/linux/i2c.h
··· 37 37 #include <linux/of.h> /* for struct device_node */ 38 38 39 39 extern struct bus_type i2c_bus_type; 40 + extern struct device_type i2c_adapter_type; 40 41 41 42 /* --- General options ------------------------------------------------ */ 42 43 ··· 382 381 static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data) 383 382 { 384 383 dev_set_drvdata(&dev->dev, data); 384 + } 385 + 386 + static inline int i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter) 387 + { 388 + return adapter->dev.parent != NULL 389 + && adapter->dev.parent->bus == &i2c_bus_type 390 + && adapter->dev.parent->type == &i2c_adapter_type; 385 391 } 386 392 387 393 /* Adapter locking functions, exported for shared pin cases */