aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/i2c-core.c
diff options
context:
space:
mode:
authorMichael Lawnick <ml.lawnick@gmx.de>2010-08-11 12:21:02 -0400
committerJean Delvare <khali@linux-fr.org>2010-08-11 12:21:02 -0400
commit0826374bff57411d239f2fcb15da3c35af0a93cd (patch)
tree514d4361cfc9cc546306612de3464def7fe8a7cd /drivers/i2c/i2c-core.c
parentdafc50d141c27959dbd3a1cfe9857a86d23402a7 (diff)
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>
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r--drivers/i2c/i2c-core.c64
1 files changed, 57 insertions, 7 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 97f96b66653c..6649176de940 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -20,7 +20,9 @@
20/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>. 20/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
21 All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> 21 All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
22 SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and 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#include <linux/module.h> 27#include <linux/module.h>
26#include <linux/kernel.h> 28#include <linux/kernel.h>
@@ -423,10 +425,48 @@ static int __i2c_check_addr_busy(struct device *dev, void *addrp)
423 return 0; 425 return 0;
424} 426}
425 427
428/* walk up mux tree */
429static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
430{
431 int result;
432
433 result = device_for_each_child(&adapter->dev, &addr,
434 __i2c_check_addr_busy);
435
436 if (!result && i2c_parent_is_i2c_adapter(adapter))
437 result = i2c_check_mux_parents(
438 to_i2c_adapter(adapter->dev.parent), addr);
439
440 return result;
441}
442
443/* recurse down mux tree */
444static int i2c_check_mux_children(struct device *dev, void *addrp)
445{
446 int result;
447
448 if (dev->type == &i2c_adapter_type)
449 result = device_for_each_child(dev, addrp,
450 i2c_check_mux_children);
451 else
452 result = __i2c_check_addr_busy(dev, addrp);
453
454 return result;
455}
456
426static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) 457static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
427{ 458{
428 return device_for_each_child(&adapter->dev, &addr, 459 int result = 0;
429 __i2c_check_addr_busy); 460
461 if (i2c_parent_is_i2c_adapter(adapter))
462 result = i2c_check_mux_parents(
463 to_i2c_adapter(adapter->dev.parent), addr);
464
465 if (!result)
466 result = device_for_each_child(&adapter->dev, &addr,
467 i2c_check_mux_children);
468
469 return result;
430} 470}
431 471
432/** 472/**
@@ -435,7 +475,10 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
435 */ 475 */
436void i2c_lock_adapter(struct i2c_adapter *adapter) 476void i2c_lock_adapter(struct i2c_adapter *adapter)
437{ 477{
438 rt_mutex_lock(&adapter->bus_lock); 478 if (i2c_parent_is_i2c_adapter(adapter))
479 i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent));
480 else
481 rt_mutex_lock(&adapter->bus_lock);
439} 482}
440EXPORT_SYMBOL_GPL(i2c_lock_adapter); 483EXPORT_SYMBOL_GPL(i2c_lock_adapter);
441 484
@@ -445,7 +488,10 @@ EXPORT_SYMBOL_GPL(i2c_lock_adapter);
445 */ 488 */
446static int i2c_trylock_adapter(struct i2c_adapter *adapter) 489static int i2c_trylock_adapter(struct i2c_adapter *adapter)
447{ 490{
448 return rt_mutex_trylock(&adapter->bus_lock); 491 if (i2c_parent_is_i2c_adapter(adapter))
492 return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent));
493 else
494 return rt_mutex_trylock(&adapter->bus_lock);
449} 495}
450 496
451/** 497/**
@@ -454,7 +500,10 @@ static int i2c_trylock_adapter(struct i2c_adapter *adapter)
454 */ 500 */
455void i2c_unlock_adapter(struct i2c_adapter *adapter) 501void i2c_unlock_adapter(struct i2c_adapter *adapter)
456{ 502{
457 rt_mutex_unlock(&adapter->bus_lock); 503 if (i2c_parent_is_i2c_adapter(adapter))
504 i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent));
505 else
506 rt_mutex_unlock(&adapter->bus_lock);
458} 507}
459EXPORT_SYMBOL_GPL(i2c_unlock_adapter); 508EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
460 509
@@ -743,10 +792,11 @@ static const struct attribute_group *i2c_adapter_attr_groups[] = {
743 NULL 792 NULL
744}; 793};
745 794
746static struct device_type i2c_adapter_type = { 795struct device_type i2c_adapter_type = {
747 .groups = i2c_adapter_attr_groups, 796 .groups = i2c_adapter_attr_groups,
748 .release = i2c_adapter_dev_release, 797 .release = i2c_adapter_dev_release,
749}; 798};
799EXPORT_SYMBOL_GPL(i2c_adapter_type);
750 800
751#ifdef CONFIG_I2C_COMPAT 801#ifdef CONFIG_I2C_COMPAT
752static struct class_compat *i2c_adapter_compat_class; 802static struct class_compat *i2c_adapter_compat_class;