From eee543e8248150e8fb833943c71f40c7b1724600 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:51 +0200 Subject: i2c-mux: Add support for device auto-detection Let I2C bus segments behind multiplexers have a class. This allows for device auto-detection on these segments. As long as parent segments don't share the same class, it should be fine. I implemented support in drivers i2c-mux-gpio and i2c-mux-pca954x. I left i2c-mux-pca9541 and i2c-mux-pinctrl alone for the moment as I don't know if this feature makes sense for the use cases of these drivers. Signed-off-by: Jean Delvare Cc: Peter Korsgaard Cc: David Daney Cc: Michael Lawnick Cc: Rodolfo Giometti --- drivers/i2c/i2c-mux.c | 22 ++++++++++++++++++++++ drivers/i2c/muxes/i2c-mux-gpio.c | 4 +++- drivers/i2c/muxes/i2c-mux-pca9541.c | 2 +- drivers/i2c/muxes/i2c-mux-pca954x.c | 10 ++++++---- drivers/i2c/muxes/i2c-mux-pinctrl.c | 2 +- 5 files changed, 33 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 1038c38..d94e0ce 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -88,9 +88,23 @@ static u32 i2c_mux_functionality(struct i2c_adapter *adap) return parent->algo->functionality(parent); } +/* Return all parent classes, merged */ +static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent) +{ + unsigned int class = 0; + + do { + class |= parent->class; + parent = i2c_parent_is_i2c_adapter(parent); + } while (parent); + + return class; +} + struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, struct device *mux_dev, void *mux_priv, u32 force_nr, u32 chan_id, + unsigned int class, int (*select) (struct i2c_adapter *, void *, u32), int (*deselect) (struct i2c_adapter *, @@ -127,6 +141,14 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, priv->adap.algo_data = priv; priv->adap.dev.parent = &parent->dev; + /* Sanity check on class */ + if (i2c_mux_parent_classes(parent) & class) + dev_err(&parent->dev, + "Segment %d behind mux can't share classes with ancestors\n", + chan_id); + else + priv->adap.class = class; + /* * Try to populate the mux adapter's of_node, expands to * nothing if !CONFIG_OF. diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 68b1f8e..56889e0 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -104,8 +104,10 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) for (i = 0; i < pdata->n_values; i++) { u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; + unsigned int class = pdata->classes ? pdata->classes[i] : 0; - mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, + mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, + i, class, i2c_mux_gpio_select, deselect); if (!mux->adap[i]) { ret = -ENODEV; diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index f8f72f3..f3b8f9a 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -354,7 +354,7 @@ static int pca9541_probe(struct i2c_client *client, if (pdata) force = pdata->modes[0].adap_id; data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client, - force, 0, + force, 0, 0, pca9541_select_chan, pca9541_release_chan); diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index f2dfe0d..8e43872 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -186,7 +186,7 @@ static int pca954x_probe(struct i2c_client *client, { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = client->dev.platform_data; - int num, force; + int num, force, class; struct pca954x *data; int ret = -ENODEV; @@ -216,18 +216,20 @@ static int pca954x_probe(struct i2c_client *client, /* Now create an adapter for each channel */ for (num = 0; num < chips[data->type].nchans; num++) { force = 0; /* dynamic adap number */ + class = 0; /* no class by default */ if (pdata) { - if (num < pdata->num_modes) + if (num < pdata->num_modes) { /* force static number */ force = pdata->modes[num].adap_id; - else + class = pdata->modes[num].class; + } else /* discard unconfigured channels */ break; } data->virt_adaps[num] = i2c_add_mux_adapter(adap, &client->dev, client, - force, num, pca954x_select_chan, + force, num, class, pca954x_select_chan, (pdata && pdata->modes[num].deselect_on_exit) ? pca954x_deselect_mux : NULL); diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 46a6697..5f097f3 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -221,7 +221,7 @@ static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev) (mux->pdata->base_bus_num + i) : 0; mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, - mux, bus, i, + mux, bus, i, 0, i2c_mux_pinctrl_select, deselect); if (!mux->busses[i]) { -- cgit v1.1 From 71b578452ec6b2e8a470e3dae89055cd1068a9f0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Oct 2012 22:23:52 +0200 Subject: i2c-smbus: Convert kzalloc to devm_kzalloc Converting kzalloc to devm_kzalloc simplifies the code and ensures that the result, alert, is freed after the irq allocated by the subsequent devm_request_irq. This in turn ensures that when an interrupt can be triggered, the alert structure is still available. The problem of a free after a devm_request_irq was found using the following semantic match (http://coccinelle.lip6.fr/) // @r exists@ expression e1,e2,x,a,b,c,d; identifier free; position p1,p2; @@ devm_request_irq@p1(e1,e2,...,x) ... when any when != e2 = a when != x = b if (...) { ... when != e2 = c when != x = d free@p2(...,x,...); ... return ...; } // Signed-off-by: Julia Lawall Signed-off-by: Jean Delvare --- drivers/i2c/i2c-smbus.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index df3e0bf..92cdd23 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -142,7 +142,8 @@ static int smbalert_probe(struct i2c_client *ara, struct i2c_adapter *adapter = ara->adapter; int res; - alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL); + alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), + GFP_KERNEL); if (!alert) return -ENOMEM; @@ -154,10 +155,8 @@ static int smbalert_probe(struct i2c_client *ara, if (setup->irq > 0) { res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, 0, "smbus_alert", alert); - if (res) { - kfree(alert); + if (res) return res; - } } i2c_set_clientdata(ara, alert); @@ -167,14 +166,12 @@ static int smbalert_probe(struct i2c_client *ara, return 0; } -/* IRQ resource is managed so it is freed automatically */ +/* IRQ and memory resources are managed so they are freed automatically */ static int smbalert_remove(struct i2c_client *ara) { struct i2c_smbus_alert *alert = i2c_get_clientdata(ara); cancel_work_sync(&alert->alert); - - kfree(alert); return 0; } -- cgit v1.1 From 230da094352869ac36bca524a294deb7bb3dd876 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Fri, 5 Oct 2012 22:23:52 +0200 Subject: i2c: Convert struct i2c_msg initialization to C99 format Convert the struct i2c_msg initialization to C99 format. This makes maintaining and editing the code simpler. Also helps once other fields like transferred are added in future. Signed-off-by: Shubhrajyoti D Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 2421d95..a7edf98 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1989,12 +1989,22 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ ? 2 : 1; - struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, - { addr, flags | I2C_M_RD, 0, msgbuf1 } - }; int i; u8 partial_pec = 0; int status; + struct i2c_msg msg[2] = { + { + .addr = addr, + .flags = flags, + .len = 1, + .buf = msgbuf0, + }, { + .addr = addr, + .flags = flags | I2C_M_RD, + .len = 0, + .buf = msgbuf1, + }, + }; msgbuf0[0] = command; switch (size) { -- cgit v1.1 From 3ddb59d4bcaeca8109ac5eb8ad17368e940ac05e Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Fri, 5 Oct 2012 22:23:52 +0200 Subject: i2c: Make I2C available on UML Remove the global dependency of the I2C subsystem on HAS_IOMEM and move the dependency to the i2c/busses submenu, with an exception for i2c-stub. The generic I2C part does not need to have HAS_IOMEM set and thus now becomes available in UML, so the I2C subsystem can now be used, e.g. by the i2c-stub driver, for development of I2C device drivers. [JD: Some adjustments.] [Heiko Carstens: Keep I2C disabled on S390.] Signed-off-by: Peter Huewe Signed-off-by: Jean Delvare --- drivers/i2c/Kconfig | 17 ++++++++++++++++- drivers/i2c/busses/Kconfig | 14 +------------- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 5a3bb3d..2f8c76b 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -4,7 +4,7 @@ menuconfig I2C tristate "I2C support" - depends on HAS_IOMEM + depends on !S390 select RT_MUTEXES ---help--- I2C (pronounce: I-squared-C) is a slow serial bus protocol used in @@ -49,6 +49,7 @@ config I2C_CHARDEV config I2C_MUX tristate "I2C bus multiplexing support" + depends on HAS_IOMEM help Say Y here if you want the I2C core to support the ability to handle multiplexed I2C bus topologies, by presenting each @@ -86,6 +87,19 @@ config I2C_SMBUS source drivers/i2c/algos/Kconfig source drivers/i2c/busses/Kconfig +config I2C_STUB + tristate "I2C/SMBus Test Stub" + depends on EXPERIMENTAL && m + default 'n' + help + This module may be useful to developers of SMBus client drivers, + especially for certain kinds of sensor chips. + + If you do build this module, be sure to read the notes and warnings + in . + + If you don't know what to do here, definitely say N. + config I2C_DEBUG_CORE bool "I2C Core debugging messages" help @@ -103,6 +117,7 @@ config I2C_DEBUG_ALGO config I2C_DEBUG_BUS bool "I2C Bus debugging messages" + depends on HAS_IOMEM help Say Y here if you want the I2C bus drivers to produce a bunch of debug messages to the system log. Select this if you are having diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 42d9fdd..8eed054 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -3,6 +3,7 @@ # menu "I2C Hardware Bus support" + depends on HAS_IOMEM comment "PC SMBus host controller drivers" depends on PCI @@ -849,19 +850,6 @@ config I2C_SIBYTE help Supports the SiByte SOC on-chip I2C interfaces (2 channels). -config I2C_STUB - tristate "I2C/SMBus Test Stub" - depends on EXPERIMENTAL && m - default 'n' - help - This module may be useful to developers of SMBus client drivers, - especially for certain kinds of sensor chips. - - If you do build this module, be sure to read the notes and warnings - in . - - If you don't know what to do here, definitely say N. - config SCx200_I2C tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)" depends on SCx200_GPIO -- cgit v1.1 From 401e72b55d29f1a08d3dfd7a6a6c2087203b6524 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Fri, 5 Oct 2012 22:23:52 +0200 Subject: i2c/scx200_*: Replace printks with pr_s Replace printks with pr_s, add pr_fmt()s to replace NAMEs Signed-off-by: Jim Cromie Reviewed-by: Joe Perches Signed-off-by: Jean Delvare --- drivers/i2c/busses/scx200_acb.c | 24 +++++++++++------------- drivers/i2c/busses/scx200_i2c.c | 15 +++++++-------- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 2eacb77..08aab57 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -23,6 +23,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -37,8 +39,6 @@ #include -#define NAME "scx200_acb" - MODULE_AUTHOR("Christer Weinigel "); MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver"); MODULE_ALIAS("platform:cs5535-smb"); @@ -398,7 +398,7 @@ static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface) outb(0x70, ACBCTL2); if (inb(ACBCTL2) != 0x70) { - pr_debug(NAME ": ACBCTL2 readback failed\n"); + pr_debug("ACBCTL2 readback failed\n"); return -ENXIO; } @@ -406,8 +406,7 @@ static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface) val = inb(ACBCTL1); if (val) { - pr_debug(NAME ": disabled, but ACBCTL1=0x%02x\n", - val); + pr_debug("disabled, but ACBCTL1=0x%02x\n", val); return -ENXIO; } @@ -417,8 +416,8 @@ static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface) val = inb(ACBCTL1); if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) { - pr_debug(NAME ": enabled, but NMINTE won't be set, " - "ACBCTL1=0x%02x\n", val); + pr_debug("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", + val); return -ENXIO; } @@ -433,7 +432,7 @@ static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text, iface = kzalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { - printk(KERN_ERR NAME ": can't allocate memory\n"); + pr_err("can't allocate memory\n"); return NULL; } @@ -459,14 +458,14 @@ static int __devinit scx200_acb_create(struct scx200_acb_iface *iface) rc = scx200_acb_probe(iface); if (rc) { - printk(KERN_WARNING NAME ": probe failed\n"); + pr_warn("probe failed\n"); return rc; } scx200_acb_reset(iface); if (i2c_add_adapter(adapter) < 0) { - printk(KERN_ERR NAME ": failed to register\n"); + pr_err("failed to register\n"); return -ENODEV; } @@ -493,8 +492,7 @@ static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text, return NULL; if (!request_region(base, 8, iface->adapter.name)) { - printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", - base, base + 8 - 1); + pr_err("can't allocate io 0x%lx-0x%lx\n", base, base + 8 - 1); goto errout_free; } @@ -583,7 +581,7 @@ static __init void scx200_scan_isa(void) static int __init scx200_acb_init(void) { - pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); + pr_debug("NatSemi SCx200 ACCESS.bus Driver\n"); /* First scan for ISA-based devices */ scx200_scan_isa(); /* XXX: should we care about errors? */ diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 7ee0d50..ae1258b 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -31,8 +33,6 @@ #include -#define NAME "scx200_i2c" - MODULE_AUTHOR("Christer Weinigel "); MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver"); MODULE_LICENSE("GPL"); @@ -88,17 +88,17 @@ static struct i2c_adapter scx200_i2c_ops = { static int scx200_i2c_init(void) { - pr_debug(NAME ": NatSemi SCx200 I2C Driver\n"); + pr_debug("NatSemi SCx200 I2C Driver\n"); if (!scx200_gpio_present()) { - printk(KERN_ERR NAME ": no SCx200 gpio pins available\n"); + pr_err("no SCx200 gpio pins available\n"); return -ENODEV; } - pr_debug(NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", scl, sda); + pr_debug("SCL=GPIO%02u, SDA=GPIO%02u\n", scl, sda); if (scl == -1 || sda == -1 || scl == sda) { - printk(KERN_ERR NAME ": scl and sda must be specified\n"); + pr_err("scl and sda must be specified\n"); return -EINVAL; } @@ -107,8 +107,7 @@ static int scx200_i2c_init(void) scx200_gpio_configure(sda, ~2, 5); if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) { - printk(KERN_ERR NAME ": adapter %s registration failed\n", - scx200_i2c_ops.name); + pr_err("adapter %s registration failed\n", scx200_i2c_ops.name); return -ENODEV; } -- cgit v1.1 From bccd780f867c82571181f6ca03e243beba697607 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:53 +0200 Subject: i2c-designware: i2c_dw_xfer_msg can be static i2c_dw_xfer_msg is only called internally so it can be static. It original was, before the driver split. No idea why it was changed at that time. Signed-off-by: Jean Delvare Acked-by: Dirk Brandewie --- drivers/i2c/busses/i2c-designware-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 7b8ebbe..cbba7db 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -370,7 +370,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) * messages into the tx buffer. Even if the size of i2c_msg data is * longer than the size of the tx buffer, it handles everything. */ -void +static void i2c_dw_xfer_msg(struct dw_i2c_dev *dev) { struct i2c_msg *msgs = dev->msgs; -- cgit v1.1 From 7fe442a1a50f8b4fe49f685f21b08dd8f070f429 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:53 +0200 Subject: i2c-parport: i2c_parport_irq can be static i2c_parport_irq is only called internally so it can be static. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-parport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 2456568..81d8878 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -151,7 +151,7 @@ static const struct i2c_algo_bit_data parport_algo_data = { /* ----- I2c and parallel port call-back functions and structures --------- */ -void i2c_parport_irq(void *data) +static void i2c_parport_irq(void *data) { struct i2c_par *adapter = data; struct i2c_client *ara = adapter->ara; -- cgit v1.1 From 01d56a6aa1c3a506426c8f3ff87c8d698023f336 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:53 +0200 Subject: i2c-viapro: Add VIA VX900 device ID The SMBus controller in the VIA VX900 appears to be compatible with the VIA VX855, so just add the device ID. This closes kernel bug #43096. Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 3 ++- drivers/i2c/busses/i2c-viapro.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8eed054..7f69f50 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -225,7 +225,7 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" + tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx/VX900" depends on PCI help If you say yes to this option, support will be included for the VIA @@ -241,6 +241,7 @@ config I2C_VIAPRO CX700 VX800/VX820 VX855/VX875 + VX900 This driver can also be built as a module. If so, the module will be called i2c-viapro. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 333011c..271c9a2 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -401,6 +401,7 @@ found: case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_VX800: case PCI_DEVICE_ID_VIA_VX855: + case PCI_DEVICE_ID_VIA_VX900: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -470,6 +471,8 @@ static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX900), + .driver_data = SMBBA3 }, { 0, } }; -- cgit v1.1 From 3ad7ea18ae8c7ddda46b7276e0bda73e707ea9c1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:53 +0200 Subject: i2c-i801: Support SMBus multiplexing on Asus Z8 series Add support for SMBus multiplexing on Asus Z8 motherboard series. On these boards, the memory slots are behind a GPIO-controlled I2C multiplexer. Models with 6 or 12 memory slots have 2 segments behind the multiplexer, while models with 18 memory slots have 3 such segments. On these boards, only the memory slots are behind the multiplexer, so it is possible to keep the autodetection mechanism. The code is generic enough so it could work on other boards as long as the multiplexer is controlled by GPIO pins. For other forms of multiplexing (for example using an I2C device) additional code will be needed. Thanks to Asus for providing a board to develop and test this feature, as well as all the technical information required. At the moment, the GPIO driver must be loaded before the i2c-i801 driver, but I hope to solve this soon, using deferred probing on the i2c-mux-gpio side. Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 214 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 214 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7f69f50..ff01c38 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -81,6 +81,7 @@ config I2C_I801 tristate "Intel 82801 (ICH/PCH)" depends on PCI select CHECK_SIGNATURE if X86 && DMI + select GPIOLIB if I2C_MUX help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 33e9b0c..bb1d729 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -80,6 +80,13 @@ #include #include #include +#include + +#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE +#include +#include +#include +#endif /* I801 SMBus address offsets */ #define SMBHSTSTS(p) (0 + (p)->smba) @@ -158,6 +165,15 @@ #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 +struct i801_mux_config { + char *gpio_chip; + unsigned values[3]; + int n_values; + unsigned classes[3]; + unsigned gpios[2]; /* Relative to gpio_chip->base */ + int n_gpios; +}; + struct i801_priv { struct i2c_adapter adapter; unsigned long smba; @@ -175,6 +191,12 @@ struct i801_priv { int count; int len; u8 *data; + +#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE + const struct i801_mux_config *mux_drvdata; + unsigned mux_priv[2]; + struct platform_device *mux_pdev; +#endif }; static struct pci_driver i801_driver; @@ -900,6 +922,193 @@ static void __init input_apanel_init(void) {} static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {} #endif /* CONFIG_X86 && CONFIG_DMI */ +#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE +static struct i801_mux_config i801_mux_config_asus_z8_d12 = { + .gpio_chip = "gpio_ich", + .values = { 0x02, 0x03 }, + .n_values = 2, + .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, + .gpios = { 52, 53 }, + .n_gpios = 2, +}; + +static struct i801_mux_config i801_mux_config_asus_z8_d18 = { + .gpio_chip = "gpio_ich", + .values = { 0x02, 0x03, 0x01 }, + .n_values = 3, + .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, + .gpios = { 52, 53 }, + .n_gpios = 2, +}; + +static struct dmi_system_id __devinitdata mux_dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"), + }, + .driver_data = &i801_mux_config_asus_z8_d18, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"), + }, + .driver_data = &i801_mux_config_asus_z8_d18, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"), + }, + .driver_data = &i801_mux_config_asus_z8_d12, + }, + { } +}; + +static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, + void *data) +{ + return !strcmp(chip->label, data); +} + +/* Setup multiplexing if needed */ +static int __devinit i801_add_mux(struct i801_priv *priv) +{ + struct device *dev = &priv->adapter.dev; + const struct i801_mux_config *mux_config; + struct gpio_chip *gpio; + struct i2c_mux_gpio_platform_data gpio_data; + int i, err; + + if (!priv->mux_drvdata) + return 0; + mux_config = priv->mux_drvdata; + + /* Find GPIO chip */ + gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label); + if (gpio) { + dev_info(dev, + "GPIO chip %s found, SMBus multiplexing enabled\n", + mux_config->gpio_chip); + } else { + dev_err(dev, + "GPIO chip %s not found, SMBus multiplexing disabled\n", + mux_config->gpio_chip); + return -ENODEV; + } + + /* Find absolute GPIO pin numbers */ + if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) { + dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n", + ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios); + return -ENODEV; + } + for (i = 0; i < mux_config->n_gpios; i++) + priv->mux_priv[i] = gpio->base + mux_config->gpios[i]; + + /* Prepare the platform data */ + memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data)); + gpio_data.parent = priv->adapter.nr; + gpio_data.values = mux_config->values; + gpio_data.n_values = mux_config->n_values; + gpio_data.classes = mux_config->classes; + gpio_data.gpios = priv->mux_priv; + gpio_data.n_gpios = mux_config->n_gpios; + gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; + + /* Register the mux device */ + priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", + priv->mux_priv[0], &gpio_data, + sizeof(struct i2c_mux_gpio_platform_data)); + if (IS_ERR(priv->mux_pdev)) { + err = PTR_ERR(priv->mux_pdev); + priv->mux_pdev = NULL; + dev_err(dev, "Failed to register i2c-mux-gpio device\n"); + return err; + } + + return 0; +} + +static void __devexit i801_del_mux(struct i801_priv *priv) +{ + if (priv->mux_pdev) + platform_device_unregister(priv->mux_pdev); +} + +static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv) +{ + const struct dmi_system_id *id; + const struct i801_mux_config *mux_config; + unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + int i; + + id = dmi_first_match(mux_dmi_table); + if (id) { + /* Remove from branch classes from trunk */ + mux_config = id->driver_data; + for (i = 0; i < mux_config->n_values; i++) + class &= ~mux_config->classes[i]; + + /* Remember for later */ + priv->mux_drvdata = mux_config; + } + + return class; +} +#else +static inline int i801_add_mux(struct i801_priv *priv) { return 0; } +static inline void i801_del_mux(struct i801_priv *priv) { } + +static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) +{ + return I2C_CLASS_HWMON | I2C_CLASS_SPD; +} +#endif + static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { @@ -913,7 +1122,7 @@ static int __devinit i801_probe(struct pci_dev *dev, i2c_set_adapdata(&priv->adapter, priv); priv->adapter.owner = THIS_MODULE; - priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + priv->adapter.class = i801_get_adapter_class(priv); priv->adapter.algo = &smbus_algorithm; priv->pci_dev = dev; @@ -1033,6 +1242,8 @@ static int __devinit i801_probe(struct pci_dev *dev, } i801_probe_optional_slaves(priv); + /* We ignore errors - multiplexing is optional */ + i801_add_mux(priv); pci_set_drvdata(dev, priv); @@ -1052,6 +1263,7 @@ static void __devexit i801_remove(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); + i801_del_mux(priv); i2c_del_adapter(&priv->adapter); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); -- cgit v1.1 From 2614a8594152cad49047ed02255a3d9fbbbea8dd Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 5 Oct 2012 22:23:53 +0200 Subject: i2c-mux-gpio: Use devm_kzalloc instead of kzalloc Use the devm_kzalloc managed function to stripdown the error and remove code. Signed-off-by: Maxime Ripard Acked-by: Peter Korsgaard Signed-off-by: Jean Delvare --- drivers/i2c/muxes/i2c-mux-gpio.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 56889e0..7c23bb5 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -71,7 +71,7 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) return -ENODEV; } - mux = kzalloc(sizeof(*mux), GFP_KERNEL); + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); if (!mux) { ret = -ENOMEM; goto alloc_failed; @@ -79,11 +79,12 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) mux->parent = parent; mux->data = *pdata; - mux->adap = kzalloc(sizeof(struct i2c_adapter *) * pdata->n_values, - GFP_KERNEL); + mux->adap = devm_kzalloc(&pdev->dev, + sizeof(*mux->adap) * pdata->n_values, + GFP_KERNEL); if (!mux->adap) { ret = -ENOMEM; - goto alloc_failed2; + goto alloc_failed; } if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { @@ -130,9 +131,6 @@ add_adapter_failed: err_request_gpio: for (; i > 0; i--) gpio_free(pdata->gpios[i - 1]); - kfree(mux->adap); -alloc_failed2: - kfree(mux); alloc_failed: i2c_put_adapter(parent); @@ -152,8 +150,6 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); i2c_put_adapter(mux->parent); - kfree(mux->adap); - kfree(mux); return 0; } -- cgit v1.1 From e7ee51405835cac72e7b6e0ff26dba608cf186cc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:54 +0200 Subject: i2c-mux-gpio: Add support for dynamically allocated GPIO pins The code instantiating an i2c-mux-gpio platform device doesn't necessarily know in advance the GPIO pin numbers it wants to use. If pins are on a GPIO device which gets its base GPIO number assigned dynamically at run-time, the values can't be hard-coded. In that case, let the caller tell i2c-mux-gpio the name of the GPIO chip and the (relative) GPIO pin numbers to use. At probe time, the i2c-mux-gpio driver will look for the chip and apply the proper offset to turn relative GPIO pin numbers to absolute GPIO pin numbers. The same could be (and was so far) done on the caller's end, however doing it in i2c-mux-gpio has two benefits: * It avoids duplicating the code on every caller's side (about 30 lines of code.) * It allows for deferred probing for the muxed part of the I2C bus only. If finding the GPIO chip is the caller's responsibility, then deferred probing (if the GPIO chip isn't there yet) will not only affect the mux and the I2C bus segments behind it, but also the I2C bus trunk. Signed-off-by: Jean Delvare Cc: Peter Korsgaard --- drivers/i2c/muxes/i2c-mux-gpio.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 7c23bb5..566a675 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -21,6 +21,7 @@ struct gpiomux { struct i2c_adapter *parent; struct i2c_adapter **adap; /* child busses */ struct i2c_mux_gpio_platform_data data; + unsigned gpio_base; }; static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) @@ -28,7 +29,8 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) int i; for (i = 0; i < mux->data.n_gpios; i++) - gpio_set_value(mux->data.gpios[i], val & (1 << i)); + gpio_set_value(mux->gpio_base + mux->data.gpios[i], + val & (1 << i)); } static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan) @@ -49,13 +51,19 @@ static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan) return 0; } +static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, + void *data) +{ + return !strcmp(chip->label, data); +} + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); - unsigned initial_state; + unsigned initial_state, gpio_base; int i, ret; pdata = pdev->dev.platform_data; @@ -64,6 +72,23 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) return -ENODEV; } + /* + * If a GPIO chip name is provided, the GPIO pin numbers provided are + * relative to its base GPIO number. Otherwise they are absolute. + */ + if (pdata->gpio_chip) { + struct gpio_chip *gpio; + + gpio = gpiochip_find(pdata->gpio_chip, + match_gpio_chip_by_label); + if (!gpio) + return -EPROBE_DEFER; + + gpio_base = gpio->base; + } else { + gpio_base = 0; + } + parent = i2c_get_adapter(pdata->parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", @@ -79,6 +104,7 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) mux->parent = parent; mux->data = *pdata; + mux->gpio_base = gpio_base; mux->adap = devm_kzalloc(&pdev->dev, sizeof(*mux->adap) * pdata->n_values, GFP_KERNEL); @@ -96,10 +122,10 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(pdata->gpios[i], "i2c-mux-gpio"); + ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(pdata->gpios[i], + gpio_direction_output(gpio_base + pdata->gpios[i], initial_state & (1 << i)); } @@ -130,7 +156,7 @@ add_adapter_failed: i = pdata->n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(pdata->gpios[i - 1]); + gpio_free(gpio_base + pdata->gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -146,7 +172,7 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) i2c_del_mux_adapter(mux->adap[i]); for (i = 0; i < mux->data.n_gpios; i++) - gpio_free(mux->data.gpios[i]); + gpio_free(mux->gpio_base + mux->data.gpios[i]); platform_set_drvdata(pdev, NULL); i2c_put_adapter(mux->parent); -- cgit v1.1 From f82b86267a7a7cc2fc9779fa2957467c242395d8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 5 Oct 2012 22:23:54 +0200 Subject: i2c-i801: Let i2c-mux-gpio find the GPIO chip Now that i2c-mux-gpio is able to find the GPIO chip by itself, we can delegate this task. The great thing here is that i2c-mux-gpio can defer device probing until the gpio chip is available, so we no longer depend on the module loading order. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-i801.c | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index bb1d729..3779315 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -194,7 +194,6 @@ struct i801_priv { #if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE const struct i801_mux_config *mux_drvdata; - unsigned mux_priv[2]; struct platform_device *mux_pdev; #endif }; @@ -1008,60 +1007,32 @@ static struct dmi_system_id __devinitdata mux_dmi_table[] = { { } }; -static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, - void *data) -{ - return !strcmp(chip->label, data); -} - /* Setup multiplexing if needed */ static int __devinit i801_add_mux(struct i801_priv *priv) { struct device *dev = &priv->adapter.dev; const struct i801_mux_config *mux_config; - struct gpio_chip *gpio; struct i2c_mux_gpio_platform_data gpio_data; - int i, err; + int err; if (!priv->mux_drvdata) return 0; mux_config = priv->mux_drvdata; - /* Find GPIO chip */ - gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label); - if (gpio) { - dev_info(dev, - "GPIO chip %s found, SMBus multiplexing enabled\n", - mux_config->gpio_chip); - } else { - dev_err(dev, - "GPIO chip %s not found, SMBus multiplexing disabled\n", - mux_config->gpio_chip); - return -ENODEV; - } - - /* Find absolute GPIO pin numbers */ - if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) { - dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n", - ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios); - return -ENODEV; - } - for (i = 0; i < mux_config->n_gpios; i++) - priv->mux_priv[i] = gpio->base + mux_config->gpios[i]; - /* Prepare the platform data */ memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data)); gpio_data.parent = priv->adapter.nr; gpio_data.values = mux_config->values; gpio_data.n_values = mux_config->n_values; gpio_data.classes = mux_config->classes; - gpio_data.gpios = priv->mux_priv; + gpio_data.gpio_chip = mux_config->gpio_chip; + gpio_data.gpios = mux_config->gpios; gpio_data.n_gpios = mux_config->n_gpios; gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; /* Register the mux device */ priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", - priv->mux_priv[0], &gpio_data, + PLATFORM_DEVID_AUTO, &gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); if (IS_ERR(priv->mux_pdev)) { err = PTR_ERR(priv->mux_pdev); -- cgit v1.1 From c415b303a704e5c5f766fc0404093910c36cc4ab Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Fri, 5 Oct 2012 22:23:55 +0200 Subject: i2c-piix4: Fix build failure Fix build failure in Intel PIIX4 I2C driver. Signed-off-by: Daniel J Blueman Signed-off-by: Jean Delvare Cc: stable@vger.kernel.org [v3.6] --- drivers/i2c/busses/i2c-piix4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index ef511df..8bbd6ec 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include -- cgit v1.1