aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-11-30 14:50:44 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-11-30 14:50:44 -0800
commitaf5fdf80645304e7077ab876a43b325425c7ef70 (patch)
treef832bcdc45c60a7858b64f0a340cd10934c3eb9f /drivers
parentMerge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm (diff)
parentat24: Use timeout also for read (diff)
downloadlinux-dev-af5fdf80645304e7077ab876a43b325425c7ef70.tar.xz
linux-dev-af5fdf80645304e7077ab876a43b325425c7ef70.zip
Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging: at24: Use timeout also for read i2c: Fix userspace_device list corruption MAINTAINERS: Add missing i2c files i2c/tsl2550: Fix lux value in extended mode
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/chips/tsl2550.c3
-rw-r--r--drivers/i2c/i2c-core.c11
-rw-r--r--drivers/misc/eeprom/at24.c76
3 files changed, 59 insertions, 31 deletions
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);
}
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);
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,