Commit a405764c1ec835a41ccda943b9156aee25e15d5e
Committed by
Heiko Schocher
1 parent
dec1861be9
Exists in
v2017.01-smarct4x
and in
40 other branches
drivers/i2c/fsl_i2c: modify i2c_read to handle multi-byte write
Most of the I2C slaves support accesses in the typical style that is : read/write series of bytes at particular address offset. These transactions look like:" (1) START:Address:Tx:Offset:RESTART:Address[0..4]:Tx/Rx:data[0..n]:STOP" However there are certain devices which support accesses in terms of the transactions as follows: (2) "START:Address:Tx:Txdata[0..n1]:Clock_stretching: RESTART:Address:Rx:data[0..n2]" Here Txdata is typically a command and some associated data, similarly Rxdata could be command status plus some data received as a response to the command sent. Type (1) transactions are currently supportd in the i2c driver using i2c_read and i2c_write APIs. I2C EEPROMs, RTC, etc fall in this category. To handle type (2) along with type (1) transactions, i2c_read() function has been modified. Signed-off-by: Shaveta Leekha <shaveta@freescale.com> Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
Showing 1 changed file with 34 additions and 7 deletions Side-by-side Diff
drivers/i2c/fsl_i2c.c
... | ... | @@ -423,18 +423,45 @@ |
423 | 423 | struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr]; |
424 | 424 | int i = -1; /* signal error */ |
425 | 425 | u8 *a = (u8*)&addr; |
426 | + int len = alen * -1; | |
426 | 427 | |
427 | 428 | if (i2c_wait4bus(adap) < 0) |
428 | 429 | return -1; |
429 | 430 | |
430 | - if ((!length || alen > 0) | |
431 | - && i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 | |
432 | - && __i2c_write(adap, &a[4 - alen], alen) == alen) | |
433 | - i = 0; /* No error so far */ | |
431 | + /* To handle the need of I2C devices that require to write few bytes | |
432 | + * (more than 4 bytes of address as in the case of else part) | |
433 | + * of data before reading, Negative equivalent of length(bytes to write) | |
434 | + * is passed, but used the +ve part of len for writing data | |
435 | + */ | |
436 | + if (alen < 0) { | |
437 | + /* Generate a START and send the Address and | |
438 | + * the Tx Bytes to the slave. | |
439 | + * "START: Address: Write bytes data[len]" | |
440 | + * IF part supports writing any number of bytes in contrast | |
441 | + * to the else part, which supports writing address offset | |
442 | + * of upto 4 bytes only. | |
443 | + * bytes that need to be written are passed in | |
444 | + * "data", which will eventually keep the data READ, | |
445 | + * after writing the len bytes out of it | |
446 | + */ | |
447 | + if (i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0) | |
448 | + i = __i2c_write(adap, data, len); | |
434 | 449 | |
435 | - if (length && | |
436 | - i2c_write_addr(adap, dev, I2C_READ_BIT, alen ? 1 : 0) != 0) | |
437 | - i = __i2c_read(adap, data, length); | |
450 | + if (i != len) | |
451 | + return -1; | |
452 | + | |
453 | + if (length && i2c_write_addr(adap, dev, I2C_READ_BIT, 1) != 0) | |
454 | + i = __i2c_read(adap, data, length); | |
455 | + } else { | |
456 | + if ((!length || alen > 0) && | |
457 | + i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 && | |
458 | + __i2c_write(adap, &a[4 - alen], alen) == alen) | |
459 | + i = 0; /* No error so far */ | |
460 | + | |
461 | + if (length && | |
462 | + i2c_write_addr(adap, dev, I2C_READ_BIT, alen ? 1 : 0) != 0) | |
463 | + i = __i2c_read(adap, data, length); | |
464 | + } | |
438 | 465 | |
439 | 466 | writeb(I2C_CR_MEN, &device->cr); |
440 | 467 |