diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-30 10:03:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-30 10:03:46 -0700 |
commit | 42fe55ce905212542426fa6407a76534a5fb696a (patch) | |
tree | 874c5984e4222ea253b78c5be4755b3d31da54e2 | |
parent | 19ce0a995ff230b364c7329fd488c70e91c171d9 (diff) | |
parent | 14674e70119ea01549ce593d8901a797f8a90f74 (diff) |
Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
Pull i2c updates from Jean Delvare.
* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
i2c: Split I2C_M_NOSTART support out of I2C_FUNC_PROTOCOL_MANGLING
i2c-dev: Add support for I2C_M_RECV_LEN
-rw-r--r-- | Documentation/i2c/functionality | 9 | ||||
-rw-r--r-- | Documentation/i2c/i2c-protocol | 9 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 2 | ||||
-rw-r--r-- | drivers/i2c/algos/i2c-algo-bit.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nuc900.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 3 | ||||
-rw-r--r-- | drivers/i2c/i2c-dev.c | 30 | ||||
-rw-r--r-- | drivers/input/joystick/as5011.c | 1 | ||||
-rw-r--r-- | drivers/video/matrox/matroxfb_maven.c | 1 | ||||
-rw-r--r-- | include/linux/i2c.h | 5 |
10 files changed, 51 insertions, 14 deletions
diff --git a/Documentation/i2c/functionality b/Documentation/i2c/functionality index 42c17c1fb3c..b0ff2ab596c 100644 --- a/Documentation/i2c/functionality +++ b/Documentation/i2c/functionality @@ -18,9 +18,9 @@ For the most up-to-date list of functionality constants, please check adapters typically can not do these) I2C_FUNC_10BIT_ADDR Handles the 10-bit address extensions I2C_FUNC_PROTOCOL_MANGLING Knows about the I2C_M_IGNORE_NAK, - I2C_M_REV_DIR_ADDR, I2C_M_NOSTART and - I2C_M_NO_RD_ACK flags (which modify the - I2C protocol!) + I2C_M_REV_DIR_ADDR and I2C_M_NO_RD_ACK + flags (which modify the I2C protocol!) + I2C_FUNC_NOSTART Can skip repeated start sequence I2C_FUNC_SMBUS_QUICK Handles the SMBus write_quick command I2C_FUNC_SMBUS_READ_BYTE Handles the SMBus read_byte command I2C_FUNC_SMBUS_WRITE_BYTE Handles the SMBus write_byte command @@ -50,6 +50,9 @@ A few combinations of the above flags are also defined for your convenience: emulated by a real I2C adapter (using the transparent emulation layer) +In kernel versions prior to 3.5 I2C_FUNC_NOSTART was implemented as +part of I2C_FUNC_PROTOCOL_MANGLING. + ADAPTER IMPLEMENTATION ---------------------- diff --git a/Documentation/i2c/i2c-protocol b/Documentation/i2c/i2c-protocol index 10518dd5881..0b3e62d1f77 100644 --- a/Documentation/i2c/i2c-protocol +++ b/Documentation/i2c/i2c-protocol @@ -49,7 +49,9 @@ a byte read, followed by a byte write: Modified transactions ===================== -We have found some I2C devices that needs the following modifications: +The following modifications to the I2C protocol can also be generated, +with the exception of I2C_M_NOSTART these are usually only needed to +work around device issues: Flag I2C_M_NOSTART: In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some @@ -60,6 +62,11 @@ We have found some I2C devices that needs the following modifications: we do not generate Addr, but we do generate the startbit S. This will probably confuse all other clients on your bus, so don't try this. + This is often used to gather transmits from multiple data buffers in + system memory into something that appears as a single transfer to the + I2C device but may also be used between direction changes by some + rare devices. + Flags I2C_M_REV_DIR_ADDR This toggles the Rd/Wr flag. That is, if you want to do a write, but need to emit an Rd instead of a Wr, or vice versa, you set this diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 5f6b2478bf1..fa6bf5279d2 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -42,7 +42,7 @@ static int regmap_i2c_gather_write(void *context, /* If the I2C controller can't do a gather tell the core, it * will substitute in a linear write for us. */ - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_PROTOCOL_MANGLING)) + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_NOSTART)) return -ENOTSUPP; xfer[0].addr = i2c->addr; diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 7f0b8321974..fad22b0bb5b 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -608,7 +608,7 @@ bailout: static u32 bit_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c index 03b61577888..a26dfb8cd58 100644 --- a/drivers/i2c/busses/i2c-nuc900.c +++ b/drivers/i2c/busses/i2c-nuc900.c @@ -502,7 +502,8 @@ static int nuc900_i2c_xfer(struct i2c_adapter *adap, /* declare our i2c functionality */ static u32 nuc900_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | + I2C_FUNC_PROTOCOL_MANGLING; } /* i2c bus registration info */ diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index fa0b1349087..01959154572 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -626,7 +626,8 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, /* declare our i2c functionality */ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | + I2C_FUNC_PROTOCOL_MANGLING; } /* i2c bus registration info */ diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 45048323b75..5ec2261574e 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -265,19 +265,41 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, res = 0; for (i = 0; i < rdwr_arg.nmsgs; i++) { - /* Limit the size of the message to a sane amount; - * and don't let length change either. */ - if ((rdwr_pa[i].len > 8192) || - (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { + /* Limit the size of the message to a sane amount */ + if (rdwr_pa[i].len > 8192) { res = -EINVAL; break; } + data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); if (IS_ERR(rdwr_pa[i].buf)) { res = PTR_ERR(rdwr_pa[i].buf); break; } + + /* + * If the message length is received from the slave (similar + * to SMBus block read), we must ensure that the buffer will + * be large enough to cope with a message length of + * I2C_SMBUS_BLOCK_MAX as this is the maximum underlying bus + * drivers allow. The first byte in the buffer must be + * pre-filled with the number of extra bytes, which must be + * at least one to hold the message length, but can be + * greater (for example to account for a checksum byte at + * the end of the message.) + */ + if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { + if (!(rdwr_pa[i].flags & I2C_M_RD) || + rdwr_pa[i].buf[0] < 1 || + rdwr_pa[i].len < rdwr_pa[i].buf[0] + + I2C_SMBUS_BLOCK_MAX) { + res = -EINVAL; + break; + } + + rdwr_pa[i].len = rdwr_pa[i].buf[0]; + } } if (res < 0) { int j; diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 3063464474b..57d19d4e0a2 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -231,6 +231,7 @@ static int __devinit as5011_probe(struct i2c_client *client, } if (!i2c_check_functionality(client->adapter, + I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING)) { dev_err(&client->dev, "need i2c bus that supports protocol mangling\n"); diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 31b8f67477b..217678e0b98 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -1243,6 +1243,7 @@ static int maven_probe(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING)) goto ERROR0; if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index b66cb601435..ddfa04108ba 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -541,7 +541,7 @@ struct i2c_msg { __u16 flags; #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #define I2C_M_RD 0x0001 /* read data, from slave to master */ -#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ @@ -554,8 +554,9 @@ struct i2c_msg { #define I2C_FUNC_I2C 0x00000001 #define I2C_FUNC_10BIT_ADDR 0x00000002 -#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_NOSTART etc. */ +#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */ #define I2C_FUNC_SMBUS_PEC 0x00000008 +#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */ #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 |