i2c: Move to Linux like `struct i2c_msg`

Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.

Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.

The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.

Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.

Patched with Coccinelle using the clumsy spatch below and some manual
changes:

* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.

    @@ @@
    -struct i2c_seg
    +struct i2c_msg

    @@ identifier msg; expression e; @@
    (
     struct i2c_msg msg = {
    -    .read = 0,
    +    .flags = 0,
     };
    |
     struct i2c_msg msg = {
    -    .read = 1,
    +    .flags = I2C_M_RD,
     };
    |
     struct i2c_msg msg = {
    -    .chip = e,
    +    .slave = e,
     };
    )

    @@ struct i2c_msg msg; statement S1, S2; @@
    (
    -if (msg.read)
    +if (msg.flags & I2C_M_RD)
     S1 else S2
    |
    -if (msg.read)
    +if (msg.flags & I2C_M_RD)
     S1
    )

    @@ struct i2c_msg *msg; statement S1, S2; @@
    (
    -if (msg->read)
    +if (msg->flags & I2C_M_RD)
     S1 else S2
    |
    -if (msg->read)
    +if (msg->flags & I2C_M_RD)
     S1
    )

    @@ struct i2c_msg msg; expression e; @@
    (
    -msg.read = 0;
    +msg.flags = 0;
    |
    -msg.read = 1;
    +msg.flags = I2C_M_RD;
    |
    -msg.read = e;
    +msg.flags = e ? I2C_M_RD : 0;
    |
    -!!(msg.read)
    +(msg.flags & I2C_M_RD)
    |
    -(msg.read)
    +(msg.flags & I2C_M_RD)
    )

    @@ struct i2c_msg *msg; expression e; @@
    (
    -msg->read = 0;
    +msg->flags = 0;
    |
    -msg->read = 1;
    +msg->flags = I2C_M_RD;
    |
    -msg->read = e;
    +msg->flags = e ? I2C_M_RD : 0;
    |
    -!!(msg->read)
    +(msg->flags & I2C_M_RD)
    |
    -(msg->read)
    +(msg->flags & I2C_M_RD)
    )

    @@ struct i2c_msg msg; @@
    -msg.chip
    +msg.slave

    @@ struct i2c_msg *msg; expression e; @@
    -msg[e].chip
    +msg[e].slave

    @ slave disable ptr_to_array @ struct i2c_msg *msg; @@
    -msg->chip
    +msg->slave

Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
diff --git a/src/cpu/allwinner/a10/twi.c b/src/cpu/allwinner/a10/twi.c
index 3ef5606..123d34e 100644
--- a/src/cpu/allwinner/a10/twi.c
+++ b/src/cpu/allwinner/a10/twi.c
@@ -185,10 +185,10 @@
 	return len;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count)
 {
 	int i, ret = CB_SUCCESS;
-	struct i2c_seg *seg = segments;
+	struct i2c_msg *seg = segments;
 	struct a1x_twi *twi = (void *)TWI_BASE(bus);
 
 
@@ -198,12 +198,12 @@
 	for (i = 0; i < count; i++) {
 		seg = segments + i;
 
-		if (seg->read) {
-			ret = i2c_read(twi, seg->chip, seg->buf, seg->len);
+		if (seg->flags & I2C_M_RD) {
+			ret = i2c_read(twi, seg->slave, seg->buf, seg->len);
 			if (ret < 0)
 				break;
 		} else {
-			ret = i2c_write(twi, seg->chip, seg->buf, seg->len);
+			ret = i2c_write(twi, seg->slave, seg->buf, seg->len);
 			if (ret < 0)
 				break;
 		}
diff --git a/src/device/i2c.c b/src/device/i2c.c
index d4670a0..67470d4 100644
--- a/src/device/i2c.c
+++ b/src/device/i2c.c
@@ -49,7 +49,7 @@
 	return ops->dev_to_bus(pbus->dev);
 }
 
-int i2c_dev_transfer(struct device *dev, struct i2c_seg *segments, int count)
+int i2c_dev_transfer(struct device *dev, struct i2c_msg *segments, int count)
 {
 	int bus = i2c_dev_find_bus(dev);
 	if (bus < 0)
diff --git a/src/device/software_i2c.c b/src/device/software_i2c.c
index be7aebe..368d145 100644
--- a/src/device/software_i2c.c
+++ b/src/device/software_i2c.c
@@ -238,19 +238,20 @@
 	return byte;
 }
 
-int software_i2c_transfer(unsigned bus, struct i2c_seg *segments, int count)
+int software_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count)
 {
 	int i;
-	struct i2c_seg *seg;
+	struct i2c_msg *seg;
 
 	for (seg = segments; seg - segments < count; seg++) {
 		if (start_cond(bus) < 0)
 			return -1;
-		if (out_byte(bus, seg->chip << 1 | !!seg->read) < 0)
+		const u8 addr_dir = seg->slave << 1 | !!(seg->flags & I2C_M_RD);
+		if (out_byte(bus, addr_dir) < 0)
 			return -1;
 		for (i = 0; i < seg->len; i++) {
 			int ret;
-			if (seg->read) {
+			if (seg->flags & I2C_M_RD) {
 				ret = in_byte(bus, i < seg->len - 1);
 				seg->buf[i] = (u8)ret;
 			} else {
diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c
index cc44b48..1b078f4 100644
--- a/src/drivers/i2c/tpm/tpm.c
+++ b/src/drivers/i2c/tpm/tpm.c
@@ -144,9 +144,10 @@
 		 * retries should usually not be needed, but are kept just to
 		 * be safe on the safe side.
 		 */
-		struct i2c_seg aseg = { .read = 0, .chip = tpm_dev->addr,
+		struct i2c_msg aseg = { .flags = 0, .slave = tpm_dev->addr,
 					.buf = &addr, .len = 1 };
-		struct i2c_seg dseg = { .read = 1, .chip = tpm_dev->addr,
+		struct i2c_msg dseg = { .flags = I2C_M_RD,
+					.slave = tpm_dev->addr,
 					.buf = buffer, .len = len };
 		for (count = 0; count < MAX_COUNT; count++) {
 			rc = i2c_transfer(tpm_dev->bus, &aseg, 1) ||
diff --git a/src/drivers/i2c/ww_ring/ww_ring.c b/src/drivers/i2c/ww_ring/ww_ring.c
index bfecc60..5fb593c 100644
--- a/src/drivers/i2c/ww_ring/ww_ring.c
+++ b/src/drivers/i2c/ww_ring/ww_ring.c
@@ -111,7 +111,7 @@
  * the transfer function ignores errors when accessing the reset register.
  */
 
-static int ledc_transfer(TiLp55231 *ledc, struct i2c_seg *segs,
+static int ledc_transfer(TiLp55231 *ledc, struct i2c_msg *segs,
 			 int seg_count, int reset)
 {
 	int rv, max_attempts = 2;
@@ -128,7 +128,7 @@
 		if (!reset)
 			printk(BIOS_WARNING,
 			       "%s: dev %#x, reg %#x, %s transaction error.\n",
-			       __func__, segs->chip, segs->buf[0],
+			       __func__, segs->slave, segs->buf[0],
 			       seg_count == 1 ? "write" : "read");
 		else
 			rv = 0;
@@ -144,7 +144,7 @@
 static int ledc_write(TiLp55231 *ledc, uint8_t start_addr,
 		      const uint8_t *data, unsigned count)
 {
-	struct i2c_seg seg;
+	struct i2c_msg seg;
 
 	if (count > (sizeof(ledc->data_buffer) - 1)) {
 		printk(BIOS_WARNING, "%s: transfer size too large (%d bytes)\n",
@@ -155,8 +155,8 @@
 	memcpy(ledc->data_buffer + 1, data, count);
 	ledc->data_buffer[0] = start_addr;
 
-	seg.read = 0;
-	seg.chip = ledc->dev_addr;
+	seg.flags = 0;
+	seg.slave = ledc->dev_addr;
 	seg.buf = ledc->data_buffer;
 	seg.len = count + 1;
 
@@ -166,15 +166,15 @@
 /* To keep things simple, read is limited to one byte at a time. */
 static int ledc_read(TiLp55231 *ledc, uint8_t addr, uint8_t *data)
 {
-	struct i2c_seg seg[2];
+	struct i2c_msg seg[2];
 
-	seg[0].read = 0;
-	seg[0].chip = ledc->dev_addr;
+	seg[0].flags = 0;
+	seg[0].slave = ledc->dev_addr;
 	seg[0].buf = &addr;
 	seg[0].len = 1;
 
-	seg[1].read = 1;
-	seg[1].chip = ledc->dev_addr;
+	seg[1].flags = I2C_M_RD;
+	seg[1].slave = ledc->dev_addr;
 	seg[1].buf = data;
 	seg[1].len = 1;
 
diff --git a/src/ec/google/chromeec/ec_i2c.c b/src/ec/google/chromeec/ec_i2c.c
index eca1eb9..40bd0bb 100644
--- a/src/ec/google/chromeec/ec_i2c.c
+++ b/src/ec/google/chromeec/ec_i2c.c
@@ -45,20 +45,20 @@
 
 struct i2c_ec {
 	int bus;
-	struct i2c_seg segs[SEGS_PER_CMD];
+	struct i2c_msg segs[SEGS_PER_CMD];
 };
 
 static struct i2c_ec ec_dev = {
 	.bus = CONFIG_EC_GOOGLE_CHROMEEC_I2C_BUS,
 	.segs[CMD_INDEX] = {
-		.read = 0,
-		.chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP,
+		.flags = 0,
+		.slave = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP,
 		/* Framing byte to be transferred prior to request. */
 		.buf = &req_buf.framing_bytes[3],
 	},
 	.segs[RESP_INDEX] = {
-		.read = 1,
-		.chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP,
+		.flags = I2C_M_RD,
+		.slave = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP,
 		/* return code and total length before full response. */
 		.buf = &resp_buf.framing_bytes[2],
 	},
@@ -100,7 +100,7 @@
 
 	if (i2c_transfer(ec->bus, ec->segs, ARRAY_SIZE(ec->segs)) != 0) {
 		printk(BIOS_ERR, "%s: Cannot complete read from i2c-%d:%#x\n",
-		       __func__, ec->bus, ec->segs[0].chip);
+		       __func__, ec->bus, ec->segs[0].slave);
 		return -1;
 	}
 
diff --git a/src/include/device/i2c.h b/src/include/device/i2c.h
index 6115bd1..9939bc6 100644
--- a/src/include/device/i2c.h
+++ b/src/include/device/i2c.h
@@ -19,6 +19,41 @@
 #include <stdint.h>
 #include <stdlib.h>
 
+/**
+ * struct i2c_msg - an I2C transaction segment beginning with START
+ * @addr: Slave address, either seven or ten bits.  When this is a ten
+ *	bit address, I2C_M_TEN must be set in @flags.
+ * @flags: I2C_M_RD is handled by all adapters.
+ * @len: Number of data bytes in @buf being read from or written to the
+ *	I2C slave address.  For read transactions where I2C_M_RECV_LEN
+ *	is set, the caller guarantees that this buffer can hold up to
+ *	32 bytes in addition to the initial length byte sent by the
+ *	slave (plus, if used, the SMBus PEC).
+ * @buf: The buffer into which data is read, or from which it's written.
+ *
+ * An i2c_msg is the low level representation of one segment of an I2C
+ * transaction.  It is visible to drivers in the @i2c_transfer() procedure.
+ *
+ * All I2C adapters implement the standard rules for I2C transactions. Each
+ * transaction begins with a START.  That is followed by the slave address,
+ * and a bit encoding read versus write.  Then follow all the data bytes,
+ * possibly including a byte with SMBus PEC.  The transfer terminates with
+ * a NAK, or when all those bytes have been transferred and ACKed.  If this
+ * is the last message in a group, it is followed by a STOP.  Otherwise it
+ * is followed by the next @i2c_msg transaction segment, beginning with a
+ * (repeated) START.
+ */
+struct i2c_msg {
+	uint16_t flags;
+#define I2C_M_RD		0x0001	/* read data, from slave to master */
+#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
+#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
+#define I2C_M_NOSTART		0x4000	/* don't send a repeated START */
+	uint16_t slave;		/* slave address			*/
+	uint16_t len;		/* msg length				*/
+	uint8_t *buf;		/* pointer to msg data			*/
+};
+
 enum i2c_speed {
 	I2C_SPEED_STANDARD	= 100000,
 	I2C_SPEED_FAST		= 400000,
@@ -32,15 +67,9 @@
 	I2C_MODE_10_BIT
 };
 
-struct i2c_seg {
-	int read;
-	uint8_t chip;
-	uint8_t *buf;
-	int len;
-};
 
-int platform_i2c_transfer(unsigned int bus, struct i2c_seg *segments,
-	int count);
+int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
+			  int count);
 
 #define SOFTWARE_I2C_MAX_BUS 10		/* increase as necessary */
 
@@ -53,15 +82,16 @@
 
 extern struct software_i2c_ops *software_i2c[];
 
-int software_i2c_transfer(unsigned int bus, struct i2c_seg *segments,
-	int count);
-void software_i2c_wedge_ack(unsigned int bus, u8 chip);
-void software_i2c_wedge_read(unsigned int bus, u8 chip, u8 reg, int bit_count);
-void software_i2c_wedge_write(unsigned int bus, u8 chip, u8 reg, int bit_count);
+int software_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
+			  int count);
+void software_i2c_wedge_ack(unsigned int bus, u8 slave);
+void software_i2c_wedge_read(unsigned int bus, u8 slave, u8 reg, int bit_count);
+void software_i2c_wedge_write(unsigned int bus, u8 slave, u8 reg,
+			      int bit_count);
 
-int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t *data,
+int i2c_read_field(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t *data,
 		   uint8_t mask, uint8_t shift);
-int i2c_write_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t data,
+int i2c_write_field(unsigned int bus, uint8_t slave, uint8_t reg, uint8_t data,
 		    uint8_t mask, uint8_t shift);
 
 /*
@@ -70,7 +100,7 @@
  * Need this ugly stub to arbitrate since I2C device drivers hardcode
  * 'i2c_transfer()' as their entry point.
  */
-static inline int i2c_transfer(unsigned int bus, struct i2c_seg *segments,
+static inline int i2c_transfer(unsigned int bus, struct i2c_msg *segments,
 			       int count)
 {
 	if (CONFIG_SOFTWARE_I2C)
@@ -85,11 +115,11 @@
  *
  * [start][slave addr][r][data][stop]
  */
-static inline int i2c_read_raw(unsigned int bus, uint8_t chip, uint8_t *data,
+static inline int i2c_read_raw(unsigned int bus, uint8_t slave, uint8_t *data,
 			       int len)
 {
-	struct i2c_seg seg = {
-		.read = 1, .chip = chip, .buf = data, .len = len
+	struct i2c_msg seg = {
+		.flags = I2C_M_RD, .slave = slave, .buf = data, .len = len
 	};
 
 	return i2c_transfer(bus, &seg, 1);
@@ -100,11 +130,11 @@
  *
  * [start][slave addr][w][data][stop]
  */
-static inline int i2c_write_raw(unsigned int bus, uint8_t chip, uint8_t *data,
+static inline int i2c_write_raw(unsigned int bus, uint8_t slave, uint8_t *data,
 				int len)
 {
-	struct i2c_seg seg = {
-		.read = 0, .chip = chip, .buf = data, .len = len
+	struct i2c_msg seg = {
+		.flags = 0, .slave = slave, .buf = data, .len = len
 	};
 
 	return i2c_transfer(bus, &seg, 1);
@@ -115,19 +145,19 @@
  *
  * [start][slave addr][w][register addr][start][slave addr][r][data...][stop]
  */
-static inline int i2c_read_bytes(unsigned int bus, uint8_t chip, uint8_t reg,
+static inline int i2c_read_bytes(unsigned int bus, uint8_t slave, uint8_t reg,
 				 uint8_t *data, int len)
 {
-	struct i2c_seg seg[2];
+	struct i2c_msg seg[2];
 
-	seg[0].read = 0;
-	seg[0].chip = chip;
-	seg[0].buf  = &reg;
-	seg[0].len  = 1;
-	seg[1].read = 1;
-	seg[1].chip = chip;
-	seg[1].buf  = data;
-	seg[1].len  = len;
+	seg[0].flags = 0;
+	seg[0].slave = slave;
+	seg[0].buf   = &reg;
+	seg[0].len   = 1;
+	seg[1].flags = I2C_M_RD;
+	seg[1].slave = slave;
+	seg[1].buf   = data;
+	seg[1].len   = len;
 
 	return i2c_transfer(bus, seg, ARRAY_SIZE(seg));
 }
@@ -137,19 +167,19 @@
  *
  * [start][slave addr][w][register addr][start][slave addr][r][data][stop]
  */
-static inline int i2c_readb(unsigned int bus, uint8_t chip, uint8_t reg,
+static inline int i2c_readb(unsigned int bus, uint8_t slave, uint8_t reg,
 			    uint8_t *data)
 {
-	struct i2c_seg seg[2];
+	struct i2c_msg seg[2];
 
-	seg[0].read = 0;
-	seg[0].chip = chip;
-	seg[0].buf = &reg;
-	seg[0].len = 1;
-	seg[1].read = 1;
-	seg[1].chip = chip;
-	seg[1].buf = data;
-	seg[1].len = 1;
+	seg[0].flags = 0;
+	seg[0].slave = slave;
+	seg[0].buf   = &reg;
+	seg[0].len   = 1;
+	seg[1].flags = I2C_M_RD;
+	seg[1].slave = slave;
+	seg[1].buf   = data;
+	seg[1].len   = 1;
 
 	return i2c_transfer(bus, seg, ARRAY_SIZE(seg));
 }
@@ -159,16 +189,16 @@
  *
  * [start][slave addr][w][register addr][data][stop]
  */
-static inline int i2c_writeb(unsigned int bus, uint8_t chip, uint8_t reg,
+static inline int i2c_writeb(unsigned int bus, uint8_t slave, uint8_t reg,
 			     uint8_t data)
 {
-	struct i2c_seg seg;
+	struct i2c_msg seg;
 	uint8_t buf[] = {reg, data};
 
-	seg.read = 0;
-	seg.chip = chip;
-	seg.buf = buf;
-	seg.len = ARRAY_SIZE(buf);
+	seg.flags = 0;
+	seg.slave = slave;
+	seg.buf   = buf;
+	seg.len   = ARRAY_SIZE(buf);
 
 	return i2c_transfer(bus, &seg, 1);
 }
@@ -188,7 +218,7 @@
 int i2c_dev_find_bus(struct device *dev);
 
 /* Variants of I2C helper functions that take a device instead of bus number */
-int i2c_dev_transfer(struct device *dev, struct i2c_seg *segments, int count);
+int i2c_dev_transfer(struct device *dev, struct i2c_msg *segments, int count);
 int i2c_dev_readb(struct device *dev, uint8_t reg, uint8_t *data);
 int i2c_dev_writeb(struct device *dev, uint8_t reg, uint8_t data);
 int i2c_dev_read_bytes(struct device *dev, uint8_t reg, uint8_t *data, int len);
diff --git a/src/soc/broadcom/cygnus/i2c.c b/src/soc/broadcom/cygnus/i2c.c
index fe14000..bc43a88 100644
--- a/src/soc/broadcom/cygnus/i2c.c
+++ b/src/soc/broadcom/cygnus/i2c.c
@@ -103,13 +103,14 @@
 		I2C_MASTER_RX_FIFO_FLUSH | I2C_MASTER_TX_FIFO_FLUSH);
 }
 
-static int i2c_write(struct cygnus_i2c_regs *reg_addr, struct i2c_seg *segment)
+static int i2c_write(struct cygnus_i2c_regs *reg_addr,
+		     struct i2c_msg *segment)
 {
 	uint8_t *data = segment->buf;
 	unsigned int val, status;
 	int i, ret;
 
-	write32(&reg_addr->i2c_master_data_wr, segment->chip << 1);
+	write32(&reg_addr->i2c_master_data_wr, segment->slave << 1);
 
 	for (i = 0; i < segment->len; i++) {
 		val = data[i];
@@ -150,13 +151,13 @@
 	return ret;
 }
 
-static int i2c_read(struct cygnus_i2c_regs *reg_addr, struct i2c_seg *segment)
+static int i2c_read(struct cygnus_i2c_regs *reg_addr, struct i2c_msg *segment)
 {
 	uint8_t *data = segment->buf;
 	int i, ret;
 	unsigned int status;
 
-	write32(&reg_addr->i2c_master_data_wr, segment->chip << 1 | 1);
+	write32(&reg_addr->i2c_master_data_wr, segment->slave << 1 | 1);
 
 	/*
 	 * Now we can activate the transfer. Specify the number of bytes to read
@@ -190,7 +191,7 @@
 }
 
 static int i2c_do_xfer(struct cygnus_i2c_regs *reg_addr,
-	struct i2c_seg *segment)
+	struct i2c_msg *segment)
 {
 	int ret;
 
@@ -206,7 +207,7 @@
 		return EBUSY;
 	}
 
-	if (segment->read)
+	if (segment->flags & I2C_M_RD)
 		ret = i2c_read(reg_addr, segment);
 	else
 		ret = i2c_write(reg_addr, segment);
@@ -214,12 +215,13 @@
 	return ret;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
+			  int seg_count)
 {
 	int i;
 	int res = 0;
 	struct cygnus_i2c_regs *regs = i2c_bus[bus];
-	struct i2c_seg *seg = segments;
+	struct i2c_msg *seg = segments;
 
 	for (i = 0; i < seg_count; i++, seg++) {
 		res = i2c_do_xfer(regs, seg);
diff --git a/src/soc/intel/common/block/i2c/lpss_i2c.c b/src/soc/intel/common/block/i2c/lpss_i2c.c
index 5b188f8..711517f 100644
--- a/src/soc/intel/common/block/i2c/lpss_i2c.c
+++ b/src/soc/intel/common/block/i2c/lpss_i2c.c
@@ -258,7 +258,7 @@
 
 /* Transfer one byte of one segment, sending stop bit if requested */
 static int lpss_i2c_transfer_byte(struct lpss_i2c_regs *regs,
-				  struct i2c_seg *segment,
+				  struct i2c_msg *segment,
 				  size_t byte, int send_stop)
 {
 	struct stopwatch sw;
@@ -266,7 +266,7 @@
 
 	stopwatch_init_usecs_expire(&sw, LPSS_I2C_TIMEOUT_US);
 
-	if (!segment->read) {
+	if (!(segment->flags & I2C_M_RD)) {
 		/* Write op only: Wait for FIFO not full */
 		while (!(read32(&regs->status) & STATUS_TX_FIFO_NOT_FULL)) {
 			if (stopwatch_expired(&sw)) {
@@ -283,7 +283,7 @@
 
 	write32(&regs->cmd_data, cmd);
 
-	if (segment->read) {
+	if (segment->flags & I2C_M_RD) {
 		/* Read op only: Wait for FIFO data and store it */
 		while (!(read32(&regs->status) & STATUS_RX_FIFO_NOT_EMPTY)) {
 			if (stopwatch_expired(&sw)) {
@@ -298,7 +298,8 @@
 }
 
 /* Global I2C bus handler, defined in include/i2c.h */
-int platform_i2c_transfer(unsigned int bus, struct i2c_seg *segments, int count)
+int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
+			  int count)
 {
 	struct stopwatch sw;
 	struct lpss_i2c_regs *regs;
@@ -325,11 +326,12 @@
 	while (count--) {
 		if (CONFIG_SOC_INTEL_COMMON_LPSS_I2C_DEBUG)
 			printk(BIOS_DEBUG, "i2c %u:%02x %s %d bytes : ",
-			       bus, segments->chip, segments->read ? "R" : "W",
+			       bus, segments->slave,
+			       (segments->flags & I2C_M_RD) ? "R" : "W",
 			       segments->len);
 
 		/* Set target slave address */
-		write32(&regs->target_addr, segments->chip);
+		write32(&regs->target_addr, segments->slave);
 
 		/* Read or write each byte in segment */
 		for (byte = 0; byte < segments->len; byte++) {
@@ -341,8 +343,9 @@
 			if (lpss_i2c_transfer_byte(regs, segments, byte,
 						   count == 0) < 0) {
 				printk(BIOS_ERR, "I2C %s failed: bus %u "
-				       "addr 0x%02x\n", segments->read ?
-				       "read" : "write", bus, segments->chip);
+				       "addr 0x%02x\n",
+				       (segments->flags & I2C_M_RD) ?
+				       "read" : "write", bus, segments->slave);
 				goto out;
 			}
 		}
diff --git a/src/soc/intel/quark/i2c.c b/src/soc/intel/quark/i2c.c
index 2601738..e8dba53 100644
--- a/src/soc/intel/quark/i2c.c
+++ b/src/soc/intel/quark/i2c.c
@@ -186,8 +186,8 @@
 	return bytes_transferred;
 }
 
-int platform_i2c_transfer(unsigned int bus, struct i2c_seg *segment,
-	int seg_count)
+int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segment,
+			  int seg_count)
 {
 	int bytes_transferred;
 	uint8_t chip;
@@ -212,9 +212,9 @@
 			printk(BIOS_ERR,
 				"I2C segment[%d]: %s 0x%02x %s 0x%p, 0x%08x bytes\n",
 				index,
-				segment[index].read ? "Read from" : "Write to",
-				segment[index].chip,
-				segment[index].read ? "to " : "from",
+				(segment[index].flags & I2C_M_RD) ? "Read from" : "Write to",
+				segment[index].slave,
+				(segment[index].flags & I2C_M_RD) ? "to " : "from",
 				segment[index].buf,
 				segment[index].len);
 			printk(BIOS_ERR, "I2C %s\n",
@@ -243,7 +243,7 @@
 	regs->ic_con = cmd;
 
 	/* Set the target chip address */
-	chip = segment->chip;
+	chip = segment->slave;
 	regs->ic_tar = chip;
 
 	/* Enable the I2C controller */
@@ -270,13 +270,13 @@
 		total_bytes += length;
 		ASSERT(segment->buf != NULL);
 		ASSERT(length >= 1);
-		ASSERT(segment->chip == chip);
+		ASSERT(segment->slave == chip);
 
 		/* Determine if this is the last segment of the transaction */
 		stop = (index == seg_count) ? IC_DATA_CMD_STOP : 0;
 
 		/* Fill the FIFO with the necessary command bytes */
-		if (segment->read) {
+		if (segment->flags & I2C_M_RD) {
 			/* Place read commands into the FIFO */
 			rx_buffer = segment->buf;
 			data_bytes = platform_i2c_read(restart, rx_buffer,
diff --git a/src/soc/mediatek/mt8173/i2c.c b/src/soc/mediatek/mt8173/i2c.c
index f07ffc9..1d541e5 100644
--- a/src/soc/mediatek/mt8173/i2c.c
+++ b/src/soc/mediatek/mt8173/i2c.c
@@ -136,7 +136,7 @@
 	I2CLOG("addr address %x\n", (uint32_t)regs);
 }
 
-static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_seg *seg,
+static uint32_t mtk_i2c_transfer(uint8_t bus, struct i2c_msg *seg,
 				 enum i2c_modes read)
 {
 	uint32_t ret_code = I2C_OK;
@@ -154,7 +154,7 @@
 	regs = i2c[bus].i2c_regs;
 	dma_regs = i2c[bus].i2c_dma_regs;
 
-	addr = seg[0].chip;
+	addr = seg[0].slave;
 
 	switch (read) {
 	case I2C_WRITE_MODE:
@@ -305,26 +305,31 @@
 	return ret_code;
 }
 
-static uint8_t mtk_i2c_should_combine(struct i2c_seg *seg, int left_count)
+static uint8_t mtk_i2c_should_combine(struct i2c_msg *seg, int left_count)
 {
-	if (left_count >= 2 && seg[0].read == 0 && seg[1].read == 1 &&
-	    seg[0].chip == seg[1].chip)
+	if (left_count >= 2 &&
+	    !(seg[0].flags & I2C_M_RD) &&
+	    (seg[1].flags & I2C_M_RD) &&
+	    seg[0].slave == seg[1].slave)
 		return 1;
 	else
 		return 0;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
+			  int seg_count)
 {
 	int ret = 0;
 	int i;
 	int read;
 
 	for (i = 0; i < seg_count; i++) {
-		if (mtk_i2c_should_combine(&segments[i], seg_count - i))
+		if (mtk_i2c_should_combine(&segments[i], seg_count - i)) {
 			read = I2C_WRITE_READ_MODE;
-		else
-			read = segments[i].read;
+		} else {
+			read = (segments[i].flags & I2C_M_RD) ?
+				I2C_READ_MODE : I2C_WRITE_MODE;
+		}
 
 		ret = mtk_i2c_transfer(bus, &segments[i], read);
 
diff --git a/src/soc/nvidia/tegra/i2c.c b/src/soc/nvidia/tegra/i2c.c
index 926b768..e371a9d 100644
--- a/src/soc/nvidia/tegra/i2c.c
+++ b/src/soc/nvidia/tegra/i2c.c
@@ -187,9 +187,9 @@
 	return 0;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count)
 {
-	struct i2c_seg *seg = segments;
+	struct i2c_msg *seg = segments;
 	int i;
 
 	if (bus >= g_num_i2c_buses) {
@@ -199,8 +199,9 @@
 	}
 
 	for (i = 0; i < count; seg++, i++) {
-		if (i2c_transfer_segment(bus, seg->chip, i < count - 1,
-					 seg->read, seg->buf, seg->len))
+		if (i2c_transfer_segment(bus, seg->slave, i < count - 1,
+					 seg->flags & I2C_M_RD,
+					 seg->buf, seg->len))
 			return -1;
 	}
 	return 0;
diff --git a/src/soc/qualcomm/ipq40xx/i2c.c b/src/soc/qualcomm/ipq40xx/i2c.c
index 772bf8b..0cffaac 100644
--- a/src/soc/qualcomm/ipq40xx/i2c.c
+++ b/src/soc/qualcomm/ipq40xx/i2c.c
@@ -155,19 +155,20 @@
 	return 0;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
+			  int seg_count)
 {
-	struct i2c_seg *seg = segments;
+	struct i2c_msg *seg = segments;
 	int ret = 0;
 
 	if (i2c_init(bus))
 		return 1;
 
 	while (!ret && seg_count--) {
-		if (seg->read)
-			ret = i2c_read(bus, seg->chip, seg->buf, seg->len);
+		if (seg->flags & I2C_M_RD)
+			ret = i2c_read(bus, seg->slave, seg->buf, seg->len);
 		else
-			ret = i2c_write(bus, seg->chip, seg->buf, seg->len,
+			ret = i2c_write(bus, seg->slave, seg->buf, seg->len,
 					(seg_count ? 0 : 1));
 		seg++;
 	}
diff --git a/src/soc/qualcomm/ipq806x/i2c.c b/src/soc/qualcomm/ipq806x/i2c.c
index e121ae8..009cb94 100644
--- a/src/soc/qualcomm/ipq806x/i2c.c
+++ b/src/soc/qualcomm/ipq806x/i2c.c
@@ -142,19 +142,20 @@
 	return 0;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
+			  int seg_count)
 {
-	struct i2c_seg *seg = segments;
+	struct i2c_msg *seg = segments;
 	int ret = 0;
 
 	if (i2c_init(bus))
 		return 1;
 
 	while (!ret && seg_count--) {
-		if (seg->read)
-			ret = i2c_read(bus, seg->chip, seg->buf, seg->len);
+		if (seg->flags & I2C_M_RD)
+			ret = i2c_read(bus, seg->slave, seg->buf, seg->len);
 		else
-			ret = i2c_write(bus, seg->chip, seg->buf, seg->len,
+			ret = i2c_write(bus, seg->slave, seg->buf, seg->len,
 					(seg_count ? 0 : 1));
 		seg++;
 	}
diff --git a/src/soc/rockchip/common/i2c.c b/src/soc/rockchip/common/i2c.c
index 032efda..5847f16 100644
--- a/src/soc/rockchip/common/i2c.c
+++ b/src/soc/rockchip/common/i2c.c
@@ -124,7 +124,7 @@
 	return res;
 }
 
-static int i2c_read(struct rk_i2c_regs *reg_addr, struct i2c_seg segment)
+static int i2c_read(struct rk_i2c_regs *reg_addr, struct i2c_msg segment)
 {
 	int res = 0;
 	uint8_t *data = segment.buf;
@@ -136,7 +136,7 @@
 	unsigned int con = 0;
 	unsigned int i, j;
 
-	write32(&reg_addr->i2c_mrxaddr, I2C_8BIT | segment.chip << 1 | 1);
+	write32(&reg_addr->i2c_mrxaddr, I2C_8BIT | segment.slave << 1 | 1);
 	write32(&reg_addr->i2c_mrxraddr, 0);
 	con = I2C_MODE_TRX | I2C_EN | I2C_ACT2NAK;
 	while (bytes_remaining) {
@@ -182,7 +182,7 @@
 	return res;
 }
 
-static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_seg segment)
+static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_msg segment)
 {
 	int res = 0;
 	uint8_t *data = segment.buf;
@@ -194,7 +194,7 @@
 	unsigned int j = 1;
 	u32 txdata = 0;
 
-	txdata |= (segment.chip << 1);
+	txdata |= (segment.slave << 1);
 	while (bytes_remaining) {
 		bytes_transferred = MIN(bytes_remaining, 32);
 		words_transferred = ALIGN_UP(bytes_transferred, 4) / 4;
@@ -239,25 +239,26 @@
 	return res;
 }
 
-static int i2c_do_xfer(void *reg_addr, struct i2c_seg segment)
+static int i2c_do_xfer(void *reg_addr, struct i2c_msg segment)
 {
 	int res = 0;
 
 	if (i2c_send_start(reg_addr))
 		return I2C_TIMEOUT;
-	if (segment.read)
+	if (segment.flags & I2C_M_RD)
 		res = i2c_read(reg_addr, segment);
 	else
 		res = i2c_write(reg_addr, segment);
 	return i2c_send_stop(reg_addr) || res;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
+			  int seg_count)
 {
 	int i;
 	int res = 0;
 	struct rk_i2c_regs *regs = (struct rk_i2c_regs *)(i2c_bus[bus]);
-	struct i2c_seg *seg = segments;
+	struct i2c_msg *seg = segments;
 
 	for (i = 0; i < seg_count; i++, seg++) {
 		res = i2c_do_xfer(regs, *seg);
diff --git a/src/soc/samsung/exynos5250/i2c.c b/src/soc/samsung/exynos5250/i2c.c
index 2f3f28f..6319a10 100644
--- a/src/soc/samsung/exynos5250/i2c.c
+++ b/src/soc/samsung/exynos5250/i2c.c
@@ -234,7 +234,8 @@
 	return 0;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int seg_count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
+			  int seg_count)
 {
 	struct s3c24x0_i2c_bus *i2c = &i2c_busses[bus];
 	struct i2c_regs *regs = i2c->regs;
@@ -247,12 +248,12 @@
 
 	int i;
 	for (i = 0; i < seg_count; i++) {
-		struct i2c_seg *seg = &segments[i];
+		struct i2c_msg *seg = &segments[i];
 
-		res = i2c_send_start(regs, seg->read, seg->chip);
+		res = i2c_send_start(regs, seg->flags & I2C_M_RD, seg->slave);
 		if (res)
 			break;
-		if (seg->read)
+		if (seg->flags & I2C_M_RD)
 			res = i2c_recv_buf(regs, seg->buf, seg->len);
 		else
 			res = i2c_xmit_buf(regs, seg->buf, seg->len);
diff --git a/src/soc/samsung/exynos5420/i2c.c b/src/soc/samsung/exynos5420/i2c.c
index 9a9b197..ae9560f 100644
--- a/src/soc/samsung/exynos5420/i2c.c
+++ b/src/soc/samsung/exynos5420/i2c.c
@@ -445,11 +445,12 @@
 	return len ? -1 : 0;
 }
 
-static int hsi2c_segment(struct i2c_seg *seg, struct hsi2c_regs *regs, int stop)
+static int hsi2c_segment(struct i2c_msg *seg, struct hsi2c_regs *regs,
+			 int stop)
 {
 	const uint32_t usi_ctl = Hsi2cFuncModeI2c | Hsi2cMaster;
 
-	write32(&regs->i2c_addr, HSI2C_SLV_ADDR_MAS(seg->chip));
+	write32(&regs->i2c_addr, HSI2C_SLV_ADDR_MAS(seg->slave));
 
 	/*
 	 * We really only want to stop after this transaction (I think) if the
@@ -461,7 +462,7 @@
 	uint32_t autoconf =
 		seg->len | Hsi2cMasterRun | Hsi2cStopAfterTrans;
 
-	if (seg->read) {
+	if (seg->flags & I2C_M_RD) {
 		write32(&regs->usi_ctl, usi_ctl | Hsi2cRxchon);
 		write32(&regs->i2c_auto_conf, autoconf | Hsi2cReadWrite);
 
@@ -482,7 +483,7 @@
 	return 0;
 }
 
-static int hsi2c_transfer(struct i2c_bus *i2c, struct i2c_seg *segments,
+static int hsi2c_transfer(struct i2c_bus *i2c, struct i2c_msg *segments,
 			  int count)
 {
 	struct hsi2c_regs *regs = i2c->hsregs;
@@ -627,7 +628,7 @@
 	return 0;
 }
 
-int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int count)
+int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count)
 {
 	struct i2c_bus *i2c = &i2c_busses[bus];
 	if (i2c->is_highspeed)
@@ -643,12 +644,12 @@
 
 	int i;
 	for (i = 0; i < count; i++) {
-		struct i2c_seg *seg = &segments[i];
+		struct i2c_msg *seg = &segments[i];
 
-		res = i2c_send_start(regs, seg->read, seg->chip);
+		res = i2c_send_start(regs, seg->flags & I2C_M_RD, seg->slave);
 		if (res)
 			break;
-		if (seg->read)
+		if (seg->flags & I2C_M_RD)
 			res = i2c_recv_buf(regs, seg->buf, seg->len);
 		else
 			res = i2c_xmit_buf(regs, seg->buf, seg->len);