Skip to content

Commit

Permalink
Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/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
  • Loading branch information
Linus Torvalds committed Nov 30, 2009
2 parents 07a6d5a + 4d29196 commit af5fdf8
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 33 deletions.
3 changes: 1 addition & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -2562,8 +2562,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 <till@harbaum.org>
Expand Down
3 changes: 3 additions & 0 deletions drivers/i2c/chips/tsl2550.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
}
Expand Down
11 changes: 11 additions & 0 deletions drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
76 changes: 45 additions & 31 deletions drivers/misc/eeprom/at24.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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,
Expand Down

0 comments on commit af5fdf8

Please sign in to comment.