From fccb56e4d82132ac15359efc9e419371e4533437 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:27 +0200 Subject: i2c: Kill i2c_adapter.class_dev Kill i2c_adapter.class_dev. Instead, set the class of i2c_adapter.dev to i2c_adapter_class, so that a symlink will be created for every i2c_adapter in /sys/class/i2c-adapter. The same change must be mirrored to i2c-isa as it duplicates some of the i2c-core functionalities. User-space tools and libraries might need some adjustments. In particular, libsensors from lm_sensors 2.10.3 or later is required for proper discovery of i2c adapter names after this change. Signed-off-by: Jean Delvare --- Documentation/feature-removal-schedule.txt | 14 +++--------- drivers/i2c/busses/i2c-isa.c | 18 +--------------- drivers/i2c/i2c-core.c | 34 +----------------------------- include/linux/i2c.h | 3 --- 4 files changed, 5 insertions(+), 64 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5c88ba1ea26..c4b3bdad15d 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -190,18 +190,10 @@ Who: Jean Delvare --------------------------- -What: i2c_adapter.dev - i2c_adapter.list +What: i2c_adapter.list When: July 2007 -Why: Superfluous, given i2c_adapter.class_dev: - * The "dev" was a stand-in for the physical device node that legacy - drivers would not have; but now it's almost always present. Any - remaining legacy drivers must upgrade (they now trigger warnings). - * The "list" duplicates class device children. - The delay in removing this is so upgraded lm_sensors and libsensors - can get deployed. (Removal causes minor changes in the sysfs layout, - notably the location of the adapter type name and parenting the i2c - client hardware directly from their controller.) +Why: Superfluous, this list duplicates the one maintained by the driver + core. Who: Jean Delvare , David Brownell diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 5f33bc9c1e0..a2e75bc9178 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -141,6 +141,7 @@ static int __init i2c_isa_init(void) 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; + isa_adapter.dev.class = &i2c_adapter_class; err = device_register(&isa_adapter.dev); if (err) { printk(KERN_ERR "i2c-isa: Failed to register device\n"); @@ -152,24 +153,10 @@ static int __init i2c_isa_init(void) goto exit_unregister; } - /* 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); - err = class_device_register(&isa_adapter.class_dev); - if (err) { - printk(KERN_ERR "i2c-isa: Failed to register class device\n"); - goto exit_remove_name; - } - dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name); return 0; -exit_remove_name: - device_remove_file(&isa_adapter.dev, &dev_attr_name); exit_unregister: init_completion(&isa_adapter.dev_released); /* Needed? */ device_unregister(&isa_adapter.dev); @@ -201,15 +188,12 @@ static void __exit i2c_isa_exit(void) /* 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); } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 21fe1406c8b..40a744d73e8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -123,28 +123,9 @@ struct device_driver i2c_adapter_driver = { /* I2C bus adapters -- one roots each I2C or SMBUS segment */ -static void i2c_adapter_class_dev_release(struct class_device *dev) -{ - struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev); - complete(&adap->class_dev_released); -} - -static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf) -{ - struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev); - return sprintf(buf, "%s\n", adap->name); -} - -static struct class_device_attribute i2c_adapter_attrs[] = { - __ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL), - { }, -}; - struct class i2c_adapter_class = { .owner = THIS_MODULE, .name = "i2c-adapter", - .class_dev_attrs = i2c_adapter_attrs, - .release = &i2c_adapter_class_dev_release, }; static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -223,6 +204,7 @@ int i2c_add_adapter(struct i2c_adapter *adap) sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); adap->dev.driver = &i2c_adapter_driver; adap->dev.release = &i2c_adapter_dev_release; + adap->dev.class = &i2c_adapter_class; res = device_register(&adap->dev); if (res) goto out_list; @@ -230,15 +212,6 @@ int i2c_add_adapter(struct i2c_adapter *adap) if (res) goto out_unregister; - /* Add this adapter to the i2c_adapter class */ - memset(&adap->class_dev, 0x00, sizeof(struct class_device)); - adap->class_dev.dev = &adap->dev; - adap->class_dev.class = &i2c_adapter_class; - strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE); - res = class_device_register(&adap->class_dev); - if (res) - goto out_remove_name; - dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); /* inform drivers of new adapters */ @@ -253,8 +226,6 @@ out_unlock: mutex_unlock(&core_lists); return res; -out_remove_name: - device_remove_file(&adap->dev, &dev_attr_name); out_unregister: init_completion(&adap->dev_released); /* Needed? */ device_unregister(&adap->dev); @@ -314,15 +285,12 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* clean up the sysfs representation */ init_completion(&adap->dev_released); - init_completion(&adap->class_dev_released); - class_device_unregister(&adap->class_dev); device_remove_file(&adap->dev, &dev_attr_name); device_unregister(&adap->dev); list_del(&adap->list); /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); - wait_for_completion(&adap->class_dev_released); /* free dynamically allocated bus id */ idr_remove(&i2c_adapter_idr, adap->nr); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 9428092017e..7a59dc65665 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -228,17 +228,14 @@ struct i2c_adapter { int timeout; int retries; struct device dev; /* the adapter device */ - struct class_device class_dev; /* the class device */ int nr; struct list_head clients; struct list_head list; char name[I2C_NAME_SIZE]; struct completion dev_released; - struct completion class_dev_released; }; #define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) -#define class_dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, class_dev) static inline void *i2c_get_adapdata (struct i2c_adapter *dev) { -- cgit v1.2.3 From b31366f4394f7b1e8e1726ba049f294934db4495 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:28 +0200 Subject: i2c: i2c_adapter devices need no driver Kill i2c_adapter_driver as it doesn't make sense and it prevents further i2c-core cleanups. i2c_adapter devices are virtual devices (ex-class devices) and as such they don't need a driver. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-isa.c | 1 - drivers/i2c/i2c-core.c | 14 +------------- include/linux/i2c.h | 1 - 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index a2e75bc9178..745830bb8e2 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -139,7 +139,6 @@ static int __init i2c_isa_init(void) 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; isa_adapter.dev.class = &i2c_adapter_class; err = device_register(&isa_adapter.dev); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 40a744d73e8..8dca4848ad9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -113,12 +113,6 @@ void i2c_adapter_dev_release(struct device *dev) complete(&adap->dev_released); } -struct device_driver i2c_adapter_driver = { - .owner = THIS_MODULE, - .name = "i2c_adapter", - .bus = &i2c_bus_type, -}; - /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ @@ -202,7 +196,6 @@ int i2c_add_adapter(struct i2c_adapter *adap) "physical device\n", adap->name); } sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); - adap->dev.driver = &i2c_adapter_driver; adap->dev.release = &i2c_adapter_dev_release; adap->dev.class = &i2c_adapter_class; res = device_register(&adap->dev); @@ -575,9 +568,6 @@ static int __init i2c_init(void) int retval; retval = bus_register(&i2c_bus_type); - if (retval) - return retval; - retval = driver_register(&i2c_adapter_driver); if (retval) return retval; return class_register(&i2c_adapter_class); @@ -586,7 +576,6 @@ static int __init i2c_init(void) static void __exit i2c_exit(void) { class_unregister(&i2c_adapter_class); - driver_unregister(&i2c_adapter_driver); bus_unregister(&i2c_bus_type); } @@ -1174,9 +1163,8 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, } -/* Next four are needed by i2c-isa */ +/* Next three 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); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 7a59dc65665..47c2a190737 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -38,7 +38,6 @@ /* --- For i2c-isa ---------------------------------------------------- */ extern void i2c_adapter_dev_release(struct device *dev); -extern struct device_driver i2c_adapter_driver; extern struct class i2c_adapter_class; extern struct bus_type i2c_bus_type; -- cgit v1.2.3 From 4ad4eac60667f7c321faae28a3437f7a8b3d17cb Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:28 +0200 Subject: i2c: i2c_register_driver() cleanup Minor cleanup in i2c_register_driver(): use list_for_each_entry(). Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8dca4848ad9..7bfd67f4143 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -304,8 +304,6 @@ int i2c_del_adapter(struct i2c_adapter *adap) int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { - struct list_head *item; - struct i2c_adapter *adapter; int res; /* add the driver to the list of i2c drivers in the driver core */ @@ -323,8 +321,9 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) /* now look for instances of driver on our adapters */ if (driver->attach_adapter) { - list_for_each(item,&adapters) { - adapter = list_entry(item, struct i2c_adapter, list); + struct i2c_adapter *adapter; + + list_for_each_entry(adapter, &adapters, list) { driver->attach_adapter(adapter); } } -- cgit v1.2.3 From 2096b956d24c4b5950b808fc23b218425d79ebb1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:28 +0200 Subject: i2c: Shrink struct i2c_client This shrinks the size of "struct i2c_client" by 40 bytes: - Substantially shrinks the string used to identify the chip type - The "flags" don't need to be so big - Removes some internal padding It also adds kerneldoc for that struct, explaining how "name" is really a chip type identifier; it's otherwise potentially confusing. Because the I2C_NAME_SIZE symbol was abused for both i2c_client.name and for i2c_adapter.name, this needed to affect i2c_adapter too. The adapters which used that symbol now use the more-obviously-correct idiom of taking the size of that field. JD: Shorten i2c_adapter.name from 50 to 48 bytes while we're here, to avoid wasting space in padding. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-ali1535.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 2 +- drivers/i2c/busses/i2c-amd8111.c | 2 +- drivers/i2c/busses/i2c-i801.c | 2 +- drivers/i2c/busses/i2c-ixp2000.c | 2 +- drivers/i2c/busses/i2c-ixp4xx.c | 2 +- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- drivers/i2c/busses/i2c-nforce2.c | 2 +- drivers/i2c/busses/i2c-pasemi.c | 2 +- drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-viapro.c | 2 +- drivers/i2c/busses/scx200_acb.c | 2 +- drivers/media/dvb/b2c2/flexcop-i2c.c | 3 ++- drivers/media/dvb/dvb-usb/dvb-usb-i2c.c | 2 +- drivers/media/dvb/frontends/dibx000_common.c | 4 ++-- drivers/video/intelfb/intelfb_i2c.c | 3 ++- drivers/video/matrox/i2c-matroxfb.c | 2 +- include/linux/i2c.h | 23 ++++++++++++++--------- 19 files changed, 35 insertions(+), 28 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 1e277ba5a9f..f14372ac2fc 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -497,7 +497,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ ali1535_adapter.dev.parent = &dev->dev; - snprintf(ali1535_adapter.name, I2C_NAME_SIZE, + snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), "SMBus ALI1535 adapter at %04x", ali1535_smba); return i2c_add_adapter(&ali1535_adapter); } diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index e47fe01bf42..93bf87d7096 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -492,7 +492,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ ali15x3_adapter.dev.parent = &dev->dev; - snprintf(ali15x3_adapter.name, I2C_NAME_SIZE, + snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name), "SMBus ALI15X3 adapter at %04x", ali15x3_smba); return i2c_add_adapter(&ali15x3_adapter); } diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 0c70f829334..c9fca7b4926 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -365,7 +365,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev, } smbus->adapter.owner = THIS_MODULE; - snprintf(smbus->adapter.name, I2C_NAME_SIZE, + snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "SMBus2 AMD8111 adapter at %04x", smbus->base); smbus->adapter.id = I2C_HW_SMBUS_AMD8111; smbus->adapter.class = I2C_CLASS_HWMON; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index a320e7d82c1..611b57192c9 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -527,7 +527,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; - snprintf(i801_adapter.name, I2C_NAME_SIZE, + snprintf(i801_adapter.name, sizeof(i801_adapter.name), "SMBus I801 adapter at %04lx", i801_smba); err = i2c_add_adapter(&i801_adapter); if (err) { diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index efa3ecc5522..6352121a282 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -118,7 +118,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev) drv_data->adapter.id = I2C_HW_B_IXP2000, strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - I2C_NAME_SIZE); + sizeof(drv_data->adapter.name)); drv_data->adapter.algo_data = &drv_data->algo_data, drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 08e89b83984..069ed7f3b39 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -127,7 +127,7 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev) drv_data->adapter.id = I2C_HW_B_IXP4XX; drv_data->adapter.class = I2C_CLASS_HWMON; strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - I2C_NAME_SIZE); + sizeof(drv_data->adapter.name)); drv_data->adapter.algo_data = &drv_data->algo_data; drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a3283b907eb..a55b3335d1b 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -508,7 +508,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) } strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", - I2C_NAME_SIZE); + sizeof(drv_data->adapter.name)); init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 1514ec5b77f..cdc67dc914c 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -240,7 +240,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; smbus->adapter.dev.parent = &dev->dev; - snprintf(smbus->adapter.name, I2C_NAME_SIZE, + snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "SMBus nForce2 adapter at %04x", smbus->base); error = i2c_add_adapter(&smbus->adapter); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index bf89eeef74e..58e32714afb 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -358,7 +358,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, } smbus->adapter.owner = THIS_MODULE; - snprintf(smbus->adapter.name, I2C_NAME_SIZE, + snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "PA Semi SMBus adapter at 0x%lx", smbus->base); smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 21b18090408..5a52bf5e3fb 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -428,7 +428,7 @@ static int __devinit piix4_probe(struct pci_dev *dev, /* set up the sysfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev; - snprintf(piix4_adapter.name, I2C_NAME_SIZE, + snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), "SMBus PIIX4 adapter at %04x", piix4_smba); if ((retval = i2c_add_adapter(&piix4_adapter))) { diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 4157b0cd604..dc235bb8e24 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -300,7 +300,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev, /* set up the sysfs linkage to our parent device */ sis96x_adapter.dev.parent = &dev->dev; - snprintf(sis96x_adapter.name, I2C_NAME_SIZE, + snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name), "SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base); if ((retval = i2c_add_adapter(&sis96x_adapter))) { diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 03c5fc86854..7a2bc06304f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -404,7 +404,7 @@ found: } vt596_adapter.dev.parent = &pdev->dev; - snprintf(vt596_adapter.name, I2C_NAME_SIZE, + snprintf(vt596_adapter.name, sizeof(vt596_adapter.name), "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 0b082c5a019..d816ab089fe 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -441,7 +441,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); - snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index); + snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index); adapter->owner = THIS_MODULE; adapter->id = I2C_HW_SMBUS_SCX200; adapter->algo = &scx200_acb_algorithm; diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 5347a406fff..02a0ea6e1c1 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -183,7 +183,8 @@ int flexcop_i2c_init(struct flexcop_device *fc) mutex_init(&fc->i2c_mutex); memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); - strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE); + strncpy(fc->i2c_adap.name, "B2C2 FlexCop device", + sizeof(fc->i2c_adap.name)); i2c_set_adapdata(&fc->i2c_adap,fc); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 70df31b0a8a..088b6dee3a7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) return -EINVAL; } - strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE); + strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); #ifdef I2C_ADAP_CLASS_TV_DIGITAL d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, #else diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index a18c8f45a2e..315e09e95b0 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -105,9 +105,9 @@ struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enu } EXPORT_SYMBOL(dibx000_get_i2c_adapter); -static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst) +static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) { - strncpy(i2c_adap->name, name, I2C_NAME_SIZE); + strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo; i2c_adap->algo_data = NULL; diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index f4ede5f6b58..61e4c8759b2 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -104,7 +104,8 @@ static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, chan->dinfo = dinfo; chan->reg = reg; - snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name); + snprintf(chan->adapter.name, sizeof(chan->adapter.name), + "intelfb %s", name); chan->adapter.owner = THIS_MODULE; chan->adapter.id = I2C_HW_B_INTELFB; chan->adapter.algo_data = &chan->algo; diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 5ec718a5fe2..4baab7be58d 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -111,7 +111,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, b->mask.data = data; b->mask.clock = clock; b->adapter = matrox_i2c_adapter_template; - snprintf(b->adapter.name, I2C_NAME_SIZE, name, + snprintf(b->adapter.name, sizeof(b->adapter.name), name, minfo->fbcon.node); i2c_set_adapdata(&b->adapter, b); b->adapter.algo_data = &b->bac; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 47c2a190737..953e71fb07b 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -140,25 +140,30 @@ struct i2c_driver { }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) -#define I2C_NAME_SIZE 50 - -/* - * i2c_client identifies a single device (i.e. chip) that is connected to an - * i2c bus. The behaviour is defined by the routines of the driver. This - * function is mainly used for lookup & other admin. functions. +#define I2C_NAME_SIZE 20 + +/** + * struct i2c_client - represent an I2C slave device + * @addr: Address used on the I2C bus connected to the parent adapter. + * @name: Indicates the type of the device, usually a chip name that's + * generic enough to hide second-sourcing and compatible revisions. + * @dev: Driver model device node for the slave. + * + * An i2c_client identifies a single device (i.e. chip) connected to an + * i2c bus. The behaviour is defined by the routines of the driver. */ struct i2c_client { - unsigned int flags; /* div., see below */ + unsigned short flags; /* div., see below */ unsigned short addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ /* _LOWER_ 7 bits */ + char name[I2C_NAME_SIZE]; struct i2c_adapter *adapter; /* the adapter we sit on */ struct i2c_driver *driver; /* and our access routines */ int usage_count; /* How many accesses currently */ /* to the client */ struct device dev; /* the device structure */ struct list_head list; - char name[I2C_NAME_SIZE]; struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -231,7 +236,7 @@ struct i2c_adapter { int nr; struct list_head clients; struct list_head list; - char name[I2C_NAME_SIZE]; + char name[48]; struct completion dev_released; }; #define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) -- cgit v1.2.3 From 16ffadfc680bd0683dc88573c1d72cbf1e27030e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:28 +0200 Subject: i2c: Class attribute cleanup This patch is a minor cleanup/code shrink, using class infrastructure in i2c-core to manage the i2c_adapter attribute. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-isa.c | 20 -------------------- drivers/i2c/i2c-core.c | 30 +++++++++++++----------------- 2 files changed, 13 insertions(+), 37 deletions(-) diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 745830bb8e2..819e8991f27 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -64,16 +64,6 @@ static u32 isa_func(struct i2c_adapter *adapter) } -/* 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); - - /* 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. */ @@ -146,20 +136,11 @@ static int __init i2c_isa_init(void) printk(KERN_ERR "i2c-isa: Failed to register device\n"); goto exit; } - err = device_create_file(&isa_adapter.dev, &dev_attr_name); - if (err) { - printk(KERN_ERR "i2c-isa: Failed to create name file\n"); - goto exit_unregister; - } dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name); return 0; -exit_unregister: - init_completion(&isa_adapter.dev_released); /* Needed? */ - device_unregister(&isa_adapter.dev); - wait_for_completion(&isa_adapter.dev_released); exit: return err; } @@ -187,7 +168,6 @@ static void __exit i2c_isa_exit(void) /* Clean up the sysfs representation */ dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n"); init_completion(&isa_adapter.dev_released); - device_remove_file(&isa_adapter.dev, &dev_attr_name); device_unregister(&isa_adapter.dev); /* Wait for sysfs to drop all references */ diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 7bfd67f4143..1e3e1a5b4d8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -107,28 +107,32 @@ struct bus_type i2c_bus_type = { /* ------------------------------------------------------------------------- */ +/* I2C bus adapters -- one roots each I2C or SMBUS segment */ + void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = dev_to_i2c_adapter(dev); complete(&adap->dev_released); } -/* ------------------------------------------------------------------------- */ +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); +} -/* I2C bus adapters -- one roots each I2C or SMBUS segment */ +static struct device_attribute i2c_adapter_attrs[] = { + __ATTR(name, S_IRUGO, show_adapter_name, NULL), + { }, +}; struct class i2c_adapter_class = { .owner = THIS_MODULE, .name = "i2c-adapter", + .dev_attrs = i2c_adapter_attrs, }; -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 void i2c_client_release(struct device *dev) { @@ -201,9 +205,6 @@ int i2c_add_adapter(struct i2c_adapter *adap) res = device_register(&adap->dev); if (res) goto out_list; - res = device_create_file(&adap->dev, &dev_attr_name); - if (res) - goto out_unregister; dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); @@ -219,10 +220,6 @@ out_unlock: mutex_unlock(&core_lists); return res; -out_unregister: - init_completion(&adap->dev_released); /* Needed? */ - device_unregister(&adap->dev); - wait_for_completion(&adap->dev_released); out_list: list_del(&adap->list); idr_remove(&i2c_adapter_idr, adap->nr); @@ -278,7 +275,6 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* clean up the sysfs representation */ init_completion(&adap->dev_released); - device_remove_file(&adap->dev, &dev_attr_name); device_unregister(&adap->dev); list_del(&adap->list); -- cgit v1.2.3 From ef2c8321f5a27ff9ecdae1ee587430cafa495586 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:28 +0200 Subject: i2c: Rename dev_to_i2c_adapter() Rename dev_to_i2c_adapter() as to_i2c_adapter(), since the previous syntax was a surprising and needless difference from normal naming conventions in Linux. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 4 ++-- include/linux/i2c.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 1e3e1a5b4d8..ae07b874a5d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -111,14 +111,14 @@ struct bus_type i2c_bus_type = { void i2c_adapter_dev_release(struct device *dev) { - struct i2c_adapter *adap = dev_to_i2c_adapter(dev); + struct i2c_adapter *adap = to_i2c_adapter(dev); complete(&adap->dev_released); } static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_adapter *adap = dev_to_i2c_adapter(dev); + struct i2c_adapter *adap = to_i2c_adapter(dev); return sprintf(buf, "%s\n", adap->name); } diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 953e71fb07b..568dd1007b5 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -239,7 +239,7 @@ struct i2c_adapter { char name[48]; struct completion dev_released; }; -#define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) +#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) static inline void *i2c_get_adapdata (struct i2c_adapter *dev) { -- cgit v1.2.3 From 1ecac07abaca1a4084d0259d4a15b55188852a2e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:28 +0200 Subject: i2c-algo-bit: Always send a stop condition before leaving The i2c-algo-bit driver doesn't behave well on read errors: it'll bail out without even sending a stop condition on the bus, so the bus will be stuck. So make sure that we always send a stop condition on the bus before we leave. The best way to make sure is to always send it at the end of function bit_xfer. Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 95aa5395a5b..28b7e25ca79 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -312,12 +312,10 @@ static int try_address(struct i2c_adapter *i2c_adap, int i,ret = -1; for (i=0;i<=retries;i++) { ret = i2c_outb(i2c_adap,addr); - if (ret==1) - break; /* success! */ + if (ret == 1 || i == retries) + break; i2c_stop(adap); udelay(5/*adap->udelay*/); - if (i==retries) /* no success */ - break; i2c_start(adap); udelay(adap->udelay); } @@ -331,7 +329,6 @@ static int try_address(struct i2c_adapter *i2c_adap, static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { - struct i2c_algo_bit_data *adap = i2c_adap->algo_data; char c; const char *temp = msg->buf; int count = msg->len; @@ -349,7 +346,6 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) wrcount++; } else { /* arbitration or no acknowledge */ dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n"); - i2c_stop(adap); return (retval<0)? retval : -EFAULT; /* got a better one ?? */ } @@ -480,27 +476,34 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, if ((ret != 0) && !nak_ok) { DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n" ,msgs[i].addr,i)); - return (ret<0) ? ret : -EREMOTEIO; + goto bailout; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); - if (ret < pmsg->len ) { - return (ret<0)? ret : -EREMOTEIO; + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EREMOTEIO; + goto bailout; } } else { /* write bytes from buffer */ ret = sendbytes(i2c_adap, pmsg); DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); - if (ret < pmsg->len ) { - return (ret<0) ? ret : -EREMOTEIO; + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EREMOTEIO; + goto bailout; } } } + ret = i; + +bailout: i2c_stop(adap); - return num; + return ret; } static u32 bit_func(struct i2c_adapter *adap) -- cgit v1.2.3 From 209d27c3b1676c0497108f0642c51a08b98a7856 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:29 +0200 Subject: i2c: Emulate SMBus block read over I2C Let the I2C bus drivers emulate the SMBus Block Read and Block Process Call transactions if they wish. This requires to define a new message flag, which i2c-core will use to let the underlying I2C bus driver know that the first received byte will specify the length of the read message. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 34 ++++++++++++++++++++++++++-------- include/linux/i2c.h | 1 + 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ae07b874a5d..fd921ce0b75 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -590,8 +590,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) #ifdef DEBUG for (ret = 0; ret < num; ret++) { dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " - "len=%d\n", ret, msgs[ret].flags & I2C_M_RD ? - 'R' : 'W', msgs[ret].addr, msgs[ret].len); + "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD) + ? 'R' : 'W', msgs[ret].addr, msgs[ret].len, + (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); } #endif @@ -1050,9 +1051,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - dev_err(&adapter->dev, "Block read not supported " - "under I2C emulation!\n"); - return -1; + msg[1].flags |= I2C_M_RECV_LEN; + msg[1].len = 1; /* block length will be added by + the underlying bus driver */ } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { @@ -1066,9 +1067,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, } break; case I2C_SMBUS_BLOCK_PROC_CALL: - dev_dbg(&adapter->dev, "Block process call not supported " - "under I2C emulation!\n"); - return -1; + num = 2; /* Another special case */ + read_write = I2C_SMBUS_READ; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { + dev_err(&adapter->dev, "%s called with invalid " + "block proc call size (%d)\n", __FUNCTION__, + data->block[0]); + return -1; + } + msg[0].len = data->block[0] + 2; + for (i = 1; i < msg[0].len; i++) + msgbuf0[i] = data->block[i-1]; + msg[1].flags |= I2C_M_RECV_LEN; + msg[1].len = 1; /* block length will be added by + the underlying bus driver */ + break; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = I2C_SMBUS_BLOCK_MAX; @@ -1132,6 +1145,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + for (i = 0; i < msgbuf1[0] + 1; i++) + data->block[i] = msgbuf1[i]; + break; } return 0; } diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 568dd1007b5..563c9651dd3 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -366,6 +366,7 @@ struct i2c_msg { #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800 +#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ }; -- cgit v1.2.3 From 3c4bb241d34ee3d9ab87aad265734885385f179b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:29 +0200 Subject: i2c-algo-bit: Emulate SMBus block read Now that i2c-core lets the i2c bus drivers emulate the SMBus block read and SMBus block process call transaction types, let's implement that in the popular i2c bit-banging driver. This will also act as a reference implementation for other bus drivers which want to do the same. Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 28b7e25ca79..fcef6ff3d28 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -391,6 +391,21 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) }; scllo(adap); sdahi(adap); + + /* Some SMBus transactions require that we receive the + transaction length as the first read byte. */ + if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) { + if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + printk(KERN_ERR "i2c-algo-bit: readbytes: " + "invalid block length (%d)\n", inval); + return -EREMOTEIO; + } + /* The original count value accounts for the extra + bytes, that is, either 1 for a regular transaction, + or 2 for a PEC transaction. */ + count += inval; + msg->len += inval; + } } return rdcount; } @@ -509,6 +524,8 @@ bailout: static u32 bit_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; } -- cgit v1.2.3 From cacf2269b6cde2ff2c29a13dff5ce6886ff1dc73 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:29 +0200 Subject: i2c-parport: Optimize binary size Initialize the fields of the i2c_adapter structure individually, rather than copying a whole static template structure. This shaves off 474 bytes or 14% (on i386) from the binary size. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-parport.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 66696a40c7b..b9f1c5c7b57 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -143,13 +143,6 @@ static struct i2c_algo_bit_data parport_algo_data = { /* ----- I2c and parallel port call-back functions and structures --------- */ -static struct i2c_adapter parport_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON, - .id = I2C_HW_B_LP, - .name = "Parallel port adapter", -}; - static void i2c_parport_attach (struct parport *port) { struct i2c_par *adapter; @@ -169,7 +162,11 @@ static void i2c_parport_attach (struct parport *port) } /* Fill the rest of the structure */ - adapter->adapter = parport_adapter; + adapter->adapter.owner = THIS_MODULE; + adapter->adapter.class = I2C_CLASS_HWMON; + adapter->adapter.id = I2C_HW_B_LP; + strlcpy(adapter->adapter.name, "Parallel port adapter", + sizeof(adapter->adapter.name)); adapter->algo_data = parport_algo_data; if (!adapter_parm[type].getscl.val) adapter->algo_data.getscl = NULL; -- cgit v1.2.3 From f75803de6ae9aaebaf096d4590b40503c896eca7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:29 +0200 Subject: i2c-nforce2: Add support for the MCP61 and MCP65 Signed-off-by: Jean Delvare Cc: Hans-Frieder Vogt --- Documentation/i2c/busses/i2c-nforce2 | 2 ++ drivers/i2c/busses/i2c-nforce2.c | 4 ++++ include/linux/pci_ids.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2 index 7f61fbc03f7..fae3495bcba 100644 --- a/Documentation/i2c/busses/i2c-nforce2 +++ b/Documentation/i2c/busses/i2c-nforce2 @@ -9,6 +9,8 @@ Supported adapters: * nForce4 MCP-04 10de:0034 * nForce4 MCP51 10de:0264 * nForce4 MCP55 10de:0368 + * nForce4 MCP61 10de:03EB + * nForce4 MCP65 10de:0446 Datasheet: not publicly available, but seems to be similar to the AMD-8111 SMBus 2.0 adapter. diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index cdc67dc914c..3cd0d63e7b5 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -33,6 +33,8 @@ nForce4 MCP-04 0034 nForce4 MCP51 0264 nForce4 MCP55 0368 + nForce MCP61 03EB + nForce MCP65 0446 This driver supports the 2 SMBuses that are included in the MCP of the nForce2/3/4/5xx chipsets. @@ -200,6 +202,8 @@ static struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) }, { 0 } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 1b0ddbb8a80..5a48e963d06 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1213,11 +1213,13 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5 #define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC #define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE #define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448 #define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450 #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 -- cgit v1.2.3 From 7c59b6615fed9d3006b1e7b865fb07e483129611 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:29 +0200 Subject: i2c: Cleanup the includes of Clean up the includes of . Only include this header file when we actually need it. Signed-off-by: Jean Delvare --- arch/powerpc/platforms/powermac/cpufreq_32.c | 1 - drivers/media/video/cx2341x.c | 1 - drivers/media/video/ovcamchip/ovcamchip_priv.h | 1 + drivers/media/video/usbvision/usbvision-cards.c | 1 - include/media/ovcamchip.h | 1 - include/media/tuner.h | 1 + sound/oss/dmasound/tas_ioctl.h | 1 - 7 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 8943a9456bb..1fe35dab0e9 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 88dbdddeec4..d73c86aeeaa 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h index 1231335a9f4..50c7763d44b 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_priv.h +++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h @@ -15,6 +15,7 @@ #ifndef __LINUX_OVCAMCHIP_PRIV_H #define __LINUX_OVCAMCHIP_PRIV_H +#include #include #ifdef DEBUG diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 13f69fe6360..51ab265d566 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -24,7 +24,6 @@ #include -#include #include #include #include "usbvision.h" diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h index 0f43451f8bb..05b9569ef1c 100644 --- a/include/media/ovcamchip.h +++ b/include/media/ovcamchip.h @@ -16,7 +16,6 @@ #include #include -#include /* --------------------------------- */ /* ENUMERATIONS */ diff --git a/include/media/tuner.h b/include/media/tuner.h index a41ac41113a..6dcf3c45707 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -23,6 +23,7 @@ #define _TUNER_H #include +#include #include extern int tuner_debug; diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h index dccae3a40e0..9d12b373b4a 100644 --- a/sound/oss/dmasound/tas_ioctl.h +++ b/sound/oss/dmasound/tas_ioctl.h @@ -1,7 +1,6 @@ #ifndef _TAS_IOCTL_H_ #define _TAS_IOCTL_H_ -#include #include -- cgit v1.2.3 From 4b4686e7a6fe8347938beef518e9b309127945f1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:30 +0200 Subject: scx200_acb: Fix PCI device reference count The scx200_acb driver supports two kind of devices, PCI ones and ISA ones. Even ISA ones are detected using the presence of a given PCI device, and we get a reference to it, but never put it back, so we have a leak. Fix it. Signed-off-by: Jean Delvare --- drivers/i2c/busses/scx200_acb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index d816ab089fe..0db56e7bc34 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -599,6 +599,7 @@ static __init int scx200_scan_pci(void) else { int i; + pci_dev_put(pdev); for (i = 0; i < MAX_DEVICES; ++i) { if (base[i] == 0) continue; -- cgit v1.2.3 From 3af07bd297b6ba3d77474fdb3b2656dd3f0404d5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:30 +0200 Subject: i2c-parport: Fix a minor race on driver unload When unloading the driver, we really want to unregister the i2c adapter before we power it off, rather than the other way around. Also speed up the bus a bit when we can sense SCL. The slaves will stretch the line as needed. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-parport.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index b9f1c5c7b57..8c953707253 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2004 Jean Delvare + Copyright (C) 2003-2007 Jean Delvare Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -137,7 +137,7 @@ static struct i2c_algo_bit_data parport_algo_data = { .setscl = parport_setscl, .getsda = parport_getsda, .getscl = parport_getscl, - .udelay = 60, + .udelay = 10, /* ~50 kbps */ .timeout = HZ, }; @@ -168,8 +168,11 @@ static void i2c_parport_attach (struct parport *port) strlcpy(adapter->adapter.name, "Parallel port adapter", sizeof(adapter->adapter.name)); adapter->algo_data = parport_algo_data; - if (!adapter_parm[type].getscl.val) + /* Slow down if we can't sense SCL */ + if (!adapter_parm[type].getscl.val) { adapter->algo_data.getscl = NULL; + adapter->algo_data.udelay = 50; /* ~10 kbps */ + } adapter->algo_data.data = port; adapter->adapter.algo_data = &adapter->algo_data; @@ -211,11 +214,12 @@ static void i2c_parport_detach (struct parport *port) for (prev = NULL, adapter = adapter_list; adapter; prev = adapter, adapter = adapter->next) { if (adapter->pdev->port == port) { + i2c_del_adapter(&adapter->adapter); + /* Un-init if needed (power off...) */ if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); - i2c_del_adapter(&adapter->adapter); parport_unregister_device(adapter->pdev); if (prev) prev->next = adapter->next; -- cgit v1.2.3 From c6e8bb2ca5e50547557650c9251d24f55a8f4cfb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:30 +0200 Subject: i2c-parport-light: Port to the new device driver model Also fix a small race on driver unload: we need to unregister the i2c adapter before we power it off. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-parport-light.c | 144 ++++++++++++++++++++++++++------- 1 file changed, 117 insertions(+), 27 deletions(-) diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 4bc42810b9a..49a95e2887b 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * - * i2c-parport.c I2C bus over parallel port * + * i2c-parport-light.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2004 Jean Delvare + Copyright (C) 2003-2007 Jean Delvare Based on older i2c-velleman.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,9 @@ #include "i2c-parport.h" #define DEFAULT_BASE 0x378 +#define DRVNAME "i2c-parport-light" + +static struct platform_device *pdev; static u16 base; module_param(base, ushort, 0); @@ -106,7 +110,7 @@ static struct i2c_algo_bit_data parport_algo_data = { .timeout = HZ, }; -/* ----- I2c structure ---------------------------------------------------- */ +/* ----- Driver registration ---------------------------------------------- */ static struct i2c_adapter parport_adapter = { .owner = THIS_MODULE, @@ -116,55 +120,141 @@ static struct i2c_adapter parport_adapter = { .name = "Parallel port adapter (light)", }; -/* ----- Module loading, unloading and information ------------------------ */ +static int __devinit i2c_parport_probe(struct platform_device *pdev) +{ + int err; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) + return -EBUSY; + + /* Reset hardware to a sane state (SCL and SDA high) */ + parport_setsda(NULL, 1); + parport_setscl(NULL, 1); + /* Other init if needed (power on...) */ + if (adapter_parm[type].init.val) + line_set(1, &adapter_parm[type].init); + + parport_adapter.dev.parent = &pdev->dev; + err = i2c_bit_add_bus(&parport_adapter); + if (err) { + dev_err(&pdev->dev, "Unable to register with I2C\n"); + goto exit_region; + } + return 0; + +exit_region: + release_region(res->start, res->end - res->start + 1); + return err; +} + +static int __devexit i2c_parport_remove(struct platform_device *pdev) +{ + struct resource *res; + + i2c_del_adapter(&parport_adapter); + + /* Un-init if needed (power off...) */ + if (adapter_parm[type].init.val) + line_set(0, &adapter_parm[type].init); + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, res->end - res->start + 1); + return 0; +} + +static struct platform_driver i2c_parport_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = i2c_parport_probe, + .remove = __devexit_p(i2c_parport_remove), +}; + +static int __init i2c_parport_device_add(u16 address) +{ + struct resource res = { + .start = address, + .end = address + 2, + .name = DRVNAME, + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc(DRVNAME, -1); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); +exit: + return err; +} static int __init i2c_parport_init(void) { + int err; + if (type < 0) { - printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + printk(KERN_ERR DRVNAME ": adapter type unspecified\n"); return -ENODEV; } if (type >= ARRAY_SIZE(adapter_parm)) { - printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); + printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type); return -ENODEV; } if (base == 0) { - printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE); + pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE); base = DEFAULT_BASE; } - if (!request_region(base, 3, "i2c-parport")) - return -ENODEV; - if (!adapter_parm[type].getscl.val) parport_algo_data.getscl = NULL; - /* Reset hardware to a sane state (SCL and SDA high) */ - parport_setsda(NULL, 1); - parport_setscl(NULL, 1); - /* Other init if needed (power on...) */ - if (adapter_parm[type].init.val) - line_set(1, &adapter_parm[type].init); + /* Sets global pdev as a side effect */ + err = i2c_parport_device_add(base); + if (err) + goto exit; - if (i2c_bit_add_bus(&parport_adapter) < 0) { - printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); - release_region(base, 3); - return -ENODEV; - } + err = platform_driver_register(&i2c_parport_driver); + if (err) + goto exit_device; return 0; + +exit_device: + platform_device_unregister(pdev); +exit: + return err; } static void __exit i2c_parport_exit(void) { - /* Un-init if needed (power off...) */ - if (adapter_parm[type].init.val) - line_set(0, &adapter_parm[type].init); - - i2c_del_adapter(&parport_adapter); - release_region(base, 3); + platform_driver_unregister(&i2c_parport_driver); + platform_device_unregister(pdev); } MODULE_AUTHOR("Jean Delvare "); -- cgit v1.2.3 From 4a5d30302ec82c53613915d5eb8381b8efe1dd0e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:30 +0200 Subject: i2c-elektor: Port to the new device driver model Port the i2c-elektor driver to the new device driver model. I'm using Rene Herman's new isa bus type, as it fits the needs nicely. One benefit is that we can now give a proper parent to our i2c adapter. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-elektor.c | 51 ++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 83496746481..804f0a551c0 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -207,7 +208,7 @@ static struct i2c_adapter pcf_isa_ops = { .name = "i2c-elektor", }; -static int __init i2c_pcfisa_init(void) +static int __devinit elektor_match(struct device *dev, unsigned int id) { #ifdef __alpha__ /* check to see we have memory mapped PCF8584 connected to the @@ -222,9 +223,8 @@ static int __init i2c_pcfisa_init(void) /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - pr_debug("%s: found cy82c693, config " - "register 0x47 = 0x%02x\n", - pcf_isa_ops.name, config); + dev_dbg(dev, "found cy82c693, config " + "register 0x47 = 0x%02x\n", config); /* UP2000 board has this register set to 0xe1, but the most significant bit as seems can be @@ -244,9 +244,9 @@ static int __init i2c_pcfisa_init(void) 8.25 MHz (PCI/4) clock (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - pr_info("%s: found API UP2000 like " - "board, will probe PCF8584 " - "later\n", pcf_isa_ops.name); + dev_info(dev, "found API UP2000 like " + "board, will probe PCF8584 " + "later\n"); } } pci_dev_put(cy693_dev); @@ -256,22 +256,27 @@ static int __init i2c_pcfisa_init(void) /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - printk(KERN_ERR "%s: incorrect base address (%#x) specified " - "for mmapped I/O\n", pcf_isa_ops.name, base); - return -ENODEV; + dev_err(dev, "incorrect base address (%#x) specified " + "for mmapped I/O\n", base); + return 0; } if (base == 0) { base = DEFAULT_BASE; } + return 1; +} +static int __devinit elektor_probe(struct device *dev, unsigned int id) +{ init_waitqueue_head(&pcf_wait); if (pcf_isa_init()) return -ENODEV; + pcf_isa_ops.dev.parent = dev; if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) goto fail; - dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base); + dev_info(dev, "found device at %#x\n", base); return 0; @@ -291,7 +296,7 @@ static int __init i2c_pcfisa_init(void) return -ENODEV; } -static void i2c_pcfisa_exit(void) +static int __devexit elektor_remove(struct device *dev, unsigned int id) { i2c_del_adapter(&pcf_isa_ops); @@ -307,6 +312,28 @@ static void i2c_pcfisa_exit(void) iounmap(base_iomem); release_mem_region(base, 2); } + + return 0; +} + +static struct isa_driver i2c_elektor_driver = { + .match = elektor_match, + .probe = elektor_probe, + .remove = __devexit_p(elektor_remove), + .driver = { + .owner = THIS_MODULE, + .name = "i2c-elektor", + }, +}; + +static int __init i2c_pcfisa_init(void) +{ + return isa_register_driver(&i2c_elektor_driver, 1); +} + +static void __exit i2c_pcfisa_exit(void) +{ + isa_unregister_driver(&i2c_elektor_driver); } MODULE_AUTHOR("Hans Berglund "); -- cgit v1.2.3 From 5cedb05db3c3084c9641403dd24c310a6b3ea19f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:30 +0200 Subject: i2c-pca-isa: Port to the new device driver model Port the i2c-pca-isa driver to the new device driver model. I'm using Rene Herman's new isa bus type, as it fits the needs nicely. One benefit is that we can now give a proper parent to our i2c adapter. Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 2 +- drivers/i2c/busses/i2c-pca-isa.c | 35 ++++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ece31d2c6c6..d7e6cbb9cbe 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -547,7 +547,7 @@ config I2C_VOODOO3 config I2C_PCA_ISA tristate "PCA9564 on an ISA bus" - depends on I2C + depends on I2C && ISA select I2C_ALGOPCA default n help diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index cc6536a19ec..5f94e617fe0 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -119,27 +120,26 @@ static struct i2c_adapter pca_isa_ops = { .name = "PCA9564 ISA Adapter", }; -static int __init pca_isa_init(void) +static int __devinit pca_isa_probe(struct device *dev, unsigned int id) { - init_waitqueue_head(&pca_wait); - printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq); + dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq); if (!request_region(base, IO_SIZE, "i2c-pca-isa")) { - printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base); + dev_err(dev, "I/O address %#08lx is in use\n", base); goto out; } if (irq > -1) { if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) { - printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq); + dev_err(dev, "Request irq%d failed\n", irq); goto out_region; } } if (i2c_pca_add_bus(&pca_isa_ops) < 0) { - printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n"); + dev_err(dev, "Failed to add i2c bus\n"); goto out_irq; } @@ -154,7 +154,7 @@ static int __init pca_isa_init(void) return -ENODEV; } -static void pca_isa_exit(void) +static int __devexit pca_isa_remove(struct device *dev, unsigned int id) { i2c_del_adapter(&pca_isa_ops); @@ -163,6 +163,27 @@ static void pca_isa_exit(void) free_irq(irq, &pca_isa_ops); } release_region(base, IO_SIZE); + + return 0; +} + +static struct isa_driver pca_isa_driver = { + .probe = pca_isa_probe, + .remove = __devexit_p(pca_isa_remove), + .driver = { + .owner = THIS_MODULE, + .name = "i2c-pca-isa", + } +}; + +static int __init pca_isa_init(void) +{ + return isa_register_driver(&pca_isa_driver, 1); +} + +static void __exit pca_isa_exit(void) +{ + isa_unregister_driver(&pca_isa_driver); } MODULE_AUTHOR("Ian Campbell "); -- cgit v1.2.3 From 7b4fbc50fabb810523be522fe7ec5cc40f85c7a1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:30 +0200 Subject: i2c: i2c stack can probe() One of a series of I2C infrastructure updates to support enumeration using the standard Linux driver model. This patch updates probe() and associated hotplug/coldplug support, but not remove(). Nothing yet _uses_ it to create I2C devices, so those hotplug/coldplug mechanisms will be the only externally visible change. This patch will be an overall NOP since the I2C stack doesn't yet create clients/devices except as part of binding them to legacy drivers. Some code is moved earlier in the source code, helping group more of the per-device infrastructure in one place and simplifying handling per-device attributes. Terminology being adopted: "legacy drivers" create devices (i2c_client) themselves, while "new style" ones follow the driver model (the i2c_client is handed to the probe routine). It's an either/or thing; the two models don't mix, and drivers that try mixing them won't even be registered. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 141 ++++++++++++++++++++++++++++++++++--------------- include/linux/i2c.h | 13 ++++- 2 files changed, 110 insertions(+), 44 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index fd921ce0b75..a2ad83ad0f5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -44,15 +44,58 @@ static DEFINE_IDR(i2c_adapter_idr); /* ------------------------------------------------------------------------- */ -/* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { - return 1; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_driver *driver = to_i2c_driver(drv); + + /* make legacy i2c drivers bypass driver model probing entirely; + * such drivers scan each i2c adapter/bus themselves. + */ + if (!driver->probe) + return 0; + + /* new style drivers use the same kind of driver matching policy + * as platform devices or SPI: compare device and driver IDs. + */ + return strcmp(client->driver_name, drv->name) == 0; } +#ifdef CONFIG_HOTPLUG + +/* uevent helps with hotplug: modprobe -q $(MODALIAS) */ +static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct i2c_client *client = to_i2c_client(dev); + int i = 0, length = 0; + + /* by definition, legacy drivers can't hotplug */ + if (dev->driver || !client->driver_name) + return 0; + + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, + "MODALIAS=%s", client->driver_name)) + return -ENOMEM; + envp[i] = NULL; + dev_dbg(dev, "uevent\n"); + return 0; +} + +#else +#define i2c_device_uevent NULL +#endif /* CONFIG_HOTPLUG */ + static int i2c_device_probe(struct device *dev) { - return -ENODEV; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_driver *driver = to_i2c_driver(dev->driver); + + if (!driver->probe) + return -ENODEV; + client->driver = driver; + dev_dbg(dev, "probe\n"); + return driver->probe(client); } static int i2c_device_remove(struct device *dev) @@ -95,9 +138,38 @@ static int i2c_device_resume(struct device * dev) return driver->resume(to_i2c_client(dev)); } +static void i2c_client_release(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + complete(&client->released); +} + +static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%s\n", client->name); +} + +static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return client->driver_name + ? sprintf(buf, "%s\n", client->driver_name) + : 0; +} + +static struct device_attribute i2c_dev_attrs[] = { + __ATTR(name, S_IRUGO, show_client_name, NULL), + /* modalias helps coldplug: modprobe $(cat .../modalias) */ + __ATTR(modalias, S_IRUGO, show_modalias, NULL), + { }, +}; + struct bus_type i2c_bus_type = { .name = "i2c", + .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, + .uevent = i2c_device_uevent, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, @@ -134,31 +206,6 @@ struct class i2c_adapter_class = { }; -static void i2c_client_release(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); -} - -static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - return sprintf(buf, "%s\n", client->name); -} - -/* - * We can't use the DEVICE_ATTR() macro here, as we used the same name for - * an i2c adapter attribute (above). - */ -static struct device_attribute dev_attr_client_name = - __ATTR(name, S_IRUGO, &show_client_name, NULL); - - -/* --------------------------------------------------- - * registering functions - * --------------------------------------------------- - */ - /* ----- * i2c_add_adapter is called from within the algorithm layer, * when a new hw adapter registers. A new device is register to be @@ -208,7 +255,7 @@ int i2c_add_adapter(struct i2c_adapter *adap) dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* inform drivers of new adapters */ + /* let legacy drivers scan this bus for matching devices */ list_for_each(item,&drivers) { driver = list_entry(item, struct i2c_driver, list); if (driver->attach_adapter) @@ -292,16 +339,32 @@ int i2c_del_adapter(struct i2c_adapter *adap) } -/* ----- - * What follows is the "upwards" interface: commands for talking to clients, - * which implement the functions to access the physical information of the - * chips. +/* ------------------------------------------------------------------------- */ + +/* + * An i2c_driver is used with one or more i2c_client (device) nodes to access + * i2c slave chips, on a bus instance associated with some i2c_adapter. There + * are two models for binding the driver to its device: "new style" drivers + * follow the standard Linux driver model and just respond to probe() calls + * issued if the driver core sees they match(); "legacy" drivers create device + * nodes themselves. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { int res; + /* new style driver methods can't mix with legacy ones */ + if (driver->probe) { + if (driver->attach_adapter || driver->detach_adapter + || driver->detach_client) { + printk(KERN_WARNING + "i2c-core: driver [%s] is confused\n", + driver->driver.name); + return -EINVAL; + } + } + /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; @@ -315,7 +378,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) list_add_tail(&driver->list,&drivers); pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); - /* now look for instances of driver on our adapters */ + /* legacy drivers scan i2c busses directly */ if (driver->attach_adapter) { struct i2c_adapter *adapter; @@ -380,6 +443,8 @@ int i2c_del_driver(struct i2c_driver *driver) return 0; } +/* ------------------------------------------------------------------------- */ + static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) { struct list_head *item; @@ -430,9 +495,6 @@ int i2c_attach_client(struct i2c_client *client) res = device_register(&client->dev); if (res) goto out_list; - res = device_create_file(&client->dev, &dev_attr_client_name); - if (res) - goto out_unregister; mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { @@ -445,10 +507,6 @@ int i2c_attach_client(struct i2c_client *client) return 0; -out_unregister: - init_completion(&client->released); /* Needed? */ - device_unregister(&client->dev); - wait_for_completion(&client->released); out_list: list_del(&client->list); dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " @@ -483,7 +541,6 @@ int i2c_detach_client(struct i2c_client *client) mutex_lock(&adapter->clist_lock); list_del(&client->list); init_completion(&client->released); - device_remove_file(&client->dev, &dev_attr_client_name); device_unregister(&client->dev); mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 563c9651dd3..8dcccc0f482 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -113,7 +113,7 @@ struct i2c_driver { * can be used by the driver to test if the bus meets its conditions * & seek for the presence of the chip(s) it supports. If found, it * registers the client(s) that are on the bus to the i2c admin. via - * i2c_attach_client. + * i2c_attach_client. (LEGACY I2C DRIVERS ONLY) */ int (*attach_adapter)(struct i2c_adapter *); int (*detach_adapter)(struct i2c_adapter *); @@ -121,10 +121,16 @@ struct i2c_driver { /* tells the driver that a client is about to be deleted & gives it * the chance to remove its private data. Also, if the client struct * has been dynamically allocated by the driver in the function above, - * it must be freed here. + * it must be freed here. (LEGACY I2C DRIVERS ONLY) */ int (*detach_client)(struct i2c_client *); + /* Standard driver model interfaces, for "new style" i2c drivers. + * With the driver model, device enumeration is NEVER done by drivers; + * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) + */ + int (*probe)(struct i2c_client *); + /* driver model interfaces that don't relate to enumeration */ void (*shutdown)(struct i2c_client *); int (*suspend)(struct i2c_client *, pm_message_t mesg); @@ -148,6 +154,8 @@ struct i2c_driver { * @name: Indicates the type of the device, usually a chip name that's * generic enough to hide second-sourcing and compatible revisions. * @dev: Driver model device node for the slave. + * @driver_name: Identifies new-style driver used with this device; also + * used as the module name for hotplug/coldplug modprobe support. * * An i2c_client identifies a single device (i.e. chip) connected to an * i2c bus. The behaviour is defined by the routines of the driver. @@ -163,6 +171,7 @@ struct i2c_client { int usage_count; /* How many accesses currently */ /* to the client */ struct device dev; /* the device structure */ + char driver_name[KOBJ_NAME_LEN]; struct list_head list; struct completion released; }; -- cgit v1.2.3 From a1d9e6e49f4b473a6945a6b553f5070e8c793e0a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:30 +0200 Subject: i2c: i2c stack can remove() More update for new style driver support: add a remove() method, and use it in the relevant code paths. Again, nothing will use this yet since there's nothing to create devices feeding this infrastructure. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++---- include/linux/i2c.h | 1 + 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a2ad83ad0f5..3aac1b5c7cb 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -41,6 +41,7 @@ static LIST_HEAD(drivers); static DEFINE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); +#define is_newstyle_driver(d) ((d)->probe || (d)->remove) /* ------------------------------------------------------------------------- */ @@ -52,7 +53,7 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) /* make legacy i2c drivers bypass driver model probing entirely; * such drivers scan each i2c adapter/bus themselves. */ - if (!driver->probe) + if (!is_newstyle_driver(driver)) return 0; /* new style drivers use the same kind of driver matching policy @@ -100,7 +101,24 @@ static int i2c_device_probe(struct device *dev) static int i2c_device_remove(struct device *dev) { - return 0; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_driver *driver; + int status; + + if (!dev->driver) + return 0; + + driver = to_i2c_driver(dev->driver); + if (driver->remove) { + dev_dbg(dev, "remove\n"); + status = driver->remove(client); + } else { + dev->driver = NULL; + status = 0; + } + if (status == 0) + client->driver = NULL; + return status; } static void i2c_device_shutdown(struct device *dev) @@ -177,6 +195,26 @@ struct bus_type i2c_bus_type = { .resume = i2c_device_resume, }; +static void i2c_unregister_device(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_driver *driver = client->driver; + + if (driver && !is_newstyle_driver(driver)) { + dev_err(&client->dev, "can't unregister devices " + "with legacy drivers\n"); + WARN_ON(1); + return; + } + + mutex_lock(&adapter->clist_lock); + list_del(&client->list); + mutex_unlock(&adapter->clist_lock); + + device_unregister(&client->dev); +} + + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ @@ -310,9 +348,19 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ list_for_each_safe(item, _n, &adap->clients) { + struct i2c_driver *driver; + client = list_entry(item, struct i2c_client, list); + driver = client->driver; - if ((res=client->driver->detach_client(client))) { + /* new style, follow standard driver model */ + if (!driver || is_newstyle_driver(driver)) { + i2c_unregister_device(client); + continue; + } + + /* legacy drivers create and remove clients themselves */ + if ((res = driver->detach_client(client))) { dev_err(&adap->dev, "detach_client failed for client " "[%s] at address 0x%02x\n", client->name, client->addr); @@ -355,7 +403,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) int res; /* new style driver methods can't mix with legacy ones */ - if (driver->probe) { + if (is_newstyle_driver(driver)) { if (driver->attach_adapter || driver->detach_adapter || driver->detach_client) { printk(KERN_WARNING @@ -392,6 +440,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) } EXPORT_SYMBOL(i2c_register_driver); +/** + * i2c_del_driver - unregister I2C driver + * @driver: the driver being unregistered + */ int i2c_del_driver(struct i2c_driver *driver) { struct list_head *item1, *item2, *_n; @@ -402,6 +454,10 @@ int i2c_del_driver(struct i2c_driver *driver) mutex_lock(&core_lists); + /* new-style driver? */ + if (is_newstyle_driver(driver)) + goto unregister; + /* 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. @@ -434,6 +490,7 @@ int i2c_del_driver(struct i2c_driver *driver) } } + unregister: driver_unregister(&driver->driver); list_del(&driver->list); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 8dcccc0f482..6802c3a0a3a 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -130,6 +130,7 @@ struct i2c_driver { * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) */ int (*probe)(struct i2c_client *); + int (*remove)(struct i2c_client *); /* driver model interfaces that don't relate to enumeration */ void (*shutdown)(struct i2c_client *); -- cgit v1.2.3 From 4298cfc3eb6110df989f784be516c6340c597a66 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:31 +0200 Subject: i2c: i2c probe() and remove() documented Update Documentation/i2c to match previous patches updating probe() and remove() logic. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- Documentation/i2c/summary | 29 +++++++++----- Documentation/i2c/writing-clients | 82 ++++++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 19 deletions(-) diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary index 41dde877679..aea60bf7e8f 100644 --- a/Documentation/i2c/summary +++ b/Documentation/i2c/summary @@ -4,17 +4,23 @@ I2C and SMBus ============= I2C (pronounce: I squared C) is a protocol developed by Philips. It is a -slow two-wire protocol (10-400 kHz), but it suffices for many types of -devices. +slow two-wire protocol (variable speed, up to 400 kHz), with a high speed +extension (3.4 MHz). It provides an inexpensive bus for connecting many +types of devices with infrequent or low bandwidth communications needs. +I2C is widely used with embedded systems. Some systems use variants that +don't meet branding requirements, and so are not advertised as being I2C. -SMBus (System Management Bus) is a subset of the I2C protocol. Many -modern mainboards have a System Management Bus. There are a lot of -devices which can be connected to a SMBus; the most notable are modern -memory chips with EEPROM memories and chips for hardware monitoring. +SMBus (System Management Bus) is based on the I2C protocol, and is mostly +a subset of I2C protocols and signaling. Many I2C devices will work on an +SMBus, but some SMBus protocols add semantics beyond what is required to +achieve I2C branding. Modern PC mainboards rely on SMBus. The most common +devices connected through SMBus are RAM modules configured using I2C EEPROMs, +and hardware monitoring chips. -Because the SMBus is just a special case of the generalized I2C bus, we -can simulate the SMBus protocol on plain I2C busses. The reverse is -regretfully impossible. +Because the SMBus is mostly a subset of the generalized I2C bus, we can +use its protocols on many I2C systems. However, there are systems that don't +meet both SMBus and I2C electrical constraints; and others which can't +implement all the common SMBus protocol semantics or messages. Terminology @@ -29,6 +35,7 @@ When we talk about I2C, we use the following terms: An Algorithm driver contains general code that can be used for a whole class of I2C adapters. Each specific adapter driver depends on one algorithm driver. + A Driver driver (yes, this sounds ridiculous, sorry) contains the general code to access some type of device. Each detected device gets its own data in the Client structure. Usually, Driver and Client are more closely @@ -40,6 +47,10 @@ a separate Adapter and Algorithm driver), and drivers for your I2C devices in this package. See the lm_sensors project http://www.lm-sensors.nu for device drivers. +At this time, Linux only operates I2C (or SMBus) in master mode; you can't +use these APIs to make a Linux system behave as a slave/device, either to +speak a custom protocol or to emulate some other device. + Included Bus Drivers ==================== diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index fbcff96f4ca..54255fd68ec 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -1,5 +1,5 @@ This is a small guide for those who want to write kernel drivers for I2C -or SMBus devices. +or SMBus devices, using Linux as the protocol host/master (not slave). To set up a driver, you need to do several things. Some are optional, and some things can be done slightly or completely different. Use this as a @@ -29,8 +29,16 @@ static struct i2c_driver foo_driver = { .driver = { .name = "foo", }, + + /* iff driver uses driver model ("new style") binding model: */ + .probe = foo_probe, + .remove = foo_remove, + + /* else, driver uses "legacy" binding model: */ .attach_adapter = foo_attach_adapter, .detach_client = foo_detach_client, + + /* these may be used regardless of the driver binding model */ .shutdown = foo_shutdown, /* optional */ .suspend = foo_suspend, /* optional */ .resume = foo_resume, /* optional */ @@ -40,7 +48,8 @@ static struct i2c_driver foo_driver = { The name field is the driver name, and must not contain spaces. It should match the module name (if the driver can be compiled as a module), although you can use MODULE_ALIAS (passing "foo" in this example) to add -another name for the module. +another name for the module. If the driver name doesn't match the module +name, the module won't be automatically loaded (hotplug/coldplug). All other fields are for call-back functions which will be explained below. @@ -141,6 +150,59 @@ Writing is done the same way. Probing and attaching ===================== +The Linux I2C stack was originally written to support access to hardware +monitoring chips on PC motherboards, and thus it embeds some assumptions +that are more appropriate to SMBus (and PCs) than to I2C. One of these +assumptions is that most adapters and devices drivers support the SMBUS_QUICK +protocol to probe device presence. Another is that devices and their drivers +can be sufficiently configured using only such probe primitives. + +As Linux and its I2C stack became more widely used in embedded systems +and complex components such as DVB adapters, those assumptions became more +problematic. Drivers for I2C devices that issue interrupts need more (and +different) configuration information, as do drivers handling chip variants +that can't be distinguished by protocol probing, or which need some board +specific information to operate correctly. + +Accordingly, the I2C stack now has two models for associating I2C devices +with their drivers: the original "legacy" model, and a newer one that's +fully compatible with the Linux 2.6 driver model. These models do not mix, +since the "legacy" model requires drivers to create "i2c_client" device +objects after SMBus style probing, while the Linux driver model expects +drivers to be given such device objects in their probe() routines. + + +Standard Driver Model Binding ("New Style") +------------------------------------------- + +System infrastructure, typically board-specific initialization code or +boot firmware, reports what I2C devices exist. For example, there may be +a table, in the kernel or from the boot loader, identifying I2C devices +and linking them to board-specific configuration information about IRQs +and other wiring artifacts, chip type, and so on. That could be used to +create i2c_client objects for each I2C device. + +I2C device drivers using this binding model work just like any other +kind of driver in Linux: they provide a probe() method to bind to +those devices, and a remove() method to unbind. + + static int foo_probe(struct i2c_client *client); + static int foo_remove(struct i2c_client *client); + +Remember that the i2c_driver does not create those client handles. The +handle may be used during foo_probe(). If foo_probe() reports success +(zero not a negative status code) it may save the handle and use it until +foo_remove() returns. That binding model is used by most Linux drivers. + +Drivers match devices when i2c_client.driver_name and the driver name are +the same; this approach is used in several other busses that don't have +device typing support in the hardware. The driver and module name should +match, so hotplug/coldplug mechanisms will modprobe the driver. + + +Legacy Driver Binding Model +--------------------------- + Most i2c devices can be present on several i2c addresses; for some this is determined in hardware (by soldering some chip pins to Vcc or Ground), for others this can be changed in software (by writing to specific client @@ -162,8 +224,8 @@ NOTE: If you want to write a `sensors' driver, the interface is slightly -Probing classes ---------------- +Probing classes (Legacy model) +------------------------------ All parameters are given as lists of unsigned 16-bit integers. Lists are terminated by I2C_CLIENT_END. @@ -210,8 +272,8 @@ Note that you *have* to call the defined variable `normal_i2c', without any prefix! -Attaching to an adapter ------------------------ +Attaching to an adapter (Legacy model) +-------------------------------------- Whenever a new adapter is inserted, or for all adapters if the driver is being registered, the callback attach_adapter() is called. Now is the @@ -237,8 +299,8 @@ them (unless a `force' parameter was used). In addition, addresses that are already in use (by some other registered client) are skipped. -The detect client function --------------------------- +The detect client function (Legacy model) +----------------------------------------- The detect client function is called by i2c_probe. The `kind' parameter contains -1 for a probed detection, 0 for a forced detection, or a positive @@ -427,8 +489,8 @@ For now, you can ignore the `flags' parameter. It is there for future use. } -Removing the client -=================== +Removing the client (Legacy model) +================================== The detach_client call back function is called when a client should be removed. It may actually fail, but only when panicking. This code is -- cgit v1.2.3 From 9c1600eda42e52796f49b36cf15b9debcfd09bea Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:31 +0200 Subject: i2c: Add i2c_board_info and i2c_new_device() This provides partial support for new-style I2C driver binding. It builds on "struct i2c_board_info" declarations that identify I2C devices on a given board. This is needed on systems with I2C devices that can't be fully probed and/or autoconfigured, such as many embedded Linux configurations where the way a given I2C device is wired may affect how it must be used. There are two models for declaring such devices: * LATE -- using a public function i2c_new_device(). This lets modules declare I2C devices found *AFTER* a given I2C adapter becomes available. For example, a PCI card could create adapters giving access to utility chips on that card, and this would be used to associate those chips with those adapters. * EARLY -- from arch_initcall() level code, using a non-exported function i2c_register_board_info(). This copies the declarations *BEFORE* such an i2c_adapter becomes available, arranging that i2c_new_device() will be called later when i2c-core registers the relevant i2c_adapter. For example, arch/.../.../board-*.c files would declare the I2C devices along with their platform data, and I2C devices would behave much like PNPACPI devices. (That is, both enumerate from board-specific tables.) To match the exported i2c_new_device(), the previously-private function i2c_unregister_device() is now exported. Pending later patches using these new APIs, this is effectively a NOP. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/Makefile | 2 +- drivers/i2c/Kconfig | 5 +++ drivers/i2c/Makefile | 1 + drivers/i2c/i2c-boardinfo.c | 90 +++++++++++++++++++++++++++++++++++++++++++++ drivers/i2c/i2c-core.c | 90 +++++++++++++++++++++++++++++++++++++++++++-- drivers/i2c/i2c-core.h | 31 ++++++++++++++++ include/linux/i2c.h | 62 +++++++++++++++++++++++++++++++ 7 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 drivers/i2c/i2c-boardinfo.c create mode 100644 drivers/i2c/i2c-core.h diff --git a/drivers/Makefile b/drivers/Makefile index 920c975bb6d..26ca9031ea4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_RTC_LIB) += rtc/ -obj-$(CONFIG_I2C) += i2c/ +obj-y += i2c/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_PHONE) += telephony/ diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 11935f66fcd..74c8518b69e 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -22,6 +22,11 @@ config I2C This I2C support can also be built as a module. If so, the module will be called i2c-core. +config I2C_BOARDINFO + boolean + depends on I2C + default y + config I2C_CHARDEV tristate "I2C device interface" depends on I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 71c5a854ac5..ba26e6cbe74 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -2,6 +2,7 @@ # Makefile for the i2c core. # +obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-y += busses/ chips/ algos/ diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c new file mode 100644 index 00000000000..ffb35f09df0 --- /dev/null +++ b/drivers/i2c/i2c-boardinfo.c @@ -0,0 +1,90 @@ +/* + * i2c-boardinfo.h - collect pre-declarations of I2C devices + * + * 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 +#include + +#include "i2c-core.h" + + +/* These symbols are exported ONLY FOR the i2c core. + * No other users will be supported. + */ +DEFINE_MUTEX(__i2c_board_lock); +EXPORT_SYMBOL_GPL(__i2c_board_lock); + +LIST_HEAD(__i2c_board_list); +EXPORT_SYMBOL_GPL(__i2c_board_list); + +int __i2c_first_dynamic_bus_num; +EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); + + +/** + * i2c_register_board_info - statically declare I2C devices + * @busnum: identifies the bus to which these devices belong + * @info: vector of i2c device descriptors + * @len: how many descriptors in the vector; may be zero to reserve + * the specified bus number. + * + * Systems using the Linux I2C driver stack can declare tables of board info + * while they initialize. This should be done in board-specific init code + * near arch_initcall() time, or equivalent, before any I2C adapter driver is + * registered. For example, mainboard init code could define several devices, + * as could the init code for each daughtercard in a board stack. + * + * The I2C devices will be created later, after the adapter for the relevant + * bus has been registered. After that moment, standard driver model tools + * are used to bind "new style" I2C drivers to the devices. The bus number + * for any device declared using this routine is not available for dynamic + * allocation. + * + * The board info passed can safely be __initdata, but be careful of embedded + * pointers (for platform_data, functions, etc) since that won't be copied. + */ +int __init +i2c_register_board_info(int busnum, + struct i2c_board_info const *info, unsigned len) +{ + int status; + + mutex_lock(&__i2c_board_lock); + + /* dynamic bus numbers will be assigned after the last static one */ + if (busnum >= __i2c_first_dynamic_bus_num) + __i2c_first_dynamic_bus_num = busnum + 1; + + for (status = 0; len; len--, info++) { + struct i2c_devinfo *devinfo; + + devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); + if (!devinfo) { + pr_debug("i2c-core: can't register boardinfo!\n"); + status = -ENOMEM; + break; + } + + devinfo->busnum = busnum; + devinfo->board_info = *info; + list_add_tail(&devinfo->list, &__i2c_board_list); + } + + mutex_unlock(&__i2c_board_lock); + + return status; +} diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3aac1b5c7cb..a7dcdc69b9e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -35,6 +35,8 @@ #include #include +#include "i2c-core.h" + static LIST_HEAD(adapters); static LIST_HEAD(drivers); @@ -162,6 +164,11 @@ static void i2c_client_release(struct device *dev) complete(&client->released); } +static void i2c_client_dev_release(struct device *dev) +{ + kfree(to_i2c_client(dev)); +} + static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); @@ -195,7 +202,60 @@ struct bus_type i2c_bus_type = { .resume = i2c_device_resume, }; -static void i2c_unregister_device(struct i2c_client *client) +/** + * i2c_new_device - instantiate an i2c device for use with a new style driver + * @adap: the adapter managing the device + * @info: describes one I2C device; bus_num is ignored + * + * Create a device to work with a new style i2c driver, where binding is + * handled through driver model probe()/remove() methods. This call is not + * appropriate for use by mainboad initialization logic, which usually runs + * during an arch_initcall() long before any i2c_adapter could exist. + * + * This returns the new i2c client, which may be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client * +i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) +{ + struct i2c_client *client; + int status; + + client = kzalloc(sizeof *client, GFP_KERNEL); + if (!client) + return NULL; + + client->adapter = adap; + + client->dev.platform_data = info->platform_data; + client->flags = info->flags; + client->addr = info->addr; + client->irq = info->irq; + + strlcpy(client->driver_name, info->driver_name, + sizeof(client->driver_name)); + strlcpy(client->name, info->type, sizeof(client->name)); + + /* a new style driver may be bound to this device when we + * return from this function, or any later moment (e.g. maybe + * hotplugging will load the driver module). and the device + * refcount model is the standard driver model one. + */ + status = i2c_attach_client(client); + if (status < 0) { + kfree(client); + client = NULL; + } + return client; +} +EXPORT_SYMBOL_GPL(i2c_new_device); + + +/** + * i2c_unregister_device - reverse effect of i2c_new_device() + * @client: value returned from i2c_new_device() + */ +void i2c_unregister_device(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct i2c_driver *driver = client->driver; @@ -213,6 +273,7 @@ static void i2c_unregister_device(struct i2c_client *client) device_unregister(&client->dev); } +EXPORT_SYMBOL_GPL(i2c_unregister_device); /* ------------------------------------------------------------------------- */ @@ -243,6 +304,22 @@ struct class i2c_adapter_class = { .dev_attrs = i2c_adapter_attrs, }; +static void i2c_scan_static_board_info(struct i2c_adapter *adapter) +{ + struct i2c_devinfo *devinfo; + + mutex_lock(&__i2c_board_lock); + list_for_each_entry(devinfo, &__i2c_board_list, list) { + if (devinfo->busnum == adapter->nr + && !i2c_new_device(adapter, + &devinfo->board_info)) + printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n", + i2c_adapter_id(adapter), + devinfo->board_info.addr); + } + mutex_unlock(&__i2c_board_lock); +} + /* ----- * i2c_add_adapter is called from within the algorithm layer, @@ -311,7 +388,6 @@ out_list: goto out_unlock; } - int i2c_del_adapter(struct i2c_adapter *adap) { struct list_head *item, *_n; @@ -541,9 +617,15 @@ int i2c_attach_client(struct i2c_client *client) client->usage_count = 0; client->dev.parent = &client->adapter->dev; - client->dev.driver = &client->driver->driver; client->dev.bus = &i2c_bus_type; - client->dev.release = &i2c_client_release; + + if (client->driver) + client->dev.driver = &client->driver->driver; + + if (client->driver && !is_newstyle_driver(client->driver)) + client->dev.release = i2c_client_release; + else + client->dev.release = i2c_client_dev_release; snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h new file mode 100644 index 00000000000..cd5bff87485 --- /dev/null +++ b/drivers/i2c/i2c-core.h @@ -0,0 +1,31 @@ +/* + * i2c-core.h - interfaces internal to the I2C framework + * + * 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. + */ + +struct i2c_devinfo { + struct list_head list; + int busnum; + struct i2c_board_info board_info; +}; + +/* board_lock protects board_list and first_dynamic_bus_num. + * only i2c core components are allowed to use these symbols. + */ +extern struct mutex __i2c_board_lock; +extern struct list_head __i2c_board_list; +extern int __i2c_first_dynamic_bus_num; + diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6802c3a0a3a..382a43bf3ad 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -172,6 +172,7 @@ struct i2c_client { int usage_count; /* How many accesses currently */ /* to the client */ struct device dev; /* the device structure */ + int irq; /* irq issued by device (or -1) */ char driver_name[KOBJ_NAME_LEN]; struct list_head list; struct completion released; @@ -193,6 +194,67 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data) dev_set_drvdata (&dev->dev, data); } +/** + * struct i2c_board_info - template for device creation + * @driver_name: identifies the driver to be bound to the device + * @type: optional chip type information, to initialize i2c_client.name + * @flags: to initialize i2c_client.flags + * @addr: stored in i2c_client.addr + * @platform_data: stored in i2c_client.dev.platform_data + * @irq: stored in i2c_client.irq + + * I2C doesn't actually support hardware probing, although controllers and + * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's + * a device at a given address. Drivers commonly need more information than + * that, such as chip type, configuration, associated IRQ, and so on. + * + * i2c_board_info is used to build tables of information listing I2C devices + * that are present. This information is used to grow the driver model tree + * for "new style" I2C drivers. For mainboards this is done statically using + * i2c_register_board_info(), where @bus_num represents an adapter that isn't + * yet available. For add-on boards, i2c_new_device() does this dynamically + * with the adapter already known. + */ +struct i2c_board_info { + char driver_name[KOBJ_NAME_LEN]; + char type[I2C_NAME_SIZE]; + unsigned short flags; + unsigned short addr; + void *platform_data; + int irq; +}; + +/** + * I2C_BOARD_INFO - macro used to list an i2c device and its driver + * @driver: identifies the driver to use with the device + * @dev_addr: the device's address on the bus. + * + * This macro initializes essential fields of a struct i2c_board_info, + * declaring what has been provided on a particular board. Optional + * fields (such as the chip type, its associated irq, or device-specific + * platform_data) are provided using conventional syntax. + */ +#define I2C_BOARD_INFO(driver,dev_addr) \ + .driver_name = (driver), .addr = (dev_addr) + + +/* Add-on boards should register/unregister their devices; e.g. a board + * with integrated I2C, a config eeprom, sensors, and a codec that's + * used in conjunction with the primary hardware. + */ +extern struct i2c_client * +i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info); + +extern void i2c_unregister_device(struct i2c_client *); + +/* Mainboard arch_initcall() code should register all its I2C devices. + * This is done at arch_initcall time, before declaring any i2c adapters. + * Modules for add-on boards must use other calls. + */ +extern int +i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n); + + /* * The following structs are for those who like to implement new bus drivers: * i2c_algorithm is the interface to a class of hardware solutions which can -- cgit v1.2.3 From 6e13e641841833cc2aa5baefe89bb04bc388801b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:31 +0200 Subject: i2c: Add i2c_add_numbered_adapter() This adds a call, i2c_add_numbered_adapter(), registering an I2C adapter with a specific bus number and then creating I2C device nodes for any pre-declared devices on that bus. It builds on previous patches adding I2C probe() and remove() support, and that pre-declaration of devices. This completes the core support for "new style" I2C device drivers. Those follow the standard driver model for binding devices to drivers (using probe and remove methods) rather than a legacy model (where the driver tries to autoconfigure each bus, and registers devices itself). Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 126 +++++++++++++++++++++++++++++++++++++++---------- include/linux/i2c.h | 1 + 2 files changed, 101 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a7dcdc69b9e..c50229bd9f8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -320,38 +320,19 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) mutex_unlock(&__i2c_board_lock); } - -/* ----- - * i2c_add_adapter is called from within the algorithm layer, - * when a new hw adapter registers. A new device is register to be - * available for clients. - */ -int i2c_add_adapter(struct i2c_adapter *adap) +static int i2c_register_adapter(struct i2c_adapter *adap) { - int id, res = 0; + int res = 0; struct list_head *item; struct i2c_driver *driver; - mutex_lock(&core_lists); - - if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) { - res = -ENOMEM; - goto out_unlock; - } - - res = idr_get_new(&i2c_adapter_idr, adap, &id); - if (res < 0) { - if (res == -EAGAIN) - res = -ENOMEM; - goto out_unlock; - } - - adap->nr = id & MAX_ID_MASK; mutex_init(&adap->bus_lock); mutex_init(&adap->clist_lock); - list_add_tail(&adap->list,&adapters); INIT_LIST_HEAD(&adap->clients); + mutex_lock(&core_lists); + list_add_tail(&adap->list, &adapters); + /* Add the adapter to the driver core. * If the parent pointer is not set up, * we add this adapter to the host bus. @@ -370,6 +351,10 @@ int i2c_add_adapter(struct i2c_adapter *adap) dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); + /* create pre-declared device nodes for new-style drivers */ + if (adap->nr < __i2c_first_dynamic_bus_num) + i2c_scan_static_board_info(adap); + /* let legacy drivers scan this bus for matching devices */ list_for_each(item,&drivers) { driver = list_entry(item, struct i2c_driver, list); @@ -388,6 +373,93 @@ out_list: goto out_unlock; } +/** + * i2c_add_adapter - declare i2c adapter, use dynamic bus number + * @adapter: the adapter to add + * + * This routine is used to declare an I2C adapter when its bus number + * doesn't matter. Examples: for I2C adapters dynamically added by + * USB links or PCI plugin cards. + * + * When this returns zero, a new bus number was allocated and stored + * in adap->nr, and the specified adapter became available for clients. + * Otherwise, a negative errno value is returned. + */ +int i2c_add_adapter(struct i2c_adapter *adapter) +{ + int id, res = 0; + +retry: + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) + return -ENOMEM; + + mutex_lock(&core_lists); + /* "above" here means "above or equal to", sigh */ + res = idr_get_new_above(&i2c_adapter_idr, adapter, + __i2c_first_dynamic_bus_num, &id); + mutex_unlock(&core_lists); + + if (res < 0) { + if (res == -EAGAIN) + goto retry; + return res; + } + + adapter->nr = id; + return i2c_register_adapter(adapter); +} +EXPORT_SYMBOL(i2c_add_adapter); + +/** + * i2c_add_numbered_adapter - declare i2c adapter, use static bus number + * @adap: the adapter to register (with adap->nr initialized) + * + * This routine is used to declare an I2C adapter when its bus number + * matters. Example: for I2C adapters from system-on-chip CPUs, or + * otherwise built in to the system's mainboard, and where i2c_board_info + * is used to properly configure I2C devices. + * + * If no devices have pre-been declared for this bus, then be sure to + * register the adapter before any dynamically allocated ones. Otherwise + * the required bus ID may not be available. + * + * When this returns zero, the specified adapter became available for + * clients using the bus number provided in adap->nr. Also, the table + * of I2C devices pre-declared using i2c_register_board_info() is scanned, + * and the appropriate driver model device nodes are created. Otherwise, a + * negative errno value is returned. + */ +int i2c_add_numbered_adapter(struct i2c_adapter *adap) +{ + int id; + int status; + + if (adap->nr & ~MAX_ID_MASK) + return -EINVAL; + +retry: + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) + return -ENOMEM; + + mutex_lock(&core_lists); + /* "above" here means "above or equal to", sigh; + * we need the "equal to" result to force the result + */ + status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id); + if (status == 0 && id != adap->nr) { + status = -EBUSY; + idr_remove(&i2c_adapter_idr, id); + } + mutex_unlock(&core_lists); + if (status == -EAGAIN) + goto retry; + + if (status == 0) + status = i2c_register_adapter(adap); + return status; +} +EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); + int i2c_del_adapter(struct i2c_adapter *adap) { struct list_head *item, *_n; @@ -452,7 +524,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); - /* free dynamically allocated bus id */ + /* free bus id */ idr_remove(&i2c_adapter_idr, adap->nr); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -493,6 +565,9 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; + /* for new style drivers, when registration returns the driver core + * will have called probe() for all matching-but-unbound devices. + */ res = driver_register(&driver->driver); if (res) return res; @@ -1377,7 +1452,6 @@ EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); 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_del_driver); EXPORT_SYMBOL(i2c_attach_client); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 382a43bf3ad..36d6814a6df 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -363,6 +363,7 @@ struct i2c_client_address_data { */ extern int i2c_add_adapter(struct i2c_adapter *); extern int i2c_del_adapter(struct i2c_adapter *); +extern int i2c_add_numbered_adapter(struct i2c_adapter *); extern int i2c_register_driver(struct module *, struct i2c_driver *); extern int i2c_del_driver(struct i2c_driver *); -- cgit v1.2.3 From c05646069ccf8e94031ca9c8ab18fff35ba4405e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:31 +0200 Subject: i2c: i2c EXPORT_SYMBOL cleanup Make i2c-core.c obey Documentation/CodingStyle better by snugging the EXPORT_SYMBOL declarations next to the relevant definitions. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 64 ++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c50229bd9f8..18124398b46 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -201,6 +201,7 @@ struct bus_type i2c_bus_type = { .suspend = i2c_device_suspend, .resume = i2c_device_resume, }; +EXPORT_SYMBOL_GPL(i2c_bus_type); /** * i2c_new_device - instantiate an i2c device for use with a new style driver @@ -285,6 +286,7 @@ void i2c_adapter_dev_release(struct device *dev) struct i2c_adapter *adap = to_i2c_adapter(dev); complete(&adap->dev_released); } +EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */ static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -303,6 +305,7 @@ struct class i2c_adapter_class = { .name = "i2c-adapter", .dev_attrs = i2c_adapter_attrs, }; +EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { @@ -533,6 +536,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) mutex_unlock(&core_lists); return res; } +EXPORT_SYMBOL(i2c_del_adapter); /* ------------------------------------------------------------------------- */ @@ -650,6 +654,7 @@ int i2c_del_driver(struct i2c_driver *driver) mutex_unlock(&core_lists); return 0; } +EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ @@ -676,6 +681,7 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr) return rval; } +EXPORT_SYMBOL(i2c_check_addr); int i2c_attach_client(struct i2c_client *client) { @@ -729,7 +735,7 @@ out_unlock: mutex_unlock(&adapter->clist_lock); return res; } - +EXPORT_SYMBOL(i2c_attach_client); int i2c_detach_client(struct i2c_client *client) { @@ -762,6 +768,7 @@ int i2c_detach_client(struct i2c_client *client) out: return res; } +EXPORT_SYMBOL(i2c_detach_client); static int i2c_inc_use_client(struct i2c_client *client) { @@ -794,6 +801,7 @@ int i2c_use_client(struct i2c_client *client) return 0; } +EXPORT_SYMBOL(i2c_use_client); int i2c_release_client(struct i2c_client *client) { @@ -808,6 +816,7 @@ int i2c_release_client(struct i2c_client *client) return 0; } +EXPORT_SYMBOL(i2c_release_client); void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { @@ -828,6 +837,7 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) } mutex_unlock(&adap->clist_lock); } +EXPORT_SYMBOL(i2c_clients_command); static int __init i2c_init(void) { @@ -877,6 +887,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) return -ENOSYS; } } +EXPORT_SYMBOL(i2c_transfer); int i2c_master_send(struct i2c_client *client,const char *buf ,int count) { @@ -895,6 +906,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) transmitted, else error code. */ return (ret == 1) ? count : ret; } +EXPORT_SYMBOL(i2c_master_send); int i2c_master_recv(struct i2c_client *client, char *buf ,int count) { @@ -914,7 +926,7 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) transmitted, else error code. */ return (ret == 1) ? count : ret; } - +EXPORT_SYMBOL(i2c_master_recv); int i2c_control(struct i2c_client *client, unsigned int cmd, unsigned long arg) @@ -936,6 +948,7 @@ int i2c_control(struct i2c_client *client, } return ret; } +EXPORT_SYMBOL(i2c_control); /* ---------------------------------------------------- * the i2c address scanning function @@ -1077,6 +1090,7 @@ int i2c_probe(struct i2c_adapter *adapter, return 0; } +EXPORT_SYMBOL(i2c_probe); struct i2c_adapter* i2c_get_adapter(int id) { @@ -1090,11 +1104,13 @@ struct i2c_adapter* i2c_get_adapter(int id) mutex_unlock(&core_lists); return adapter; } +EXPORT_SYMBOL(i2c_get_adapter); void i2c_put_adapter(struct i2c_adapter *adap) { module_put(adap->owner); } +EXPORT_SYMBOL(i2c_put_adapter); /* The SMBus parts */ @@ -1163,6 +1179,7 @@ s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value) return i2c_smbus_xfer(client->adapter,client->addr,client->flags, value,0,I2C_SMBUS_QUICK,NULL); } +EXPORT_SYMBOL(i2c_smbus_write_quick); s32 i2c_smbus_read_byte(struct i2c_client *client) { @@ -1173,12 +1190,14 @@ s32 i2c_smbus_read_byte(struct i2c_client *client) else return data.byte; } +EXPORT_SYMBOL(i2c_smbus_read_byte); s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } +EXPORT_SYMBOL(i2c_smbus_write_byte); s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) { @@ -1189,6 +1208,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) else return data.byte; } +EXPORT_SYMBOL(i2c_smbus_read_byte_data); s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) { @@ -1198,6 +1218,7 @@ s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data); } +EXPORT_SYMBOL(i2c_smbus_write_byte_data); s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) { @@ -1208,6 +1229,7 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) else return data.word; } +EXPORT_SYMBOL(i2c_smbus_read_word_data); s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) { @@ -1217,6 +1239,7 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) I2C_SMBUS_WRITE,command, I2C_SMBUS_WORD_DATA,&data); } +EXPORT_SYMBOL(i2c_smbus_write_word_data); s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) @@ -1231,6 +1254,7 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA,&data); } +EXPORT_SYMBOL(i2c_smbus_write_block_data); /* Returns the number of read bytes */ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) @@ -1245,6 +1269,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val memcpy(values, &data.block[1], data.block[0]); return data.block[0]; } +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) @@ -1259,6 +1284,7 @@ s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data); } +EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ @@ -1445,41 +1471,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, return res; } - - -/* Next three are needed by i2c-isa */ -EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); -EXPORT_SYMBOL_GPL(i2c_adapter_class); -EXPORT_SYMBOL_GPL(i2c_bus_type); - -EXPORT_SYMBOL(i2c_del_adapter); -EXPORT_SYMBOL(i2c_del_driver); -EXPORT_SYMBOL(i2c_attach_client); -EXPORT_SYMBOL(i2c_detach_client); -EXPORT_SYMBOL(i2c_use_client); -EXPORT_SYMBOL(i2c_release_client); -EXPORT_SYMBOL(i2c_clients_command); -EXPORT_SYMBOL(i2c_check_addr); - -EXPORT_SYMBOL(i2c_master_send); -EXPORT_SYMBOL(i2c_master_recv); -EXPORT_SYMBOL(i2c_control); -EXPORT_SYMBOL(i2c_transfer); -EXPORT_SYMBOL(i2c_get_adapter); -EXPORT_SYMBOL(i2c_put_adapter); -EXPORT_SYMBOL(i2c_probe); - EXPORT_SYMBOL(i2c_smbus_xfer); -EXPORT_SYMBOL(i2c_smbus_write_quick); -EXPORT_SYMBOL(i2c_smbus_read_byte); -EXPORT_SYMBOL(i2c_smbus_write_byte); -EXPORT_SYMBOL(i2c_smbus_read_byte_data); -EXPORT_SYMBOL(i2c_smbus_write_byte_data); -EXPORT_SYMBOL(i2c_smbus_read_word_data); -EXPORT_SYMBOL(i2c_smbus_write_word_data); -EXPORT_SYMBOL(i2c_smbus_write_block_data); -EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); -EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); -- cgit v1.2.3 From 0f3b48385213355a2d4408bec1b481ffcf0e8638 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:31 +0200 Subject: i2c-algo-bit: Add i2c_bit_add_numbered_bus Add i2c_bit_add_numbered_bus(), which is equivalent to i2c_bit_add_bus except that it calls i2c_add_numbered_adapter() at the end instead of i2c_add_adapter(). Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 25 ++++++++++++++++++++++++- include/linux/i2c-algo-bit.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index fcef6ff3d28..fc16f9d268a 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -540,7 +540,7 @@ static const struct i2c_algorithm i2c_bit_algo = { /* * registering functions to load algorithms at runtime */ -int i2c_bit_add_bus(struct i2c_adapter *adap) +static int i2c_bit_prepare_bus(struct i2c_adapter *adap) { struct i2c_algo_bit_data *bit_adap = adap->algo_data; @@ -558,10 +558,33 @@ int i2c_bit_add_bus(struct i2c_adapter *adap) adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ + return 0; +} + +int i2c_bit_add_bus(struct i2c_adapter *adap) +{ + int err; + + err = i2c_bit_prepare_bus(adap); + if (err) + return err; + return i2c_add_adapter(adap); } EXPORT_SYMBOL(i2c_bit_add_bus); +int i2c_bit_add_numbered_bus(struct i2c_adapter *adap) +{ + int err; + + err = i2c_bit_prepare_bus(adap); + if (err) + return err; + + return i2c_add_numbered_adapter(adap); +} +EXPORT_SYMBOL(i2c_bit_add_numbered_bus); + MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index 937da70cb4c..d91dab88635 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -44,5 +44,6 @@ struct i2c_algo_bit_data { }; int i2c_bit_add_bus(struct i2c_adapter *); +int i2c_bit_add_numbered_bus(struct i2c_adapter *); #endif /* _LINUX_I2C_ALGO_BIT_H */ -- cgit v1.2.3 From 12b5053ac58709c7d475888bc18d1f61958afc4e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:31 +0200 Subject: i2c: Add i2c_new_probed_device() Add a new helper function to instantiate an i2c device. It is meant as a replacement for i2c_new_device() when you don't know for sure at which address your I2C/SMBus device lives. This happens frequently on TV adapters for example, you know there is a tuner chip on the bus, but depending on the exact board model and revision, it can live at different addresses. So, the new i2c_new_probed_device() function will probe the bus according to a list of addresses, and as soon as one of these addresses responds, it will call i2c_new_device() on that one address. This function will make it possible to port the old i2c drivers to the new model quickly. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/i2c.h | 9 ++++++++ 2 files changed, 72 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 18124398b46..0fd4acbffb7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1092,6 +1092,69 @@ int i2c_probe(struct i2c_adapter *adapter, } EXPORT_SYMBOL(i2c_probe); +struct i2c_client * +i2c_new_probed_device(struct i2c_adapter *adap, + struct i2c_board_info *info, + unsigned short const *addr_list) +{ + int i; + + /* Stop here if the bus doesn't support probing */ + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) { + dev_err(&adap->dev, "Probing not supported\n"); + return NULL; + } + + mutex_lock(&adap->clist_lock); + for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { + /* Check address validity */ + if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { + dev_warn(&adap->dev, "Invalid 7-bit address " + "0x%02x\n", addr_list[i]); + continue; + } + + /* Check address availability */ + if (__i2c_check_addr(adap, addr_list[i])) { + dev_dbg(&adap->dev, "Address 0x%02x already in " + "use, not probing\n", addr_list[i]); + continue; + } + + /* Test address responsiveness + The default probe method is a quick write, but it is known + to corrupt the 24RF08 EEPROMs due to a state machine bug, + and could also irreversibly write-protect some EEPROMs, so + for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte + read instead. Also, some bus drivers don't implement + quick write, so we fallback to a byte read it that case + too. */ + if ((addr_list[i] & ~0x07) == 0x30 + || (addr_list[i] & ~0x0f) == 0x50 + || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { + if (i2c_smbus_xfer(adap, addr_list[i], 0, + I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE, NULL) >= 0) + break; + } else { + if (i2c_smbus_xfer(adap, addr_list[i], 0, + I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL) >= 0) + break; + } + } + mutex_unlock(&adap->clist_lock); + + if (addr_list[i] == I2C_CLIENT_END) { + dev_dbg(&adap->dev, "Probing failed, no device found\n"); + return NULL; + } + + info->addr = addr_list[i]; + return i2c_new_device(adap, info); +} +EXPORT_SYMBOL_GPL(i2c_new_probed_device); + struct i2c_adapter* i2c_get_adapter(int id) { struct i2c_adapter *adapter; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 36d6814a6df..da95ce79d07 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -245,6 +245,15 @@ struct i2c_board_info { extern struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info); +/* If you don't know the exact address of an I2C device, use this variant + * instead, which can probe for device presence in a list of possible + * addresses. + */ +extern struct i2c_client * +i2c_new_probed_device(struct i2c_adapter *adap, + struct i2c_board_info *info, + unsigned short const *addr_list); + extern void i2c_unregister_device(struct i2c_client *); /* Mainboard arch_initcall() code should register all its I2C devices. -- cgit v1.2.3 From ce9e0794c23fb1d0222cb10009a198b427dcf6ad Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:32 +0200 Subject: i2c: Document i2c_new_device() Document the new i2c_new_device(), i2c_new_probed_device() and i2c_unregister_device() functions. Signed-off-by: Jean Delvare --- Documentation/i2c/writing-clients | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 54255fd68ec..e62fbfa1282 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -200,6 +200,44 @@ device typing support in the hardware. The driver and module name should match, so hotplug/coldplug mechanisms will modprobe the driver. +Device Creation (Standard driver model) +--------------------------------------- + +If you know for a fact that an I2C device is connected to a given I2C bus, +you can instantiate that device by simply filling an i2c_board_info +structure with the device address and driver name, and calling +i2c_new_device(). This will create the device, then the driver core will +take care of finding the right driver and will call its probe() method. +If a driver supports different device types, you can specify the type you +want using the type field. You can also specify an IRQ and platform data +if needed. + +Sometimes you know that a device is connected to a given I2C bus, but you +don't know the exact address it uses. This happens on TV adapters for +example, where the same driver supports dozens of slightly different +models, and I2C device addresses change from one model to the next. In +that case, you can use the i2c_new_probed_device() variant, which is +similar to i2c_new_device(), except that it takes an additional list of +possible I2C addresses to probe. A device is created for the first +responsive address in the list. If you expect more than one device to be +present in the address range, simply call i2c_new_probed_device() that +many times. + +The call to i2c_new_device() or i2c_new_probed_device() typically happens +in the I2C bus driver. You may want to save the returned i2c_client +reference for later use. + + +Device Deletion (Standard driver model) +--------------------------------------- + +Each I2C device which has been created using i2c_new_device() or +i2c_new_probed_device() can be unregistered by calling +i2c_unregister_device(). If you don't call it explicitly, it will be +called automatically before the underlying I2C bus itself is removed, as a +device can't survive its parent in the device driver model. + + Legacy Driver Binding Model --------------------------- -- cgit v1.2.3 From a97f1ed090fc01a5876a7caf2cbdf93470436201 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:32 +0200 Subject: i2c: Move i2c-isa-only exported symbol declarations Move the declaration of i2c-isa-only exported symbols to i2c-isa itself, that's the best way to ensure nobody will attempt to use them. Hopefully we'll get rid of the exports themselves soon anyway. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-isa.c | 4 ++++ include/linux/i2c.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 819e8991f27..b0e1370075d 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -41,6 +41,10 @@ #include #include +/* Exported by i2c-core for i2c-isa only */ +extern void i2c_adapter_dev_release(struct device *dev); +extern struct class i2c_adapter_class; + static u32 isa_func(struct i2c_adapter *adapter); /* This is the actual algorithm we define */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index da95ce79d07..3af7111c668 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -35,10 +35,6 @@ #include /* for completion */ #include -/* --- For i2c-isa ---------------------------------------------------- */ - -extern void i2c_adapter_dev_release(struct device *dev); -extern struct class i2c_adapter_class; extern struct bus_type i2c_bus_type; /* --- General options ------------------------------------------------ */ -- cgit v1.2.3 From b3e820968ad47219f7d559117a30e85cf96b4e4e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:32 +0200 Subject: i2c: Make i2c_del_driver a void function Make i2c_del_driver a void function, like all other driver removal functions. It always returned 0 even when errors occured, and nobody ever actually checked the return value anyway. And we cannot fail a module removal anyway. Signed-off-by: Jean Delvare --- Documentation/i2c/writing-clients | 5 +---- drivers/i2c/i2c-core.c | 12 +++--------- drivers/macintosh/therm_windtunnel.c | 3 ++- include/linux/i2c.h | 2 +- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index e62fbfa1282..f7e04ec849b 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -586,10 +586,7 @@ the driver module is usually enough. void foo_cleanup(void) { if (foo_initialized == 1) { - if ((res = i2c_del_driver(&foo_driver))) { - printk("foo: Driver registration failed, module not removed.\n"); - return; - } + i2c_del_driver(&foo_driver); foo_initialized --; } } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0fd4acbffb7..a58f89a6418 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -599,14 +599,12 @@ EXPORT_SYMBOL(i2c_register_driver); * i2c_del_driver - unregister I2C driver * @driver: the driver being unregistered */ -int i2c_del_driver(struct i2c_driver *driver) +void i2c_del_driver(struct i2c_driver *driver) { struct list_head *item1, *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; - int res = 0; - mutex_lock(&core_lists); /* new-style driver? */ @@ -620,11 +618,10 @@ int i2c_del_driver(struct i2c_driver *driver) list_for_each(item1,&adapters) { adap = list_entry(item1, struct i2c_adapter, list); if (driver->detach_adapter) { - if ((res = driver->detach_adapter(adap))) { + if (driver->detach_adapter(adap)) { dev_err(&adap->dev, "detach_adapter failed " "for driver [%s]\n", driver->driver.name); - goto out_unlock; } } else { list_for_each_safe(item2, _n, &adap->clients) { @@ -634,12 +631,11 @@ int i2c_del_driver(struct i2c_driver *driver) dev_dbg(&adap->dev, "detaching client [%s] " "at 0x%02x\n", client->name, client->addr); - if ((res = driver->detach_client(client))) { + if (driver->detach_client(client)) { dev_err(&adap->dev, "detach_client " "failed for client [%s] at " "0x%02x\n", client->name, client->addr); - goto out_unlock; } } } @@ -650,9 +646,7 @@ int i2c_del_driver(struct i2c_driver *driver) list_del(&driver->list); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - out_unlock: mutex_unlock(&core_lists); - return 0; } EXPORT_SYMBOL(i2c_del_driver); diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 35233de460a..3d0354e96a9 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -459,7 +459,8 @@ therm_of_probe( struct of_device *dev, const struct of_device_id *match ) static int therm_of_remove( struct of_device *dev ) { - return i2c_del_driver( &g4fan_driver ); + i2c_del_driver( &g4fan_driver ); + return 0; } static struct of_device_id therm_of_match[] = {{ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 3af7111c668..3fe2ad37da3 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -371,7 +371,7 @@ extern int i2c_del_adapter(struct i2c_adapter *); extern int i2c_add_numbered_adapter(struct i2c_adapter *); extern int i2c_register_driver(struct module *, struct i2c_driver *); -extern int i2c_del_driver(struct i2c_driver *); +extern void i2c_del_driver(struct i2c_driver *); static inline int i2c_add_driver(struct i2c_driver *driver) { -- cgit v1.2.3 From 6edac5803fb66f514d454d8e45595a170f04ea0e Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Tue, 1 May 2007 23:26:32 +0200 Subject: i2c-algo-sgi: Comment and whitespace cleanups Signed-off-by: Ladislav Michl Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-sgi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c index ac2d5053078..6eaf145e1ad 100644 --- a/drivers/i2c/algos/i2c-algo-sgi.c +++ b/drivers/i2c/algos/i2c-algo-sgi.c @@ -1,6 +1,7 @@ /* - * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters. - * + * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and + * MACE (SGI O2) chips. + * * This file is subject to the terms and conditions of the GNU General Public * License version 2 as published by the Free Software Foundation. * @@ -162,8 +163,8 @@ static const struct i2c_algorithm sgi_algo = { .functionality = sgi_func, }; -/* - * registering functions to load algorithms at runtime +/* + * registering functions to load algorithms at runtime */ int i2c_sgi_add_bus(struct i2c_adapter *adap) { -- cgit v1.2.3 From d24ecfcc3953f9c3b833508cd839be614a3f3c64 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Tue, 1 May 2007 23:26:32 +0200 Subject: i2c: Blackfin Two Wire Interface driver The i2c linux driver for blackfin architecture which supports blackfin on-chip TWI controller i2c operation. Signed-off-by: Bryan Wu Reviewed-by: Alexey Dobriyan Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Jean Delvare --- MAINTAINERS | 7 + drivers/i2c/busses/Kconfig | 16 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bfin-twi.c | 644 ++++++++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 3 +- 5 files changed, 670 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/busses/i2c-bfin-twi.c diff --git a/MAINTAINERS b/MAINTAINERS index af1c7926c15..2b378ab99fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -733,6 +733,13 @@ M: tigran@aivazian.fsnet.co.uk L: linux-kernel@vger.kernel.org S: Maintained +BLACKFIN I2C TWI DRIVER +P: Sonic Zhang +M: sonic.zhang@analog.com +L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) +W: http://blackfin.uclinux.org/ +S: Supported + BLOCK LAYER P: Jens Axboe M: axboe@kernel.dk diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d7e6cbb9cbe..62b9363dd40 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -91,6 +91,22 @@ config I2C_AU1550 This driver can also be built as a module. If so, the module will be called i2c-au1550. +config I2C_BLACKFIN_TWI + tristate "Blackfin TWI I2C support" + depends on I2C && (BF534 || BF536 || BF537) + help + This is the TWI I2C device driver for Blackfin 534/536/537. + This driver can also be built as a module. If so, the module + will be called i2c-bfin-twi. + +config I2C_BLACKFIN_TWI_CLK_KHZ + int "Blackfin TWI I2C clock (kHz)" + depends on I2C_BLACKFIN_TWI + range 10 400 + default 50 + help + The unit of the TWI clock is kHz. + config I2C_ELEKTOR tristate "Elektor ISA card" depends on I2C && ISA && BROKEN_ON_SMP diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 290b5401835..e51493cfbee 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o +obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c new file mode 100644 index 00000000000..6311039dfe6 --- /dev/null +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -0,0 +1,644 @@ +/* + * drivers/i2c/busses/i2c-bfin-twi.c + * + * Description: Driver for Blackfin Two Wire Interface + * + * Author: sonicz + * + * Copyright (c) 2005-2007 Analog Devices, Inc. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define POLL_TIMEOUT (2 * HZ) + +/* SMBus mode*/ +#define TWI_I2C_MODE_STANDARD 0x01 +#define TWI_I2C_MODE_STANDARDSUB 0x02 +#define TWI_I2C_MODE_COMBINED 0x04 + +struct bfin_twi_iface { + struct mutex twi_lock; + int irq; + spinlock_t lock; + char read_write; + u8 command; + u8 *transPtr; + int readNum; + int writeNum; + int cur_mode; + int manual_stop; + int result; + int timeout_count; + struct timer_list timeout_timer; + struct i2c_adapter adap; + struct completion complete; +}; + +static struct bfin_twi_iface twi_iface; + +static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) +{ + unsigned short twi_int_status = bfin_read_TWI_INT_STAT(); + unsigned short mast_stat = bfin_read_TWI_MASTER_STAT(); + + if (twi_int_status & XMTSERV) { + /* Transmit next data */ + if (iface->writeNum > 0) { + bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); + iface->writeNum--; + } + /* start receive immediately after complete sending in + * combine mode. + */ + else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() + | MDIR | RSTART); + } else if (iface->manual_stop) + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() + | STOP); + SSYNC(); + /* Clear status */ + bfin_write_TWI_INT_STAT(XMTSERV); + SSYNC(); + } + if (twi_int_status & RCVSERV) { + if (iface->readNum > 0) { + /* Receive next data */ + *(iface->transPtr) = bfin_read_TWI_RCV_DATA8(); + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + /* Change combine mode into sub mode after + * read first data. + */ + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + /* Get read number from first byte in block + * combine mode. + */ + if (iface->readNum == 1 && iface->manual_stop) + iface->readNum = *iface->transPtr + 1; + } + iface->transPtr++; + iface->readNum--; + } else if (iface->manual_stop) { + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() + | STOP); + SSYNC(); + } + /* Clear interrupt source */ + bfin_write_TWI_INT_STAT(RCVSERV); + SSYNC(); + } + if (twi_int_status & MERR) { + bfin_write_TWI_INT_STAT(MERR); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_STAT(0x3e); + bfin_write_TWI_MASTER_CTL(0); + SSYNC(); + iface->result = -1; + /* if both err and complete int stats are set, return proper + * results. + */ + if (twi_int_status & MCOMP) { + bfin_write_TWI_INT_STAT(MCOMP); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + SSYNC(); + /* If it is a quick transfer, only address bug no data, + * not an err, return 1. + */ + if (iface->writeNum == 0 && (mast_stat & BUFRDERR)) + iface->result = 1; + /* If address not acknowledged return -1, + * else return 0. + */ + else if (!(mast_stat & ANAK)) + iface->result = 0; + } + complete(&iface->complete); + return; + } + if (twi_int_status & MCOMP) { + bfin_write_TWI_INT_STAT(MCOMP); + SSYNC(); + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + if (iface->readNum == 0) { + /* set the read number to 1 and ask for manual + * stop in block combine mode + */ + iface->readNum = 1; + iface->manual_stop = 1; + bfin_write_TWI_MASTER_CTL( + bfin_read_TWI_MASTER_CTL() + | (0xff << 6)); + } else { + /* set the readd number in other + * combine mode. + */ + bfin_write_TWI_MASTER_CTL( + (bfin_read_TWI_MASTER_CTL() & + (~(0xff << 6))) | + ( iface->readNum << 6)); + } + /* remove restart bit and enable master receive */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() & + ~RSTART); + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | + MEN | MDIR); + SSYNC(); + } else { + iface->result = 1; + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + SSYNC(); + complete(&iface->complete); + } + } +} + +/* Interrupt handler */ +static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) +{ + struct bfin_twi_iface *iface = dev_id; + unsigned long flags; + + spin_lock_irqsave(&iface->lock, flags); + del_timer(&iface->timeout_timer); + bfin_twi_handle_interrupt(iface); + spin_unlock_irqrestore(&iface->lock, flags); + return IRQ_HANDLED; +} + +static void bfin_twi_timeout(unsigned long data) +{ + struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data; + unsigned long flags; + + spin_lock_irqsave(&iface->lock, flags); + bfin_twi_handle_interrupt(iface); + if (iface->result == 0) { + iface->timeout_count--; + if (iface->timeout_count > 0) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } else { + iface->result = -1; + complete(&iface->complete); + } + } + spin_unlock_irqrestore(&iface->lock, flags); +} + +/* + * Generic i2c master transfer entrypoint + */ +static int bfin_twi_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct bfin_twi_iface *iface = adap->algo_data; + struct i2c_msg *pmsg; + int i, ret; + int rc = 0; + + if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) + return -ENXIO; + + mutex_lock(&iface->twi_lock); + + while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { + mutex_unlock(&iface->twi_lock); + yield(); + mutex_lock(&iface->twi_lock); + } + + ret = 0; + for (i = 0; rc >= 0 && i < num; i++) { + pmsg = &msgs[i]; + if (pmsg->flags & I2C_M_TEN) { + dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr " + "not supported !\n"); + rc = -EINVAL; + break; + } + + iface->cur_mode = TWI_I2C_MODE_STANDARD; + iface->manual_stop = 0; + iface->transPtr = pmsg->buf; + iface->writeNum = iface->readNum = pmsg->len; + iface->result = 0; + iface->timeout_count = 10; + /* Set Transmit device address */ + bfin_write_TWI_MASTER_ADDR(pmsg->addr); + + /* FIFO Initiation. Data in FIFO should be + * discarded before start a new operation. + */ + bfin_write_TWI_FIFO_CTL(0x3); + SSYNC(); + bfin_write_TWI_FIFO_CTL(0); + SSYNC(); + + if (pmsg->flags & I2C_M_RD) + iface->read_write = I2C_SMBUS_READ; + else { + iface->read_write = I2C_SMBUS_WRITE; + /* Transmit first data */ + if (iface->writeNum > 0) { + bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); + iface->writeNum--; + SSYNC(); + } + } + + /* clear int stat */ + bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); + + /* Interrupt mask . Enable XMT, RCV interrupt */ + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((iface->read_write == I2C_SMBUS_READ)? + RCVSERV : XMTSERV)); + SSYNC(); + + if (pmsg->len > 0 && pmsg->len <= 255) + bfin_write_TWI_MASTER_CTL(pmsg->len << 6); + else if (pmsg->len > 255) { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } else + break; + + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); + SSYNC(); + + wait_for_completion(&iface->complete); + + rc = iface->result; + if (rc == 1) + ret++; + else if (rc == -1) + break; + } + + /* Release mutex */ + mutex_unlock(&iface->twi_lock); + + return ret; +} + +/* + * SMBus type transfer entrypoint + */ + +int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + struct bfin_twi_iface *iface = adap->algo_data; + int rc = 0; + + if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) + return -ENXIO; + + mutex_lock(&iface->twi_lock); + + while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { + mutex_unlock(&iface->twi_lock); + yield(); + mutex_lock(&iface->twi_lock); + } + + iface->writeNum = 0; + iface->readNum = 0; + + /* Prepare datas & select mode */ + switch (size) { + case I2C_SMBUS_QUICK: + iface->transPtr = NULL; + iface->cur_mode = TWI_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE: + if (data == NULL) + iface->transPtr = NULL; + else { + if (read_write == I2C_SMBUS_READ) + iface->readNum = 1; + else + iface->writeNum = 1; + iface->transPtr = &data->byte; + } + iface->cur_mode = TWI_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 1; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = 1; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = &data->byte; + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 2; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = 2; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->word; + break; + case I2C_SMBUS_PROC_CALL: + iface->writeNum = 2; + iface->readNum = 2; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + iface->transPtr = (u8 *)&data->word; + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 0; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0] + 1; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = data->block; + break; + default: + return -1; + } + + iface->result = 0; + iface->manual_stop = 0; + iface->read_write = read_write; + iface->command = command; + iface->timeout_count = 10; + + /* FIFO Initiation. Data in FIFO should be discarded before + * start a new operation. + */ + bfin_write_TWI_FIFO_CTL(0x3); + SSYNC(); + bfin_write_TWI_FIFO_CTL(0); + + /* clear int stat */ + bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); + + /* Set Transmit device address */ + bfin_write_TWI_MASTER_ADDR(addr); + SSYNC(); + + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + switch (iface->cur_mode) { + case TWI_I2C_MODE_STANDARDSUB: + bfin_write_TWI_XMT_DATA8(iface->command); + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((iface->read_write == I2C_SMBUS_READ) ? + RCVSERV : XMTSERV)); + SSYNC(); + + if (iface->writeNum + 1 <= 255) + bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6); + else { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); + break; + case TWI_I2C_MODE_COMBINED: + bfin_write_TWI_XMT_DATA8(iface->command); + bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV); + SSYNC(); + + if (iface->writeNum > 0) + bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6); + else + bfin_write_TWI_MASTER_CTL(0x1 << 6); + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); + break; + default: + bfin_write_TWI_MASTER_CTL(0); + if (size != I2C_SMBUS_QUICK) { + /* Don't access xmit data register when this is a + * read operation. + */ + if (iface->read_write != I2C_SMBUS_READ) { + if (iface->writeNum > 0) { + bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); + if (iface->writeNum <= 255) + bfin_write_TWI_MASTER_CTL(iface->writeNum << 6); + else { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } + iface->writeNum--; + } else { + bfin_write_TWI_XMT_DATA8(iface->command); + bfin_write_TWI_MASTER_CTL(1 << 6); + } + } else { + if (iface->readNum > 0 && iface->readNum <= 255) + bfin_write_TWI_MASTER_CTL(iface->readNum << 6); + else if (iface->readNum > 255) { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } else { + del_timer(&iface->timeout_timer); + break; + } + } + } + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((iface->read_write == I2C_SMBUS_READ) ? + RCVSERV : XMTSERV)); + SSYNC(); + + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); + break; + } + SSYNC(); + + wait_for_completion(&iface->complete); + + rc = (iface->result >= 0) ? 0 : -1; + + /* Release mutex */ + mutex_unlock(&iface->twi_lock); + + return rc; +} + +/* + * Return what the adapter supports + */ +static u32 bfin_twi_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_I2C; +} + + +static struct i2c_algorithm bfin_twi_algorithm = { + .master_xfer = bfin_twi_master_xfer, + .smbus_xfer = bfin_twi_smbus_xfer, + .functionality = bfin_twi_functionality, +}; + + +static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state) +{ +/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/ + + /* Disable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA); + SSYNC(); + + return 0; +} + +static int i2c_bfin_twi_resume(struct platform_device *dev) +{ +/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/ + + /* Enable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); + SSYNC(); + + return 0; +} + +static int i2c_bfin_twi_probe(struct platform_device *dev) +{ + struct bfin_twi_iface *iface = &twi_iface; + struct i2c_adapter *p_adap; + int rc; + + mutex_init(&(iface->twi_lock)); + spin_lock_init(&(iface->lock)); + init_completion(&(iface->complete)); + iface->irq = IRQ_TWI; + + init_timer(&(iface->timeout_timer)); + iface->timeout_timer.function = bfin_twi_timeout; + iface->timeout_timer.data = (unsigned long)iface; + + p_adap = &iface->adap; + p_adap->id = I2C_HW_BLACKFIN; + strlcpy(p_adap->name, dev->name, sizeof(p_adap->name)); + p_adap->algo = &bfin_twi_algorithm; + p_adap->algo_data = iface; + p_adap->class = I2C_CLASS_ALL; + p_adap->dev.parent = &dev->dev; + + rc = request_irq(iface->irq, bfin_twi_interrupt_entry, + IRQF_DISABLED, dev->name, iface); + if (rc) { + dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n", + iface->irq); + return -ENODEV; + } + + /* Set TWI internal clock as 10MHz */ + bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + + /* Set Twi interface clock as specified */ + bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ ) + << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ ) + & 0xFF)); + + /* Enable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); + SSYNC(); + + rc = i2c_add_adapter(p_adap); + if (rc < 0) + free_irq(iface->irq, iface); + else + platform_set_drvdata(dev, iface); + + return rc; +} + +static int i2c_bfin_twi_remove(struct platform_device *pdev) +{ + struct bfin_twi_iface *iface = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + i2c_del_adapter(&(iface->adap)); + free_irq(iface->irq, iface); + + return 0; +} + +static struct platform_driver i2c_bfin_twi_driver = { + .probe = i2c_bfin_twi_probe, + .remove = i2c_bfin_twi_remove, + .suspend = i2c_bfin_twi_suspend, + .resume = i2c_bfin_twi_resume, + .driver = { + .name = "i2c-bfin-twi", + .owner = THIS_MODULE, + }, +}; + +static int __init i2c_bfin_twi_init(void) +{ + pr_info("I2C: Blackfin I2C TWI driver\n"); + + return platform_driver_register(&i2c_bfin_twi_driver); +} + +static void __exit i2c_bfin_twi_exit(void) +{ + platform_driver_unregister(&i2c_bfin_twi_driver); +} + +MODULE_AUTHOR("Sonic Zhang "); +MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI"); +MODULE_LICENSE("GPL"); + +module_init(i2c_bfin_twi_init); +module_exit(i2c_bfin_twi_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 9c21dc793d7..0e8da684ce6 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -258,8 +258,9 @@ /* --- MCP107 adapter */ #define I2C_HW_MPC107 0x0d0000 -/* --- Marvell mv64xxx i2c adapter */ +/* --- Embedded adapters */ #define I2C_HW_MV64XXX 0x190000 +#define I2C_HW_BLACKFIN 0x190001 /* ADI Blackfin I2C TWI driver */ /* --- Miscellaneous adapters */ #define I2C_HW_SAA7146 0x060000 /* SAA7146 video decoder bus */ -- cgit v1.2.3 From 7c175499822ba34ba60f32e4995fcc16c007d308 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 1 May 2007 23:26:32 +0200 Subject: i2c-omap: Switch to static adapter numbering Update the OMAP I2C driver to use i2c_add_numbered_adapter(), so that later patches can convert boards to using new-style drivers. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-omap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index bcd8367cede..e471e3bfdc1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -605,7 +605,8 @@ omap_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; /* i2c device drivers may be active on return from add_adapter() */ - r = i2c_add_adapter(adap); + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); goto err_free_irq; -- cgit v1.2.3 From 424ed67c7dae37e8115e1bebc3261e86a624dff2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:33 +0200 Subject: i2c-algo-bit: Implement a 50/50 SCL duty cycle The original i2c-algo-bit implementation uses a 33/66 SCL duty cycle when bits are being written on the bus. While the I2C specification doesn't forbid it, this prevents us from driving the I2C bus to its max speed, limiting us to 66 kbps max on standard I2C busses. Implementing a 50/50 duty cycle instead lets us max out the bandwidth up to the theoretical max of 100 kbps on standard I2C busses. This is particularly important when large amounts of data need to be transfered over the bus, as is the case with some TV adapters when the firmware is being uploaded. In fact this change even allows, at least in theory, fast-mode I2C support at 125, 166 and 250 kbps. There's no way to reach the theoretical max of 400 kbps with this implementation. But I don't think we want to put efforts in that direction anyway: software-driven I2C is very CPU-intensive and bad for latency. Other timing changes: * Don't set SDA high explicitly on error, we're going to issue a stop condition before we leave anyway. * If an error occurs when sending the slave address, yield the CPU before retrying, and remove the additional delay after the new start condition. Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 42 +++++++++++++++++++++------------------- include/linux/i2c-algo-bit.h | 6 ++++-- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index fc16f9d268a..d9d0ec49e60 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -57,19 +57,19 @@ static int bit_test; /* see if the line-setting functions work */ static inline void sdalo(struct i2c_algo_bit_data *adap) { setsda(adap,0); - udelay(adap->udelay); + udelay((adap->udelay + 1) / 2); } static inline void sdahi(struct i2c_algo_bit_data *adap) { setsda(adap,1); - udelay(adap->udelay); + udelay((adap->udelay + 1) / 2); } static inline void scllo(struct i2c_algo_bit_data *adap) { setscl(adap,0); - udelay(adap->udelay); + udelay(adap->udelay / 2); } /* @@ -111,18 +111,19 @@ static void i2c_start(struct i2c_algo_bit_data *adap) { /* assert: scl, sda are high */ DEBPROTO(printk("S ")); - sdalo(adap); + setsda(adap, 0); + udelay(adap->udelay); scllo(adap); } static void i2c_repstart(struct i2c_algo_bit_data *adap) { - /* scl, sda may not be high */ + /* assert: scl is low */ DEBPROTO(printk(" Sr ")); - setsda(adap,1); + sdahi(adap); sclhi(adap); - - sdalo(adap); + setsda(adap, 0); + udelay(adap->udelay); scllo(adap); } @@ -133,7 +134,8 @@ static void i2c_stop(struct i2c_algo_bit_data *adap) /* assert: scl is low */ sdalo(adap); sclhi(adap); - sdahi(adap); + setsda(adap, 1); + udelay(adap->udelay); } @@ -156,18 +158,16 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c) for ( i=7 ; i>=0 ; i-- ) { sb = c & ( 1 << i ); setsda(adap,sb); - udelay(adap->udelay); + udelay((adap->udelay + 1) / 2); DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); if (sclhi(adap)<0) { /* timed out */ - sdahi(adap); /* we don't want to block the net */ DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i)); return -ETIMEDOUT; }; /* do arbitration here: * if ( sb && ! getsda(adap) ) -> ouch! Get out of here. */ - setscl(adap, 0 ); - udelay(adap->udelay); + scllo(adap); } sdahi(adap); if (sclhi(adap)<0){ /* timeout */ @@ -204,7 +204,8 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) indata *= 2; if ( getsda(adap) ) indata |= 0x01; - scllo(adap); + setscl(adap, 0); + udelay(i == 7 ? adap->udelay / 2 : adap->udelay); } /* assert: scl is low */ DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); @@ -315,9 +316,9 @@ static int try_address(struct i2c_adapter *i2c_adap, if (ret == 1 || i == retries) break; i2c_stop(adap); - udelay(5/*adap->udelay*/); - i2c_start(adap); udelay(adap->udelay); + yield(); + i2c_start(adap); } DEB2(if (i) printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", @@ -377,20 +378,21 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) if (msg->flags & I2C_M_NO_RD_ACK) continue; + /* assert: sda is high */ if ( count > 0 ) { /* send ack */ - sdalo(adap); + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); DEBPROTO(printk(" Am ")); } else { - sdahi(adap); /* neg. ack on last byte */ + /* neg. ack on last byte */ + udelay((adap->udelay + 1) / 2); DEBPROTO(printk(" NAm ")); } if (sclhi(adap)<0) { /* timeout */ - sdahi(adap); printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); return -ETIMEDOUT; }; scllo(adap); - sdahi(adap); /* Some SMBus transactions require that we receive the transaction length as the first read byte. */ diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index d91dab88635..9ee0f800592 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -38,8 +38,10 @@ struct i2c_algo_bit_data { int (*getscl) (void *data); /* local settings */ - int udelay; /* half-clock-cycle time in microsecs */ - /* i.e. clock is (500 / udelay) KHz */ + int udelay; /* half clock cycle time in us, + minimum 2 us for fast-mode I2C, + minimum 5 us for standard-mode I2C and SMBus, + maximum 50 us for SMBus */ int timeout; /* in jiffies */ }; -- cgit v1.2.3 From 494dbb64dc5b369cc28542f4c4d634e57b0d7f18 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:33 +0200 Subject: i2c-algo-bit: Improve debugging Improve the debugging features of the i2c-algo-bit driver: * Make it possible to compile the driver without debugging support at all, making it much smaller. * Use dev_dbg() for debugging messages where possible, and dev_err() for error messages. * Remove redundant debugging messages. These changes allowed for minor code cleanups, which are included as well. Signed-off-by: Jean Delvare --- drivers/i2c/algos/i2c-algo-bit.c | 185 ++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 90 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index d9d0ec49e60..8a5f5825bb7 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -33,19 +33,30 @@ /* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x; -#define DEB2(x) if (i2c_debug>=2) x; -#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/ -#define DEBPROTO(x) if (i2c_debug>=9) { x; } - /* debug the protocol by showing transferred bits */ +#ifdef DEBUG +#define bit_dbg(level, dev, format, args...) \ + do { \ + if (i2c_debug >= level) \ + dev_dbg(dev, format, ##args); \ + } while (0) +#else +#define bit_dbg(level, dev, format, args...) \ + do {} while (0) +#endif /* DEBUG */ /* ----- global variables --------------------------------------------- */ -/* module parameters: - */ -static int i2c_debug; static int bit_test; /* see if the line-setting functions work */ +module_param(bit_test, bool, 0); +MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); + +#ifdef DEBUG +static int i2c_debug = 1; +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); +#endif /* --- setting states on the bus with the right timing: --------------- */ @@ -98,7 +109,11 @@ static int sclhi(struct i2c_algo_bit_data *adap) } cond_resched(); } - DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); +#ifdef DEBUG + if (jiffies != start && i2c_debug >= 3) + pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " + "high\n", jiffies - start); +#endif done: udelay(adap->udelay); @@ -110,7 +125,6 @@ done: static void i2c_start(struct i2c_algo_bit_data *adap) { /* assert: scl, sda are high */ - DEBPROTO(printk("S ")); setsda(adap, 0); udelay(adap->udelay); scllo(adap); @@ -119,7 +133,6 @@ static void i2c_start(struct i2c_algo_bit_data *adap) static void i2c_repstart(struct i2c_algo_bit_data *adap) { /* assert: scl is low */ - DEBPROTO(printk(" Sr ")); sdahi(adap); sclhi(adap); setsda(adap, 0); @@ -130,7 +143,6 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap) static void i2c_stop(struct i2c_algo_bit_data *adap) { - DEBPROTO(printk("P\n")); /* assert: scl is low */ sdalo(adap); sclhi(adap); @@ -147,7 +159,7 @@ static void i2c_stop(struct i2c_algo_bit_data *adap) * 0 if the device did not ack * -ETIMEDOUT if an error occurred (while raising the scl line) */ -static int i2c_outb(struct i2c_adapter *i2c_adap, char c) +static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) { int i; int sb; @@ -156,12 +168,12 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c) /* assert: scl is low */ for ( i=7 ; i>=0 ; i-- ) { - sb = c & ( 1 << i ); + sb = (c >> i) & 1; setsda(adap,sb); udelay((adap->udelay + 1) / 2); - DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); if (sclhi(adap)<0) { /* timed out */ - DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i)); + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at bit #%d\n", (int)c, i); return -ETIMEDOUT; }; /* do arbitration here: @@ -171,17 +183,17 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c) } sdahi(adap); if (sclhi(adap)<0){ /* timeout */ - DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff)); - return -ETIMEDOUT; + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at ack\n", (int)c); + return -ETIMEDOUT; }; /* read ack: SDA should be pulled down by slave */ - ack=getsda(adap); /* ack: sda is pulled low ->success. */ - DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack)); + ack = !getsda(adap); /* ack: sda is pulled low -> success */ + bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, + ack ? "A" : "NA"); - DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) ); - DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") ); scllo(adap); - return 0==ack; /* return 1 if device acked */ + return ack; /* assert: scl is low (sda undef) */ } @@ -198,7 +210,8 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) sdahi(adap); for (i=0;i<8;i++) { if (sclhi(adap)<0) { /* timeout */ - DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i)); + bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " + "#%d\n", 7 - i); return -ETIMEDOUT; }; indata *= 2; @@ -208,10 +221,7 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) udelay(i == 7 ? adap->udelay / 2 : adap->udelay); } /* assert: scl is low */ - DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); - - DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff)); - return (int) (indata & 0xff); + return indata; } /* @@ -222,73 +232,67 @@ static int test_bus(struct i2c_algo_bit_data *adap, char* name) { int scl,sda; if (adap->getscl==NULL) - printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, " - "SCL is not readable.\n"); + pr_info("%s: Testing SDA only, SCL is not readable\n", name); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda); if (!scl || !sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name); + printk(KERN_WARNING "%s: bus seems to be busy\n", name); goto bailout; } sdalo(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda); if ( 0 != sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n"); + printk(KERN_WARNING "%s: SDA stuck high!\n", name); goto bailout; } if ( 0 == scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " - "while pulling SDA low!\n"); + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA low!\n", name); goto bailout; } sdahi(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda); if ( 0 == sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n"); + printk(KERN_WARNING "%s: SDA stuck low!\n", name); goto bailout; } if ( 0 == scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " - "while pulling SDA high!\n"); + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA high!\n", name); goto bailout; } scllo(adap); sda=getsda(adap); scl=(adap->getscl==NULL?0:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda); if ( 0 != scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n"); + printk(KERN_WARNING "%s: SCL stuck high!\n", name); goto bailout; } if ( 0 == sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " - "while pulling SCL low!\n"); + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL low!\n", name); goto bailout; } sclhi(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda); if ( 0 == scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n"); + printk(KERN_WARNING "%s: SCL stuck low!\n", name); goto bailout; } if ( 0 == sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " - "while pulling SCL high!\n"); + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL high!\n", name); goto bailout; } - printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name); + pr_info("%s: Test OK\n", name); return 0; bailout: sdahi(adap); @@ -315,32 +319,31 @@ static int try_address(struct i2c_adapter *i2c_adap, ret = i2c_outb(i2c_adap,addr); if (ret == 1 || i == retries) break; + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); udelay(adap->udelay); yield(); + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); } - DEB2(if (i) - printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", - i+1, addr & 1 ? "read" : "write", addr>>1, - ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" ) - ); + if (i && ret) + bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " + "0x%02x: %s\n", i + 1, + addr & 1 ? "read from" : "write to", addr >> 1, + ret == 1 ? "success" : "failed, timeout?"); return ret; } static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { - char c; - const char *temp = msg->buf; + const unsigned char *temp = msg->buf; int count = msg->len; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; int wrcount=0; while (count > 0) { - c = *temp; - DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff)); - retval = i2c_outb(i2c_adap,c); + retval = i2c_outb(i2c_adap, *temp); if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; @@ -359,7 +362,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) int inval; int rdcount=0; /* counts bytes read */ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; - char *temp = msg->buf; + unsigned char *temp = msg->buf; int count = msg->len; while (count > 0) { @@ -368,28 +371,26 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) *temp = inval; rdcount++; } else { /* read timed out */ - printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n"); break; } temp++; count--; - if (msg->flags & I2C_M_NO_RD_ACK) + if (msg->flags & I2C_M_NO_RD_ACK) { + bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n", + inval); continue; + } /* assert: sda is high */ - if ( count > 0 ) { /* send ack */ + if (count) /* send ack */ setsda(adap, 0); - udelay((adap->udelay + 1) / 2); - DEBPROTO(printk(" Am ")); - } else { - /* neg. ack on last byte */ - udelay((adap->udelay + 1) / 2); - DEBPROTO(printk(" NAm ")); - } + udelay((adap->udelay + 1) / 2); + bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval, + count ? "A" : "NA"); if (sclhi(adap)<0) { /* timeout */ - printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); + dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n"); return -ETIMEDOUT; }; scllo(adap); @@ -398,8 +399,8 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) transaction length as the first read byte. */ if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) { if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { - printk(KERN_ERR "i2c-algo-bit: readbytes: " - "invalid block length (%d)\n", inval); + dev_err(&i2c_adap->dev, "readbytes: invalid " + "block length (%d)\n", inval); return -EREMOTEIO; } /* The original count value accounts for the extra @@ -434,27 +435,31 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); + bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); if ((ret != 1) && !nak_ok) { - printk(KERN_ERR "died at extended address code.\n"); + dev_err(&i2c_adap->dev, + "died at extended address code\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ ret = i2c_outb(i2c_adap,msg->addr & 0x7f); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ - printk(KERN_ERR "died at 2nd address code.\n"); + dev_err(&i2c_adap->dev, "died at 2nd address code\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { + bit_dbg(3, &i2c_adap->dev, "emitting repeated " + "start condition\n"); i2c_repstart(adap); /* okay, now switch into reading mode */ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) { - printk(KERN_ERR "died at extended address code.\n"); + dev_err(&i2c_adap->dev, + "died at repeated address code\n"); return -EREMOTEIO; } } @@ -481,25 +486,31 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, int i,ret; unsigned short nak_ok; + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); for (i=0;iflags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { if (i) { + bit_dbg(3, &i2c_adap->dev, "emitting " + "repeated start condition\n"); i2c_repstart(adap); } ret = bit_doAddress(i2c_adap, pmsg); if ((ret != 0) && !nak_ok) { - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n" - ,msgs[i].addr,i)); + bit_dbg(1, &i2c_adap->dev, "NAK from " + "device addr 0x%02x msg #%d\n", + msgs[i].addr, i); goto bailout; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", + ret, ret == 1 ? "" : "s"); if (ret < pmsg->len) { if (ret >= 0) ret = -EREMOTEIO; @@ -508,7 +519,9 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, } else { /* write bytes from buffer */ ret = sendbytes(i2c_adap, pmsg); - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", + ret, ret == 1 ? "" : "s"); if (ret < pmsg->len) { if (ret >= 0) ret = -EREMOTEIO; @@ -519,6 +532,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, ret = i; bailout: + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); return ret; } @@ -552,8 +566,6 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap) return -ENODEV; } - DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); - /* register new adapter to i2c module... */ adap->algo = &i2c_bit_algo; @@ -590,10 +602,3 @@ EXPORT_SYMBOL(i2c_bit_add_numbered_bus); MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); MODULE_LICENSE("GPL"); - -module_param(bit_test, bool, 0); -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); - -MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); -- cgit v1.2.3 From 7d054817b780e664bed6701b2aa637718e1905b7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:33 +0200 Subject: i2c-pxa: Clean transaction stop It was reported to me that the i2c-pxa driver was not able to process more that 50 transactions per second. Investigation revealed that the I2C unit was busy for 20 ms after every transaction. The reason seems to be that we forget to clear the STOP and ACKNACK bits at the end of the transaction. According to the PXA27x developer's manual, we shall do so. Signed-off-by: Jean Delvare Cc: Lennert Buytenhek Cc: Nicolas Pitre --- drivers/i2c/busses/i2c-pxa.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 14e83d0aac8..2fc3bcec24d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -539,6 +539,18 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) writel(icr | ICR_START | ICR_TB, _ICR(i2c)); } +static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) +{ + u32 icr; + + /* + * Clear the STOP and ACK flags + */ + icr = readl(_ICR(i2c)); + icr &= ~(ICR_STOP | ICR_ACKNAK); + writel(icr, _IRC(i2c)); +} + /* * We are protected by the adapter bus mutex. */ @@ -581,6 +593,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) * The rest of the processing occurs in the interrupt handler. */ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + i2c_pxa_stop_message(i2c); /* * We place the return code in i2c->msg_idx. -- cgit v1.2.3 From b86a1bc8e39641d0c4676943b77a3486ee296db8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:34 +0200 Subject: i2c: Restore i2c_smbus_read_block_data Add back the i2c_smbus_read_block_data helper function, it is needed by the upcoming lm93 hardware monitoring driver and possibly others. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 16 ++++++++++++++++ include/linux/i2c.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a58f89a6418..64f8e56d300 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1298,6 +1298,22 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) } EXPORT_SYMBOL(i2c_smbus_write_word_data); +/* Returns the number of read bytes */ +s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, + u8 *values) +{ + union i2c_smbus_data data; + + if (i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_DATA, &data)) + return -1; + + memcpy(values, &data.block[1], data.block[0]); + return data.block[0]; +} +EXPORT_SYMBOL(i2c_smbus_read_block_data); + s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 3fe2ad37da3..cae7d618030 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -82,6 +82,9 @@ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command); extern s32 i2c_smbus_write_word_data(struct i2c_client * client, u8 command, u16 value); +/* Returns the number of read bytes */ +extern s32 i2c_smbus_read_block_data(struct i2c_client *client, + u8 command, u8 *values); extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, const u8 *values); -- cgit v1.2.3 From 16538e6b32600f76ad212d42fc2b1f801e32ab4b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 1 May 2007 23:26:34 +0200 Subject: Use menuconfig objects - I2C Allow the whole I2C menu to be disabled at once without diving into the submenus for deselecting all options (should the user desire so). Signed-off-by: Jan Engelhardt Signed-off-by: Jean Delvare --- drivers/i2c/Kconfig | 15 ++------ drivers/i2c/algos/Kconfig | 8 +--- drivers/i2c/busses/Kconfig | 91 ++++++++++++++++++++++------------------------ drivers/i2c/chips/Kconfig | 21 +++++------ 4 files changed, 60 insertions(+), 75 deletions(-) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 74c8518b69e..434a61b415a 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -2,9 +2,7 @@ # I2C subsystem configuration # -menu "I2C support" - -config I2C +menuconfig I2C tristate "I2C support" ---help--- I2C (pronounce: I-square-C) is a slow serial bus protocol used in @@ -22,14 +20,14 @@ config I2C This I2C support can also be built as a module. If so, the module will be called i2c-core. +if I2C + config I2C_BOARDINFO boolean - depends on I2C default y config I2C_CHARDEV tristate "I2C device interface" - depends on I2C help Say Y here to use i2c-* device files, usually found in the /dev directory on your system. They make it possible to have user-space @@ -45,7 +43,6 @@ source drivers/i2c/chips/Kconfig config I2C_DEBUG_CORE bool "I2C Core debugging messages" - depends on I2C help Say Y here if you want the I2C core to produce a bunch of debug messages to the system log. Select this if you are having a @@ -53,7 +50,6 @@ config I2C_DEBUG_CORE config I2C_DEBUG_ALGO bool "I2C Algorithm debugging messages" - depends on I2C help Say Y here if you want the I2C algorithm drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -62,7 +58,6 @@ config I2C_DEBUG_ALGO config I2C_DEBUG_BUS bool "I2C Bus debugging messages" - depends on I2C help Say Y here if you want the I2C bus drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -71,12 +66,10 @@ config I2C_DEBUG_BUS config I2C_DEBUG_CHIP bool "I2C Chip debugging messages" - depends on I2C help Say Y here if you want the I2C chip drivers to produce a bunch of debug messages to the system log. Select this if you are having a problem with I2C support and want to see more of what is going on. -endmenu - +endif # I2C diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index af0203409dd..58899078810 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -3,11 +3,9 @@ # menu "I2C Algorithms" - depends on I2C config I2C_ALGOBIT tristate "I2C bit-banging interfaces" - depends on I2C help This allows you to use a range of I2C adapters called bit-banging adapters. Say Y if you own an I2C adapter belonging to this class @@ -18,7 +16,6 @@ config I2C_ALGOBIT config I2C_ALGOPCF tristate "I2C PCF 8584 interfaces" - depends on I2C help This allows you to use a range of I2C adapters called PCF adapters. Say Y if you own an I2C adapter belonging to this class and then say @@ -29,7 +26,6 @@ config I2C_ALGOPCF config I2C_ALGOPCA tristate "I2C PCA 9564 interfaces" - depends on I2C help This allows you to use a range of I2C adapters called PCA adapters. Say Y if you own an I2C adapter belonging to this class and then say @@ -40,11 +36,11 @@ config I2C_ALGOPCA config I2C_ALGO8XX tristate "MPC8xx CPM I2C interface" - depends on 8xx && I2C + depends on 8xx config I2C_ALGO_SGI tristate "I2C SGI interfaces" - depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS) + depends on SGI_IP22 || SGI_IP32 || X86_VISWS help Supports the SGI interfaces like the ones found on SGI Indy VINO or SGI O2 MACE. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 62b9363dd40..8ccf6e4e91d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -3,11 +3,10 @@ # menu "I2C Hardware Bus support" - depends on I2C config I2C_ALI1535 tristate "ALI 1535" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -19,7 +18,7 @@ config I2C_ALI1535 config I2C_ALI1563 tristate "ALI 1563" - depends on I2C && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB @@ -31,7 +30,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -41,7 +40,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -66,7 +65,7 @@ config I2C_AMD756_S4882 config I2C_AMD8111 tristate "AMD 8111" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -76,14 +75,14 @@ config I2C_AMD8111 config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on I2C && ARCH_AT91 && EXPERIMENTAL + depends on ARCH_AT91 && EXPERIMENTAL help This supports the use of the I2C interface on Atmel AT91 processors. config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" - depends on I2C && (SOC_AU1550 || SOC_AU1200) + depends on SOC_AU1550 || SOC_AU1200 help If you say yes to this option, support will be included for the Au1550 and Au1200 SMBus interface. @@ -93,7 +92,7 @@ config I2C_AU1550 config I2C_BLACKFIN_TWI tristate "Blackfin TWI I2C support" - depends on I2C && (BF534 || BF536 || BF537) + depends on BF534 || BF536 || BF537 help This is the TWI I2C device driver for Blackfin 534/536/537. This driver can also be built as a module. If so, the module @@ -109,7 +108,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ config I2C_ELEKTOR tristate "Elektor ISA card" - depends on I2C && ISA && BROKEN_ON_SMP + depends on ISA && BROKEN_ON_SMP select I2C_ALGOPCF help This supports the PCF8584 ISA bus I2C adapter. Say Y if you own @@ -120,7 +119,7 @@ config I2C_ELEKTOR config I2C_HYDRA tristate "CHRP Apple Hydra Mac I/O I2C interface" - depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL + depends on PCI && PPC_CHRP && EXPERIMENTAL select I2C_ALGOBIT help This supports the use of the I2C interface in the Apple Hydra Mac @@ -132,7 +131,7 @@ config I2C_HYDRA config I2C_I801 tristate "Intel 82801 (ICH)" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -155,7 +154,7 @@ config I2C_I801 config I2C_I810 tristate "Intel 810/815" - depends on I2C && PCI + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the Intel @@ -172,7 +171,7 @@ config I2C_I810 config I2C_PXA tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)" - depends on I2C && EXPERIMENTAL && ARCH_PXA + depends on 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 @@ -188,7 +187,7 @@ config I2C_PXA_SLAVE config I2C_PIIX4 tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Intel PIIX4 family of mainboard I2C interfaces. Specifically, the following @@ -211,7 +210,7 @@ config I2C_PIIX4 config I2C_IBM_IIC tristate "IBM PPC 4xx on-chip I2C interface" - depends on IBM_OCP && I2C + depends on IBM_OCP help Say Y here if you want to use IIC peripheral found on embedded IBM PPC 4xx based systems. @@ -221,7 +220,7 @@ config I2C_IBM_IIC config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C + depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX help Say Y here if you want to use the IIC bus controller on the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. @@ -231,11 +230,10 @@ config I2C_IOP3XX config I2C_ISA tristate - depends on I2C config I2C_IXP4XX tristate "IXP4xx GPIO-Based I2C Interface" - depends on I2C && ARCH_IXP4XX + depends on ARCH_IXP4XX select I2C_ALGOBIT help Say Y here if you have an Intel IXP4xx(420,421,422,425) based @@ -246,7 +244,7 @@ config I2C_IXP4XX config I2C_IXP2000 tristate "IXP2000 GPIO-Based I2C Interface" - depends on I2C && ARCH_IXP2000 + depends on ARCH_IXP2000 select I2C_ALGOBIT help Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based @@ -257,7 +255,7 @@ config I2C_IXP2000 config I2C_POWERMAC tristate "Powermac I2C interface" - depends on I2C && PPC_PMAC + depends on PPC_PMAC default y help This exposes the various PowerMac i2c interfaces to the linux i2c @@ -269,7 +267,7 @@ config I2C_POWERMAC config I2C_MPC tristate "MPC107/824x/85xx/52xx/86xx" - depends on I2C && PPC32 + depends on PPC32 help If you say yes to this option, support will be included for the built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and @@ -281,7 +279,7 @@ config I2C_MPC config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Nvidia nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. @@ -291,7 +289,7 @@ config I2C_NFORCE2 config I2C_OCORES tristate "OpenCores I2C Controller" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes to this option, support will be included for the OpenCores I2C controller. For details see @@ -302,7 +300,7 @@ config I2C_OCORES config I2C_OMAP tristate "OMAP I2C adapter" - depends on I2C && ARCH_OMAP + depends on ARCH_OMAP default y if MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes to this option, support will be included for the @@ -312,7 +310,7 @@ config I2C_OMAP config I2C_PARPORT tristate "Parallel port adapter" - depends on I2C && PARPORT + depends on PARPORT select I2C_ALGOBIT help This supports parallel port I2C adapters such as the ones made by @@ -336,7 +334,6 @@ config I2C_PARPORT config I2C_PARPORT_LIGHT tristate "Parallel port adapter (light)" - depends on I2C select I2C_ALGOBIT help This supports parallel port I2C adapters such as the ones made by @@ -360,13 +357,13 @@ config I2C_PARPORT_LIGHT config I2C_PASEMI tristate "PA Semi SMBus interface" - depends on PPC_PASEMI && I2C && PCI + depends on PPC_PASEMI && PCI help Supports the PA Semi PWRficient on-chip SMBus interfaces. config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" - depends on I2C && PCI + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -381,19 +378,19 @@ config I2C_PROSAVAGE config I2C_RPXLITE tristate "Embedded Planet RPX Lite/Classic support" - depends on (RPXLITE || RPXCLASSIC) && I2C + depends on RPXLITE || RPXCLASSIC select I2C_ALGO8XX config I2C_S3C2410 tristate "S3C2410 I2C Driver" - depends on I2C && ARCH_S3C2410 + depends on ARCH_S3C2410 help Say Y here to include support for I2C controller in the Samsung S3C2410 based System-on-Chip devices. config I2C_SAVAGE4 tristate "S3 Savage 4" - depends on I2C && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -404,13 +401,13 @@ config I2C_SAVAGE4 config I2C_SIBYTE tristate "SiByte SMBus interface" - depends on SIBYTE_SB1xxx_SOC && I2C + depends on SIBYTE_SB1xxx_SOC help Supports the SiByte SOC on-chip I2C interfaces (2 channels). config SCx200_I2C tristate "NatSemi SCx200 I2C using GPIO pins" - depends on SCx200_GPIO && I2C + depends on SCx200_GPIO select I2C_ALGOBIT help Enable the use of two GPIO pins of a SCx200 processor as an I2C bus. @@ -438,7 +435,7 @@ config SCx200_I2C_SDA config SCx200_ACB tristate "Geode ACCESS.bus support" - depends on X86_32 && I2C && PCI + depends on X86_32 && PCI help Enable the use of the ACCESS.bus controllers on the Geode SCx200 and SC1100 processors and the CS5535 and CS5536 Geode companion devices. @@ -450,7 +447,7 @@ config SCx200_ACB config I2C_SIS5595 tristate "SiS 5595" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -460,7 +457,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SiS630 and SiS730 SMBus (a subset of I2C) interface. @@ -470,7 +467,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -488,7 +485,7 @@ config I2C_SIS96X config I2C_STUB tristate "I2C/SMBus Test Stub" - depends on I2C && EXPERIMENTAL && 'm' + depends on EXPERIMENTAL && m default 'n' help This module may be useful to developers of SMBus client drivers, @@ -501,7 +498,7 @@ config I2C_STUB config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW) + depends on ARCH_VERSATILE || ARCH_REALVIEW select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile @@ -512,7 +509,7 @@ config I2C_VERSATILE config I2C_ACORN bool "Acorn IOC/IOMD I2C bus support" - depends on I2C && ARCH_ACORN + depends on ARCH_ACORN default y select I2C_ALGOBIT help @@ -522,7 +519,7 @@ config I2C_ACORN config I2C_VIA tristate "VIA 82C586B" - depends on I2C && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL select I2C_ALGOBIT help If you say yes to this option, support will be included for the VIA @@ -533,7 +530,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA VT82C596/82C686/82xx and CX700" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the VIA VT82C596 and later SMBus interface. Specifically, the following @@ -552,7 +549,7 @@ config I2C_VIAPRO config I2C_VOODOO3 tristate "Voodoo 3" - depends on I2C && PCI + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -563,7 +560,7 @@ config I2C_VOODOO3 config I2C_PCA_ISA tristate "PCA9564 on an ISA bus" - depends on I2C && ISA + depends on ISA select I2C_ALGOPCA default n help @@ -580,7 +577,7 @@ config I2C_PCA_ISA config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on I2C && MV64X60 && EXPERIMENTAL + depends on MV64X60 && EXPERIMENTAL help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. @@ -590,7 +587,7 @@ config I2C_MV64XXX config I2C_PNX tristate "I2C bus support for Philips PNX targets" - depends on ARCH_PNX4008 && I2C + depends on ARCH_PNX4008 help This driver supports the Philips IP3204 I2C IP block master and/or slave controller diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 87ee3ce5861..ea085a006ea 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -3,11 +3,10 @@ # menu "Miscellaneous I2C Chip support" - depends on I2C config SENSORS_DS1337 tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor DS1337 and DS1339 real-time clock chips. @@ -17,7 +16,7 @@ config SENSORS_DS1337 config SENSORS_DS1374 tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor DS1374 real-time clock chips. @@ -27,7 +26,7 @@ config SENSORS_DS1374 config SENSORS_EEPROM tristate "EEPROM reader" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL 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 @@ -38,7 +37,7 @@ config SENSORS_EEPROM config SENSORS_PCF8574 tristate "Philips PCF8574 and PCF8574A" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL default n help If you say yes here you get support for Philips PCF8574 and @@ -52,7 +51,7 @@ config SENSORS_PCF8574 config SENSORS_PCA9539 tristate "Philips PCA9539 16-bit I/O port" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for the Philips PCA9539 16-bit I/O port. @@ -62,7 +61,7 @@ config SENSORS_PCA9539 config SENSORS_PCF8591 tristate "Philips PCF8591" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL default n help If you say yes here you get support for Philips PCF8591 chips. @@ -75,7 +74,7 @@ config SENSORS_PCF8591 config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" - depends on I2C && ARCH_OMAP_OTG + depends on ARCH_OMAP_OTG help If you say yes here you get support for the Philips ISP1301 USB-On-The-Go transceiver working with the OMAP OTG controller. @@ -90,7 +89,7 @@ config ISP1301_OMAP # and having mostly OMAP-specific board support config TPS65010 tristate "TPS6501x Power Management chips" - depends on I2C && ARCH_OMAP + depends on ARCH_OMAP default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of @@ -103,7 +102,7 @@ config TPS65010 config SENSORS_M41T00 tristate "ST M41T00 RTC chip" - depends on I2C && PPC32 + depends on PPC32 help If you say yes here you get support for the ST M41T00 RTC chip. @@ -112,7 +111,7 @@ config SENSORS_M41T00 config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for the Maxim MAX6875 EEPROM-programmable, quad power-supply sequencer/supervisor. -- cgit v1.2.3 From 1c23af90dc44d05bbb6a3b5246ab664b1f943943 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Tue, 1 May 2007 23:26:34 +0200 Subject: i2c: Bitbanging I2C bus driver using the GPIO API This is a very simple bitbanging I2C bus driver utilizing the new arch-neutral GPIO API. Useful for chips that don't have a built-in I2C controller, additional I2C busses, or testing purposes. To use, include something similar to the following in the board-specific setup code: #include static struct i2c_gpio_platform_data i2c_gpio_data = { .sda_pin = GPIO_PIN_FOO, .scl_pin = GPIO_PIN_BAR, }; static struct platform_device i2c_gpio_device = { .name = "i2c-gpio", .id = 0, .dev = { .platform_data = &i2c_gpio_data, }, }; Register this platform_device, set up the I2C pins as GPIO if required and you're ready to go. This will use default values for udelay and timeout, and will work with GPIO hardware that does not support open drain mode, but allows sensing of the SDA and SCL lines even when they are being driven. Signed-off-by: Haavard Skinnemoen Signed-off-by: Jean Delvare --- MAINTAINERS | 5 + drivers/i2c/busses/Kconfig | 8 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-gpio.c | 215 ++++++++++++++++++++++++++++++++++++++++++ include/linux/i2c-gpio.h | 38 ++++++++ 5 files changed, 267 insertions(+) create mode 100644 drivers/i2c/busses/i2c-gpio.c create mode 100644 include/linux/i2c-gpio.h diff --git a/MAINTAINERS b/MAINTAINERS index 2b378ab99fc..4da67850578 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1466,6 +1466,11 @@ L: linux-scsi@vger.kernel.org W: http://www.icp-vortex.com/ S: Supported +GENERIC GPIO I2C DRIVER +P: Haavard Skinnemoen +M: hskinnemoen@atmel.com +S: Supported + GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8ccf6e4e91d..33a8a67f161 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -117,6 +117,14 @@ config I2C_ELEKTOR This support is also available as a module. If so, the module will be called i2c-elektor. +config I2C_GPIO + tristate "GPIO-based bitbanging I2C" + depends on GENERIC_GPIO + select I2C_ALGOBIT + help + This is a very simple bitbanging I2C driver utilizing the + arch-neutral GPIO API to control the SCL and SDA lines. + config I2C_HYDRA tristate "CHRP Apple Hydra Mac I/O I2C interface" depends on PCI && PPC_CHRP && EXPERIMENTAL diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index e51493cfbee..5689165f6d6 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o +obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_I810) += i2c-i810.o diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c new file mode 100644 index 00000000000..a7dd54654a9 --- /dev/null +++ b/drivers/i2c/busses/i2c-gpio.c @@ -0,0 +1,215 @@ +/* + * Bitbanging I2C bus driver using the GPIO API + * + * Copyright (C) 2007 Atmel Corporation + * + * 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. + */ +#include +#include +#include +#include +#include +#include + +#include + +/* Toggle SDA by changing the direction of the pin */ +static void i2c_gpio_setsda_dir(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + if (state) + gpio_direction_input(pdata->sda_pin); + else + gpio_direction_output(pdata->sda_pin, 0); +} + +/* + * Toggle SDA by changing the output value of the pin. This is only + * valid for pins configured as open drain (i.e. setting the value + * high effectively turns off the output driver.) + */ +static void i2c_gpio_setsda_val(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + gpio_set_value(pdata->sda_pin, state); +} + +/* Toggle SCL by changing the direction of the pin. */ +static void i2c_gpio_setscl_dir(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + if (state) + gpio_direction_input(pdata->scl_pin); + else + gpio_direction_output(pdata->scl_pin, 0); +} + +/* + * Toggle SCL by changing the output value of the pin. This is used + * for pins that are configured as open drain and for output-only + * pins. The latter case will break the i2c protocol, but it will + * often work in practice. + */ +static void i2c_gpio_setscl_val(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + gpio_set_value(pdata->scl_pin, state); +} + +int i2c_gpio_getsda(void *data) +{ + struct i2c_gpio_platform_data *pdata = data; + + return gpio_get_value(pdata->sda_pin); +} + +int i2c_gpio_getscl(void *data) +{ + struct i2c_gpio_platform_data *pdata = data; + + return gpio_get_value(pdata->scl_pin); +} + +static int __init i2c_gpio_probe(struct platform_device *pdev) +{ + struct i2c_gpio_platform_data *pdata; + struct i2c_algo_bit_data *bit_data; + struct i2c_adapter *adap; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -ENXIO; + + ret = -ENOMEM; + adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if (!adap) + goto err_alloc_adap; + bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); + if (!bit_data) + goto err_alloc_bit_data; + + ret = gpio_request(pdata->sda_pin, "sda"); + if (ret) + goto err_request_sda; + ret = gpio_request(pdata->scl_pin, "scl"); + if (ret) + goto err_request_scl; + + if (pdata->sda_is_open_drain) { + gpio_direction_output(pdata->sda_pin, 1); + bit_data->setsda = i2c_gpio_setsda_val; + } else { + gpio_direction_input(pdata->sda_pin); + bit_data->setsda = i2c_gpio_setsda_dir; + } + + if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { + gpio_direction_output(pdata->scl_pin, 1); + bit_data->setscl = i2c_gpio_setscl_val; + } else { + gpio_direction_input(pdata->scl_pin); + bit_data->setscl = i2c_gpio_setscl_dir; + } + + if (!pdata->scl_is_output_only) + bit_data->getscl = i2c_gpio_getscl; + bit_data->getsda = i2c_gpio_getsda; + + if (pdata->udelay) + bit_data->udelay = pdata->udelay; + else if (pdata->scl_is_output_only) + bit_data->udelay = 50; /* 10 kHz */ + else + bit_data->udelay = 5; /* 100 kHz */ + + if (pdata->timeout) + bit_data->timeout = pdata->timeout; + else + bit_data->timeout = HZ / 10; /* 100 ms */ + + bit_data->data = pdata; + + adap->owner = THIS_MODULE; + snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + adap->algo_data = bit_data; + adap->dev.parent = &pdev->dev; + + ret = i2c_bit_add_bus(adap); + if (ret) + goto err_add_bus; + + platform_set_drvdata(pdev, adap); + + dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", + pdata->sda_pin, pdata->scl_pin, + pdata->scl_is_output_only + ? ", no clock stretching" : ""); + + return 0; + +err_add_bus: + gpio_free(pdata->scl_pin); +err_request_scl: + gpio_free(pdata->sda_pin); +err_request_sda: + kfree(bit_data); +err_alloc_bit_data: + kfree(adap); +err_alloc_adap: + return ret; +} + +static int __exit i2c_gpio_remove(struct platform_device *pdev) +{ + struct i2c_gpio_platform_data *pdata; + struct i2c_adapter *adap; + + adap = platform_get_drvdata(pdev); + pdata = pdev->dev.platform_data; + + i2c_del_adapter(adap); + gpio_free(pdata->scl_pin); + gpio_free(pdata->sda_pin); + kfree(adap->algo_data); + kfree(adap); + + return 0; +} + +static struct platform_driver i2c_gpio_driver = { + .driver = { + .name = "i2c-gpio", + .owner = THIS_MODULE, + }, + .remove = __exit_p(i2c_gpio_remove), +}; + +static int __init i2c_gpio_init(void) +{ + int ret; + + ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe); + if (ret) + printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); + + return ret; +} +module_init(i2c_gpio_init); + +static void __exit i2c_gpio_exit(void) +{ + platform_driver_unregister(&i2c_gpio_driver); +} +module_exit(i2c_gpio_exit); + +MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h new file mode 100644 index 00000000000..c1bcb1f1d73 --- /dev/null +++ b/include/linux/i2c-gpio.h @@ -0,0 +1,38 @@ +/* + * i2c-gpio interface to platform code + * + * Copyright (C) 2007 Atmel Corporation + * + * 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. + */ +#ifndef _LINUX_I2C_GPIO_H +#define _LINUX_I2C_GPIO_H + +/** + * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio + * @sda_pin: GPIO pin ID to use for SDA + * @scl_pin: GPIO pin ID to use for SCL + * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz + * @timeout: clock stretching timeout in jiffies. If the slave keeps + * SCL low for longer than this, the transfer will time out. + * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin + * isn't actively driven high when setting the output value high. + * gpio_get_value() must return the actual pin state even if the + * pin is configured as an output. + * @scl_is_open_drain: SCL is set up as open drain. Same requirements + * as for sda_is_open_drain apply. + * @scl_is_output_only: SCL output drivers cannot be turned off. + */ +struct i2c_gpio_platform_data { + unsigned int sda_pin; + unsigned int scl_pin; + int udelay; + int timeout; + unsigned int sda_is_open_drain:1; + unsigned int scl_is_open_drain:1; + unsigned int scl_is_output_only:1; +}; + +#endif /* _LINUX_I2C_GPIO_H */ -- cgit v1.2.3 From bcda9f1eb0de0e1108c8b2765e5b7afa0dfb6c9f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 1 May 2007 23:26:34 +0200 Subject: i2c: New Simtec I2C bus driver Platform driver for the Simtec CPLD based simple I2C logic. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 12 +++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-simtec.c | 186 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 drivers/i2c/busses/i2c-simtec.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 33a8a67f161..2178c9bebfc 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -413,6 +413,18 @@ config I2C_SIBYTE help Supports the SiByte SOC on-chip I2C interfaces (2 channels). +config I2C_SIMTEC + tristate "Simtec Generic I2C interface" + select I2C_ALGOBIT + help + If you say yes to this option, support will be inclyded for + the Simtec Generic I2C interface. This driver is for the + simple I2C bus used on newer Simtec products for general + I2C, such as DDC on the Simtec BBD2016A. + + This driver can also be build as a module. If so, the module + will be called i2c-simtec. + config SCx200_I2C tristate "NatSemi SCx200 I2C using GPIO pins" depends on SCx200_GPIO diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 5689165f6d6..3a020ea8ede 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o +obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c new file mode 100644 index 00000000000..10af8d31e12 --- /dev/null +++ b/drivers/i2c/busses/i2c-simtec.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2005 Simtec Electronics + * Ben Dooks + * + * Simtec Generic I2C Controller + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +struct simtec_i2c_data { + struct resource *ioarea; + void __iomem *reg; + struct i2c_adapter adap; + struct i2c_algo_bit_data bit; +}; + +#define CMD_SET_SDA (1<<2) +#define CMD_SET_SCL (1<<3) + +#define STATE_SDA (1<<0) +#define STATE_SCL (1<<1) + +/* i2c bit-bus functions */ + +static void simtec_i2c_setsda(void *pw, int state) +{ + struct simtec_i2c_data *pd = pw; + writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg); +} + +static void simtec_i2c_setscl(void *pw, int state) +{ + struct simtec_i2c_data *pd = pw; + writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg); +} + +static int simtec_i2c_getsda(void *pw) +{ + struct simtec_i2c_data *pd = pw; + return readb(pd->reg) & STATE_SDA ? 1 : 0; +} + +static int simtec_i2c_getscl(void *pw) +{ + struct simtec_i2c_data *pd = pw; + return readb(pd->reg) & STATE_SCL ? 1 : 0; +} + +/* device registration */ + +static int simtec_i2c_probe(struct platform_device *dev) +{ + struct simtec_i2c_data *pd; + struct resource *res; + int size; + int ret; + + pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL); + if (pd == NULL) { + dev_err(&dev->dev, "cannot allocate private data\n"); + return -ENOMEM; + } + + platform_set_drvdata(dev, pd); + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&dev->dev, "cannot find IO resource\n"); + ret = -ENOENT; + goto err; + } + + size = (res->end-res->start)+1; + + pd->ioarea = request_mem_region(res->start, size, dev->name); + if (pd->ioarea == NULL) { + dev_err(&dev->dev, "cannot request IO\n"); + ret = -ENXIO; + goto err; + } + + pd->reg = ioremap(res->start, size); + if (pd->reg == NULL) { + dev_err(&dev->dev, "cannot map IO\n"); + ret = -ENXIO; + goto err_res; + } + + /* setup the private data */ + + pd->adap.owner = THIS_MODULE; + pd->adap.algo_data = &pd->bit; + pd->adap.dev.parent = &dev->dev; + + strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name)); + + pd->bit.data = pd; + pd->bit.setsda = simtec_i2c_setsda; + pd->bit.setscl = simtec_i2c_setscl; + pd->bit.getsda = simtec_i2c_getsda; + pd->bit.getscl = simtec_i2c_getscl; + pd->bit.timeout = HZ; + pd->bit.udelay = 20; + + ret = i2c_bit_add_bus(&pd->adap); + if (ret) + goto err_all; + + return 0; + + err_all: + iounmap(pd->reg); + + err_res: + release_resource(pd->ioarea); + kfree(pd->ioarea); + + err: + kfree(pd); + return ret; +} + +static int simtec_i2c_remove(struct platform_device *dev) +{ + struct simtec_i2c_data *pd = platform_get_drvdata(dev); + + i2c_del_adapter(&pd->adap); + + iounmap(pd->reg); + release_resource(pd->ioarea); + kfree(pd->ioarea); + kfree(pd); + + return 0; +} + + +/* device driver */ + +static struct platform_driver simtec_i2c_driver = { + .driver = { + .name = "simtec-i2c", + .owner = THIS_MODULE, + }, + .probe = simtec_i2c_probe, + .remove = simtec_i2c_remove, +}; + +static int __init i2c_adap_simtec_init(void) +{ + return platform_driver_register(&simtec_i2c_driver); +} + +static void __exit i2c_adap_simtec_exit(void) +{ + platform_driver_unregister(&simtec_i2c_driver); +} + +module_init(i2c_adap_simtec_init); +module_exit(i2c_adap_simtec_exit); + +MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 11de70bd4d40a1a39c1133b260bfbd6306e981d3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:34 +0200 Subject: i2c: Obsolete i2c-ixp2000, i2c-ixp4xx and scx200_i2c The new generic i2c-gpio driver should be used instead. The obsolete drivers will be removed in September 2007. Signed-off-by: Jean Delvare Cc: Deepak Saxena Cc: Jordan Crouse --- Documentation/feature-removal-schedule.txt | 8 ++++++++ drivers/i2c/busses/Kconfig | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index c4b3bdad15d..547663bdae8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -306,3 +306,11 @@ Why: Code was merged, then submitter immediately disappeared leaving Who: David S. Miller --------------------------- + +What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers +When: September 2007 +Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific + I2C-over-GPIO drivers. +Who: Jean Delvare + +--------------------------- diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2178c9bebfc..e4f1a463f41 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -240,7 +240,7 @@ config I2C_ISA tristate config I2C_IXP4XX - tristate "IXP4xx GPIO-Based I2C Interface" + tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)" depends on ARCH_IXP4XX select I2C_ALGOBIT help @@ -250,8 +250,11 @@ config I2C_IXP4XX This support is also available as a module. If so, the module will be called i2c-ixp4xx. + This driver is deprecated and will be dropped soon. Use i2c-gpio + instead. + config I2C_IXP2000 - tristate "IXP2000 GPIO-Based I2C Interface" + tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)" depends on ARCH_IXP2000 select I2C_ALGOBIT help @@ -261,6 +264,9 @@ config I2C_IXP2000 This support is also available as a module. If so, the module will be called i2c-ixp2000. + This driver is deprecated and will be dropped soon. Use i2c-gpio + instead. + config I2C_POWERMAC tristate "Powermac I2C interface" depends on PPC_PMAC @@ -426,7 +432,7 @@ config I2C_SIMTEC will be called i2c-simtec. config SCx200_I2C - tristate "NatSemi SCx200 I2C using GPIO pins" + tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)" depends on SCx200_GPIO select I2C_ALGOBIT help @@ -437,6 +443,9 @@ config SCx200_I2C This support is also available as a module. If so, the module will be called scx200_i2c. + This driver is deprecated and will be dropped soon. Use i2c-gpio + (or scx200_acb) instead. + config SCx200_I2C_SCL int "GPIO pin used for SCL" depends on SCx200_I2C -- cgit v1.2.3 From 35532d20035d04b0ec28508583a56c7a65c5fa47 Mon Sep 17 00:00:00 2001 From: Milind Arun Choudhary Date: Tue, 1 May 2007 23:26:34 +0200 Subject: i2c: SPIN_LOCK_UNLOCKED cleanup SPIN_LOCK_UNLOCKED cleanup, use __SPIN_LOCK_UNLOCKED instead. Signed-off-by: Milind Arun Choudhary Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-pxa.c | 2 +- drivers/i2c/busses/i2c-s3c2410.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 2fc3bcec24d..c059b27fa88 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -838,7 +838,7 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { }; static struct pxa_i2c i2c_pxa = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(i2c_pxa.lock), .adap = { .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 556f244aae7..3eb5958f347 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -570,7 +570,7 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = { }; static struct s3c24xx_i2c s3c24xx_i2c = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock), .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), .adap = { .name = "s3c2410-i2c", -- cgit v1.2.3 From eefcd75e72f382270f8f64e030550b10e3882b2b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 May 2007 23:26:35 +0200 Subject: i2c: Documentation update Make the documentation on how to write and port i2c drivers more in line with the current state of things: * i2c-isa is deprecated and soon gone, so stop advertising it. * Drop many sensors-specific references. Most of them were outdated anyway. * Update the example code to reflect the recent and not-so-recent API and coding style preference changes. * Simplify the example init and cleanup functions. This should make things less complex to understand for newcomers. Signed-off-by: Jean Delvare --- Documentation/i2c/porting-clients | 18 ++- Documentation/i2c/writing-clients | 292 ++++---------------------------------- 2 files changed, 39 insertions(+), 271 deletions(-) diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index ca272b263a9..7bf82c08f6c 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -1,4 +1,4 @@ -Revision 6, 2005-11-20 +Revision 7, 2007-04-19 Jean Delvare Greg KH @@ -20,6 +20,10 @@ yours for best results. Technical changes: +* [Driver type] Any driver that was relying on i2c-isa has to be + converted to a proper isa, platform or pci driver. This is not + covered by this guide. + * [Includes] Get rid of "version.h" and . Includes typically look like that: #include @@ -27,12 +31,10 @@ Technical changes: #include #include #include - #include /* for ISA drivers */ #include /* for hardware monitoring drivers */ #include #include /* if you need VRM support */ #include /* for class registration */ - #include /* if you have I/O operations */ Please respect this inclusion order. Some extra headers may be required for a given driver (e.g. "lm75.h"). @@ -69,20 +71,16 @@ Technical changes: sensors mailing list by providing a patch to the Documentation/hwmon/sysfs-interface file. -* [Attach] For I2C drivers, the attach function should make sure - that the adapter's class has I2C_CLASS_HWMON (or whatever class is - suitable for your driver), using the following construct: +* [Attach] The attach function should make sure that the adapter's + class has I2C_CLASS_HWMON (or whatever class is suitable for your + driver), using the following construct: if (!(adapter->class & I2C_CLASS_HWMON)) return 0; - ISA-only drivers of course don't need this. Call i2c_probe() instead of i2c_detect(). * [Detect] As mentioned earlier, the flags parameter is gone. The type_name and client_name strings are replaced by a single name string, which will be filled with a lowercase, short string. - In i2c-only drivers, drop the i2c_is_isa_adapter check, it's - useless. Same for isa-only drivers, as the test would always be - true. Only hybrid drivers (which are quite rare) still need it. The labels used for error paths are reduced to the number needed. It is advised that the labels are given descriptive names such as exit and exit_free. Don't forget to properly set err before diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index f7e04ec849b..3d8d36b0ad1 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -74,16 +74,13 @@ An example structure is below. struct foo_data { struct i2c_client client; - struct semaphore lock; /* For ISA access in `sensors' drivers. */ - int sysctl_id; /* To keep the /proc directory entry for - `sensors' drivers. */ enum chips type; /* To keep the chips type for `sensors' drivers. */ /* Because the i2c bus is slow, it is often useful to cache the read information of a chip for some time (for example, 1 or 2 seconds). It depends of course on the device whether this is really worthwhile or even sensible. */ - struct semaphore update_lock; /* When we are reading lots of information, + struct mutex update_lock; /* When we are reading lots of information, another process should not update the below information */ char valid; /* != 0 if the following fields are valid. */ @@ -104,8 +101,7 @@ some obscure clients). But we need generic reading and writing routines. I have found it useful to define foo_read and foo_write function for this. For some cases, it will be easier to call the i2c functions directly, but many chips have some kind of register-value idea that can easily -be encapsulated. Also, some chips have both ISA and I2C interfaces, and -it useful to abstract from this (only for `sensors' drivers). +be encapsulated. The below functions are simple examples, and should not be copied literally. @@ -128,24 +124,6 @@ literally. return i2c_smbus_write_word_data(client,reg,value); } -For sensors code, you may have to cope with ISA registers too. Something -like the below often works. Note the locking! - - int foo_read_value(struct i2c_client *client, u8 reg) - { - int res; - if (i2c_is_isa_client(client)) { - down(&(((struct foo_data *) (client->data)) -> lock)); - outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET); - res = inb_p(client->addr + FOO_DATA_REG_OFFSET); - up(&(((struct foo_data *) (client->data)) -> lock)); - return res; - } else - return i2c_smbus_read_byte_data(client,reg); - } - -Writing is done the same way. - Probing and attaching ===================== @@ -257,10 +235,6 @@ detection algorithm. You do not have to use this parameter interface; but don't try to use function i2c_probe() if you don't. -NOTE: If you want to write a `sensors' driver, the interface is slightly - different! See below. - - Probing classes (Legacy model) ------------------------------ @@ -344,10 +318,6 @@ The detect client function is called by i2c_probe. The `kind' parameter contains -1 for a probed detection, 0 for a forced detection, or a positive number for a forced detection with a chip type forced. -Below, some things are only needed if this is a `sensors' driver. Those -parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ -markers. - Returning an error different from -ENODEV in a detect function will cause the detection to stop: other addresses and adapters won't be scanned. This should only be done on fatal or internal errors, such as a memory @@ -356,64 +326,20 @@ shortage or i2c_attach_client failing. For now, you can ignore the `flags' parameter. It is there for future use. int foo_detect_client(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) + int kind) { int err = 0; int i; - struct i2c_client *new_client; + struct i2c_client *client; struct foo_data *data; - const char *client_name = ""; /* For non-`sensors' drivers, put the real - name here! */ + const char *name = ""; /* Let's see whether this adapter can support what we need. - Please substitute the things you need here! - For `sensors' drivers, add `! is_isa &&' to the if statement */ + Please substitute the things you need here! */ if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE)) goto ERROR0; - /* SENSORS ONLY START */ - const char *type_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - /* Do this only if the chip can additionally be found on the ISA bus - (hybrid chip). */ - - if (is_isa) { - - /* Discard immediately if this ISA range is already used */ - /* FIXME: never use check_region(), only request_region() */ - if (check_region(address,FOO_EXTENT)) - goto ERROR0; - - /* Probe whether there is anything on this address. - Some example code is below, but you will have to adapt this - for your own driver */ - - if (kind < 0) /* Only if no force parameter was used */ { - /* We may need long timeouts at least for some chips. */ - #define REALLY_SLOW_IO - i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; - #undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f,address+5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i,address+5); - return 0; - } - } - } - - /* SENSORS ONLY END */ - /* 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 several i2c functions safely */ @@ -423,13 +349,12 @@ For now, you can ignore the `flags' parameter. It is there for future use. goto ERROR0; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); + client = &data->client; + i2c_set_clientdata(client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &foo_driver; - new_client->flags = 0; + client->addr = address; + client->adapter = adapter; + client->driver = &foo_driver; /* Now, we do the remaining detection. If no `force' parameter is used. */ @@ -437,19 +362,17 @@ For now, you can ignore the `flags' parameter. It is there for future use. parameter was used. */ if (kind < 0) { /* The below is of course bogus */ - if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE) + if (foo_read(client, FOO_REG_GENERIC) != FOO_GENERIC_VALUE) goto ERROR1; } - /* SENSORS ONLY START */ - /* Next, specific detection. This is especially important for `sensors' devices. */ /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter was used. */ if (kind <= 0) { - i = foo_read(new_client,FOO_REG_CHIPTYPE); + i = foo_read(client, FOO_REG_CHIPTYPE); if (i == FOO_TYPE_1) kind = chip1; /* As defined in the enum */ else if (i == FOO_TYPE_2) @@ -463,63 +386,31 @@ For now, you can ignore the `flags' parameter. It is there for future use. /* Now set the type and chip names */ if (kind == chip1) { - type_name = "chip1"; /* For /proc entry */ - client_name = "CHIP 1"; + name = "chip1"; } else if (kind == chip2) { - type_name = "chip2"; /* For /proc entry */ - client_name = "CHIP 2"; + name = "chip2"; } - /* Reserve the ISA region */ - if (is_isa) - request_region(address,FOO_EXTENT,type_name); - - /* SENSORS ONLY END */ - /* Fill in the remaining client fields. */ - strcpy(new_client->name,client_name); - - /* SENSORS ONLY BEGIN */ + strlcpy(client->name, name, I2C_NAME_SIZE); data->type = kind; - /* SENSORS ONLY END */ - - data->valid = 0; /* Only if you use this field */ - init_MUTEX(&data->update_lock); /* Only if you use this field */ + mutex_init(&data->update_lock); /* Only if you use this field */ /* Any other initializations in data must be done here too. */ - /* Tell the i2c layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* SENSORS ONLY BEGIN */ - /* Register a new directory entry with module sensors. See below for - the `template' structure. */ - if ((i = i2c_register_entry(new_client, type_name, - foo_dir_table_template,THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* SENSORS ONLY END */ - /* This function can write default values to the client registers, if needed. */ - foo_init_client(new_client); + foo_init_client(client); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto ERROR1; + return 0; /* OK, this is not exactly good programming practice, usually. But it is very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR2: - /* SENSORS ONLY START */ - if (is_isa) - release_region(address,FOO_EXTENT); - /* SENSORS ONLY END */ ERROR1: kfree(data); ERROR0: @@ -536,22 +427,12 @@ much simpler than the attachment code, fortunately! int foo_detach_client(struct i2c_client *client) { - int err,i; - - /* SENSORS ONLY START */ - /* Deregister with the `i2c-proc' module. */ - i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id); - /* SENSORS ONLY END */ + int err; /* Try to detach the client from i2c space */ if ((err = i2c_detach_client(client))) return err; - /* HYBRID SENSORS CHIP ONLY START */ - if i2c_is_isa_client(client) - release_region(client->addr,LM78_EXTENT); - /* HYBRID SENSORS CHIP ONLY END */ - kfree(i2c_get_clientdata(client)); return 0; } @@ -564,42 +445,34 @@ When the kernel is booted, or when your foo driver module is inserted, you have to do some initializing. Fortunately, just attaching (registering) the driver module is usually enough. - /* Keep track of how far we got in the initialization process. If several - things have to initialized, and we fail halfway, only those things - have to be cleaned up! */ - static int __initdata foo_initialized = 0; - static int __init foo_init(void) { int res; - printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE); if ((res = i2c_add_driver(&foo_driver))) { printk("foo: Driver registration failed, module not inserted.\n"); - foo_cleanup(); return res; } - foo_initialized ++; return 0; } - void foo_cleanup(void) + static void __exit foo_cleanup(void) { - if (foo_initialized == 1) { - i2c_del_driver(&foo_driver); - foo_initialized --; - } + i2c_del_driver(&foo_driver); } /* Substitute your own name and email address */ MODULE_AUTHOR("Frodo Looijaard " MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices"); + /* a few non-GPL license types are also allowed */ + MODULE_LICENSE("GPL"); + module_init(foo_init); module_exit(foo_cleanup); Note that some functions are marked by `__init', and some data structures -by `__init_data'. Hose functions and structures can be removed after +by `__initdata'. These functions and structures can be removed after kernel booting (or module loading) is completed. @@ -729,110 +602,7 @@ General purpose routines Below all general purpose routines are listed, that were not mentioned before. - /* This call returns a unique low identifier for each registered adapter, - * or -1 if the adapter was not registered. + /* This call returns a unique low identifier for each registered adapter. */ extern int i2c_adapter_id(struct i2c_adapter *adap); - -The sensors sysctl/proc interface -================================= - -This section only applies if you write `sensors' drivers. - -Each sensors driver creates a directory in /proc/sys/dev/sensors for each -registered client. The directory is called something like foo-i2c-4-65. -The sensors module helps you to do this as easily as possible. - -The template ------------- - -You will need to define a ctl_table template. This template will automatically -be copied to a newly allocated structure and filled in where necessary when -you call sensors_register_entry. - -First, I will give an example definition. - static ctl_table foo_dir_table_template[] = { - { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real,NULL,&foo_func }, - { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real,NULL,&foo_func }, - { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real,NULL,&foo_data }, - { 0 } - }; - -In the above example, three entries are defined. They can either be -accessed through the /proc interface, in the /proc/sys/dev/sensors/* -directories, as files named func1, func2 and data, or alternatively -through the sysctl interface, in the appropriate table, with identifiers -FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA. - -The third, sixth and ninth parameters should always be NULL, and the -fourth should always be 0. The fifth is the mode of the /proc file; -0644 is safe, as the file will be owned by root:root. - -The seventh and eighth parameters should be &i2c_proc_real and -&i2c_sysctl_real if you want to export lists of reals (scaled -integers). You can also use your own function for them, as usual. -Finally, the last parameter is the call-back to gather the data -(see below) if you use the *_proc_real functions. - - -Gathering the data ------------------- - -The call back functions (foo_func and foo_data in the above example) -can be called in several ways; the operation parameter determines -what should be done: - - * If operation == SENSORS_PROC_REAL_INFO, you must return the - magnitude (scaling) in nrels_mag; - * If operation == SENSORS_PROC_REAL_READ, you must read information - from the chip and return it in results. The number of integers - to display should be put in nrels_mag; - * If operation == SENSORS_PROC_REAL_WRITE, you must write the - supplied information to the chip. nrels_mag will contain the number - of integers, results the integers themselves. - -The *_proc_real functions will display the elements as reals for the -/proc interface. If you set the magnitude to 2, and supply 345 for -SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would -write 45.6 to the /proc file, it would be returned as 4560 for -SENSORS_PROC_REAL_WRITE. A magnitude may even be negative! - -An example function: - - /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and - register values. Note the use of the read cache. */ - void foo_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) - { - struct foo_data *data = client->data; - int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - /* Update the readings cache (if necessary) */ - foo_update_client(client); - /* Get the readings from the cache */ - results[0] = FOO_FROM_REG(data->foo_func_base[nr]); - results[1] = FOO_FROM_REG(data->foo_func_more[nr]); - results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - /* Update the cache */ - data->foo_base[nr] = FOO_TO_REG(results[0]); - /* Update the chip */ - foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]); - } - if (*nrels_mag >= 2) { - /* Update the cache */ - data->foo_more[nr] = FOO_TO_REG(results[1]); - /* Update the chip */ - foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]); - } - } - } -- cgit v1.2.3 From e8c76eed2ecdb8e9ca5339761d2c076d32b7cbca Mon Sep 17 00:00:00 2001 From: Till Harbaum Date: Tue, 1 May 2007 23:26:35 +0200 Subject: i2c: New i2c-tiny-usb bus driver Add a driver for the i2c-tiny-usb interface. This is a simple do-it-yourself USB to I2C interface targeted at experimental and home use. See the i2c-tiny-usb homepage for hardware details: http://www.harbaum.org/till/i2c_tiny_usb Signed-off-by: Till Harbaum Signed-off-by: Jean Delvare --- MAINTAINERS | 7 + drivers/i2c/busses/Kconfig | 11 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-tiny-usb.c | 277 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 drivers/i2c/busses/i2c-tiny-usb.c diff --git a/MAINTAINERS b/MAINTAINERS index 4da67850578..0912ef618b3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1643,6 +1643,13 @@ L: i2c@lm-sensors.org T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/ S: Maintained +I2C-TINY-USB DRIVER +P: Till Harbaum +M: till@harbaum.org +L: i2c@lm-sensors.org +T: http://www.harbaum.org/till/i2c_tiny_usb +S: Maintained + i386 BOOT CODE P: Riley H. Williams M: Riley@Williams.Name diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e4f1a463f41..838dc1c19d6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -525,6 +525,17 @@ config I2C_STUB If you don't know what to do here, definitely say N. +config I2C_TINY_USB + tristate "I2C-Tiny-USB" + depends on USB + help + If you say yes to this option, support will be included for the + i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See + http://www.harbaum.org/till/i2c_tiny_usb for hardware details. + + This driver can also be built as a module. If so, the module + will be called i2c-tiny-usb. + config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" depends on ARCH_VERSATILE || ARCH_REALVIEW diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3a020ea8ede..14d1432f698 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o +obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_VIA) += i2c-via.o diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c new file mode 100644 index 00000000000..907999049d5 --- /dev/null +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -0,0 +1,277 @@ +/* + * driver for the i2c-tiny-usb adapter - 1.0 + * http://www.harbaum.org/till/i2c_tiny_usb + * + * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org) + * + * 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. + * + */ + +#include +#include +#include + +/* include interfaces to usb layer */ +#include + +/* include interface to i2c layer */ +#include + +/* commands via USB, must match command ids in the firmware */ +#define CMD_ECHO 0 +#define CMD_GET_FUNC 1 +#define CMD_SET_DELAY 2 +#define CMD_GET_STATUS 3 + +#define CMD_I2C_IO 4 +#define CMD_I2C_IO_BEGIN (1<<0) +#define CMD_I2C_IO_END (1<<1) + +/* i2c bit delay, default is 10us -> 100kHz */ +static int delay = 10; +module_param(delay, int, 0); +MODULE_PARM_DESC(delay, "bit delay in microseconds, " + "e.g. 10 for 100kHz (default is 100kHz)"); + +static int usb_read(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len); + +static int usb_write(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len); + +/* ----- begin of i2c layer ---------------------------------------------- */ + +#define STATUS_IDLE 0 +#define STATUS_ADDRESS_ACK 1 +#define STATUS_ADDRESS_NAK 2 + +static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + unsigned char status; + struct i2c_msg *pmsg; + int i; + + dev_dbg(&adapter->dev, "master xfer %d messages:\n", num); + + for (i = 0 ; i < num ; i++) { + int cmd = CMD_I2C_IO; + + if (i == 0) + cmd |= CMD_I2C_IO_BEGIN; + + if (i == num-1) + cmd |= CMD_I2C_IO_END; + + pmsg = &msgs[i]; + + dev_dbg(&adapter->dev, + " %d: %s (flags %d) %d bytes to 0x%02x\n", + i, pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->flags, pmsg->len, pmsg->addr); + + /* and directly send the message */ + if (pmsg->flags & I2C_M_RD) { + /* read data */ + if (usb_read(adapter, cmd, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len) != pmsg->len) { + dev_err(&adapter->dev, + "failure reading data\n"); + return -EREMOTEIO; + } + } else { + /* write data */ + if (usb_write(adapter, cmd, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len) != pmsg->len) { + dev_err(&adapter->dev, + "failure writing data\n"); + return -EREMOTEIO; + } + } + + /* read status */ + if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) { + dev_err(&adapter->dev, "failure reading status\n"); + return -EREMOTEIO; + } + + dev_dbg(&adapter->dev, " status = %d\n", status); + if (status == STATUS_ADDRESS_NAK) + return -EREMOTEIO; + } + + return i; +} + +static u32 usb_func(struct i2c_adapter *adapter) +{ + u32 func; + + /* get functionality from adapter */ + if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) != + sizeof(func)) { + dev_err(&adapter->dev, "failure reading functionality\n"); + return 0; + } + + return func; +} + +/* This is the actual algorithm we define */ +static const struct i2c_algorithm usb_algorithm = { + .master_xfer = usb_xfer, + .functionality = usb_func, +}; + +/* ----- end of i2c layer ------------------------------------------------ */ + +/* ----- begin of usb layer ---------------------------------------------- */ + +/* The usb i2c interface uses a vid/pid pair donated by */ +/* Future Technology Devices International Ltd. */ +static struct usb_device_id i2c_tiny_usb_table [] = { + { USB_DEVICE(0x0403, 0xc631) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table); + +/* Structure to hold all of our device specific stuff */ +struct i2c_tiny_usb { + struct usb_device *usb_dev; /* the usb device for this device */ + struct usb_interface *interface; /* the interface for this device */ + struct i2c_adapter adapter; /* i2c related things */ +}; + +static int usb_read(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len) +{ + struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; + + /* do control transfer */ + return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0), + cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | + USB_DIR_IN, value, index, data, len, 2000); +} + +static int usb_write(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len) +{ + struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; + + /* do control transfer */ + return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0), + cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, data, len, 2000); +} + +static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev) +{ + usb_put_dev(dev->usb_dev); + kfree(dev); +} + +static int i2c_tiny_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct i2c_tiny_usb *dev; + int retval = -ENOMEM; + u16 version; + + dev_dbg(&interface->dev, "probing usb device\n"); + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&interface->dev, "Out of memory\n"); + goto error; + } + + dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice); + dev_info(&interface->dev, + "version %x.%02x found at bus %03d address %03d\n", + version >> 8, version & 0xff, + dev->usb_dev->bus->busnum, dev->usb_dev->devnum); + + /* setup i2c adapter description */ + dev->adapter.owner = THIS_MODULE; + dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.algo = &usb_algorithm; + dev->adapter.algo_data = dev; + snprintf(dev->adapter.name, I2C_NAME_SIZE, + "i2c-tiny-usb at bus %03d device %03d", + dev->usb_dev->bus->busnum, dev->usb_dev->devnum); + + if (usb_write(&dev->adapter, CMD_SET_DELAY, + cpu_to_le16(delay), 0, NULL, 0) != 0) { + dev_err(&dev->adapter.dev, + "failure setting delay to %dus\n", delay); + retval = -EIO; + goto error; + } + + dev->adapter.dev.parent = &dev->interface->dev; + + /* and finally attach to i2c layer */ + i2c_add_adapter(&dev->adapter); + + /* inform user about successful attachment to i2c layer */ + dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n"); + + return 0; + + error: + if (dev) + i2c_tiny_usb_free(dev); + + return retval; +} + +static void i2c_tiny_usb_disconnect(struct usb_interface *interface) +{ + struct i2c_tiny_usb *dev = usb_get_intfdata(interface); + + i2c_del_adapter(&dev->adapter); + usb_set_intfdata(interface, NULL); + i2c_tiny_usb_free(dev); + + dev_dbg(&interface->dev, "disconnected\n"); +} + +static struct usb_driver i2c_tiny_usb_driver = { + .name = "i2c-tiny-usb", + .probe = i2c_tiny_usb_probe, + .disconnect = i2c_tiny_usb_disconnect, + .id_table = i2c_tiny_usb_table, +}; + +static int __init usb_i2c_tiny_usb_init(void) +{ + /* register this driver with the USB subsystem */ + return usb_register(&i2c_tiny_usb_driver); +} + +static void __exit usb_i2c_tiny_usb_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&i2c_tiny_usb_driver); +} + +module_init(usb_i2c_tiny_usb_init); +module_exit(usb_i2c_tiny_usb_exit); + +/* ----- end of usb layer ------------------------------------------------ */ + +MODULE_AUTHOR("Till Harbaum "); +MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e00a8cdf325346c531c841ee85c803792db60157 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 1 May 2007 23:26:35 +0200 Subject: i2c-s3c2410: Fix I2C SDA to SCL setup time Fix the setup time for SDA to SCL due to the way the S3C24XX I2C controller works. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-s3c2410.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3eb5958f347..e8395be0d92 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -61,6 +61,8 @@ struct s3c24xx_i2c { unsigned int msg_idx; unsigned int msg_ptr; + unsigned int tx_setup; + enum s3c24xx_i2c_state state; void __iomem *regs; @@ -199,8 +201,11 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr); writeb(addr, i2c->regs + S3C2410_IICDS); - // delay a bit and reset iiccon before setting start (per samsung) - udelay(1); + /* delay here to ensure the data byte has gotten onto the bus + * before the transaction is started */ + + ndelay(i2c->tx_setup); + dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon); writel(iiccon, i2c->regs + S3C2410_IICCON); @@ -322,7 +327,15 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) if (!is_msgend(i2c)) { byte = i2c->msg->buf[i2c->msg_ptr++]; writeb(byte, i2c->regs + S3C2410_IICDS); - + + /* delay after writing the byte to allow the + * data setup time on the bus, as writing the + * data to the register causes the first bit + * to appear on SDA, and SCL will change as + * soon as the interrupt is acknowledged */ + + ndelay(i2c->tx_setup); + } else if (!is_lastmsg(i2c)) { /* we need to go to the next i2c message */ @@ -570,9 +583,10 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = { }; static struct s3c24xx_i2c s3c24xx_i2c = { - .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock), - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), - .adap = { + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock), + .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), + .tx_setup = 50, + .adap = { .name = "s3c2410-i2c", .owner = THIS_MODULE, .algo = &s3c24xx_i2c_algorithm, -- cgit v1.2.3 From 5b68790cd5e2879067bcbc45b01eeb6081e7d731 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 1 May 2007 23:26:35 +0200 Subject: i2c-s3c2410: Fix bug in releasing driver When compiled as a module, the i2c-s3c2410 driver does not free either the IRQ or the i2c adapter it attached to the system. As part of this fix, move to the usual kernel style of freeing items as part of the probe error path making the remove process easier. Signed-off-by: Ben Dooks Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-s3c2410.c | 70 +++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index e8395be0d92..e68a96f589f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -745,26 +745,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) return 0; } -static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c) -{ - if (i2c->clk != NULL && !IS_ERR(i2c->clk)) { - clk_disable(i2c->clk); - clk_put(i2c->clk); - i2c->clk = NULL; - } - - if (i2c->regs != NULL) { - iounmap(i2c->regs); - i2c->regs = NULL; - } - - if (i2c->ioarea != NULL) { - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - i2c->ioarea = NULL; - } -} - /* s3c24xx_i2c_probe * * called by the bus driver when a suitable device is found @@ -783,7 +763,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); ret = -ENOENT; - goto out; + goto err_noclk; } dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); @@ -796,7 +776,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "cannot find IO resource\n"); ret = -ENOENT; - goto out; + goto err_clk; } i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, @@ -805,7 +785,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->ioarea == NULL) { dev_err(&pdev->dev, "cannot request IO\n"); ret = -ENXIO; - goto out; + goto err_clk; } i2c->regs = ioremap(res->start, (res->end-res->start)+1); @@ -813,7 +793,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); ret = -ENXIO; - goto out; + goto err_ioarea; } dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res); @@ -827,7 +807,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_init(i2c); if (ret != 0) - goto out; + goto err_iomap; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending @@ -837,7 +817,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "cannot find IRQ\n"); ret = -ENOENT; - goto out; + goto err_iomap; } ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED, @@ -845,7 +825,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ\n"); - goto out; + goto err_iomap; } i2c->irq = res; @@ -855,17 +835,29 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto out; + goto err_irq; } platform_set_drvdata(pdev, i2c); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); + return 0; - out: - if (ret < 0) - s3c24xx_i2c_free(i2c); + err_irq: + free_irq(i2c->irq->start, i2c); + + err_iomap: + iounmap(i2c->regs); + + err_ioarea: + release_resource(i2c->ioarea); + kfree(i2c->ioarea); + + err_clk: + clk_disable(i2c->clk); + clk_put(i2c->clk); + err_noclk: return ret; } @@ -877,11 +869,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) static int s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); - - if (i2c != NULL) { - s3c24xx_i2c_free(i2c); - platform_set_drvdata(pdev, NULL); - } + + i2c_del_adapter(&i2c->adap); + free_irq(i2c->irq->start, i2c); + + clk_disable(i2c->clk); + clk_put(i2c->clk); + + iounmap(i2c->regs); + + release_resource(i2c->ioarea); + kfree(i2c->ioarea); return 0; } -- cgit v1.2.3