From 5f5bfb09d81c9a1d26238ae6668e584c14ae3daf Mon Sep 17 00:00:00 2001 From: Michele Jr De Candia Date: Thu, 26 Nov 2009 09:22:32 +0100 Subject: i2c/tsl2550: Fix lux value in extended mode According to the TAOS Application Note 'Controlling a Backlight with the TSL2550 Ambient Light Sensor' (page 14), the actual lux value in extended mode should be obtained multiplying the calculated lux value by 5. Signed-off-by: Michele Jr De Candia Signed-off-by: Jean Delvare --- drivers/i2c/chips/tsl2550.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c index aa96bd2d27ea..a0702f36a72f 100644 --- a/drivers/i2c/chips/tsl2550.c +++ b/drivers/i2c/chips/tsl2550.c @@ -257,6 +257,7 @@ static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO, static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf) { + struct tsl2550_data *data = i2c_get_clientdata(client); u8 ch0, ch1; int ret; @@ -274,6 +275,8 @@ static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf) ret = tsl2550_calculate_lux(ch0, ch1); if (ret < 0) return ret; + if (data->operating_mode == 1) + ret *= 5; return sprintf(buf, "%d\n", ret); } -- cgit v1.2.2 From 03b70d625c10d1605012d41489d9df18467c5f55 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 26 Nov 2009 09:22:32 +0100 Subject: MAINTAINERS: Add missing i2c files Add missing header files to the i2c subsystem section. Signed-off-by: Jean Delvare --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c824b4d62754..d5e8d5ad115d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2533,8 +2533,7 @@ S: Maintained F: Documentation/i2c/ F: drivers/i2c/ F: include/linux/i2c.h -F: include/linux/i2c-dev.h -F: include/linux/i2c-id.h +F: include/linux/i2c-*.h I2C-TINY-USB DRIVER M: Till Harbaum -- cgit v1.2.2 From bbd2d9c9198c6efd449e9d395b3eaf2d03aa3bba Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 26 Nov 2009 09:22:33 +0100 Subject: i2c: Fix userspace_device list corruption Fix userspace_device list corruption. The corruption was caused by clients not being removed when adapters with such clients were themselves removed. Something like the following would trigger it (assuming i2c-stub gets adapter number 3): # modprobe i2c-stub chip_addr=0x50 # echo 24c08 0x50 > /sys/bus/i2c/devices/i2c-3/new_device # rmmod i2c-stub # modprobe i2c-stub chip_addr=0x50 # echo 24c08 0x50 > /sys/bus/i2c/devices/i2c-3/new_device For the records, the stack trace in the kernel logs look like this: kernel: WARNING: at lib/list_debug.c:30 __list_add+0x8b/0x90() kernel: Hardware name: (...) kernel: list_add corruption. prev->next should be next (c137fc84), but was (null). (prev=f57111b8). kernel: Modules linked in: (...) kernel: Pid: 4669, comm: bash Not tainted 2.6.32-rc8 #259 kernel: Call Trace: kernel: [] ? __list_add+0x8b/0x90 kernel: [] ? __list_add+0x8b/0x90 kernel: [] warn_slowpath_common+0x6c/0xc0 kernel: [] ? __list_add+0x8b/0x90 kernel: [] warn_slowpath_fmt+0x26/0x30 kernel: [] __list_add+0x8b/0x90 kernel: [] i2c_sysfs_new_device+0x1c5/0x250 kernel: [] ? might_fault+0x2e/0x80 kernel: [] ? i2c_sysfs_new_device+0x0/0x250 kernel: [] dev_attr_store+0x25/0x30 kernel: [] sysfs_write_file+0x9c/0xf0 kernel: [] vfs_write+0x9c/0x160 kernel: [] ? sysfs_write_file+0x0/0xf0 kernel: [] sys_write+0x3d/0x70 kernel: [] sysenter_do_call+0x12/0x36 Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8d80fceca6a4..296504355142 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -762,6 +762,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) { int res = 0; struct i2c_adapter *found; + struct i2c_client *client, *next; /* First make sure that this adapter was ever added */ mutex_lock(&core_lock); @@ -781,6 +782,16 @@ int i2c_del_adapter(struct i2c_adapter *adap) if (res) return res; + /* Remove devices instantiated from sysfs */ + list_for_each_entry_safe(client, next, &userspace_devices, detected) { + if (client->adapter == adap) { + dev_dbg(&adap->dev, "Removing %s at 0x%x\n", + client->name, client->addr); + list_del(&client->detected); + i2c_unregister_device(client); + } + } + /* Detach any active clients. This can't fail, thus we do not checking the returned value. */ res = device_for_each_child(&adap->dev, NULL, __unregister_client); -- cgit v1.2.2 From 4d29196c535088e807061ce2a0aa526daec2edfb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 26 Nov 2009 09:22:33 +0100 Subject: at24: Use timeout also for read Writes may take some time on EEPROMs, so for consecutive writes, we already have a loop waiting for the EEPROM to become ready. Use such a loop for reads, too, in case somebody wants to immediately read after a write. Detailed bug report and test case can be found here: http://article.gmane.org/gmane.linux.drivers.i2c/4660 Reported-by: Aleksandar Ivanov Signed-off-by: Wolfram Sang Tested-by: Aleksandar Ivanov Cc: David Brownell Signed-off-by: Jean Delvare --- drivers/misc/eeprom/at24.c | 76 +++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index db39f4a52f53..2cb2736d65aa 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -158,6 +158,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, struct i2c_msg msg[2]; u8 msgbuf[2]; struct i2c_client *client; + unsigned long timeout, read_time; int status, i; memset(msg, 0, sizeof(msg)); @@ -183,47 +184,60 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, if (count > io_limit) count = io_limit; - /* Smaller eeproms can work given some SMBus extension calls */ if (at24->use_smbus) { + /* Smaller eeproms can work given some SMBus extension calls */ if (count > I2C_SMBUS_BLOCK_MAX) count = I2C_SMBUS_BLOCK_MAX; - status = i2c_smbus_read_i2c_block_data(client, offset, - count, buf); - dev_dbg(&client->dev, "smbus read %zu@%d --> %d\n", - count, offset, status); - return (status < 0) ? -EIO : status; + } else { + /* + * When we have a better choice than SMBus calls, use a + * combined I2C message. Write address; then read up to + * io_limit data bytes. Note that read page rollover helps us + * here (unlike writes). msgbuf is u8 and will cast to our + * needs. + */ + i = 0; + if (at24->chip.flags & AT24_FLAG_ADDR16) + msgbuf[i++] = offset >> 8; + msgbuf[i++] = offset; + + msg[0].addr = client->addr; + msg[0].buf = msgbuf; + msg[0].len = i; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; } /* - * When we have a better choice than SMBus calls, use a combined - * I2C message. Write address; then read up to io_limit data bytes. - * Note that read page rollover helps us here (unlike writes). - * msgbuf is u8 and will cast to our needs. + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. */ - i = 0; - if (at24->chip.flags & AT24_FLAG_ADDR16) - msgbuf[i++] = offset >> 8; - msgbuf[i++] = offset; - - msg[0].addr = client->addr; - msg[0].buf = msgbuf; - msg[0].len = i; + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + read_time = jiffies; + if (at24->use_smbus) { + status = i2c_smbus_read_i2c_block_data(client, offset, + count, buf); + } else { + status = i2c_transfer(client->adapter, msg, 2); + if (status == 2) + status = count; + } + dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", + count, offset, status, jiffies); - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; + if (status == count) + return count; - status = i2c_transfer(client->adapter, msg, 2); - dev_dbg(&client->dev, "i2c read %zu@%d --> %d\n", - count, offset, status); + /* REVISIT: at HZ=100, this is sloooow */ + msleep(1); + } while (time_before(read_time, timeout)); - if (status == 2) - return count; - else if (status >= 0) - return -EIO; - else - return status; + return -ETIMEDOUT; } static ssize_t at24_read(struct at24_data *at24, -- cgit v1.2.2