diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-09-10 01:14:47 (GMT) |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-09-10 01:14:47 (GMT) |
commit | d344c5e0856ad03278d8700b503762dbc8b86e12 (patch) | |
tree | a6d893a643470a3c2580a58f3228a55fa1fd1d82 /drivers/i2c | |
parent | 010988e888a0abbe7118635c1b33d049caae6b29 (diff) | |
parent | 87fc767b832ef5a681a0ff9d203c3289bc3be2bf (diff) | |
download | linux-fsl-qoriq-d344c5e0856ad03278d8700b503762dbc8b86e12.tar.xz |
Manual merge with Linus
Diffstat (limited to 'drivers/i2c')
47 files changed, 1497 insertions, 904 deletions
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index cd17039..71c5a85 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -4,12 +4,8 @@ obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o -obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o obj-y += busses/ chips/ algos/ -i2c-sensor-objs := i2c-sensor-detect.o i2c-sensor-vid.o - - ifeq ($(CONFIG_I2C_DEBUG_CORE),y) EXTRA_CFLAGS += -DDEBUG endif diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index fb5b732..df05df1 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -519,8 +519,6 @@ static u32 bit_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm i2c_bit_algo = { - .name = "Bit-shift algorithm", - .id = I2C_ALGO_BIT, .master_xfer = bit_xfer, .functionality = bit_func, }; @@ -541,8 +539,6 @@ int i2c_bit_add_bus(struct i2c_adapter *adap) DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); /* register new adapter to i2c module... */ - - adap->id |= i2c_bit_algo.id; adap->algo = &i2c_bit_algo; adap->timeout = 100; /* default values, should */ diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c index e6cae39..2db7bfc 100644 --- a/drivers/i2c/algos/i2c-algo-ite.c +++ b/drivers/i2c/algos/i2c-algo-ite.c @@ -713,8 +713,6 @@ static u32 iic_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm iic_algo = { - .name = "ITE IIC algorithm", - .id = I2C_ALGO_IIC, .master_xfer = iic_xfer, .algo_control = algo_control, /* ioctl */ .functionality = iic_func, @@ -738,8 +736,6 @@ int i2c_iic_add_bus(struct i2c_adapter *adap) adap->name)); /* register new adapter to i2c module... */ - - adap->id |= iic_algo.id; adap->algo = &iic_algo; adap->timeout = 100; /* default values, should */ diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index cc3a952..beb10ed 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -187,12 +187,14 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, int numbytes = 0; int state; int ret; + int timeout = 100; - state = pca_status(adap); - if ( state != 0xF8 ) { - dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state ); - /* FIXME: what to do. Force stop ? */ - return -EREMOTEIO; + while ((state = pca_status(adap)) != 0xf8 && timeout--) { + msleep(10); + } + if (state != 0xf8) { + dev_dbg(&i2c_adap->dev, "bus is not idle. status is %#04x\n", state); + return -EIO; } DEB1("{{{ XFER %d messages\n", num); @@ -354,8 +356,6 @@ static int pca_init(struct i2c_algo_pca_data *adap) } static struct i2c_algorithm pca_algo = { - .name = "PCA9564 algorithm", - .id = I2C_ALGO_PCA, .master_xfer = pca_xfer, .functionality = pca_func, }; @@ -369,8 +369,6 @@ int i2c_pca_add_bus(struct i2c_adapter *adap) int rval; /* register new adapter to i2c module... */ - - adap->id |= pca_algo.id; adap->algo = &pca_algo; adap->timeout = 100; /* default values, should */ diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 8d087da..6e498df 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -459,8 +459,6 @@ static u32 pcf_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm pcf_algo = { - .name = "PCF8584 algorithm", - .id = I2C_ALGO_PCF, .master_xfer = pcf_xfer, .functionality = pcf_func, }; @@ -476,8 +474,6 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap) DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); /* register new adapter to i2c module... */ - - adap->id |= pcf_algo.id; adap->algo = &pcf_algo; adap->timeout = 100; /* default values, should */ diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c index 422721b..932c4fa 100644 --- a/drivers/i2c/algos/i2c-algo-sgi.c +++ b/drivers/i2c/algos/i2c-algo-sgi.c @@ -149,7 +149,7 @@ static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, err = i2c_write(adap, p->buf, p->len); } - return err; + return (err < 0) ? err : i; } static u32 sgi_func(struct i2c_adapter *adap) @@ -158,8 +158,6 @@ static u32 sgi_func(struct i2c_adapter *adap) } static struct i2c_algorithm sgi_algo = { - .name = "SGI algorithm", - .id = I2C_ALGO_SGI, .master_xfer = sgi_xfer, .functionality = sgi_func, }; @@ -169,7 +167,6 @@ static struct i2c_algorithm sgi_algo = { */ int i2c_sgi_add_bus(struct i2c_adapter *adap) { - adap->id |= sgi_algo.id; adap->algo = &sgi_algo; return i2c_add_adapter(adap); diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index f278549..8ed5ad1 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c @@ -135,8 +135,6 @@ static u32 bit_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static struct i2c_algorithm i2c_sibyte_algo = { - .name = "SiByte algorithm", - .id = I2C_ALGO_SIBYTE, .smbus_xfer = smbus_xfer, .algo_control = algo_control, /* ioctl */ .functionality = bit_func, @@ -151,8 +149,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; /* register new adapter to i2c module... */ - - i2c_adap->id |= i2c_sibyte_algo.id; i2c_adap->algo = &i2c_sibyte_algo; /* Set the frequency to 100 kHz */ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 916ba5e..8334496 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -144,6 +144,22 @@ config I2C_I810 This driver can also be built as a module. If so, the module will be called i2c-i810. +config I2C_PXA + tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL && ARCH_PXA + help + If you have devices in the PXA I2C bus, say yes to this option. + This driver can also be built as a module. If so, the module + will be called i2c-pxa. + +config I2C_PXA_SLAVE + bool "Intel PXA2XX I2C Slave comms support" + depends on I2C_PXA + help + Support I2C slave mode communications on the PXA I2C bus. This + is necessary for systems where the PXA may be a target on the + I2C bus. + config I2C_PIIX4 tristate "Intel PIIX4" depends on I2C && PCI @@ -182,14 +198,8 @@ config I2C_IOP3XX will be called i2c-iop3xx. config I2C_ISA - tristate "ISA Bus support" + tristate depends on I2C - help - If you say yes to this option, support will be included for i2c - interfaces that are on the ISA bus. - - This driver can also be built as a module. If so, the module - will be called i2c-isa. config I2C_ITE tristate "ITE I2C Adapter" diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 42d6d81..980b3e9 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o +obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index f634a07..f021acd 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -472,8 +472,6 @@ static u32 ali1535_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-i2c SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = ali1535_access, .functionality = ali1535_func, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index fdd881a..8694750 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -366,8 +366,6 @@ static void ali1563_shutdown(struct pci_dev *dev) } static struct i2c_algorithm ali1563_algorithm = { - .name = "Non-i2c SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = ali1563_access, .functionality = ali1563_func, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 0f781a1..b3f50bf 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -462,8 +462,6 @@ static u32 ali15x3_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = ali15x3_access, .functionality = ali15x3_func, }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 6347ebc..6ad0603 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -295,8 +295,6 @@ static u32 amd756_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = amd756_access, .functionality = amd756_func, }; diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index d664448..45ea24b 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -323,8 +323,6 @@ static u32 amd8111_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus 2.0 adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = amd8111_access, .functionality = amd8111_func, }; diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index a7ff112..d06edce 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -283,8 +283,6 @@ au1550_func(struct i2c_adapter *adap) } static struct i2c_algorithm au1550_algo = { - .name = "Au1550 algorithm", - .id = I2C_ALGO_AU1550, .master_xfer = au1550_xfer, .functionality = au1550_func, }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 1ab4131..709beab 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -535,8 +535,6 @@ static u32 i801_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = i801_access, .functionality = i801_func, }; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 93ca36d..a3ed959 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -627,8 +627,6 @@ static u32 iic_func(struct i2c_adapter *adap) } static struct i2c_algorithm iic_algo = { - .name = "IBM IIC algorithm", - .id = I2C_ALGO_OCP, .master_xfer = iic_xfer, .functionality = iic_func }; @@ -727,7 +725,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ adap = &dev->adap; strcpy(adap->name, "IBM IIC"); i2c_set_adapdata(adap, dev); - adap->id = I2C_HW_OCP | iic_algo.id; + adap->id = I2C_HW_OCP; adap->algo = &iic_algo; adap->client_register = NULL; adap->client_unregister = NULL; diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 6b682e9..7bd9102 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -399,8 +399,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap) } static struct i2c_algorithm iop3xx_i2c_algo = { - .name = "IOP3xx I2C algorithm", - .id = I2C_ALGO_IOP3XX, .master_xfer = iop3xx_i2c_master_xfer, .algo_control = iop3xx_i2c_algo_control, .functionality = iop3xx_i2c_func, diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 00e7f71..bdc6806 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -1,6 +1,8 @@ /* - i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring + i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips + Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> + + Based on the i2c-isa pseudo-adapter from the lm_sensors project Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> This program is free software; you can redistribute it and/or modify @@ -18,30 +20,36 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* This implements an i2c algorithm/adapter for ISA bus. Not that this is - on first sight very useful; almost no functionality is preserved. - Except that it makes writing drivers for chips which can be on both - the SMBus and the ISA bus very much easier. See lm78.c for an example - of this. */ +/* This implements an i2c-core-like thing for ISA hardware monitoring + chips. Such chips are linked to the i2c subsystem for historical + reasons (because the early ISA hardware monitoring chips such as the + LM78 had both an I2C and an ISA interface). They used to be + registered with the main i2c-core, but as a first step in the + direction of a clean separation between I2C and ISA chip drivers, + we now have this separate core for ISA ones. It is significantly + more simple than the real one, of course, because we don't have to + handle multiple busses: there is only one (fake) ISA adapter. + It is worth noting that we still rely on i2c-core for some things + at the moment - but hopefully this won't last. */ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/i2c.h> +#include <linux/i2c-isa.h> static u32 isa_func(struct i2c_adapter *adapter); /* This is the actual algorithm we define */ static struct i2c_algorithm isa_algorithm = { - .name = "ISA bus algorithm", - .id = I2C_ALGO_ISA, .functionality = isa_func, }; /* There can only be one... */ static struct i2c_adapter isa_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_ISA, .class = I2C_CLASS_HWMON, .algo = &isa_algorithm, .name = "ISA main adapter", @@ -53,17 +61,146 @@ static u32 isa_func(struct i2c_adapter *adapter) return 0; } + +/* Copied from i2c-core */ +static ssize_t show_adapter_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_adapter *adap = dev_to_i2c_adapter(dev); + return sprintf(buf, "%s\n", adap->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL); + +static int i2c_isa_device_probe(struct device *dev) +{ + return -ENODEV; +} + +static int i2c_isa_device_remove(struct device *dev) +{ + return 0; +} + + +/* We implement an interface which resembles i2c_{add,del}_driver, + but for i2c-isa drivers. We don't have to remember and handle lists + of drivers and adapters so this is much more simple, of course. */ + +int i2c_isa_add_driver(struct i2c_driver *driver) +{ + int res; + + /* Add the driver to the list of i2c drivers in the driver core */ + driver->driver.name = driver->name; + driver->driver.bus = &i2c_bus_type; + driver->driver.probe = i2c_isa_device_probe; + driver->driver.remove = i2c_isa_device_remove; + res = driver_register(&driver->driver); + if (res) + return res; + dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->name); + + /* Now look for clients */ + driver->attach_adapter(&isa_adapter); + + return 0; +} + +int i2c_isa_del_driver(struct i2c_driver *driver) +{ + struct list_head *item, *_n; + struct i2c_client *client; + int res; + + /* Detach all clients belonging to this one driver */ + list_for_each_safe(item, _n, &isa_adapter.clients) { + client = list_entry(item, struct i2c_client, list); + if (client->driver != driver) + continue; + dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n", + client->name, client->addr); + if ((res = driver->detach_client(client))) { + dev_err(&isa_adapter.dev, "Failed, driver " + "%s not unregistered!\n", + driver->name); + return res; + } + } + + /* Get the driver off the core list */ + driver_unregister(&driver->driver); + dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->name); + + return 0; +} + + static int __init i2c_isa_init(void) { - return i2c_add_adapter(&isa_adapter); + init_MUTEX(&isa_adapter.clist_lock); + INIT_LIST_HEAD(&isa_adapter.clients); + + isa_adapter.nr = ANY_I2C_ISA_BUS; + isa_adapter.dev.parent = &platform_bus; + sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr); + isa_adapter.dev.driver = &i2c_adapter_driver; + isa_adapter.dev.release = &i2c_adapter_dev_release; + device_register(&isa_adapter.dev); + device_create_file(&isa_adapter.dev, &dev_attr_name); + + /* Add this adapter to the i2c_adapter class */ + memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device)); + isa_adapter.class_dev.dev = &isa_adapter.dev; + isa_adapter.class_dev.class = &i2c_adapter_class; + strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id, + BUS_ID_SIZE); + class_device_register(&isa_adapter.class_dev); + + dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name); + + return 0; } static void __exit i2c_isa_exit(void) { - i2c_del_adapter(&isa_adapter); +#ifdef DEBUG + struct list_head *item, *_n; + struct i2c_client *client = NULL; +#endif + + /* There should be no more active client */ +#ifdef DEBUG + dev_dbg(&isa_adapter.dev, "Looking for clients\n"); + list_for_each_safe(item, _n, &isa_adapter.clients) { + client = list_entry(item, struct i2c_client, list); + dev_err(&isa_adapter.dev, "Driver %s still has an active " + "ISA client at 0x%x\n", client->driver->name, + client->addr); + } + if (client != NULL) + return; +#endif + + /* Clean up the sysfs representation */ + dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n"); + init_completion(&isa_adapter.dev_released); + init_completion(&isa_adapter.class_dev_released); + class_device_unregister(&isa_adapter.class_dev); + device_remove_file(&isa_adapter.dev, &dev_attr_name); + device_unregister(&isa_adapter.dev); + + /* Wait for sysfs to drop all references */ + dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n"); + wait_for_completion(&isa_adapter.dev_released); + wait_for_completion(&isa_adapter.class_dev_released); + + dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name); } -MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); +EXPORT_SYMBOL(i2c_isa_add_driver); +EXPORT_SYMBOL(i2c_isa_del_driver); + +MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("ISA bus access through i2c"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 94ae808..37b49c2 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -87,12 +87,9 @@ static const char *__kw_state_names[] = { }; #endif /* DEBUG */ -static int probe; - MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); MODULE_LICENSE("GPL"); -module_param(probe, bool, 0); #ifdef POLLED_MODE /* Don't schedule, the g5 fan controller is too @@ -498,8 +495,6 @@ keywest_func(struct i2c_adapter * adapter) /* For now, we only handle combined mode (smbus) */ static struct i2c_algorithm keywest_algorithm = { - .name = "Keywest i2c", - .id = I2C_ALGO_SMBUS, .smbus_xfer = keywest_smbus_xfer, .master_xfer = keywest_xfer, .functionality = keywest_func, @@ -621,7 +616,6 @@ create_iface(struct device_node *np, struct device *dev) sprintf(chan->adapter.name, "%s %d", np->parent->name, i); chan->iface = iface; chan->chan_no = i; - chan->adapter.id = I2C_ALGO_SMBUS; chan->adapter.algo = &keywest_algorithm; chan->adapter.algo_data = NULL; chan->adapter.client_register = NULL; @@ -635,15 +629,6 @@ create_iface(struct device_node *np, struct device *dev) chan->adapter.name); i2c_set_adapdata(&chan->adapter, NULL); } - if (probe) { - printk("Probe: "); - for (addr = 0x00; addr <= 0x7f; addr++) { - if (i2c_smbus_xfer(&chan->adapter,addr, - 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) - printk("%02x ", addr); - } - printk("\n"); - } } printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 9ad3e92..f065583 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -272,8 +272,6 @@ static u32 mpc_functionality(struct i2c_adapter *adap) } static struct i2c_algorithm mpc_algo = { - .name = "MPC algorithm", - .id = I2C_ALGO_MPC107, .master_xfer = mpc_xfer, .functionality = mpc_functionality, }; @@ -281,7 +279,7 @@ static struct i2c_algorithm mpc_algo = { static struct i2c_adapter mpc_ops = { .owner = THIS_MODULE, .name = "MPC adapter", - .id = I2C_ALGO_MPC107 | I2C_HW_MPC107, + .id = I2C_HW_MPC107, .algo = &mpc_algo, .class = I2C_CLASS_HWMON, .timeout = 1, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 5b85278..99abca4 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -423,18 +423,16 @@ static int mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); - int i, rc = 0; + int i, rc; for (i=0; i<num; i++) - if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) != 0) - break; + if ((rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i])) < 0) + return rc; - return rc; + return num; } static struct i2c_algorithm mv64xxx_i2c_algo = { - .name = MV64XXX_I2C_CTLR_NAME " algorithm", - .id = I2C_ALGO_MV64XXX, .master_xfer = mv64xxx_i2c_xfer, .functionality = mv64xxx_i2c_functionality, }; @@ -523,7 +521,7 @@ mv64xxx_i2c_probe(struct device *dev) drv_data->freq_m = pdata->freq_m; drv_data->freq_n = pdata->freq_n; drv_data->irq = platform_get_irq(pd, 0); - drv_data->adapter.id = I2C_ALGO_MV64XXX | I2C_HW_MV64XXX; + drv_data->adapter.id = I2C_HW_MV64XXX; drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.class = I2C_CLASS_HWMON; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 74eb89a..e0b7a91 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -110,8 +110,6 @@ static u32 nforce2_func(struct i2c_adapter *adapter); static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = nforce2_access, .functionality = nforce2_func, }; @@ -131,7 +129,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, struct nforce2_smbus *smbus = adap->algo_data; unsigned char protocol, pec, temp; unsigned char len = 0; /* to keep the compiler quiet */ - int timeout = 0; int i; protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : @@ -191,29 +188,10 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, case I2C_SMBUS_PROC_CALL: dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); return -1; - /* - outb_p(command, NVIDIA_SMB_CMD); - outb_p(data->word, NVIDIA_SMB_DATA); - outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1); - protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec; - read_write = I2C_SMBUS_READ; - break; - */ case I2C_SMBUS_BLOCK_PROC_CALL: dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n"); return -1; - /* - protocol |= pec; - len = min_t(u8, data->block[0], 31); - outb_p(command, NVIDIA_SMB_CMD); - outb_p(len, NVIDIA_SMB_BCNT); - for (i = 0; i < len; i++) - outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i); - protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec; - read_write = I2C_SMBUS_READ; - break; - */ case I2C_SMBUS_WORD_DATA_PEC: case I2C_SMBUS_BLOCK_DATA_PEC: @@ -232,12 +210,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, temp = inb_p(NVIDIA_SMB_STS); -#if 0 - do { - i2c_do_pause(1); - temp = inb_p(NVIDIA_SMB_STS); - } while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT)); -#endif if (~temp & NVIDIA_SMB_STS_DONE) { udelay(500); temp = inb_p(NVIDIA_SMB_STS); @@ -247,9 +219,10 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, temp = inb_p(NVIDIA_SMB_STS); } - if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE) - || (temp & NVIDIA_SMB_STS_STATUS)) + if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { + dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp); return -1; + } if (read_write == I2C_SMBUS_WRITE) return 0; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 6d34ee3..6d48a4d 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -399,8 +399,6 @@ static u32 piix4_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = piix4_access, .functionality = piix4_func, }; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c new file mode 100644 index 0000000..fdf53ce --- /dev/null +++ b/drivers/i2c/busses/i2c-pxa.c @@ -0,0 +1,1022 @@ +/* + * i2c_adap_pxa.c + * + * I2C adapter for the PXA I2C bus access. + * + * Copyright (C) 2002 Intrinsyc Software Inc. + * Copyright (C) 2004-2005 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * History: + * Apr 2002: Initial version [CS] + * Jun 2002: Properly seperated algo/adap [FB] + * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem] + * Jan 2003: added limited signal handling [Kai-Uwe Bloem] + * Sep 2004: Major rework to ensure efficient bus handling [RMK] + * Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood] + * Feb 2005: Rework slave mode handling [RMK] + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/i2c-pxa.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/arch/i2c.h> +#include <asm/arch/pxa-regs.h> + +struct pxa_i2c { + spinlock_t lock; + wait_queue_head_t wait; + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_idx; + unsigned int msg_ptr; + unsigned int slave_addr; + + struct i2c_adapter adap; +#ifdef CONFIG_I2C_PXA_SLAVE + struct i2c_slave_client *slave; +#endif + + unsigned int irqlogidx; + u32 isrlog[32]; + u32 icrlog[32]; +}; + +/* + * I2C Slave mode address + */ +#define I2C_PXA_SLAVE_ADDR 0x1 + +#ifdef DEBUG + +struct bits { + u32 mask; + const char *set; + const char *unset; +}; +#define BIT(m, s, u) { .mask = m, .set = s, .unset = u } + +static inline void +decode_bits(const char *prefix, const struct bits *bits, int num, u32 val) +{ + printk("%s %08x: ", prefix, val); + while (num--) { + const char *str = val & bits->mask ? bits->set : bits->unset; + if (str) + printk("%s ", str); + bits++; + } +} + +static const struct bits isr_bits[] = { + BIT(ISR_RWM, "RX", "TX"), + BIT(ISR_ACKNAK, "NAK", "ACK"), + BIT(ISR_UB, "Bsy", "Rdy"), + BIT(ISR_IBB, "BusBsy", "BusRdy"), + BIT(ISR_SSD, "SlaveStop", NULL), + BIT(ISR_ALD, "ALD", NULL), + BIT(ISR_ITE, "TxEmpty", NULL), + BIT(ISR_IRF, "RxFull", NULL), + BIT(ISR_GCAD, "GenCall", NULL), + BIT(ISR_SAD, "SlaveAddr", NULL), + BIT(ISR_BED, "BusErr", NULL), +}; + +static void decode_ISR(unsigned int val) +{ + decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val); + printk("\n"); +} + +static const struct bits icr_bits[] = { + BIT(ICR_START, "START", NULL), + BIT(ICR_STOP, "STOP", NULL), + BIT(ICR_ACKNAK, "ACKNAK", NULL), + BIT(ICR_TB, "TB", NULL), + BIT(ICR_MA, "MA", NULL), + BIT(ICR_SCLE, "SCLE", "scle"), + BIT(ICR_IUE, "IUE", "iue"), + BIT(ICR_GCD, "GCD", NULL), + BIT(ICR_ITEIE, "ITEIE", NULL), + BIT(ICR_IRFIE, "IRFIE", NULL), + BIT(ICR_BEIE, "BEIE", NULL), + BIT(ICR_SSDIE, "SSDIE", NULL), + BIT(ICR_ALDIE, "ALDIE", NULL), + BIT(ICR_SADIE, "SADIE", NULL), + BIT(ICR_UR, "UR", "ur"), +}; + +static void decode_ICR(unsigned int val) +{ + decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val); + printk("\n"); +} + +static unsigned int i2c_debug = DEBUG; + +static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) +{ + dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR); +} + +#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__) +#else +#define i2c_debug 0 + +#define show_state(i2c) do { } while (0) +#define decode_ISR(val) do { } while (0) +#define decode_ICR(val) do { } while (0) +#endif + +#define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0) + +static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); + +static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) +{ + unsigned int i; + printk("i2c: error: %s\n", why); + printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n", + i2c->msg_num, i2c->msg_idx, i2c->msg_ptr); + printk("i2c: ICR: %08x ISR: %08x\n" + "i2c: log: ", ICR, ISR); + for (i = 0; i < i2c->irqlogidx; i++) + printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); + printk("\n"); +} + +static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) +{ + return !(ICR & ICR_SCLE); +} + +static void i2c_pxa_abort(struct pxa_i2c *i2c) +{ + unsigned long timeout = jiffies + HZ/4; + + if (i2c_pxa_is_slavemode(i2c)) { + dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__); + return; + } + + while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) { + unsigned long icr = ICR; + + icr &= ~ICR_START; + icr |= ICR_ACKNAK | ICR_STOP | ICR_TB; + + ICR = icr; + + show_state(i2c); + + msleep(1); + } + + ICR &= ~(ICR_MA | ICR_START | ICR_STOP); +} + +static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c) +{ + int timeout = DEF_TIMEOUT; + + while (timeout-- && ISR & (ISR_IBB | ISR_UB)) { + if ((ISR & ISR_SAD) != 0) + timeout += 4; + + msleep(2); + show_state(i2c); + } + + if (timeout <= 0) + show_state(i2c); + + return timeout <= 0 ? I2C_RETRY : 0; +} + +static int i2c_pxa_wait_master(struct pxa_i2c *i2c) +{ + unsigned long timeout = jiffies + HZ*4; + + while (time_before(jiffies, timeout)) { + if (i2c_debug > 1) + dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", + __func__, (long)jiffies, ISR, ICR, IBMR); + + if (ISR & ISR_SAD) { + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__); + goto out; + } + + /* wait for unit and bus being not busy, and we also do a + * quick check of the i2c lines themselves to ensure they've + * gone high... + */ + if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) { + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); + return 1; + } + + msleep(1); + } + + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__); + out: + return 0; +} + +static int i2c_pxa_set_master(struct pxa_i2c *i2c) +{ + if (i2c_debug) + dev_dbg(&i2c->adap.dev, "setting to bus master\n"); + + if ((ISR & (ISR_UB | ISR_IBB)) != 0) { + dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__); + if (!i2c_pxa_wait_master(i2c)) { + dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__); + return I2C_RETRY; + } + } + + ICR |= ICR_SCLE; + return 0; +} + +#ifdef CONFIG_I2C_PXA_SLAVE +static int i2c_pxa_wait_slave(struct pxa_i2c *i2c) +{ + unsigned long timeout = jiffies + HZ*1; + + /* wait for stop */ + + show_state(i2c); + + while (time_before(jiffies, timeout)) { + if (i2c_debug > 1) + dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n", + __func__, (long)jiffies, ISR, ICR, IBMR); + + if ((ISR & (ISR_UB|ISR_IBB|ISR_SAD)) == ISR_SAD || + (ICR & ICR_SCLE) == 0) { + if (i2c_debug > 1) + dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); + return 1; + } + + msleep(1); + } + + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__); + return 0; +} + +/* + * clear the hold on the bus, and take of anything else + * that has been configured + */ +static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode) +{ + show_state(i2c); + + if (errcode < 0) { + udelay(100); /* simple delay */ + } else { + /* we need to wait for the stop condition to end */ + + /* if we where in stop, then clear... */ + if (ICR & ICR_STOP) { + udelay(100); + ICR &= ~ICR_STOP; + } + + if (!i2c_pxa_wait_slave(i2c)) { + dev_err(&i2c->adap.dev, "%s: wait timedout\n", + __func__); + return; + } + } + + ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA); + ICR &= ~ICR_SCLE; + + if (i2c_debug) { + dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR); + decode_ICR(ICR); + } +} +#else +#define i2c_pxa_set_slave(i2c, err) do { } while (0) +#endif + +static void i2c_pxa_reset(struct pxa_i2c *i2c) +{ + pr_debug("Resetting I2C Controller Unit\n"); + + /* abort any transfer currently under way */ + i2c_pxa_abort(i2c); + + /* reset according to 9.8 */ + ICR = ICR_UR; + ISR = I2C_ISR_INIT; + ICR &= ~ICR_UR; + + ISAR = i2c->slave_addr; + + /* set control register values */ + ICR = I2C_ICR_INIT; + +#ifdef CONFIG_I2C_PXA_SLAVE + dev_info(&i2c->adap.dev, "Enabling slave mode\n"); + ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE; +#endif + + i2c_pxa_set_slave(i2c, 0); + + /* enable unit */ + ICR |= ICR_IUE; + udelay(100); +} + + +#ifdef CONFIG_I2C_PXA_SLAVE +/* + * I2C EEPROM emulation. + */ +static struct i2c_eeprom_emu eeprom = { + .size = I2C_EEPROM_EMU_SIZE, + .watch = LIST_HEAD_INIT(eeprom.watch), +}; + +struct i2c_eeprom_emu *i2c_pxa_get_eeprom(void) +{ + return &eeprom; +} + +int i2c_eeprom_emu_addwatcher(struct i2c_eeprom_emu *emu, void *data, + unsigned int addr, unsigned int size, + struct i2c_eeprom_emu_watcher *watcher) +{ + struct i2c_eeprom_emu_watch *watch; + unsigned long flags; + + if (addr + size > emu->size) + return -EINVAL; + + watch = kmalloc(sizeof(struct i2c_eeprom_emu_watch), GFP_KERNEL); + if (watch) { + watch->start = addr; + watch->end = addr + size - 1; + watch->ops = watcher; + watch->data = data; + + local_irq_save(flags); + list_add(&watch->node, &emu->watch); + local_irq_restore(flags); + } + + return watch ? 0 : -ENOMEM; +} + +void i2c_eeprom_emu_delwatcher(struct i2c_eeprom_emu *emu, void *data, + struct i2c_eeprom_emu_watcher *watcher) +{ + struct i2c_eeprom_emu_watch *watch, *n; + unsigned long flags; + + list_for_each_entry_safe(watch, n, &emu->watch, node) { + if (watch->ops == watcher && watch->data == data) { + local_irq_save(flags); + list_del(&watch->node); + local_irq_restore(flags); + kfree(watch); + } + } +} + +static void i2c_eeprom_emu_event(void *ptr, i2c_slave_event_t event) +{ + struct i2c_eeprom_emu *emu = ptr; + + eedbg(3, "i2c_eeprom_emu_event: %d\n", event); + + switch (event) { + case I2C_SLAVE_EVENT_START_WRITE: + emu->seen_start = 1; + eedbg(2, "i2c_eeprom: write initiated\n"); + break; + + case I2C_SLAVE_EVENT_START_READ: + emu->seen_start = 0; + eedbg(2, "i2c_eeprom: read initiated\n"); + break; + + case I2C_SLAVE_EVENT_STOP: + emu->seen_start = 0; + eedbg(2, "i2c_eeprom: received stop\n"); + break; + + default: + eedbg(0, "i2c_eeprom: unhandled event\n"); + break; + } +} + +static int i2c_eeprom_emu_read(void *ptr) +{ + struct i2c_eeprom_emu *emu = ptr; + int ret; + + ret = emu->bytes[emu->ptr]; + emu->ptr = (emu->ptr + 1) % emu->size; + + return ret; +} + +static void i2c_eeprom_emu_write(void *ptr, unsigned int val) +{ + struct i2c_eeprom_emu *emu = ptr; + struct i2c_eeprom_emu_watch *watch; + + if (emu->seen_start != 0) { + eedbg(2, "i2c_eeprom_emu_write: setting ptr %02x\n", val); + emu->ptr = val; + emu->seen_start = 0; + return; + } + + emu->bytes[emu->ptr] = val; + + eedbg(1, "i2c_eeprom_emu_write: ptr=0x%02x, val=0x%02x\n", + emu->ptr, val); + + list_for_each_entry(watch, &emu->watch, node) { + if (!watch->ops || !watch->ops->write) + continue; + if (watch->start <= emu->ptr && watch->end >= emu->ptr) + watch->ops->write(watch->data, emu->ptr, val); + } + + emu->ptr = (emu->ptr + 1) % emu->size; +} + +struct i2c_slave_client eeprom_client = { + .data = &eeprom, + .event = i2c_eeprom_emu_event, + .read = i2c_eeprom_emu_read, + .write = i2c_eeprom_emu_write +}; + +/* + * PXA I2C Slave mode + */ + +static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) +{ + if (isr & ISR_BED) { + /* what should we do here? */ + } else { + int ret = i2c->slave->read(i2c->slave->data); + + IDBR = ret; + ICR |= ICR_TB; /* allow next byte */ + } +} + +static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) +{ + unsigned int byte = IDBR; + + if (i2c->slave != NULL) + i2c->slave->write(i2c->slave->data, byte); + + ICR |= ICR_TB; +} + +static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) +{ + int timeout; + + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n", + (isr & ISR_RWM) ? 'r' : 't'); + + if (i2c->slave != NULL) + i2c->slave->event(i2c->slave->data, + (isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE); + + /* + * slave could interrupt in the middle of us generating a + * start condition... if this happens, we'd better back off + * and stop holding the poor thing up + */ + ICR &= ~(ICR_START|ICR_STOP); + ICR |= ICR_TB; + + timeout = 0x10000; + + while (1) { + if ((IBMR & 2) == 2) + break; + + timeout--; + + if (timeout <= 0) { + dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n"); + break; + } + } + + ICR &= ~ICR_SCLE; +} + +static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) +{ + if (i2c_debug > 2) + dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n"); + + if (i2c->slave != NULL) + i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP); + + if (i2c_debug > 2) + dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n"); + + /* + * If we have a master-mode message waiting, + * kick it off now that the slave has completed. + */ + if (i2c->msg) + i2c_pxa_master_complete(i2c, I2C_RETRY); +} +#else +static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr) +{ + if (isr & ISR_BED) { + /* what should we do here? */ + } else { + IDBR = 0; + ICR |= ICR_TB; + } +} + +static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr) +{ + ICR |= ICR_TB | ICR_ACKNAK; +} + +static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr) +{ + int timeout; + + /* + * slave could interrupt in the middle of us generating a + * start condition... if this happens, we'd better back off + * and stop holding the poor thing up + */ + ICR &= ~(ICR_START|ICR_STOP); + ICR |= ICR_TB | ICR_ACKNAK; + + timeout = 0x10000; + + while (1) { + if ((IBMR & 2) == 2) + break; + + timeout--; + + if (timeout <= 0) { + dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n"); + break; + } + } + + ICR &= ~ICR_SCLE; +} + +static void i2c_pxa_slave_stop(struct pxa_i2c *i2c) +{ + if (i2c->msg) + i2c_pxa_master_complete(i2c, I2C_RETRY); +} +#endif + +/* + * PXA I2C Master mode + */ + +static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg) +{ + unsigned int addr = (msg->addr & 0x7f) << 1; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + return addr; +} + +static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) +{ + u32 icr; + + /* + * Step 1: target slave address into IDBR + */ + IDBR = i2c_pxa_addr_byte(i2c->msg); + + /* + * Step 2: initiate the write. + */ + icr = ICR & ~(ICR_STOP | ICR_ALDIE); + ICR = icr | ICR_START | ICR_TB; +} + +/* + * We are protected by the adapter bus semaphore. + */ +static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) +{ + long timeout; + int ret; + + /* + * Wait for the bus to become free. + */ + ret = i2c_pxa_wait_bus_not_busy(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n"); + goto out; + } + + /* + * Set master mode. + */ + ret = i2c_pxa_set_master(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret); + goto out; + } + + spin_lock_irq(&i2c->lock); + + i2c->msg = msg; + i2c->msg_num = num; + i2c->msg_idx = 0; + i2c->msg_ptr = 0; + i2c->irqlogidx = 0; + + i2c_pxa_start_message(i2c); + + spin_unlock_irq(&i2c->lock); + + /* + * The rest of the processing occurs in the interrupt handler. + */ + timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + + /* + * We place the return code in i2c->msg_idx. + */ + ret = i2c->msg_idx; + + if (timeout == 0) + i2c_pxa_scream_blue_murder(i2c, "timeout"); + + out: + return ret; +} + +/* + * i2c_pxa_master_complete - complete the message and wake up. + */ +static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret) +{ + i2c->msg_ptr = 0; + i2c->msg = NULL; + i2c->msg_idx ++; + i2c->msg_num = 0; + if (ret) + i2c->msg_idx = ret; + wake_up(&i2c->wait); +} + +static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) +{ + u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + + again: + /* + * If ISR_ALD is set, we lost arbitration. + */ + if (isr & ISR_ALD) { + /* + * Do we need to do anything here? The PXA docs + * are vague about what happens. + */ + i2c_pxa_scream_blue_murder(i2c, "ALD set"); + + /* + * We ignore this error. We seem to see spurious ALDs + * for seemingly no reason. If we handle them as I think + * they should, we end up causing an I2C error, which + * is painful for some systems. + */ + return; /* ignore */ + } + + if (isr & ISR_BED) { + int ret = BUS_ERROR; + + /* + * I2C bus error - either the device NAK'd us, or + * something more serious happened. If we were NAK'd + * on the initial address phase, we can retry. + */ + if (isr & ISR_ACKNAK) { + if (i2c->msg_ptr == 0 && i2c->msg_idx == 0) + ret = I2C_RETRY; + else + ret = XFER_NAKED; + } + i2c_pxa_master_complete(i2c, ret); + } else if (isr & ISR_RWM) { + /* + * Read mode. We have just sent the address byte, and + * now we must initiate the transfer. + */ + if (i2c->msg_ptr == i2c->msg->len - 1 && + i2c->msg_idx == i2c->msg_num - 1) + icr |= ICR_STOP | ICR_ACKNAK; + + icr |= ICR_ALDIE | ICR_TB; + } else if (i2c->msg_ptr < i2c->msg->len) { + /* + * Write mode. Write the next data byte. + */ + IDBR = i2c->msg->buf[i2c->msg_ptr++]; + + icr |= ICR_ALDIE | ICR_TB; + + /* + * If this is the last byte of the last message, send + * a STOP. + */ + if (i2c->msg_ptr == i2c->msg->len && + i2c->msg_idx == i2c->msg_num - 1) + icr |= ICR_STOP; + } else if (i2c->msg_idx < i2c->msg_num - 1) { + /* + * Next segment of the message. + */ + i2c->msg_ptr = 0; + i2c->msg_idx ++; + i2c->msg++; + + /* + * If we aren't doing a repeated start and address, + * go back and try to send the next byte. Note that + * we do not support switching the R/W direction here. + */ + if (i2c->msg->flags & I2C_M_NOSTART) + goto again; + + /* + * Write the next address. + */ + IDBR = i2c_pxa_addr_byte(i2c->msg); + + /* + * And trigger a repeated start, and send the byte. + */ + icr &= ~ICR_ALDIE; + icr |= ICR_START | ICR_TB; + } else { + if (i2c->msg->len == 0) { + /* + * Device probes have a message length of zero + * and need the bus to be reset before it can + * be used again. + */ + i2c_pxa_reset(i2c); + } + i2c_pxa_master_complete(i2c, 0); + } + + i2c->icrlog[i2c->irqlogidx-1] = icr; + + ICR = icr; + show_state(i2c); +} + +static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) +{ + u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB); + + /* + * Read the byte. + */ + i2c->msg->buf[i2c->msg_ptr++] = IDBR; + + if (i2c->msg_ptr < i2c->msg->len) { + /* + * If this is the last byte of the last + * message, send a STOP. + */ + if (i2c->msg_ptr == i2c->msg->len - 1) + icr |= ICR_STOP | ICR_ACKNAK; + + icr |= ICR_ALDIE | ICR_TB; + } else { + i2c_pxa_master_complete(i2c, 0); + } + + i2c->icrlog[i2c->irqlogidx-1] = icr; + + ICR = icr; +} + +static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs) +{ + struct pxa_i2c *i2c = dev_id; + u32 isr = ISR; + + if (i2c_debug > 2 && 0) { + dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n", + __func__, isr, ICR, IBMR); + decode_ISR(isr); + } + + if (i2c->irqlogidx < sizeof(i2c->isrlog)/sizeof(u32)) + i2c->isrlog[i2c->irqlogidx++] = isr; + + show_state(i2c); + + /* + * Always clear all pending IRQs. + */ + ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED); + + if (isr & ISR_SAD) + i2c_pxa_slave_start(i2c, isr); + if (isr & ISR_SSD) + i2c_pxa_slave_stop(i2c); + + if (i2c_pxa_is_slavemode(i2c)) { + if (isr & ISR_ITE) + i2c_pxa_slave_txempty(i2c, isr); + if (isr & ISR_IRF) + i2c_pxa_slave_rxfull(i2c, isr); + } else if (i2c->msg) { + if (isr & ISR_ITE) + i2c_pxa_irq_txempty(i2c, isr); + if (isr & ISR_IRF) + i2c_pxa_irq_rxfull(i2c, isr); + } else { + i2c_pxa_scream_blue_murder(i2c, "spurious irq"); + } + + return IRQ_HANDLED; +} + + +static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct pxa_i2c *i2c = adap->algo_data; + int ret, i; + + for (i = adap->retries; i >= 0; i--) { + ret = i2c_pxa_do_xfer(i2c, msgs, num); + if (ret != I2C_RETRY) + goto out; + + if (i2c_debug) + dev_dbg(&adap->dev, "Retrying transmission\n"); + udelay(100); + } + i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); + ret = -EREMOTEIO; + out: + i2c_pxa_set_slave(i2c, ret); + return ret; +} + +static struct i2c_algorithm i2c_pxa_algorithm = { + .name = "PXA-I2C-Algorithm", + .id = I2C_ALGO_PXA, + .master_xfer = i2c_pxa_xfer, +}; + +static struct pxa_i2c i2c_pxa = { + .lock = SPIN_LOCK_UNLOCKED, + .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait), + .adap = { + .name = "pxa2xx-i2c", + .id = I2C_ALGO_PXA, + .algo = &i2c_pxa_algorithm, + .retries = 5, + }, +}; + +static int i2c_pxa_probe(struct device *dev) +{ + struct pxa_i2c *i2c = &i2c_pxa; + struct i2c_pxa_platform_data *plat = dev->platform_data; + int ret; + +#ifdef CONFIG_PXA27x + pxa_gpio_mode(GPIO117_I2CSCL_MD); + pxa_gpio_mode(GPIO118_I2CSDA_MD); + udelay(100); +#endif + + i2c->slave_addr = I2C_PXA_SLAVE_ADDR; + +#ifdef CONFIG_I2C_PXA_SLAVE + i2c->slave = &eeprom_client; + if (plat) { + i2c->slave_addr = plat->slave_addr; + if (plat->slave) + i2c->slave = plat->slave; + } +#endif + + pxa_set_cken(CKEN14_I2C, 1); + ret = request_irq(IRQ_I2C, i2c_pxa_handler, SA_INTERRUPT, + "pxa2xx-i2c", i2c); + if (ret) + goto out; + + i2c_pxa_reset(i2c); + + i2c->adap.algo_data = i2c; + i2c->adap.dev.parent = dev; + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + printk(KERN_INFO "I2C: Failed to add bus\n"); + goto err_irq; + } + + dev_set_drvdata(dev, i2c); + +#ifdef CONFIG_I2C_PXA_SLAVE + printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n", + i2c->adap.dev.bus_id, i2c->slave_addr); +#else + printk(KERN_INFO "I2C: %s: PXA I2C adapter\n", + i2c->adap.dev.bus_id); +#endif + return 0; + + err_irq: + free_irq(IRQ_I2C, i2c); + out: + return ret; +} + +static int i2c_pxa_remove(struct device *dev) +{ + struct pxa_i2c *i2c = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + i2c_del_adapter(&i2c->adap); + free_irq(IRQ_I2C, i2c); + pxa_set_cken(CKEN14_I2C, 0); + + return 0; +} + +static struct device_driver i2c_pxa_driver = { + .name = "pxa2xx-i2c", + .bus = &platform_bus_type, + .probe = i2c_pxa_probe, + .remove = i2c_pxa_remove, +}; + +static int __init i2c_adap_pxa_init(void) +{ + return driver_register(&i2c_pxa_driver); +} + +static void i2c_adap_pxa_exit(void) +{ + return driver_unregister(&i2c_pxa_driver); +} + +module_init(i2c_adap_pxa_init); +module_exit(i2c_adap_pxa_exit); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index a3b3825..73a092f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -568,7 +568,6 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) /* i2c bus registration info */ static struct i2c_algorithm s3c24xx_i2c_algorithm = { - .name = "S3C2410-I2C-Algorithm", .master_xfer = s3c24xx_i2c_xfer, .functionality = s3c24xx_i2c_func, }; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index bbd5e4e..080318d 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -357,8 +357,6 @@ static u32 sis5595_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = sis5595_access, .functionality = sis5595_func, }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index f58455e..86f0f44 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -448,8 +448,6 @@ exit: static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = sis630_access, .functionality = sis630_func, }; diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 6484792..ead2ff3 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -249,8 +249,6 @@ static u32 sis96x_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = sis96x_access, .functionality = sis96x_func, }; diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index 00d94e8..73f481e 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -109,8 +109,6 @@ static u32 stub_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .functionality = stub_func, .smbus_xfer = stub_xfer, }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 6b50080..99d209e 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -286,8 +286,6 @@ static u32 vt596_func(struct i2c_adapter *adapter) } static struct i2c_algorithm smbus_algorithm = { - .name = "Non-I2C SMBus adapter", - .id = I2C_ALGO_SMBUS, .smbus_xfer = vt596_access, .functionality = vt596_func, }; diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index a18bdd9..a1d580e 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -395,8 +395,6 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter) /* For now, we only handle combined mode (smbus) */ static struct i2c_algorithm scx200_acb_algorithm = { - .name = "NatSemi SCx200 ACCESS.bus", - .id = I2C_ALGO_SMBUS, .smbus_xfer = scx200_acb_smbus_xfer, .functionality = scx200_acb_func, }; @@ -456,7 +454,7 @@ static int __init scx200_acb_create(int base, int index) i2c_set_adapdata(adapter, iface); snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index); adapter->owner = THIS_MODULE; - adapter->id = I2C_ALGO_SMBUS; + adapter->id = I2C_HW_SMBUS_SCX200; adapter->algo = &scx200_acb_algorithm; adapter->class = I2C_CLASS_HWMON; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 43f70db..6bd44a4 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -2,17 +2,12 @@ # Miscellaneous I2C chip drivers configuration # -config I2C_SENSOR - tristate - default n - menu "Miscellaneous I2C Chip support" depends on I2C config SENSORS_DS1337 tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" depends on I2C && EXPERIMENTAL - select I2C_SENSOR help If you say yes here you get support for Dallas Semiconductor DS1337 and DS1339 real-time clock chips. @@ -23,7 +18,6 @@ config SENSORS_DS1337 config SENSORS_DS1374 tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" depends on I2C && EXPERIMENTAL - select I2C_SENSOR help If you say yes here you get support for Dallas Semiconductor DS1374 real-time clock chips. @@ -34,7 +28,6 @@ config SENSORS_DS1374 config SENSORS_EEPROM tristate "EEPROM reader" depends on I2C && EXPERIMENTAL - select I2C_SENSOR help If you say yes here you get read-only access to the EEPROM data available on modern memory DIMMs and Sony Vaio laptops. Such @@ -46,7 +39,6 @@ config SENSORS_EEPROM config SENSORS_PCF8574 tristate "Philips PCF8574 and PCF8574A" depends on I2C && EXPERIMENTAL - select I2C_SENSOR help If you say yes here you get support for Philips PCF8574 and PCF8574A chips. @@ -67,7 +59,6 @@ config SENSORS_PCA9539 config SENSORS_PCF8591 tristate "Philips PCF8591" depends on I2C && EXPERIMENTAL - select I2C_SENSOR help If you say yes here you get support for Philips PCF8591 chips. @@ -77,7 +68,6 @@ config SENSORS_PCF8591 config SENSORS_RTC8564 tristate "Epson 8564 RTC chip" depends on I2C && EXPERIMENTAL - select I2C_SENSOR help If you say yes here you get support for the Epson 8564 RTC chip. diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c index 82cf959..9d3175c 100644 --- a/drivers/i2c/chips/ds1337.c +++ b/drivers/i2c/chips/ds1337.c @@ -17,7 +17,6 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/i2c-sensor.h> #include <linux/string.h> #include <linux/rtc.h> /* get the user-level API */ #include <linux/bcd.h> @@ -39,9 +38,8 @@ * Functions declaration */ static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; -SENSORS_INSMOD_1(ds1337); +I2C_CLIENT_INSMOD_1(ds1337); static int ds1337_attach_adapter(struct i2c_adapter *adapter); static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind); @@ -227,7 +225,7 @@ int ds1337_do_command(int bus, int cmd, void *arg) static int ds1337_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, ds1337_detect); + return i2c_probe(adapter, &addr_data, ds1337_detect); } /* @@ -354,11 +352,8 @@ static int ds1337_detach_client(struct i2c_client *client) int err; struct ds1337_data *data = i2c_get_clientdata(client); - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); + if ((err = i2c_detach_client(client))) return err; - } list_del(&data->list); kfree(data); diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index a445736..0936327 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -53,7 +53,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, .probe = ignore, .ignore = ignore, - .force = ignore, }; static ulong ds1374_read_rtc(void) @@ -166,7 +165,7 @@ static void ds1374_set_tlet(ulong arg) "can't confirm time set from rtc chip\n"); } -ulong new_time; +static ulong new_time; DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time); diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index a2da31b..d58403a 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -33,15 +33,13 @@ #include <linux/sched.h> #include <linux/jiffies.h> #include <linux/i2c.h> -#include <linux/i2c-sensor.h> /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_1(eeprom); +I2C_CLIENT_INSMOD_1(eeprom); /* Size of EEPROM in bytes */ @@ -153,21 +151,16 @@ static struct bin_attribute eeprom_attr = { static int eeprom_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, eeprom_detect); + return i2c_probe(adapter, &addr_data, eeprom_detect); } -/* This function is called by i2c_detect */ +/* This function is called by i2c_probe */ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; struct eeprom_data *data; int err = 0; - /* prevent 24RF08 corruption */ - if (kind < 0) - i2c_smbus_xfer(adapter, address, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - /* There are three ways we can read the EEPROM data: (1) I2C block reads (faster, but unsupported by most adapters) (2) Consecutive byte reads (100% overhead) @@ -231,10 +224,8 @@ static int eeprom_detach_client(struct i2c_client *client) int err; err = i2c_detach_client(client); - if (err) { - dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + if (err) return err; - } kfree(i2c_get_clientdata(client)); diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index 354a262..8ee56d4 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -1489,7 +1489,7 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind) if (the_transceiver) return 0; - isp = kcalloc(1, sizeof *isp, GFP_KERNEL); + isp = kzalloc(sizeof *isp, GFP_KERNEL); if (!isp) return 0; diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 778d7e1..3f14528 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -42,7 +42,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, .probe = ignore, .ignore = ignore, - .force = ignore, }; ulong @@ -145,7 +144,7 @@ m41t00_set_tlet(ulong arg) return; } -ulong new_time; +static ulong new_time; DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time); diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 0230375..9e1aeb6 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -5,97 +5,60 @@ Based on i2c/chips/eeprom.c - The MAX6875 has two EEPROM sections: config and user. - At reset, the config EEPROM is read into the registers. + The MAX6875 has a bank of registers and two banks of EEPROM. + Address ranges are defined as follows: + * 0x0000 - 0x0046 = configuration registers + * 0x8000 - 0x8046 = configuration EEPROM + * 0x8100 - 0x82FF = user EEPROM - This driver make 3 binary files available in sysfs: - reg_config - direct access to the registers - eeprom_config - acesses configuration eeprom space - eeprom_user - free for application use + This driver makes the user EEPROM available for read. - In our application, we put device serial & model numbers in user eeprom. + The registers & config EEPROM should be accessed via i2c-dev. - Notes: - 1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT - be overwritten, so the driver explicitly prevents that. - 2) It's a good idea to keep the config (0x45) locked in config EEPROM. - You can temporarily enable config writes by changing register 0x45. + The MAX6875 ignores the lowest address bit, so each chip responds to + two addresses - 0x50/0x51 and 0x52/0x53. + + Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read + address, so this driver is destructive if loaded for the wrong EEPROM chip. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/sched.h> -#include <linux/delay.h> #include <linux/i2c.h> -#include <linux/i2c-sensor.h> +#include <asm/semaphore.h> -/* Addresses to scan */ -/* No address scanned by default, as this could corrupt standard EEPROMS. */ +/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; /* Insmod parameters */ -SENSORS_INSMOD_1(max6875); - -/* this param will prevent 'accidental' writes to the eeprom */ -static int allow_write = 0; -module_param(allow_write, int, 0); -MODULE_PARM_DESC(allow_write, - "Enable write access:\n" - "*0: Read only\n" - " 1: Read/Write access"); +I2C_CLIENT_INSMOD_1(max6875); /* The MAX6875 can only read/write 16 bytes at a time */ #define SLICE_SIZE 16 #define SLICE_BITS 4 -/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */ -#define CONFIG_EEPROM_BASE 0x8000 -#define CONFIG_EEPROM_SIZE 0x0046 -#define CONFIG_EEPROM_SLICES 5 - /* USER EEPROM is at addresses 0x8100 - 0x82FF */ #define USER_EEPROM_BASE 0x8100 #define USER_EEPROM_SIZE 0x0200 #define USER_EEPROM_SLICES 32 /* MAX6875 commands */ -#define MAX6875_CMD_BLOCK_WRITE 0x83 -#define MAX6875_CMD_BLOCK_READ 0x84 -#define MAX6875_CMD_REBOOT 0x88 - -enum max6875_area_type { - max6875_register_config=0, - max6875_eeprom_config, - max6875_eeprom_user, - max6857_max -}; - -struct eeprom_block { - enum max6875_area_type type; - u8 slices; - u32 size; - u32 valid; - u32 base; - unsigned long *updated; - u8 *data; -}; +#define MAX6875_CMD_BLK_READ 0x84 /* Each client has this additional data */ struct max6875_data { struct i2c_client client; struct semaphore update_lock; - struct eeprom_block blocks[max6857_max]; - /* the above structs point into the arrays below */ - u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)]; - unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)]; + + u32 valid; + u8 data[USER_EEPROM_SIZE]; + unsigned long last_updated[USER_EEPROM_SLICES]; }; static int max6875_attach_adapter(struct i2c_adapter *adapter); @@ -111,337 +74,160 @@ static struct i2c_driver max6875_driver = { .detach_client = max6875_detach_client, }; -static int max6875_update_slice(struct i2c_client *client, - struct eeprom_block *blk, - int slice) +static void max6875_update_slice(struct i2c_client *client, int slice) { struct max6875_data *data = i2c_get_clientdata(client); - int i, j, addr, count; - u8 rdbuf[SLICE_SIZE]; - int retval = 0; + int i, j, addr; + u8 *buf; - if (slice >= blk->slices) - return -1; + if (slice >= USER_EEPROM_SLICES) + return; down(&data->update_lock); - if (!(blk->valid & (1 << slice)) || - (jiffies - blk->updated[slice] > 300 * HZ) || - (jiffies < blk->updated[slice])) { - dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n", - slice, blk->base); + buf = &data->data[slice << SLICE_BITS]; - addr = blk->base + (slice << SLICE_BITS); - count = blk->size - (slice << SLICE_BITS); - if (count > SLICE_SIZE) { - count = SLICE_SIZE; - } + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice])) { - /* Preset the read address */ - if (addr < 0x100) { - /* select the register */ - if (i2c_smbus_write_byte(client, addr & 0xFF)) { - dev_dbg(&client->dev, "max6875 register select has failed!\n"); - retval = -1; - goto exit; - } - } else { - /* select the eeprom */ - if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { - dev_dbg(&client->dev, "max6875 address set has failed!\n"); - retval = -1; - goto exit; - } + dev_dbg(&client->dev, "Starting update of slice %u\n", slice); + + data->valid &= ~(1 << slice); + + addr = USER_EEPROM_BASE + (slice << SLICE_BITS); + + /* select the eeprom address */ + if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { + dev_err(&client->dev, "address set failed\n"); + goto exit_up; } - if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ, - rdbuf) != SLICE_SIZE) - { - retval = -1; - goto exit; + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (i2c_smbus_read_i2c_block_data(client, + MAX6875_CMD_BLK_READ, + buf) != SLICE_SIZE) { + goto exit_up; } - - memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count); } else { - for (i = 0; i < count; i++) { + for (i = 0; i < SLICE_SIZE; i++) { j = i2c_smbus_read_byte(client); - if (j < 0) - { - retval = -1; - goto exit; + if (j < 0) { + goto exit_up; } - blk->data[(slice << SLICE_BITS) + i] = (u8) j; + buf[i] = j; } } - blk->updated[slice] = jiffies; - blk->valid |= (1 << slice); + data->last_updated[slice] = jiffies; + data->valid |= (1 << slice); } - exit: +exit_up: up(&data->update_lock); - return retval; } -static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count, - enum max6875_area_type area_type) +static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, + size_t count) { - struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); + struct i2c_client *client = kobj_to_i2c_client(kobj); struct max6875_data *data = i2c_get_clientdata(client); - struct eeprom_block *blk; - int slice; - - blk = &data->blocks[area_type]; + int slice, max_slice; - if (off > blk->size) + if (off > USER_EEPROM_SIZE) return 0; - if (off + count > blk->size) - count = blk->size - off; - /* Only refresh slices which contain requested bytes */ - for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) - max6875_update_slice(client, blk, slice); + if (off + count > USER_EEPROM_SIZE) + count = USER_EEPROM_SIZE - off; - memcpy(buf, &blk->data[off], count); + /* refresh slices which contain requested bytes */ + max_slice = (off + count - 1) >> SLICE_BITS; + for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) + max6875_update_slice(client, slice); - return count; -} - -static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_read(kobj, buf, off, count, max6875_eeprom_user); -} - -static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_read(kobj, buf, off, count, max6875_eeprom_config); -} - -static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_read(kobj, buf, off, count, max6875_register_config); -} - - -static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count, - enum max6875_area_type area_type) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj)); - struct max6875_data *data = i2c_get_clientdata(client); - struct eeprom_block *blk; - int slice, addr, retval; - ssize_t sent = 0; - - blk = &data->blocks[area_type]; - - if (off > blk->size) - return 0; - if ((off + count) > blk->size) - count = blk->size - off; - - if (down_interruptible(&data->update_lock)) - return -EAGAIN; - - /* writing to a register is done with i2c_smbus_write_byte_data() */ - if (blk->type == max6875_register_config) { - for (sent = 0; sent < count; sent++) { - addr = off + sent; - if (addr == 0x44) - continue; - - retval = i2c_smbus_write_byte_data(client, addr, buf[sent]); - } - } else { - int cmd, val; - - /* We are writing to EEPROM */ - for (sent = 0; sent < count; sent++) { - addr = blk->base + off + sent; - cmd = addr >> 8; - val = (addr & 0xff) | (buf[sent] << 8); // reversed - - if (addr == 0x8044) - continue; - - retval = i2c_smbus_write_word_data(client, cmd, val); - - if (retval) { - goto error_exit; - } + memcpy(buf, &data->data[off], count); - /* A write takes up to 11 ms */ - msleep(11); - } - } - - /* Invalidate the scratch buffer */ - for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++) - blk->valid &= ~(1 << slice); - - error_exit: - up(&data->update_lock); - - return sent; -} - -static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_write(kobj, buf, off, count, max6875_eeprom_user); -} - -static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_write(kobj, buf, off, count, max6875_eeprom_config); -} - -static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - return max6875_write(kobj, buf, off, count, max6875_register_config); + return count; } static struct bin_attribute user_eeprom_attr = { .attr = { - .name = "eeprom_user", - .mode = S_IRUGO | S_IWUSR | S_IWGRP, - .owner = THIS_MODULE, - }, - .size = USER_EEPROM_SIZE, - .read = max6875_user_read, - .write = max6875_user_write, -}; - -static struct bin_attribute config_eeprom_attr = { - .attr = { - .name = "eeprom_config", - .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, - }, - .size = CONFIG_EEPROM_SIZE, - .read = max6875_config_read, - .write = max6875_config_write, -}; - -static struct bin_attribute config_register_attr = { - .attr = { - .name = "reg_config", - .mode = S_IRUGO | S_IWUSR, + .name = "eeprom", + .mode = S_IRUGO, .owner = THIS_MODULE, }, - .size = CONFIG_EEPROM_SIZE, - .read = max6875_cfgreg_read, - .write = max6875_cfgreg_write, + .size = USER_EEPROM_SIZE, + .read = max6875_read, }; static int max6875_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, max6875_detect); + return i2c_probe(adapter, &addr_data, max6875_detect); } -/* This function is called by i2c_detect */ +/* This function is called by i2c_probe */ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *real_client; + struct i2c_client *fake_client; struct max6875_data *data; int err = 0; - /* Prevent 24RF08 corruption (in case of user error) */ - if (kind < 0) - i2c_smbus_xfer(adapter, address, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - - /* There are three ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) - (2) Consecutive byte reads (100% overhead) - (3) Regular byte data reads (200% overhead) - The third method is not implemented by this driver because all - known adapters support at least the second. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access eeprom_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return 0; + + /* Only check even addresses */ + if (address & 1) + return 0; + + if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) + return -ENOMEM; memset(data, 0, sizeof(struct max6875_data)); - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &max6875_driver; - new_client->flags = 0; - - /* Setup the user section */ - data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; - data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; - data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE; - data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE; - data->blocks[max6875_eeprom_user].data = data->data; - data->blocks[max6875_eeprom_user].updated = data->last_updated; - - /* Setup the config section */ - data->blocks[max6875_eeprom_config].type = max6875_eeprom_config; - data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES; - data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE; - data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE; - data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE]; - data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES]; - - /* Setup the register section */ - data->blocks[max6875_register_config].type = max6875_register_config; - data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES; - data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE; - data->blocks[max6875_register_config].base = 0; - data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE]; - data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES]; - - /* Init the data */ - memset(data->data, 0xff, sizeof(data->data)); - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, "max6875", I2C_NAME_SIZE); + /* A fake client is created on the odd address */ + if (!(fake_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_kfree1; + } + memset(fake_client, 0, sizeof(struct i2c_client)); + + /* Init real i2c_client */ + real_client = &data->client; + i2c_set_clientdata(real_client, data); + real_client->addr = address; + real_client->adapter = adapter; + real_client->driver = &max6875_driver; + real_client->flags = 0; + strlcpy(real_client->name, "max6875", I2C_NAME_SIZE); init_MUTEX(&data->update_lock); - /* Verify that the chip is really what we think it is */ - if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) || - (max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0)) - goto exit_kfree; - - /* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */ - if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) || - (data->blocks[max6875_eeprom_config].data[0x42] != 0) || - (data->blocks[max6875_register_config].data[0x41] != 0) || - (data->blocks[max6875_register_config].data[0x42] != 0) || - (data->blocks[max6875_eeprom_config].data[0x40] != - data->blocks[max6875_register_config].data[0x40])) - goto exit_kfree; - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_kfree; - - /* create the sysfs eeprom files with the correct permissions */ - if (allow_write == 0) { - user_eeprom_attr.attr.mode &= ~S_IWUGO; - user_eeprom_attr.write = NULL; - config_eeprom_attr.attr.mode &= ~S_IWUGO; - config_eeprom_attr.write = NULL; - config_register_attr.attr.mode &= ~S_IWUGO; - config_register_attr.write = NULL; - } - sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr); - sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr); - sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr); + /* Init fake client data */ + /* set the client data to the i2c_client so that it will get freed */ + i2c_set_clientdata(fake_client, fake_client); + fake_client->addr = address | 1; + fake_client->adapter = adapter; + fake_client->driver = &max6875_driver; + fake_client->flags = 0; + strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE); + + /* Prevent 24RF08 corruption (in case of user error) */ + i2c_smbus_write_quick(real_client, 0); + + if ((err = i2c_attach_client(real_client)) != 0) + goto exit_kfree2; + + if ((err = i2c_attach_client(fake_client)) != 0) + goto exit_detach; + + sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr); return 0; -exit_kfree: +exit_detach: + i2c_detach_client(real_client); +exit_kfree2: + kfree(fake_client); +exit_kfree1: kfree(data); -exit: return err; } @@ -450,13 +236,9 @@ static int max6875_detach_client(struct i2c_client *client) int err; err = i2c_detach_client(client); - if (err) { - dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + if (err) return err; - } - kfree(i2c_get_clientdata(client)); - return 0; } diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c index 9f3ad45..225577f 100644 --- a/drivers/i2c/chips/pca9539.c +++ b/drivers/i2c/chips/pca9539.c @@ -13,14 +13,12 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon-sysfs.h> -#include <linux/i2c-sensor.h> /* Addresses to scan */ static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END}; -static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; /* Insmod parameters */ -SENSORS_INSMOD_1(pca9539); +I2C_CLIENT_INSMOD_1(pca9539); enum pca9539_cmd { @@ -109,10 +107,10 @@ static struct attribute_group pca9539_defattr_group = { static int pca9539_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, pca9539_detect); + return i2c_probe(adapter, &addr_data, pca9539_detect); } -/* This function is called by i2c_detect */ +/* This function is called by i2c_probe */ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; @@ -164,10 +162,8 @@ static int pca9539_detach_client(struct i2c_client *client) { int err; - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed.\n"); + if ((err = i2c_detach_client(client))) return err; - } kfree(i2c_get_clientdata(client)); return 0; diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index cfcf646..6525743 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -39,16 +39,14 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/i2c-sensor.h> /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_2(pcf8574, pcf8574a); +I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); /* Initial values */ #define PCF8574_INIT 255 /* All outputs on (input mode) */ @@ -113,10 +111,10 @@ static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write); static int pcf8574_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, pcf8574_detect); + return i2c_probe(adapter, &addr_data, pcf8574_detect); } -/* This function is called by i2c_detect */ +/* This function is called by i2c_probe */ int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; @@ -186,11 +184,8 @@ static int pcf8574_detach_client(struct i2c_client *client) { int err; - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); + if ((err = i2c_detach_client(client))) return err; - } kfree(i2c_get_clientdata(client)); return 0; diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index db812ad..80f1df9 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -24,15 +24,13 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/i2c-sensor.h> /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_1(pcf8591); +I2C_CLIENT_INSMOD_1(pcf8591); static int input_mode; module_param(input_mode, int, 0); @@ -164,10 +162,10 @@ static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, */ static int pcf8591_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, pcf8591_detect); + return i2c_probe(adapter, &addr_data, pcf8591_detect); } -/* This function is called by i2c_detect */ +/* This function is called by i2c_probe */ int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *new_client; @@ -241,11 +239,8 @@ static int pcf8591_detach_client(struct i2c_client *client) { int err; - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); + if ((err = i2c_detach_client(client))) return err; - } kfree(i2c_get_clientdata(client)); return 0; diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c index 588fc22..0b5385c 100644 --- a/drivers/i2c/chips/rtc8564.c +++ b/drivers/i2c/chips/rtc8564.c @@ -67,7 +67,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, .probe = ignore, .ignore = ignore, - .force = ignore, }; static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 4a9ead2..dda472e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -61,7 +61,7 @@ static int i2c_bus_resume(struct device * dev) return rc; } -static struct bus_type i2c_bus_type = { +struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .suspend = i2c_bus_suspend, @@ -78,13 +78,13 @@ static int i2c_device_remove(struct device *dev) return 0; } -static void i2c_adapter_dev_release(struct device *dev) +void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = dev_to_i2c_adapter(dev); complete(&adap->dev_released); } -static struct device_driver i2c_adapter_driver = { +struct device_driver i2c_adapter_driver = { .name = "i2c_adapter", .bus = &i2c_bus_type, .probe = i2c_device_probe, @@ -97,7 +97,7 @@ static void i2c_adapter_class_dev_release(struct class_device *dev) complete(&adap->class_dev_released); } -static struct class i2c_adapter_class = { +struct class i2c_adapter_class = { .name = "i2c-adapter", .release = &i2c_adapter_class_dev_release, }; @@ -188,6 +188,8 @@ int i2c_add_adapter(struct i2c_adapter *adap) strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE); class_device_register(&adap->class_dev); + dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); + /* inform drivers of new adapters */ list_for_each(item,&drivers) { driver = list_entry(item, struct i2c_driver, list); @@ -196,8 +198,6 @@ int i2c_add_adapter(struct i2c_adapter *adap) driver->attach_adapter(adap); } - dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr); - out_unlock: up(&core_lists); return res; @@ -220,8 +220,8 @@ int i2c_del_adapter(struct i2c_adapter *adap) break; } if (adap_from_list != adap) { - pr_debug("I2C: Attempting to delete an unregistered " - "adapter\n"); + pr_debug("i2c-core: attempting to delete unregistered " + "adapter [%s]\n", adap->name); res = -EINVAL; goto out_unlock; } @@ -230,9 +230,8 @@ int i2c_del_adapter(struct i2c_adapter *adap) driver = list_entry(item, struct i2c_driver, list); if (driver->detach_adapter) if ((res = driver->detach_adapter(adap))) { - dev_warn(&adap->dev, "can't detach adapter " - "while detaching driver %s: driver " - "not detached!\n", driver->name); + dev_err(&adap->dev, "detach_adapter failed " + "for driver [%s]\n", driver->name); goto out_unlock; } } @@ -247,9 +246,8 @@ int i2c_del_adapter(struct i2c_adapter *adap) * must be deleted, as this would cause invalid states. */ if ((res=client->driver->detach_client(client))) { - dev_err(&adap->dev, "adapter not " - "unregistered, because client at " - "address %02x can't be detached. ", + dev_err(&adap->dev, "detach_client failed for client " + "[%s] at address 0x%02x\n", client->name, client->addr); goto out_unlock; } @@ -270,7 +268,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* free dynamically allocated bus id */ idr_remove(&i2c_adapter_idr, adap->nr); - dev_dbg(&adap->dev, "adapter unregistered\n"); + dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); out_unlock: up(&core_lists); @@ -303,7 +301,7 @@ int i2c_add_driver(struct i2c_driver *driver) goto out_unlock; list_add_tail(&driver->list,&drivers); - pr_debug("i2c-core: driver %s registered.\n", driver->name); + pr_debug("i2c-core: driver [%s] registered\n", driver->name); /* now look for instances of driver on our adapters */ if (driver->flags & I2C_DF_NOTIFY) { @@ -331,21 +329,17 @@ int i2c_del_driver(struct i2c_driver *driver) /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver * afterwards. - */ - pr_debug("i2c-core: unregister_driver - looking for clients.\n"); - /* removing clients does not depend on the notify flag, else + * + * Removing clients does not depend on the notify flag, else * invalid operation might (will!) result, when using stale client * pointers. */ list_for_each(item1,&adapters) { adap = list_entry(item1, struct i2c_adapter, list); - dev_dbg(&adap->dev, "examining adapter\n"); if (driver->detach_adapter) { if ((res = driver->detach_adapter(adap))) { - dev_warn(&adap->dev, "while unregistering " - "dummy driver %s, adapter could " - "not be detached properly; driver " - "not unloaded!",driver->name); + dev_err(&adap->dev, "detach_adapter failed " + "for driver [%s]\n", driver->name); goto out_unlock; } } else { @@ -353,16 +347,13 @@ int i2c_del_driver(struct i2c_driver *driver) client = list_entry(item2, struct i2c_client, list); if (client->driver != driver) continue; - pr_debug("i2c-core.o: detaching client %s:\n", client->name); + dev_dbg(&adap->dev, "detaching client [%s] " + "at 0x%02x\n", client->name, + client->addr); if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "while " - "unregistering driver " - "`%s', the client at " - "address %02x of " - "adapter could not " - "be detached; driver " - "not unloaded!", - driver->name, + dev_err(&adap->dev, "detach_client " + "failed for client [%s] at " + "0x%02x\n", client->name, client->addr); goto out_unlock; } @@ -372,7 +363,7 @@ int i2c_del_driver(struct i2c_driver *driver) driver_unregister(&driver->driver); list_del(&driver->list); - pr_debug("i2c-core: driver unregistered: %s\n", driver->name); + pr_debug("i2c-core: driver [%s] unregistered\n", driver->name); out_unlock: up(&core_lists); @@ -417,15 +408,12 @@ int i2c_attach_client(struct i2c_client *client) if (adapter->client_register) { if (adapter->client_register(client)) { - dev_warn(&adapter->dev, "warning: client_register " - "seems to have failed for client %02x\n", - client->addr); + dev_dbg(&adapter->dev, "client_register " + "failed for client [%s] at 0x%02x\n", + client->name, client->addr); } } - dev_dbg(&adapter->dev, "client [%s] registered to adapter\n", - client->name); - if (client->flags & I2C_CLIENT_ALLOW_USE) client->usage_count = 0; @@ -436,7 +424,8 @@ int i2c_attach_client(struct i2c_client *client) snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); - pr_debug("registering %s\n", client->dev.bus_id); + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", + client->name, client->dev.bus_id); device_register(&client->dev); device_create_file(&client->dev, &dev_attr_client_name); @@ -449,8 +438,12 @@ int i2c_detach_client(struct i2c_client *client) struct i2c_adapter *adapter = client->adapter; int res = 0; - if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0)) + if ((client->flags & I2C_CLIENT_ALLOW_USE) + && (client->usage_count > 0)) { + dev_warn(&client->dev, "Client [%s] still busy, " + "can't detach\n", client->name); return -EBUSY; + } if (adapter->client_unregister) { res = adapter->client_unregister(client); @@ -669,98 +662,128 @@ int i2c_control(struct i2c_client *client, * Will not work for 10-bit addresses! * ---------------------------------------------------- */ +static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, + int (*found_proc) (struct i2c_adapter *, int, int)) +{ + int err; + + /* Make sure the address is valid */ + if (addr < 0x03 || addr > 0x77) { + dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", + addr); + return -EINVAL; + } + + /* Skip if already in use */ + if (i2c_check_addr(adapter, addr)) + return 0; + + /* Make sure there is something at this address, unless forced */ + if (kind < 0) { + if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, + I2C_SMBUS_QUICK, NULL) < 0) + return 0; + + /* prevent 24RF08 corruption */ + if ((addr & ~0x0f) == 0x50) + i2c_smbus_xfer(adapter, addr, 0, 0, 0, + I2C_SMBUS_QUICK, NULL); + } + + /* Finally call the custom detection function */ + err = found_proc(adapter, addr, kind); + + /* -ENODEV can be returned if there is a chip at the given address + but it isn't supported by this chip driver. We catch it here as + this isn't an error. */ + return (err == -ENODEV) ? 0 : err; +} + int i2c_probe(struct i2c_adapter *adapter, struct i2c_client_address_data *address_data, int (*found_proc) (struct i2c_adapter *, int, int)) { - int addr,i,found,err; + int i, err; int adap_id = i2c_adapter_id(adapter); /* Forget it if we can't probe using SMBUS_QUICK */ if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) return -1; - for (addr = 0x00; addr <= 0x7f; addr++) { - - /* Skip if already in use */ - if (i2c_check_addr(adapter,addr)) - continue; - - /* If it is in one of the force entries, we don't do any detection - at all */ - found = 0; - - for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) { - if (((adap_id == address_data->force[i]) || - (address_data->force[i] == ANY_I2C_BUS)) && - (addr == address_data->force[i+1])) { - dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", - adap_id, addr); - if ((err = found_proc(adapter,addr,0))) - return err; - found = 1; - } - } - if (found) - continue; - - /* If this address is in one of the ignores, we can forget about - it right now */ - for (i = 0; - !found && (address_data->ignore[i] != I2C_CLIENT_END); - i += 2) { - if (((adap_id == address_data->ignore[i]) || - ((address_data->ignore[i] == ANY_I2C_BUS))) && - (addr == address_data->ignore[i+1])) { - dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, " - "addr %04x\n", adap_id ,addr); - found = 1; + /* Force entries are done first, and are not affected by ignore + entries */ + if (address_data->forces) { + unsigned short **forces = address_data->forces; + int kind; + + for (kind = 0; forces[kind]; kind++) { + for (i = 0; forces[kind][i] != I2C_CLIENT_END; + i += 2) { + if (forces[kind][i] == adap_id + || forces[kind][i] == ANY_I2C_BUS) { + dev_dbg(&adapter->dev, "found force " + "parameter for adapter %d, " + "addr 0x%02x, kind %d\n", + adap_id, forces[kind][i + 1], + kind); + err = i2c_probe_address(adapter, + forces[kind][i + 1], + kind, found_proc); + if (err) + return err; + } } } - if (found) - continue; + } - /* Now, we will do a detection, but only if it is in the normal or - probe entries */ - for (i = 0; - !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); - i += 1) { - if (addr == address_data->normal_i2c[i]) { - found = 1; - dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, " - "addr %02x\n", adap_id, addr); - } + /* Probe entries are done second, and are not affected by ignore + entries either */ + for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { + if (address_data->probe[i] == adap_id + || address_data->probe[i] == ANY_I2C_BUS) { + dev_dbg(&adapter->dev, "found probe parameter for " + "adapter %d, addr 0x%02x\n", adap_id, + address_data->probe[i + 1]); + err = i2c_probe_address(adapter, + address_data->probe[i + 1], + -1, found_proc); + if (err) + return err; } + } - for (i = 0; - !found && (address_data->probe[i] != I2C_CLIENT_END); - i += 2) { - if (((adap_id == address_data->probe[i]) || - ((address_data->probe[i] == ANY_I2C_BUS))) && - (addr == address_data->probe[i+1])) { - found = 1; - dev_dbg(&adapter->dev, "found probe parameter for adapter %d, " - "addr %04x\n", adap_id,addr); + /* Normal entries are done last, unless shadowed by an ignore entry */ + for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { + int j, ignore; + + ignore = 0; + for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; + j += 2) { + if ((address_data->ignore[j] == adap_id || + address_data->ignore[j] == ANY_I2C_BUS) + && address_data->ignore[j + 1] + == address_data->normal_i2c[i]) { + dev_dbg(&adapter->dev, "found ignore " + "parameter for adapter %d, " + "addr 0x%02x\n", adap_id, + address_data->ignore[j + 1]); } + ignore = 1; + break; } - if (!found) + if (ignore) continue; - /* OK, so we really should examine this address. First check - whether there is some client here at all! */ - if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) - if ((err = found_proc(adapter,addr,-1))) - return err; + dev_dbg(&adapter->dev, "found normal entry for adapter %d, " + "addr 0x%02x\n", adap_id, + address_data->normal_i2c[i]); + err = i2c_probe_address(adapter, address_data->normal_i2c[i], + -1, found_proc); + if (err) + return err; } - return 0; -} -/* - * return id number for a specific adapter - */ -int i2c_adapter_id(struct i2c_adapter *adap) -{ - return adap->nr; + return 0; } struct i2c_adapter* i2c_get_adapter(int id) @@ -1171,6 +1194,12 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, } +/* Next four are needed by i2c-isa */ +EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); +EXPORT_SYMBOL_GPL(i2c_adapter_driver); +EXPORT_SYMBOL_GPL(i2c_adapter_class); +EXPORT_SYMBOL_GPL(i2c_bus_type); + EXPORT_SYMBOL(i2c_add_adapter); EXPORT_SYMBOL(i2c_del_adapter); EXPORT_SYMBOL(i2c_add_driver); @@ -1186,7 +1215,6 @@ EXPORT_SYMBOL(i2c_master_send); EXPORT_SYMBOL(i2c_master_recv); EXPORT_SYMBOL(i2c_control); EXPORT_SYMBOL(i2c_transfer); -EXPORT_SYMBOL(i2c_adapter_id); EXPORT_SYMBOL(i2c_get_adapter); EXPORT_SYMBOL(i2c_put_adapter); EXPORT_SYMBOL(i2c_probe); diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index bc5d557..aa7a4fa 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -434,7 +434,8 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap) devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor), S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor); - dev_dbg(&adap->dev, "Registered as minor %d\n", i2c_dev->minor); + pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", + adap->name, i2c_dev->minor); /* register this i2c device with the driver core */ i2c_dev->adap = adap; @@ -471,7 +472,7 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap) wait_for_completion(&i2c_dev->released); kfree(i2c_dev); - dev_dbg(&adap->dev, "Adapter unregistered\n"); + pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name); return 0; } diff --git a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c deleted file mode 100644 index f99a816..0000000 --- a/drivers/i2c/i2c-sensor-detect.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - i2c-sensor-detect.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl> and - Mark D. Studebaker <mdsxyz123@yahoo.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/i2c-sensor.h> - -static unsigned short empty[] = {I2C_CLIENT_END}; -static unsigned int empty_isa[] = {I2C_CLIENT_ISA_END}; - -/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ -int i2c_detect(struct i2c_adapter *adapter, - struct i2c_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int addr, i, found, j, err; - struct i2c_force_data *this_force; - int is_isa = i2c_is_isa_adapter(adapter); - int adapter_id = - is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter); - unsigned short *normal_i2c; - unsigned int *normal_isa; - unsigned short *probe; - unsigned short *ignore; - - /* Forget it if we can't probe using SMBUS_QUICK */ - if ((!is_isa) && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) - return -1; - - /* Use default "empty" list if the adapter doesn't specify any */ - normal_i2c = probe = ignore = empty; - normal_isa = empty_isa; - if (address_data->normal_i2c) - normal_i2c = address_data->normal_i2c; - if (address_data->normal_isa) - normal_isa = address_data->normal_isa; - if (address_data->probe) - probe = address_data->probe; - if (address_data->ignore) - ignore = address_data->ignore; - - for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { - if (!is_isa && i2c_check_addr(adapter, addr)) - continue; - - /* If it is in one of the force entries, we don't do any - detection at all */ - found = 0; - for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) { - for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) { - if ( ((adapter_id == this_force->force[j]) || - ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) && - (addr == this_force->force[j + 1]) ) { - dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr); - if ((err = found_proc(adapter, addr, this_force->kind))) - return err; - found = 1; - } - } - } - if (found) - continue; - - /* If this address is in one of the ignores, we can forget about it - right now */ - for (i = 0; !found && (ignore[i] != I2C_CLIENT_END); i += 2) { - if ( ((adapter_id == ignore[i]) || - ((ignore[i] == ANY_I2C_BUS) && - !is_isa)) && - (addr == ignore[i + 1])) { - dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - if (found) - continue; - - /* Now, we will do a detection, but only if it is in the normal or - probe entries */ - if (is_isa) { - for (i = 0; !found && (normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) { - if (addr == normal_isa[i]) { - dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - } else { - for (i = 0; !found && (normal_i2c[i] != I2C_CLIENT_END); i += 1) { - if (addr == normal_i2c[i]) { - found = 1; - dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x\n", adapter_id, addr); - } - } - } - - for (i = 0; - !found && (probe[i] != I2C_CLIENT_END); - i += 2) { - if (((adapter_id == probe[i]) || - ((probe[i] == ANY_I2C_BUS) && !is_isa)) - && (addr == probe[i + 1])) { - dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr); - found = 1; - } - } - if (!found) - continue; - - /* OK, so we really should examine this address. First check - whether there is some client here at all! */ - if (is_isa || - (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) - if ((err = found_proc(adapter, addr, -1))) - return err; - } - return 0; -} - -EXPORT_SYMBOL(i2c_detect); - -MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " - "Rudolf Marek <r.marek@sh.cvut.cz>"); - -MODULE_DESCRIPTION("i2c-sensor driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/i2c-sensor-vid.c b/drivers/i2c/i2c-sensor-vid.c deleted file mode 100644 index 922e22f..0000000 --- a/drivers/i2c/i2c-sensor-vid.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - i2c-sensor-vid.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> - -struct vrm_model { - u8 vendor; - u8 eff_family; - u8 eff_model; - int vrm_type; -}; - -#define ANY 0xFF - -#ifdef CONFIG_X86 - -static struct vrm_model vrm_models[] = { - {X86_VENDOR_AMD, 0x6, ANY, 90}, /* Athlon Duron etc */ - {X86_VENDOR_AMD, 0xF, ANY, 24}, /* Athlon 64, Opteron */ - {X86_VENDOR_INTEL, 0x6, 0x9, 85}, /* 0.13um too */ - {X86_VENDOR_INTEL, 0x6, 0xB, 85}, /* 0xB Tualatin */ - {X86_VENDOR_INTEL, 0x6, ANY, 82}, /* any P6 */ - {X86_VENDOR_INTEL, 0x7, ANY, 0}, /* Itanium */ - {X86_VENDOR_INTEL, 0xF, 0x3, 100}, /* P4 Prescott */ - {X86_VENDOR_INTEL, 0xF, ANY, 90}, /* P4 before Prescott */ - {X86_VENDOR_INTEL, 0x10,ANY, 0}, /* Itanium 2 */ - {X86_VENDOR_UNKNOWN, ANY, ANY, 0} /* stop here */ - }; - -static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor) -{ - int i = 0; - - while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) { - if (vrm_models[i].vendor==vendor) - if ((vrm_models[i].eff_family==eff_family)&& \ - ((vrm_models[i].eff_model==eff_model)|| \ - (vrm_models[i].eff_model==ANY))) - return vrm_models[i].vrm_type; - i++; - } - - return 0; -} - -int i2c_which_vrm(void) -{ - struct cpuinfo_x86 *c = cpu_data; - u32 eax; - u8 eff_family, eff_model; - int vrm_ret; - - if (c->x86 < 6) return 0; /* any CPU with familly lower than 6 - dont have VID and/or CPUID */ - eax = cpuid_eax(1); - eff_family = ((eax & 0x00000F00)>>8); - eff_model = ((eax & 0x000000F0)>>4); - if (eff_family == 0xF) { /* use extended model & family */ - eff_family += ((eax & 0x00F00000)>>20); - eff_model += ((eax & 0x000F0000)>>16)<<4; - } - vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor); - if (vrm_ret == 0) - printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your" - " x86 CPU\n"); - return vrm_ret; -} - -/* and now for something completely different for Non-x86 world*/ -#else -int i2c_which_vrm(void) -{ - printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your CPU\n"); - return 0; -} -#endif - -EXPORT_SYMBOL(i2c_which_vrm); |