* [PATCH v2] i2c: virtual i2c adapter support.
@ 2008-06-19 17:14 Rodolfo Giometti
[not found] ` <1213895701-9872-1-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-19 17:14 UTC (permalink / raw)
To: i2c-GZX6beZjE8VD60Wz+7aTrA; +Cc: Ben Dooks, Kumar Gala
Changelog v2:
* i2c-virt: license issue fix up.
* i2c: fix up race condition during virtual adapters removal.
* i2c: better code for virtual adapters definition.
Rodolfo
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] i2c: virtual i2c adapter support.
[not found] ` <1213895701-9872-1-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
@ 2008-06-19 17:14 ` Rodolfo Giometti
[not found] ` <1213895701-9872-2-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-19 17:14 UTC (permalink / raw)
To: i2c-GZX6beZjE8VD60Wz+7aTrA; +Cc: Ben Dooks, Kumar Gala
Simplifies access to complex multiplexed I2C bus topologies, by
presenting each multiplexed bus segment as a virtual I2C adapter. In
this manner I2C devices "after" the multiplexer can ba managed as
usual.
Signed-off-by: Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
---
drivers/i2c/Kconfig | 9 +++
drivers/i2c/Makefile | 1 +
drivers/i2c/i2c-core.c | 37 +++++++---
drivers/i2c/i2c-virt.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c-id.h | 3 +
include/linux/i2c.h | 18 +++++
6 files changed, 246 insertions(+), 11 deletions(-)
create mode 100644 drivers/i2c/i2c-virt.c
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 9686734..053fe2f 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -27,6 +27,15 @@ config I2C_BOARDINFO
boolean
default y
+config I2C_VIRT
+ tristate "I2C virtual adapter support"
+ depends on I2C
+ help
+ Say Y here if you want the I2C core to support the ability to have
+ virtual adapters. Virtual adapters are useful to handle multiplexed
+ I2C bus topologies, by presenting each multiplexed segment as a
+ I2C adapter.
+
config I2C_CHARDEV
tristate "I2C device interface"
help
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index ba26e6c..db72ed9 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_VIRT) += i2c-virt.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/ chips/ algos/
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d0175f4..a0261ea 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -573,34 +573,32 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data)
}
/**
- * i2c_del_adapter - unregister I2C adapter
+ * i2c_del_adapter_nolock - unregister I2C adapter
* @adap: the adapter being unregistered
* Context: can sleep
*
* This unregisters an I2C adapter which was previously registered
- * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter but without lock
+ * protection! For normal usage you may wish using @i2c_del_adapter.
*/
-int i2c_del_adapter(struct i2c_adapter *adap)
+int i2c_del_adapter_nolock(struct i2c_adapter *adap)
{
struct list_head *item, *_n;
struct i2c_client *client;
- int res = 0;
-
- mutex_lock(&core_lock);
+ int res;
/* First make sure that this adapter was ever added */
if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
pr_debug("i2c-core: attempting to delete unregistered "
"adapter [%s]\n", adap->name);
- res = -EINVAL;
- goto out_unlock;
+ return -EINVAL;
}
/* Tell drivers about this removal */
res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
i2c_do_del_adapter);
if (res)
- goto out_unlock;
+ return res;
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
@@ -621,7 +619,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
dev_err(&adap->dev, "detach_client failed for client "
"[%s] at address 0x%02x\n", client->name,
client->addr);
- goto out_unlock;
+ return res;
}
}
@@ -637,8 +635,25 @@ int i2c_del_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
- out_unlock:
+ return 0;
+}
+EXPORT_SYMBOL(i2c_del_adapter_nolock);
+
+/**
+ * i2c_del_adapter - unregister I2C adapter
+ * @adap: the adapter being unregistered
+ * Context: can sleep
+ *
+ * The same as @i2c_del_adapter_nolock but with lock protection.
+ */
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+ int res;
+
+ mutex_lock(&core_lock);
+ res = i2c_del_adapter_nolock(adap);
mutex_unlock(&core_lock);
+
return res;
}
EXPORT_SYMBOL(i2c_del_adapter);
diff --git a/drivers/i2c/i2c-virt.c b/drivers/i2c/i2c-virt.c
new file mode 100644
index 0000000..b057f68
--- /dev/null
+++ b/drivers/i2c/i2c-virt.c
@@ -0,0 +1,189 @@
+/*
+ * i2c-virt.c - Virtual I2C bus driver.
+ *
+ * Copyright (c) 2008 Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
+ * Copyright (c) 2008 Eurotech S.p.A. <info-ymFC7zkAqBI1GQ1Ptb7lUw@public.gmane.org>
+ *
+ * Simplifies access to complex multiplexed I2C bus topologies, by presenting
+ * each multiplexed bus segment as a virtual I2C adapter. Supports multi-level
+ * mux'ing (mux behind a mux).
+ *
+ * Based on:
+ * i2c-virt.c from Kumar Gala <galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
+ * i2c-virtual.c from Copyright (c) 2004 Google, Inc. (Ken Harrenstien)
+ * i2c-virtual.c from Brian Kuschak <bkuschak-/E1597aS9LQAvxtiuMwx3w@public.gmane.org>
+ * which was:
+ * Adapted from i2c-adap-ibm_ocp.c
+ * Original file Copyright 2000-2002 MontaVista Software Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+
+struct i2c_virt_priv {
+ struct i2c_adapter adap;
+ struct i2c_algorithm algo;
+
+ struct i2c_adapter *parent_adap;
+ struct i2c_client *client; /* The mux chip/device */
+
+ u32 id; /* the mux id */
+
+ int (*select)(struct i2c_adapter *, struct i2c_client *, u32);
+ /* Enable the mux */
+ int (*deselect)(struct i2c_adapter *, struct i2c_client *, u32);
+ /* Disable the mux */
+};
+
+#define VIRT_TIMEOUT (HZ/2)
+#define VIRT_RETRIES 3
+
+static int i2c_virt_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_virt_priv *priv = adap->algo_data;
+ struct i2c_adapter *parent = priv->parent_adap;
+ int ret;
+
+ /* Grab the lock for the parent adapter. We already hold the lock for
+ * the virtual adapter. Then select the right mux port and perform
+ * the transfer.
+ */
+
+ mutex_lock(&parent->bus_lock);
+
+ ret = priv->select(parent, priv->client, priv->id);
+ if (ret >= 0)
+ ret = parent->algo->master_xfer(parent, msgs, num);
+ priv->deselect(parent, priv->client, priv->id);
+
+ mutex_unlock(&parent->bus_lock);
+
+ return ret;
+}
+
+static int i2c_virt_smbus_xfer(struct i2c_adapter *adap,
+ u16 addr, unsigned short flags,
+ char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct i2c_virt_priv *priv = adap->algo_data;
+ struct i2c_adapter *parent = priv->parent_adap;
+ int ret;
+
+ /* Grab the lock for the parent adapter. We already hold the lock for
+ * the virtual adapter. Then select the right mux port and perform
+ * the transfer.
+ */
+
+ mutex_lock(&parent->bus_lock);
+
+ ret = priv->select(parent, priv->client, priv->id);
+ if (ret == 0)
+ ret = parent->algo->smbus_xfer(parent, addr, flags,
+ read_write, command, size, data);
+ priv->deselect(parent, priv->client, priv->id);
+
+ mutex_unlock(&parent->bus_lock);
+
+ return ret;
+}
+
+/* Return the parent's functionality for the virtual adapter */
+static u32 i2c_virt_functionality(struct i2c_adapter *adap)
+{
+ struct i2c_virt_priv *priv = adap->algo_data;
+ struct i2c_adapter *parent = priv->parent_adap;
+
+ return parent->algo->functionality(parent);
+}
+
+struct i2c_adapter *i2c_add_virt_adapter(struct i2c_adapter *parent,
+ struct i2c_client *client,
+ u32 force_nr, u32 mux_val,
+ int (*select_cb) (struct i2c_adapter *,
+ struct i2c_client *, u32),
+ int (*deselect_cb) (struct i2c_adapter *,
+ struct i2c_client *, u32))
+{
+ struct i2c_virt_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(struct i2c_virt_priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ /* Set up private adapter data */
+ priv->parent_adap = parent;
+ priv->client = client;
+ priv->id = mux_val;
+ priv->select = select_cb;
+ priv->deselect = deselect_cb;
+
+ /* Need to do algo dynamically because we don't know ahead
+ * of time what sort of physical adapter we'll be dealing with.
+ */
+ if (parent->algo->master_xfer)
+ priv->algo.master_xfer = i2c_virt_master_xfer;
+ if (parent->algo->smbus_xfer)
+ priv->algo.smbus_xfer = i2c_virt_smbus_xfer;
+ priv->algo.functionality = i2c_virt_functionality;
+
+ /* Now fill out new adapter structure */
+ snprintf(priv->adap.name, sizeof(priv->adap.name),
+ "i2c-%d-virt (mux %02x:%02x)",
+ i2c_adapter_id(parent), client->addr, mux_val);
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.id = I2C_HW_VIRT | i2c_adapter_id(parent);
+ priv->adap.algo = &priv->algo;
+ priv->adap.algo_data = priv;
+ priv->adap.timeout = VIRT_TIMEOUT;
+ priv->adap.retries = VIRT_RETRIES;
+ priv->adap.dev.parent = &parent->dev;
+
+ if (force_nr) {
+ priv->adap.nr = force_nr;
+ ret = i2c_add_numbered_adapter(&priv->adap);
+ } else
+ ret = i2c_add_adapter(&priv->adap);
+ if (ret < 0) {
+ kfree(priv);
+ return NULL;
+ }
+
+ dev_info(&parent->dev, "i2c-virt-%d: Virtual I2C bus - "
+ "physical bus i2c-%d, multiplexer 0x%02x port %d\n",
+ i2c_adapter_id(&priv->adap), i2c_adapter_id(parent),
+ client->addr, mux_val);
+
+ return &priv->adap;
+}
+EXPORT_SYMBOL_GPL(i2c_add_virt_adapter);
+
+int i2c_del_virt_adapter(struct i2c_adapter *adap)
+{
+ struct i2c_virt_priv *priv = adap->algo_data;
+ int ret;
+
+ /* Should use nolock version since I2C core_lock is hold by
+ * @i2c_del_driver.
+ */
+ ret = i2c_del_adapter_nolock(adap);
+ if (ret < 0)
+ return ret;
+ kfree(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_del_virt_adapter);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org, " \
+ "Kumar Gala <galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>");
+MODULE_DESCRIPTION("Virtual I2C driver for multiplexed I2C busses");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 580acc9..ba19ef9 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -176,4 +176,7 @@
#define I2C_HW_SAA7146 0x060000 /* SAA7146 video decoder bus */
#define I2C_HW_SAA7134 0x090000 /* SAA7134 video decoder bus */
+/* --- Virtual adapter mark */
+#define I2C_HW_VIRT 0x80000000
+
#endif /* LINUX_I2C_ID_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index fb9af6a..2ea8555 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -381,6 +381,7 @@ struct i2c_client_address_data {
extern int i2c_add_adapter(struct i2c_adapter *);
extern int i2c_del_adapter(struct i2c_adapter *);
extern int i2c_add_numbered_adapter(struct i2c_adapter *);
+extern int i2c_del_adapter_nolock(struct i2c_adapter *);
extern int i2c_register_driver(struct module *, struct i2c_driver *);
extern void i2c_del_driver(struct i2c_driver *);
@@ -553,6 +554,23 @@ union i2c_smbus_data {
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_I2C_BLOCK_DATA 8
+/*
+ * Called to create a 'virtual' i2c bus which represents a multiplexed bus
+ * segment. The client and mux_val are passed to the select and deselect
+ * callback functions to perform hardware-specific mux control.
+ *
+ * The caller is expected to have the core_lists lock
+ */
+struct i2c_adapter *i2c_add_virt_adapter(struct i2c_adapter *parent,
+ struct i2c_client *client,
+ u32 force_nr, u32 mux_val,
+ int (*select_cb) (struct i2c_adapter *,
+ struct i2c_client *, u32),
+ int (*deselect_cb) (struct i2c_adapter *,
+ struct i2c_client *, u32));
+
+int i2c_del_virt_adapter(struct i2c_adapter *adap);
+
#ifdef __KERNEL__
--
1.5.4.3
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH] i2c: multiplexer i2c devices.
[not found] ` <1213895701-9872-2-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
@ 2008-06-19 17:15 ` Rodolfo Giometti
[not found] ` <1213895701-9872-3-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
2008-06-22 8:37 ` [PATCH] i2c: virtual i2c adapter support Peter Korsgaard
1 sibling, 1 reply; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-19 17:15 UTC (permalink / raw)
To: i2c-GZX6beZjE8VD60Wz+7aTrA; +Cc: Ben Dooks, Kumar Gala
Define a proper configuration structure and new directory to hold
multiplexer i2c device drivers.
Signed-off-by: Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
---
drivers/i2c/Kconfig | 2 ++
drivers/i2c/Makefile | 2 +-
drivers/i2c/muxes/Kconfig | 8 ++++++++
3 files changed, 11 insertions(+), 1 deletions(-)
create mode 100644 drivers/i2c/muxes/Kconfig
create mode 100644 drivers/i2c/muxes/Makefile
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 053fe2f..efc39a1 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -36,6 +36,8 @@ config I2C_VIRT
I2C bus topologies, by presenting each multiplexed segment as a
I2C adapter.
+source drivers/i2c/muxes/Kconfig
+
config I2C_CHARDEV
tristate "I2C device interface"
help
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index db72ed9..6e59b8e 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_VIRT) += i2c-virt.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
-obj-y += busses/ chips/ algos/
+obj-y += busses/ chips/ muxes/ algos/
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
new file mode 100644
index 0000000..f69f326
--- /dev/null
+++ b/drivers/i2c/muxes/Kconfig
@@ -0,0 +1,8 @@
+#
+# Multiplexer I2C chip drivers configuration
+#
+
+menu "Multiplexer I2C Chip support"
+ depends on I2C && I2C_VIRT && EXPERIMENTAL
+
+endmenu
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
new file mode 100644
index 0000000..e69de29
--
1.5.4.3
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH] i2c: driver for PCA954x I2C multiplexer series.
[not found] ` <1213895701-9872-3-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
@ 2008-06-19 17:15 ` Rodolfo Giometti
0 siblings, 0 replies; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-19 17:15 UTC (permalink / raw)
To: i2c-GZX6beZjE8VD60Wz+7aTrA; +Cc: Ben Dooks, Kumar Gala
Signed-off-by: Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
---
drivers/i2c/muxes/Kconfig | 9 ++
drivers/i2c/muxes/Makefile | 8 +
drivers/i2c/muxes/pca954x.c | 300 +++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c/pca954x.h | 6 +
4 files changed, 323 insertions(+), 0 deletions(-)
create mode 100644 drivers/i2c/muxes/pca954x.c
create mode 100644 include/linux/i2c/pca954x.h
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index f69f326..5a869db 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -5,4 +5,13 @@
menu "Multiplexer I2C Chip support"
depends on I2C && I2C_VIRT && EXPERIMENTAL
+config I2CVIRT_PCA954x
+ tristate "Philips PCA953x I2C Mux/switches"
+ help
+ If you say yes here you get support for the Philips PCA954x
+ I2C mux/switch devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called pca954x.
+
endmenu
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index e69de29..918ba1d 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for multiplexer I2C chip drivers.
+
+obj-$(CONFIG_I2CVIRT_PCA954x) += pca954x.o
+
+ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
new file mode 100644
index 0000000..66efbca
--- /dev/null
+++ b/drivers/i2c/muxes/pca954x.c
@@ -0,0 +1,300 @@
+/*
+ * pca954x.c - I2C multiplexer
+ *
+ * Copyright (c) 2008 Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
+ * Copyright (c) 2008 Eurotech S.p.A. <info-ymFC7zkAqBI1GQ1Ptb7lUw@public.gmane.org>
+ *
+ * This module supports the PCA954x series of I2C multiplexer/switch chips
+ * made by Philips Semiconductors.
+ * This includes the:
+ * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
+ * and PCA9548.
+ *
+ * These chips are all controlled via the I2C bus itself, and all have a
+ * single 8-bit register (normally at 0x70). The upstream "parent" bus fans
+ * out to two, four, or eight downstream busses or channels; which of these
+ * are selected is determined by the chip type and register contents. A
+ * mux can select only one sub-bus at a time; a switch can select any
+ * combination simultaneously.
+ *
+ * Based on:
+ * pca954x.c from Kumar Gala <galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
+ * Copyright (C) 2006
+ *
+ * Based on:
+ * pca954x.c from Ken Harrenstien
+ * Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
+ *
+ * Based on:
+ * i2c-virtual_cb.c from Brian Kuschak <bkuschak-/E1597aS9LQAvxtiuMwx3w@public.gmane.org>
+ * and
+ * pca9540.c from Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>, which was
+ * based on pcf8574.c from the same project by Frodo Looijaard,
+ * Philip Edelbrock, Dan Eaton and Aurelien Jarno.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+
+#include <linux/i2c/pca954x.h>
+
+#define PCA954X_MAX_NCHANS 8
+
+enum pca_type {
+ pca_9540,
+ pca_9542,
+ pca_9543,
+ pca_9544,
+ pca_9545,
+ pca_9546,
+ pca_9547,
+ pca_9548,
+};
+
+struct pca954x {
+ struct i2c_client *client;
+ struct i2c_client dev;
+ unsigned int type;
+ u8 last_chan;
+ struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
+};
+
+struct chip_desc {
+ u8 nchans;
+ u8 enable; /* used for muxes only */
+ enum muxtype {
+ pca954x_ismux = 0,
+ pca954x_isswi
+ } muxtype;
+};
+
+/* Provide specs for the PCA954x types we know about */
+static struct chip_desc chips[] = {
+ [pca_9540] = {
+ .nchans = 2,
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9542] = {
+ .nchans = 2,
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9543] = {
+ .nchans = 2,
+ .enable = 0x0,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9544] = {
+ .nchans = 4,
+ .enable = 0x4,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9542] = {
+ .nchans = 4,
+ .enable = 0x0,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9542] = {
+ .nchans = 4,
+ .enable = 0x0,
+ .muxtype = pca954x_isswi,
+ },
+ [pca_9542] = {
+ .nchans = 8,
+ .enable = 0x8,
+ .muxtype = pca954x_ismux,
+ },
+ [pca_9542] = {
+ .nchans = 8,
+ .enable = 0x0,
+ .muxtype = pca954x_isswi,
+ },
+};
+
+static const struct i2c_device_id pca954x_id[] = {
+ { "pca9540", pca_9540 },
+ { "pca9542", pca_9542 },
+ { "pca9543", pca_9543 },
+ { "pca9544", pca_9544 },
+ { "pca9545", pca_9545 },
+ { "pca9546", pca_9546 },
+ { "pca9547", pca_9547 },
+ { "pca9548", pca_9548 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pca954x_id);
+
+static int pca954x_xfer(struct i2c_adapter *adap,
+ struct i2c_client *client, int read_write, u8 *val)
+{
+ int ret = -ENODEV;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg;
+ char buf[1];
+
+ msg.addr = client->addr;
+ msg.flags = (read_write == I2C_SMBUS_READ ? I2C_M_RD : 0);
+ msg.len = 1;
+ buf[0] = *val;
+ msg.buf = buf;
+ ret = adap->algo->master_xfer(adap, &msg, 1);
+ } else if (adap->algo->smbus_xfer) {
+ union i2c_smbus_data data;
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags & I2C_M_TEN,
+ read_write,
+ *val, I2C_SMBUS_BYTE, &data);
+ }
+
+ return ret;
+}
+
+static int pca954x_select_chan(struct i2c_adapter *adap,
+ struct i2c_client *client, u32 chan)
+{
+ struct pca954x *data = i2c_get_clientdata(client);
+ struct chip_desc *chip = &chips[data->type];
+ u8 regval = 0;
+ int ret = 0;
+
+ /* we make switches look like muxes, not sure how to be smarter */
+ if (chip->muxtype == pca954x_ismux)
+ regval = chan | chip->enable;
+ else
+ regval = 1 << chan;
+
+ /* Only select the channel if its different from the last channel */
+ if (data->last_chan != chan) {
+ ret = pca954x_xfer(adap, client, I2C_SMBUS_WRITE, ®val);
+ data->last_chan = chan;
+ }
+
+ return ret;
+}
+
+static int pca954x_deselect_mux(struct i2c_adapter *adap,
+ struct i2c_client *client, u32 value)
+{
+ /* We never deselect, just stay on the last channel we selected */
+ return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+
+static int pca954x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ struct pca954x_platform_data *pdata = client->dev.platform_data;
+ int i, n, f;
+ struct pca954x *data;
+ int ret = -ENODEV;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
+ goto err;
+
+ data = kzalloc(sizeof(struct pca954x), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ i2c_set_clientdata(client, data);
+
+ /* Read the mux register at addr. This does two things: it verifies
+ * that the mux is in fact present, and fetches its current
+ * contents for possible use with a future deselect algorithm.
+ */
+ i = i2c_smbus_read_byte(client);
+ if (i < 0) {
+ dev_warn(&client->dev, "probe failed\n");
+ goto exit_free;
+ }
+
+ data->type = id->driver_data;
+ data->last_chan = -1; /* force the first selection */
+
+ /* Now create virtual busses and adapters for them */
+ for (i = 0; i < chips[data->type].nchans; i++) {
+ f = 0; /* dynamic adap number */
+ if (pdata && (i < pdata->len))
+ f = pdata->adap_ids[i]; /* force static adap number */
+
+ data->virt_adaps[i] = i2c_add_virt_adapter(adap, client, f, i,
+ &pca954x_select_chan,
+ &pca954x_deselect_mux);
+ if (data->virt_adaps[i] == NULL) {
+ ret = -ENODEV;
+ goto virt_reg_failed;
+ }
+ }
+
+ dev_info(&client->dev, "registered %d virtual busses for I2C %s %s\n",
+ i, chips[data->type].muxtype == pca954x_ismux ?
+ "mux" : "switch", client->name);
+
+ return 0;
+
+virt_reg_failed:
+ for (n = 0; n < i; n++)
+ i2c_del_virt_adapter(data->virt_adaps[n]);
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+err:
+ return ret;
+}
+
+static int __devexit pca954x_remove(struct i2c_client *client)
+{
+ struct pca954x *data = i2c_get_clientdata(client);
+ struct chip_desc *chip = &chips[data->type];
+ int i, err;
+
+ for (i = 0; i < chip->nchans; ++i)
+ if (data->virt_adaps[i]) {
+ err = i2c_del_virt_adapter(data->virt_adaps[i]);
+ if (err)
+ return err;
+ data->virt_adaps[i] = NULL;
+ }
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver pca954x_driver = {
+ .driver = {
+ .name = "pca954x",
+ .owner = THIS_MODULE,
+ },
+ .probe = pca954x_probe,
+ .remove = __devexit_p(pca954x_remove),
+ .id_table = pca954x_id,
+};
+
+static int __init pca954x_init(void)
+{
+ return i2c_add_driver(&pca954x_driver);
+}
+
+static void __exit pca954x_exit(void)
+{
+ i2c_del_driver(&pca954x_driver);
+}
+
+module_init(pca954x_init);
+module_exit(pca954x_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>");
+MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c/pca954x.h b/include/linux/i2c/pca954x.h
new file mode 100644
index 0000000..ba4504f
--- /dev/null
+++ b/include/linux/i2c/pca954x.h
@@ -0,0 +1,6 @@
+/* platform data for the PCA954x I2C multiplexers */
+
+struct pca954x_platform_data {
+ int *adap_ids;
+ int len;
+};
--
1.5.4.3
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <1213895701-9872-2-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
2008-06-19 17:15 ` [PATCH] i2c: multiplexer i2c devices Rodolfo Giometti
@ 2008-06-22 8:37 ` Peter Korsgaard
[not found] ` <87fxr5sw5f.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
1 sibling, 1 reply; 16+ messages in thread
From: Peter Korsgaard @ 2008-06-22 8:37 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
>>>>> "Rodolfo" == Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org> writes:
Hi,
Rodolfo> +
Rodolfo> +struct i2c_adapter *i2c_add_virt_adapter(struct i2c_adapter *parent,
Rodolfo> + struct i2c_client *client,
Rodolfo> + u32 force_nr, u32 mux_val,
Rodolfo> + int (*select_cb) (struct i2c_adapter *,
Rodolfo> + struct i2c_client *, u32),
Rodolfo> + int (*deselect_cb) (struct i2c_adapter *,
Rodolfo> + struct i2c_client *, u32))
Rodolfo> +{
How about changing the struct i2c_client to an anonymous void *data
instead so it can be used for systems where the multiplexing hardware
isn't a i2c device? E.G. I have a driver (currently not in mainline)
for a I2C multiplexer implemented in a FPGA together with the
opencores I2C controller:
/*
* i2c-thinlitemux.c: I2C multiplexer on Barco Thinlite board.
*
* Peter Korsgaard <peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w@public.gmane.org>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#define THINLITEMUX_BUSSES 6
#define THINLITEMUX_IDLE 7
struct thinlitemux_i2c {
u16 __iomem *base;
struct i2c_adapter *parent;
struct i2c_adapter adap;
int pos;
};
static int thinlitemux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct thinlitemux_i2c *i2c = i2c_get_adapdata(adap);
int ret;
mutex_lock(&i2c->parent->bus_lock);
out_be16(i2c->base, i2c->pos);
ret = i2c->parent->algo->master_xfer(i2c->parent, msgs, num);
out_be16(i2c->base, THINLITEMUX_IDLE);
mutex_unlock(&i2c->parent->bus_lock);
return ret;
}
static u32 thinlitemux_func(struct i2c_adapter *adap)
{
struct thinlitemux_i2c *i2c = i2c_get_adapdata(adap);
return i2c->parent->algo->functionality(i2c->parent);
}
static struct i2c_algorithm thinlitemux_algorithm = {
.master_xfer = thinlitemux_xfer,
.functionality = thinlitemux_func,
};
static struct i2c_adapter thinlitemux_adapter = {
.owner = THIS_MODULE,
.name = "thinlitemux",
.class = I2C_CLASS_HWMON,
.algo = &thinlitemux_algorithm,
.timeout = 2,
.retries = 1
};
static int __devinit thinlitemux_probe(struct platform_device *pdev)
{
struct thinlitemux_i2c *i2c;
struct i2c_adapter *adap;
struct resource *res;
u16 __iomem *base;
int i, j, ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
adap = i2c_get_adapter((int)pdev->dev.platform_data);
if (!adap) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
(int)pdev->dev.platform_data);
return -ENODEV;
}
base = ioremap(res->start, res->end - res->start + 1);
if (!base) {
dev_err(&pdev->dev, "Unable to map registers\n");
ret = -EIO;
goto map_failed;
}
i2c = kzalloc(sizeof(*i2c)*THINLITEMUX_BUSSES, GFP_KERNEL);
if (!i2c) {
ret = -ENOMEM;
goto alloc_failed;
}
for (i=0; i<THINLITEMUX_BUSSES; i++) {
i2c[i].base = base;
i2c[i].pos = i;
i2c[i].parent = adap;
i2c[i].adap = thinlitemux_adapter;
i2c[i].adap.dev.parent = &adap->dev;
i2c[i].adap.nr = i+1;
snprintf(i2c[i].adap.name, I2C_NAME_SIZE, "%s.%d",
thinlitemux_adapter.name, i);
i2c_set_adapdata(&i2c[i].adap, &i2c[i]);
ret = i2c_add_numbered_adapter(&i2c[i].adap);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed;
}
}
/* disable parent bus so probes won't find devices on it */
out_be16(base, THINLITEMUX_IDLE);
dev_info(&pdev->dev, "%d port mux at 0x%lx on %s adapter\n",
THINLITEMUX_BUSSES, (unsigned long)res->start, adap->name);
platform_set_drvdata(pdev, i2c);
return 0;
add_adapter_failed:
for (j=0; j<i; j++)
i2c_del_adapter(&i2c[j].adap);
alloc_failed:
iounmap(base);
map_failed:
i2c_put_adapter(adap);
return ret;
}
static int __devexit thinlitemux_remove(struct platform_device* pdev)
{
struct thinlitemux_i2c *i2c = platform_get_drvdata(pdev);
int i;
for (i=0; i<THINLITEMUX_BUSSES; i++)
i2c_del_adapter(&i2c[i].adap);
iounmap(i2c->base);
platform_set_drvdata(pdev, NULL);
i2c_put_adapter(i2c->parent);
kfree(i2c);
return 0;
}
static struct platform_driver thinlitemux_driver = {
.probe = thinlitemux_probe,
.remove = __devexit_p(thinlitemux_remove),
.driver = {
.owner = THIS_MODULE,
.name = "thinlitei2cmux",
},
};
static int __init thinlitemux_init(void)
{
return platform_driver_register(&thinlitemux_driver);
}
static void __exit thinlitemux_exit(void)
{
platform_driver_unregister(&thinlitemux_driver);
}
module_init(thinlitemux_init);
module_exit(thinlitemux_exit);
MODULE_DESCRIPTION("Barco ThinLite I2C multiplexer driver");
MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w@public.gmane.org>");
MODULE_LICENSE("GPL");
It would be nice to be able to use the i2c-virtual stuff for it.
--
Bye, Peter Korsgaard
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <87fxr5sw5f.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
@ 2008-06-22 8:52 ` Rodolfo Giometti
[not found] ` <20080622085206.GM10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-22 8:52 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
[-- Attachment #1.1: Type: text/plain, Size: 1685 bytes --]
On Sun, Jun 22, 2008 at 10:37:16AM +0200, Peter Korsgaard wrote:
> >>>>> "Rodolfo" == Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org> writes:
>
> Hi,
>
> Rodolfo> +
> Rodolfo> +struct i2c_adapter *i2c_add_virt_adapter(struct i2c_adapter *parent,
> Rodolfo> + struct i2c_client *client,
> Rodolfo> + u32 force_nr, u32 mux_val,
> Rodolfo> + int (*select_cb) (struct i2c_adapter *,
> Rodolfo> + struct i2c_client *, u32),
> Rodolfo> + int (*deselect_cb) (struct i2c_adapter *,
> Rodolfo> + struct i2c_client *, u32))
> Rodolfo> +{
>
> How about changing the struct i2c_client to an anonymous void *data
> instead so it can be used for systems where the multiplexing hardware
> isn't a i2c device? E.G. I have a driver (currently not in mainline)
> for a I2C multiplexer implemented in a FPGA together with the
> opencores I2C controller:
> [snip]
> It would be nice to be able to use the i2c-virtual stuff for it.
Mmm... I suppose is not so easy as we wish since there are several
references to the i2c parent struct into the code.
I suppose you can get better result if you define your i2c multiplexer
as a dummy i2c device. The you can force it to be connected with a
real i2c parent by using the i2c_register_board_info() function.
What do you think about this solution? :)
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org
Linux Device Driver giometti-k2GhghHVRtY@public.gmane.org
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 157 bytes --]
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <20080622085206.GM10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
@ 2008-06-22 9:15 ` Peter Korsgaard
[not found] ` <87bq1tsue5.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-06-23 7:14 ` Jean Delvare
1 sibling, 1 reply; 16+ messages in thread
From: Peter Korsgaard @ 2008-06-22 9:15 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
>>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
Hi,
>> It would be nice to be able to use the i2c-virtual stuff for it.
Rodolfo> Mmm... I suppose is not so easy as we wish since there are several
Rodolfo> references to the i2c parent struct into the code.
That's not the problem, the struct i2c_client is. The i2c-virtual
stuff doesn't do anything with it, it simply forwards it to the
select/deselect callbacks - So changing it to a void *data shouldn't
really be a problem.
You don't derive the parent i2c bus from the i2c_client.
Rodolfo> I suppose you can get better result if you define your i2c
Rodolfo> multiplexer as a dummy i2c device. The you can force it to
Rodolfo> be connected with a real i2c parent by using the
Rodolfo> i2c_register_board_info() function.
Rodolfo> What do you think about this solution? :)
Sorry, I don't see what the problem is?
--
Bye, Peter Korsgaard
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <87bq1tsue5.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
@ 2008-06-22 9:39 ` Rodolfo Giometti
[not found] ` <20080622093939.GO10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-22 9:39 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
[-- Attachment #1.1: Type: text/plain, Size: 1537 bytes --]
On Sun, Jun 22, 2008 at 11:15:14AM +0200, Peter Korsgaard wrote:
> >>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
>
> >> It would be nice to be able to use the i2c-virtual stuff for it.
>
> Rodolfo> Mmm... I suppose is not so easy as we wish since there are several
> Rodolfo> references to the i2c parent struct into the code.
>
> That's not the problem, the struct i2c_client is. The i2c-virtual
> stuff doesn't do anything with it, it simply forwards it to the
> select/deselect callbacks - So changing it to a void *data shouldn't
> really be a problem.
>
> You don't derive the parent i2c bus from the i2c_client.
Ok, but what do you suggest to put in "struct i2c_adapter *parent"?
> Rodolfo> I suppose you can get better result if you define your i2c
> Rodolfo> multiplexer as a dummy i2c device. The you can force it to
> Rodolfo> be connected with a real i2c parent by using the
> Rodolfo> i2c_register_board_info() function.
>
> Rodolfo> What do you think about this solution? :)
>
> Sorry, I don't see what the problem is?
Maybe if you provide a littke code I may understand exactly what you
mean. ;)
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org
Linux Device Driver giometti-k2GhghHVRtY@public.gmane.org
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 157 bytes --]
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <20080622093939.GO10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
@ 2008-06-22 10:53 ` Peter Korsgaard
[not found] ` <8763s1spuw.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Peter Korsgaard @ 2008-06-22 10:53 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
>>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
Hi,
Rodolfo> On Sun, Jun 22, 2008 at 11:15:14AM +0200, Peter Korsgaard wrote:
>> That's not the problem, the struct i2c_client is. The i2c-virtual
>> stuff doesn't do anything with it, it simply forwards it to the
>> select/deselect callbacks - So changing it to a void *data shouldn't
>> really be a problem.
>>
>> You don't derive the parent i2c bus from the i2c_client.
Rodolfo> Ok, but what do you suggest to put in "struct i2c_adapter *parent"?
The real parent bus. The hardware works pretty much like the pcfs,
except it has a memory mapped register interface instead of i2c for
controlling the mux. See the driver I sent for details.
Rodolfo> What do you think about this solution? :)
>>
>> Sorry, I don't see what the problem is?
Rodolfo> Maybe if you provide a littke code I may understand exactly
Rodolfo> what you mean. ;)
But I did?!
--
Bye, Peter Korsgaard
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <8763s1spuw.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
@ 2008-06-22 12:50 ` Rodolfo Giometti
[not found] ` <20080622125010.GP10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Rodolfo Giometti @ 2008-06-22 12:50 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
[-- Attachment #1.1: Type: text/plain, Size: 1012 bytes --]
On Sun, Jun 22, 2008 at 12:53:11PM +0200, Peter Korsgaard wrote:
> >>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
>
> Rodolfo> Maybe if you provide a littke code I may understand exactly
> Rodolfo> what you mean. ;)
>
> But I did?!
I mean the code that shows how you wish adding your i2c mux by using
i2c_add_virt_adapter(). :)
However, we also should make attention at i2c_del_virt_adapter() which
must call (new) i2c_del_adapter_nolock() since the core_lock is hold
by i2c_del_driver() when the mux is an i2c device.
If you define a virtual adapter as a non-i2c device I suppose we
should use the lock...
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org
Linux Device Driver giometti-k2GhghHVRtY@public.gmane.org
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 157 bytes --]
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <20080622125010.GP10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
@ 2008-06-22 19:48 ` Peter Korsgaard
[not found] ` <87hcblqmi0.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-06-23 7:21 ` Jean Delvare
1 sibling, 1 reply; 16+ messages in thread
From: Peter Korsgaard @ 2008-06-22 19:48 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
>>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
Rodolfo> On Sun, Jun 22, 2008 at 12:53:11PM +0200, Peter Korsgaard wrote:
>> >>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
>>
Rodolfo> Maybe if you provide a littke code I may understand exactly
Rodolfo> what you mean. ;)
>>
>> But I did?!
Rodolfo> I mean the code that shows how you wish adding your i2c mux
Rodolfo> by using i2c_add_virt_adapter(). :)
Pretty much like the pcf driver, E.G. something like (not compile
tested):
#define THINLITEMUX_BUSSES 6
#define THINLITEMUX_IDLE 7
struct thinlitemux_i2c {
u16 __iomem *base;
struct i2c_adapter *parent;
struct i2c_adapter *adap{TINLITEMUX_BUSSES];
};
static int thinlitemux_select(struct i2c_adapter *adap,
struct i2c_client *client, u32 chan)
{
struct thinlitemux_i2c *i2c = (struct thinlitemux_i2c*)client;
out_be16(i2c->base, chan);
}
static int thinlitemux_deselect(struct i2c_adapter *adap,
struct i2c_client *client, u32 value)
{
struct thinlitemux_i2c *i2c = (struct thinlitemux_i2c*)client;
out_be16(i2c->base, THINLITEMUX_IDLE);
}
static int __devinit thinlitemux_probe(struct platform_device *pdev)
{
struct thinlitemux_i2c *i2c;
struct i2c_adapter *adap;
struct resource *res;
u16 __iomem *base;
int i, j, ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
if (!i2c) {
ret = -ENOMEM;
goto alloc_failed;
}
i2c->parent = i2c_get_adapter((int)pdev->dev.platform_data);
if (!i2c->parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
(int)pdev->dev.platform_data);
ret = -ENODEV;
goto no_parent;
}
i2c->base = ioremap(res->start, res->end - res->start + 1);
if (!i2c->base) {
dev_err(&pdev->dev, "Unable to map registers\n");
ret = -EIO;
goto map_failed;
}
/* disable parent bus so probes won't find devices on it */
thinlitemux_deselect(i2c->parent, NULL, 0);
for (i=0; i<THINLITEMUX_BUSSES; i++) {
i2c->adap[i] = i2c_add_virt_adapter(i2c->parent, i2c, 0, i,
&thinlitemux_select, &thinlitemux_deselect);
if (!i2c->adap[i]) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed;
}
}
dev_info(&pdev->dev, "%d port mux at 0x%lx on %s adapter\n",
THINLITEMUX_BUSSES, (unsigned long)res->start, parent->name);
platform_set_drvdata(pdev, i2c);
return 0;
add_adapter_failed:
for (j=0; j<i; j++)
i2c_del_virt_adapter(&i2c->adap[j]);
alloc_failed:
iounmap(i2c->base);
map_failed:
i2c_put_adapter(i2c->parent);
no_parent
kfree(i2c);
return ret;
}
static int __devexit thinlitemux_remove(struct platform_device* pdev)
{
struct thinlitemux_i2c *i2c = platform_get_drvdata(pdev);
int i;
for (i=0; i<THINLITEMUX_BUSSES; i++)
i2c_del_virt_adapter(&i2c->adap[i]);
iounmap(i2c->base);
platform_set_drvdata(pdev, NULL);
i2c_put_adapter(i2c->parent);
kfree(i2c);
return 0;
}
static struct platform_driver thinlitemux_driver = {
.probe = thinlitemux_probe,
.remove = __devexit_p(thinlitemux_remove),
.driver = {
.owner = THIS_MODULE,
.name = "thinlitei2cmux",
},
};
static int __init thinlitemux_init(void)
{
return platform_driver_register(&thinlitemux_driver);
}
static void __exit thinlitemux_exit(void)
{
platform_driver_unregister(&thinlitemux_driver);
}
module_init(thinlitemux_init);
module_exit(thinlitemux_exit);
MODULE_DESCRIPTION("Barco ThinLite I2C multiplexer driver");
MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w@public.gmane.org>");
MODULE_LICENSE("GPL");
Rodolfo> However, we also should make attention at
Rodolfo> i2c_del_virt_adapter() which must call (new)
Rodolfo> i2c_del_adapter_nolock() since the core_lock is hold by
Rodolfo> i2c_del_driver() when the mux is an i2c device.
Rodolfo> If you define a virtual adapter as a non-i2c device I
Rodolfo> suppose we should use the lock...
I guess we could do:
if (mutex_is_locked(&core_lock))
ret = i2c_del_adapter_nolock(adap);
else
ret = i2c_del_adapter(adap);
Except that core_lock is static in i2c-core.c.
--
Bye, Peter Korsgaard
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <20080622085206.GM10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
2008-06-22 9:15 ` Peter Korsgaard
@ 2008-06-23 7:14 ` Jean Delvare
1 sibling, 0 replies; 16+ messages in thread
From: Jean Delvare @ 2008-06-23 7:14 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala, Ben Dooks
Hi Rodolfo,
On Sun, 22 Jun 2008 10:52:06 +0200, Rodolfo Giometti wrote:
> On Sun, Jun 22, 2008 at 10:37:16AM +0200, Peter Korsgaard wrote:
> > >>>>> "Rodolfo" == Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org> writes:
> >
> > Hi,
> >
> > Rodolfo> +
> > Rodolfo> +struct i2c_adapter *i2c_add_virt_adapter(struct i2c_adapter *parent,
> > Rodolfo> + struct i2c_client *client,
> > Rodolfo> + u32 force_nr, u32 mux_val,
> > Rodolfo> + int (*select_cb) (struct i2c_adapter *,
> > Rodolfo> + struct i2c_client *, u32),
> > Rodolfo> + int (*deselect_cb) (struct i2c_adapter *,
> > Rodolfo> + struct i2c_client *, u32))
> > Rodolfo> +{
> >
> > How about changing the struct i2c_client to an anonymous void *data
> > instead so it can be used for systems where the multiplexing hardware
> > isn't a i2c device? E.G. I have a driver (currently not in mainline)
> > for a I2C multiplexer implemented in a FPGA together with the
> > opencores I2C controller:
> > [snip]
> > It would be nice to be able to use the i2c-virtual stuff for it.
>
> Mmm... I suppose is not so easy as we wish since there are several
> references to the i2c parent struct into the code.
>
> I suppose you can get better result if you define your i2c multiplexer
> as a dummy i2c device. The you can force it to be connected with a
> real i2c parent by using the i2c_register_board_info() function.
Don't even think about it. We've done dummy i2c devices before and it
took me 3 years to clean up the mess. Not again, please.
Peter is totally right, there's no reason why I2C multiplexers would
always be I2C devices themselves (and when they are, they do not have
to live on the bus they are multiplexing, even though this is the most
frequent case). That's only one of the possible cases. The core i2c
multiplexing code shouldn't assume anything about the nature of the
multiplexer, that's something for the actual implementation of specific
multiplexer drivers to deal with.
Thanks,
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <20080622125010.GP10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
2008-06-22 19:48 ` Peter Korsgaard
@ 2008-06-23 7:21 ` Jean Delvare
1 sibling, 0 replies; 16+ messages in thread
From: Jean Delvare @ 2008-06-23 7:21 UTC (permalink / raw)
To: Rodolfo Giometti; +Cc: i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala, Ben Dooks
On Sun, 22 Jun 2008 14:50:10 +0200, Rodolfo Giometti wrote:
> On Sun, Jun 22, 2008 at 12:53:11PM +0200, Peter Korsgaard wrote:
> > >>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
> >
> > Rodolfo> Maybe if you provide a littke code I may understand exactly
> > Rodolfo> what you mean. ;)
> >
> > But I did?!
>
> I mean the code that shows how you wish adding your i2c mux by using
> i2c_add_virt_adapter(). :)
>
> However, we also should make attention at i2c_del_virt_adapter() which
> must call (new) i2c_del_adapter_nolock() since the core_lock is hold
> by i2c_del_driver() when the mux is an i2c device.
>
> If you define a virtual adapter as a non-i2c device I suppose we
> should use the lock...
My feeling is that we'd be better off killing the legacy i2c binding
model before we try to add support for i2c bus multiplexers. This will
clean up the i2c-core locking model significantly and limit the number
of cases we have to think about for everything we implement.
This isn't so far away, I'm working on it these days and it isn't
impossible that kernel 2.6.28 will be completely i2c-legacy-model-free.
Thanks,
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <87hcblqmi0.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
@ 2008-06-23 7:26 ` Jean Delvare
[not found] ` <20080623092658.75bddce4-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Jean Delvare @ 2008-06-23 7:26 UTC (permalink / raw)
To: Peter Korsgaard
Cc: Ben Dooks, Rodolfo Giometti, i2c-GZX6beZjE8VD60Wz+7aTrA,
Kumar Gala
Hi Peter,
On Sun, 22 Jun 2008 21:48:39 +0200, Peter Korsgaard wrote:
> >>>>> "Rodolfo" == Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> writes:
> Rodolfo> However, we also should make attention at
> Rodolfo> i2c_del_virt_adapter() which must call (new)
> Rodolfo> i2c_del_adapter_nolock() since the core_lock is hold by
> Rodolfo> i2c_del_driver() when the mux is an i2c device.
>
> Rodolfo> If you define a virtual adapter as a non-i2c device I
> Rodolfo> suppose we should use the lock...
>
> I guess we could do:
>
> if (mutex_is_locked(&core_lock))
> ret = i2c_del_adapter_nolock(adap);
> else
> ret = i2c_del_adapter(adap);
>
> Except that core_lock is static in i2c-core.c.
This construct is broken by design. If you don't know if the mutex is
locked, it means that you're not the one holding it. If you're not the
one holding it, you don't know when it will be released. So it could be
released in the middle of whatever you are doing which requires the
lock to be held, and that's bad.
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <20080623092658.75bddce4-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
@ 2008-06-23 7:51 ` Peter Korsgaard
[not found] ` <8763s0pp0r.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Peter Korsgaard @ 2008-06-23 7:51 UTC (permalink / raw)
To: Jean Delvare
Cc: Ben Dooks, Rodolfo Giometti, i2c-GZX6beZjE8VD60Wz+7aTrA,
Kumar Gala
>>>>> "Jean" == Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> writes:
Hi,
>> Except that core_lock is static in i2c-core.c.
Jean> This construct is broken by design. If you don't know if the
Jean> mutex is locked, it means that you're not the one holding
Jean> it. If you're not the one holding it, you don't know when it
Jean> will be released. So it could be released in the middle of
Jean> whatever you are doing which requires the lock to be held, and
Jean> that's bad.
Exactly. Either we put it on hold for the core rework or we add a
i2c_del_virt_adapter_nolock() variant for the mux-on-i2c case.
--
Bye, Peter Korsgaard
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] i2c: virtual i2c adapter support.
[not found] ` <8763s0pp0r.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
@ 2008-08-21 8:45 ` Rodolfo Giometti
0 siblings, 0 replies; 16+ messages in thread
From: Rodolfo Giometti @ 2008-08-21 8:45 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: Ben Dooks, i2c-GZX6beZjE8VD60Wz+7aTrA, Kumar Gala
[-- Attachment #1.1: Type: text/plain, Size: 1401 bytes --]
On Mon, Jun 23, 2008 at 09:51:48AM +0200, Peter Korsgaard wrote:
> >>>>> "Jean" == Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> writes:
>
> Hi,
>
> >> Except that core_lock is static in i2c-core.c.
>
> Jean> This construct is broken by design. If you don't know if the
> Jean> mutex is locked, it means that you're not the one holding
> Jean> it. If you're not the one holding it, you don't know when it
> Jean> will be released. So it could be released in the middle of
> Jean> whatever you are doing which requires the lock to be held, and
> Jean> that's bad.
>
> Exactly. Either we put it on hold for the core rework or we add a
> i2c_del_virt_adapter_nolock() variant for the mux-on-i2c case.
The problem is that into i2c_del_virt_adapter() we have to call
i2c_del_adapter() and the lock is already holded by i2c_del_driver()
since the mux is an i2c chip itself.
Do you think that the problem can be resolved if we use
mutex_lock_nested(&core_lock, SINGLE_DEPTH_NESTING) into
i2c_del_adapter()?
Thanks for your help,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org
Linux Device Driver giometti-k2GhghHVRtY@public.gmane.org
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 157 bytes --]
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2008-08-21 8:45 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-19 17:14 [PATCH v2] i2c: virtual i2c adapter support Rodolfo Giometti
[not found] ` <1213895701-9872-1-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
2008-06-19 17:14 ` [PATCH] " Rodolfo Giometti
[not found] ` <1213895701-9872-2-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
2008-06-19 17:15 ` [PATCH] i2c: multiplexer i2c devices Rodolfo Giometti
[not found] ` <1213895701-9872-3-git-send-email-giometti-k2GhghHVRtY@public.gmane.org>
2008-06-19 17:15 ` [PATCH] i2c: driver for PCA954x I2C multiplexer series Rodolfo Giometti
2008-06-22 8:37 ` [PATCH] i2c: virtual i2c adapter support Peter Korsgaard
[not found] ` <87fxr5sw5f.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-06-22 8:52 ` Rodolfo Giometti
[not found] ` <20080622085206.GM10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
2008-06-22 9:15 ` Peter Korsgaard
[not found] ` <87bq1tsue5.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-06-22 9:39 ` Rodolfo Giometti
[not found] ` <20080622093939.GO10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
2008-06-22 10:53 ` Peter Korsgaard
[not found] ` <8763s1spuw.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-06-22 12:50 ` Rodolfo Giometti
[not found] ` <20080622125010.GP10695-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
2008-06-22 19:48 ` Peter Korsgaard
[not found] ` <87hcblqmi0.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-06-23 7:26 ` Jean Delvare
[not found] ` <20080623092658.75bddce4-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-06-23 7:51 ` Peter Korsgaard
[not found] ` <8763s0pp0r.fsf-uXGAPMMVk8amE9MCos8gUmSdvHPH+/yF@public.gmane.org>
2008-08-21 8:45 ` Rodolfo Giometti
2008-06-23 7:21 ` Jean Delvare
2008-06-23 7:14 ` Jean Delvare
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox