[RFC PATCH linux dev-4.10 5/7] i2c: Add bogus I2C_SMBUS_DWORD_DATA bus protocol/transaction type

Andrew Jeffery andrew at aj.id.au
Fri Jun 2 16:22:05 AEST 2017


Added so we can issue 4-byte read commands without invoking a block
transfer (which requires the length to be sent by the slave in the first
byte). The 0x3040 revision of the MAX31785 firmware can return a 'fast'
rotor read, and does so in this 4-byte format.

Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
---
 drivers/i2c/i2c-core.c   | 30 ++++++++++++++++++++++++++++++
 include/linux/i2c.h      |  2 ++
 include/uapi/linux/i2c.h |  2 ++
 3 files changed, 34 insertions(+)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 583e95042a21..4c8fe52df8ad 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -3210,6 +3210,18 @@ s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
 }
 EXPORT_SYMBOL(i2c_smbus_read_word_data);
 
+s64 i2c_smbus_read_dword_data(const struct i2c_client *client, u8 command)
+{
+	union i2c_smbus_data data;
+	int status;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_READ, command,
+				I2C_SMBUS_DWORD_DATA, &data);
+	return (status < 0) ? status : data.dword;
+}
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
+
 /**
  * i2c_smbus_write_word_data - SMBus "write word" protocol
  * @client: Handle to slave device
@@ -3443,6 +3455,17 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
 				msgbuf0[i] = data->block[i];
 		}
 		break;
+	case I2C_SMBUS_DWORD_DATA:
+		if (read_write == I2C_SMBUS_READ)
+			msg[1].len = 4;
+		else {
+			msg[0].len = 5;
+			msgbuf0[1] = data->dword & 0xff;
+			msgbuf0[2] = (data->dword >> 8) & 0xff;
+			msgbuf0[3] = (data->dword >> 16) & 0xff;
+			msgbuf0[4] = (data->dword >> 24) & 0xff;
+		}
+		break;
 	default:
 		dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
 		return -EOPNOTSUPP;
@@ -3486,6 +3509,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
 		case I2C_SMBUS_PROC_CALL:
 			data->word = msgbuf1[0] | (msgbuf1[1] << 8);
 			break;
+		case I2C_SMBUS_DWORD_DATA:
+			data->dword =
+				(msgbuf1[0] << (0 * 8)) |
+				(msgbuf1[1] << (1 * 8)) |
+				(msgbuf1[2] << (2 * 8)) |
+				(msgbuf1[3] << (3 * 8));
+			break;
 		case I2C_SMBUS_I2C_BLOCK_DATA:
 			for (i = 0; i < data->block[0]; i++)
 				data->block[i+1] = msgbuf1[i];
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 4b45ec46161f..ff15b25bdeda 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -95,6 +95,8 @@ extern s32 i2c_smbus_read_word_data(const struct i2c_client *client,
 				    u8 command);
 extern s32 i2c_smbus_write_word_data(const struct i2c_client *client,
 				     u8 command, u16 value);
+extern s64 i2c_smbus_read_dword_data(const struct i2c_client *client,
+				     u8 command);
 
 static inline s32
 i2c_smbus_read_word_swapped(const struct i2c_client *client, u8 command)
diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
index 009e27bb9abe..63ab01e3faa2 100644
--- a/include/uapi/linux/i2c.h
+++ b/include/uapi/linux/i2c.h
@@ -131,6 +131,7 @@ struct i2c_msg {
 union i2c_smbus_data {
 	__u8 byte;
 	__u16 word;
+	__u32 dword;
 	__u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
 			       /* and one more for user-space compatibility */
 };
@@ -150,5 +151,6 @@ union i2c_smbus_data {
 #define I2C_SMBUS_I2C_BLOCK_BROKEN  6
 #define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
 #define I2C_SMBUS_I2C_BLOCK_DATA    8
+#define I2C_SMBUS_DWORD_DATA	    9
 
 #endif /* _UAPI_LINUX_I2C_H */
-- 
2.11.0



More information about the openbmc mailing list