| // SPDX-License-Identifier: GPL-2.0-or-later | 
 | /* | 
 |  * Linux I2C core SMBus and SMBus emulation code | 
 |  * | 
 |  * This file contains the SMBus functions which are always included in the I2C | 
 |  * core because they can be emulated via I2C. SMBus specific extensions | 
 |  * (e.g. smbalert) are handled in a separate i2c-smbus module. | 
 |  * | 
 |  * All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> | 
 |  * SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and | 
 |  * Jean Delvare <jdelvare@suse.de> | 
 |  */ | 
 | #include <linux/device.h> | 
 | #include <linux/err.h> | 
 | #include <linux/i2c.h> | 
 | #include <linux/i2c-smbus.h> | 
 | #include <linux/property.h> | 
 | #include <linux/slab.h> | 
 | #include <linux/string_choices.h> | 
 |  | 
 | #include "i2c-core.h" | 
 |  | 
 | #define CREATE_TRACE_POINTS | 
 | #include <trace/events/smbus.h> | 
 |  | 
 |  | 
 | /* The SMBus parts */ | 
 |  | 
 | #define POLY    (0x1070U << 3) | 
 | static u8 crc8(u16 data) | 
 | { | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < 8; i++) { | 
 | 		if (data & 0x8000) | 
 | 			data = data ^ POLY; | 
 | 		data = data << 1; | 
 | 	} | 
 | 	return (u8)(data >> 8); | 
 | } | 
 |  | 
 | /** | 
 |  * i2c_smbus_pec - Incremental CRC8 over the given input data array | 
 |  * @crc: previous return crc8 value | 
 |  * @p: pointer to data buffer. | 
 |  * @count: number of bytes in data buffer. | 
 |  * | 
 |  * Incremental CRC8 over count bytes in the array pointed to by p | 
 |  */ | 
 | u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count) | 
 | { | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < count; i++) | 
 | 		crc = crc8((crc ^ p[i]) << 8); | 
 | 	return crc; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_pec); | 
 |  | 
 | /* Assume a 7-bit address, which is reasonable for SMBus */ | 
 | static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg) | 
 | { | 
 | 	/* The address will be sent first */ | 
 | 	u8 addr = i2c_8bit_addr_from_msg(msg); | 
 | 	pec = i2c_smbus_pec(pec, &addr, 1); | 
 |  | 
 | 	/* The data buffer follows */ | 
 | 	return i2c_smbus_pec(pec, msg->buf, msg->len); | 
 | } | 
 |  | 
 | /* Used for write only transactions */ | 
 | static inline void i2c_smbus_add_pec(struct i2c_msg *msg) | 
 | { | 
 | 	msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); | 
 | 	msg->len++; | 
 | } | 
 |  | 
 | /* Return <0 on CRC error | 
 |    If there was a write before this read (most cases) we need to take the | 
 |    partial CRC from the write part into account. | 
 |    Note that this function does modify the message (we need to decrease the | 
 |    message length to hide the CRC byte from the caller). */ | 
 | static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) | 
 | { | 
 | 	u8 rpec = msg->buf[--msg->len]; | 
 | 	cpec = i2c_smbus_msg_pec(cpec, msg); | 
 |  | 
 | 	if (rpec != cpec) { | 
 | 		pr_debug("Bad PEC 0x%02x vs. 0x%02x\n", | 
 | 			rpec, cpec); | 
 | 		return -EBADMSG; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * i2c_smbus_read_byte - SMBus "receive byte" protocol | 
 |  * @client: Handle to slave device | 
 |  * | 
 |  * This executes the SMBus "receive byte" protocol, returning negative errno | 
 |  * else the byte received from the device. | 
 |  */ | 
 | s32 i2c_smbus_read_byte(const struct i2c_client *client) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 | 	int status; | 
 |  | 
 | 	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 				I2C_SMBUS_READ, 0, | 
 | 				I2C_SMBUS_BYTE, &data); | 
 | 	return (status < 0) ? status : data.byte; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_read_byte); | 
 |  | 
 | /** | 
 |  * i2c_smbus_write_byte - SMBus "send byte" protocol | 
 |  * @client: Handle to slave device | 
 |  * @value: Byte to be sent | 
 |  * | 
 |  * This executes the SMBus "send byte" protocol, returning negative errno | 
 |  * else zero on success. | 
 |  */ | 
 | s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value) | 
 | { | 
 | 	return i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 			      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_write_byte); | 
 |  | 
 | /** | 
 |  * i2c_smbus_read_byte_data - SMBus "read byte" protocol | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * | 
 |  * This executes the SMBus "read byte" protocol, returning negative errno | 
 |  * else a data byte received from the device. | 
 |  */ | 
 | s32 i2c_smbus_read_byte_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_BYTE_DATA, &data); | 
 | 	return (status < 0) ? status : data.byte; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_read_byte_data); | 
 |  | 
 | /** | 
 |  * i2c_smbus_write_byte_data - SMBus "write byte" protocol | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * @value: Byte being written | 
 |  * | 
 |  * This executes the SMBus "write byte" protocol, returning negative errno | 
 |  * else zero on success. | 
 |  */ | 
 | s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, | 
 | 			      u8 value) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 | 	data.byte = value; | 
 | 	return i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 			      I2C_SMBUS_WRITE, command, | 
 | 			      I2C_SMBUS_BYTE_DATA, &data); | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_write_byte_data); | 
 |  | 
 | /** | 
 |  * i2c_smbus_read_word_data - SMBus "read word" protocol | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * | 
 |  * This executes the SMBus "read word" protocol, returning negative errno | 
 |  * else a 16-bit unsigned "word" received from the device. | 
 |  */ | 
 | s32 i2c_smbus_read_word_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_WORD_DATA, &data); | 
 | 	return (status < 0) ? status : data.word; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_read_word_data); | 
 |  | 
 | /** | 
 |  * i2c_smbus_write_word_data - SMBus "write word" protocol | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * @value: 16-bit "word" being written | 
 |  * | 
 |  * This executes the SMBus "write word" protocol, returning negative errno | 
 |  * else zero on success. | 
 |  */ | 
 | s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, | 
 | 			      u16 value) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 | 	data.word = value; | 
 | 	return i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 			      I2C_SMBUS_WRITE, command, | 
 | 			      I2C_SMBUS_WORD_DATA, &data); | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_write_word_data); | 
 |  | 
 | /** | 
 |  * i2c_smbus_read_block_data - SMBus "block read" protocol | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * @values: Byte array into which data will be read; big enough to hold | 
 |  *	the data returned by the slave.  SMBus allows at most 32 bytes. | 
 |  * | 
 |  * This executes the SMBus "block read" protocol, returning negative errno | 
 |  * else the number of data bytes in the slave's response. | 
 |  * | 
 |  * Note that using this function requires that the client's adapter support | 
 |  * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality.  Not all adapter drivers | 
 |  * support this; its emulation through I2C messaging relies on a specific | 
 |  * mechanism (I2C_M_RECV_LEN) which may not be implemented. | 
 |  */ | 
 | s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, | 
 | 			      u8 *values) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 | 	int status; | 
 |  | 
 | 	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 				I2C_SMBUS_READ, command, | 
 | 				I2C_SMBUS_BLOCK_DATA, &data); | 
 | 	if (status) | 
 | 		return status; | 
 |  | 
 | 	memcpy(values, &data.block[1], data.block[0]); | 
 | 	return data.block[0]; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_read_block_data); | 
 |  | 
 | /** | 
 |  * i2c_smbus_write_block_data - SMBus "block write" protocol | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * @length: Size of data block; SMBus allows at most 32 bytes | 
 |  * @values: Byte array which will be written. | 
 |  * | 
 |  * This executes the SMBus "block write" protocol, returning negative errno | 
 |  * else zero on success. | 
 |  */ | 
 | s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, | 
 | 			       u8 length, const u8 *values) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 |  | 
 | 	if (length > I2C_SMBUS_BLOCK_MAX) | 
 | 		length = I2C_SMBUS_BLOCK_MAX; | 
 | 	data.block[0] = length; | 
 | 	memcpy(&data.block[1], values, length); | 
 | 	return i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 			      I2C_SMBUS_WRITE, command, | 
 | 			      I2C_SMBUS_BLOCK_DATA, &data); | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_write_block_data); | 
 |  | 
 | /* Returns the number of read bytes */ | 
 | s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, | 
 | 				  u8 length, u8 *values) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 | 	int status; | 
 |  | 
 | 	if (length > I2C_SMBUS_BLOCK_MAX) | 
 | 		length = I2C_SMBUS_BLOCK_MAX; | 
 | 	data.block[0] = length; | 
 | 	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 				I2C_SMBUS_READ, command, | 
 | 				I2C_SMBUS_I2C_BLOCK_DATA, &data); | 
 | 	if (status < 0) | 
 | 		return status; | 
 |  | 
 | 	memcpy(values, &data.block[1], data.block[0]); | 
 | 	return data.block[0]; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); | 
 |  | 
 | s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, | 
 | 				   u8 length, const u8 *values) | 
 | { | 
 | 	union i2c_smbus_data data; | 
 |  | 
 | 	if (length > I2C_SMBUS_BLOCK_MAX) | 
 | 		length = I2C_SMBUS_BLOCK_MAX; | 
 | 	data.block[0] = length; | 
 | 	memcpy(data.block + 1, values, length); | 
 | 	return i2c_smbus_xfer(client->adapter, client->addr, client->flags, | 
 | 			      I2C_SMBUS_WRITE, command, | 
 | 			      I2C_SMBUS_I2C_BLOCK_DATA, &data); | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); | 
 |  | 
 | static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val) | 
 | { | 
 | 	bool is_read = msg->flags & I2C_M_RD; | 
 | 	unsigned char *dma_buf; | 
 |  | 
 | 	dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL); | 
 | 	if (!dma_buf) | 
 | 		return; | 
 |  | 
 | 	msg->buf = dma_buf; | 
 | 	msg->flags |= I2C_M_DMA_SAFE; | 
 |  | 
 | 	if (init_val) | 
 | 		msg->buf[0] = init_val; | 
 | } | 
 |  | 
 | /* | 
 |  * Simulate a SMBus command using the I2C protocol. | 
 |  * No checking of parameters is done! | 
 |  */ | 
 | static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, | 
 | 				   unsigned short flags, | 
 | 				   char read_write, u8 command, int size, | 
 | 				   union i2c_smbus_data *data) | 
 | { | 
 | 	/* | 
 | 	 * So we need to generate a series of msgs. In the case of writing, we | 
 | 	 * need to use only one message; when reading, we need two. We | 
 | 	 * initialize most things with sane defaults, to keep the code below | 
 | 	 * somewhat simpler. | 
 | 	 */ | 
 | 	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; | 
 | 	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; | 
 | 	int nmsgs = read_write == I2C_SMBUS_READ ? 2 : 1; | 
 | 	u8 partial_pec = 0; | 
 | 	int status; | 
 | 	struct i2c_msg msg[2] = { | 
 | 		{ | 
 | 			.addr = addr, | 
 | 			.flags = flags, | 
 | 			.len = 1, | 
 | 			.buf = msgbuf0, | 
 | 		}, { | 
 | 			.addr = addr, | 
 | 			.flags = flags | I2C_M_RD, | 
 | 			.len = 0, | 
 | 			.buf = msgbuf1, | 
 | 		}, | 
 | 	}; | 
 | 	bool wants_pec = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK | 
 | 			  && size != I2C_SMBUS_I2C_BLOCK_DATA); | 
 |  | 
 | 	msgbuf0[0] = command; | 
 | 	switch (size) { | 
 | 	case I2C_SMBUS_QUICK: | 
 | 		msg[0].len = 0; | 
 | 		/* Special case: The read/write field is used as data */ | 
 | 		msg[0].flags = flags | (read_write == I2C_SMBUS_READ ? | 
 | 					I2C_M_RD : 0); | 
 | 		nmsgs = 1; | 
 | 		break; | 
 | 	case I2C_SMBUS_BYTE: | 
 | 		if (read_write == I2C_SMBUS_READ) { | 
 | 			/* Special case: only a read! */ | 
 | 			msg[0].flags = I2C_M_RD | flags; | 
 | 			nmsgs = 1; | 
 | 		} | 
 | 		break; | 
 | 	case I2C_SMBUS_BYTE_DATA: | 
 | 		if (read_write == I2C_SMBUS_READ) | 
 | 			msg[1].len = 1; | 
 | 		else { | 
 | 			msg[0].len = 2; | 
 | 			msgbuf0[1] = data->byte; | 
 | 		} | 
 | 		break; | 
 | 	case I2C_SMBUS_WORD_DATA: | 
 | 		if (read_write == I2C_SMBUS_READ) | 
 | 			msg[1].len = 2; | 
 | 		else { | 
 | 			msg[0].len = 3; | 
 | 			msgbuf0[1] = data->word & 0xff; | 
 | 			msgbuf0[2] = data->word >> 8; | 
 | 		} | 
 | 		break; | 
 | 	case I2C_SMBUS_PROC_CALL: | 
 | 		nmsgs = 2; /* Special case */ | 
 | 		read_write = I2C_SMBUS_READ; | 
 | 		msg[0].len = 3; | 
 | 		msg[1].len = 2; | 
 | 		msgbuf0[1] = data->word & 0xff; | 
 | 		msgbuf0[2] = data->word >> 8; | 
 | 		break; | 
 | 	case I2C_SMBUS_BLOCK_DATA: | 
 | 		if (read_write == I2C_SMBUS_READ) { | 
 | 			msg[1].flags |= I2C_M_RECV_LEN; | 
 | 			msg[1].len = 1; /* block length will be added by | 
 | 					   the underlying bus driver */ | 
 | 			i2c_smbus_try_get_dmabuf(&msg[1], 0); | 
 | 		} else { | 
 | 			msg[0].len = data->block[0] + 2; | 
 | 			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { | 
 | 				dev_err(&adapter->dev, | 
 | 					"Invalid block write size %d\n", | 
 | 					data->block[0]); | 
 | 				return -EINVAL; | 
 | 			} | 
 |  | 
 | 			i2c_smbus_try_get_dmabuf(&msg[0], command); | 
 | 			memcpy(msg[0].buf + 1, data->block, msg[0].len - 1); | 
 | 		} | 
 | 		break; | 
 | 	case I2C_SMBUS_BLOCK_PROC_CALL: | 
 | 		nmsgs = 2; /* Another special case */ | 
 | 		read_write = I2C_SMBUS_READ; | 
 | 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { | 
 | 			dev_err(&adapter->dev, | 
 | 				"Invalid block write size %d\n", | 
 | 				data->block[0]); | 
 | 			return -EINVAL; | 
 | 		} | 
 |  | 
 | 		msg[0].len = data->block[0] + 2; | 
 | 		i2c_smbus_try_get_dmabuf(&msg[0], command); | 
 | 		memcpy(msg[0].buf + 1, data->block, msg[0].len - 1); | 
 |  | 
 | 		msg[1].flags |= I2C_M_RECV_LEN; | 
 | 		msg[1].len = 1; /* block length will be added by | 
 | 				   the underlying bus driver */ | 
 | 		i2c_smbus_try_get_dmabuf(&msg[1], 0); | 
 | 		break; | 
 | 	case I2C_SMBUS_I2C_BLOCK_DATA: | 
 | 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { | 
 | 			dev_err(&adapter->dev, "Invalid block %s size %d\n", | 
 | 				str_read_write(read_write == I2C_SMBUS_READ), | 
 | 				data->block[0]); | 
 | 			return -EINVAL; | 
 | 		} | 
 |  | 
 | 		if (read_write == I2C_SMBUS_READ) { | 
 | 			msg[1].len = data->block[0]; | 
 | 			i2c_smbus_try_get_dmabuf(&msg[1], 0); | 
 | 		} else { | 
 | 			msg[0].len = data->block[0] + 1; | 
 |  | 
 | 			i2c_smbus_try_get_dmabuf(&msg[0], command); | 
 | 			memcpy(msg[0].buf + 1, data->block + 1, data->block[0]); | 
 | 		} | 
 | 		break; | 
 | 	default: | 
 | 		dev_err(&adapter->dev, "Unsupported transaction %d\n", size); | 
 | 		return -EOPNOTSUPP; | 
 | 	} | 
 |  | 
 | 	if (wants_pec) { | 
 | 		/* Compute PEC if first message is a write */ | 
 | 		if (!(msg[0].flags & I2C_M_RD)) { | 
 | 			if (nmsgs == 1) /* Write only */ | 
 | 				i2c_smbus_add_pec(&msg[0]); | 
 | 			else /* Write followed by read */ | 
 | 				partial_pec = i2c_smbus_msg_pec(0, &msg[0]); | 
 | 		} | 
 | 		/* Ask for PEC if last message is a read */ | 
 | 		if (msg[nmsgs - 1].flags & I2C_M_RD) | 
 | 			msg[nmsgs - 1].len++; | 
 | 	} | 
 |  | 
 | 	status = __i2c_transfer(adapter, msg, nmsgs); | 
 | 	if (status < 0) | 
 | 		goto cleanup; | 
 | 	if (status != nmsgs) { | 
 | 		status = -EIO; | 
 | 		goto cleanup; | 
 | 	} | 
 | 	status = 0; | 
 |  | 
 | 	/* Check PEC if last message is a read */ | 
 | 	if (wants_pec && (msg[nmsgs - 1].flags & I2C_M_RD)) { | 
 | 		status = i2c_smbus_check_pec(partial_pec, &msg[nmsgs - 1]); | 
 | 		if (status < 0) | 
 | 			goto cleanup; | 
 | 	} | 
 |  | 
 | 	if (read_write == I2C_SMBUS_READ) | 
 | 		switch (size) { | 
 | 		case I2C_SMBUS_BYTE: | 
 | 			data->byte = msgbuf0[0]; | 
 | 			break; | 
 | 		case I2C_SMBUS_BYTE_DATA: | 
 | 			data->byte = msgbuf1[0]; | 
 | 			break; | 
 | 		case I2C_SMBUS_WORD_DATA: | 
 | 		case I2C_SMBUS_PROC_CALL: | 
 | 			data->word = msgbuf1[0] | (msgbuf1[1] << 8); | 
 | 			break; | 
 | 		case I2C_SMBUS_I2C_BLOCK_DATA: | 
 | 			memcpy(data->block + 1, msg[1].buf, data->block[0]); | 
 | 			break; | 
 | 		case I2C_SMBUS_BLOCK_DATA: | 
 | 		case I2C_SMBUS_BLOCK_PROC_CALL: | 
 | 			if (msg[1].buf[0] > I2C_SMBUS_BLOCK_MAX) { | 
 | 				dev_err(&adapter->dev, | 
 | 					"Invalid block size returned: %d\n", | 
 | 					msg[1].buf[0]); | 
 | 				status = -EPROTO; | 
 | 				goto cleanup; | 
 | 			} | 
 | 			memcpy(data->block, msg[1].buf, msg[1].buf[0] + 1); | 
 | 			break; | 
 | 		} | 
 |  | 
 | cleanup: | 
 | 	if (msg[0].flags & I2C_M_DMA_SAFE) | 
 | 		kfree(msg[0].buf); | 
 | 	if (msg[1].flags & I2C_M_DMA_SAFE) | 
 | 		kfree(msg[1].buf); | 
 |  | 
 | 	return status; | 
 | } | 
 |  | 
 | /** | 
 |  * i2c_smbus_xfer - execute SMBus protocol operations | 
 |  * @adapter: Handle to I2C bus | 
 |  * @addr: Address of SMBus slave on that bus | 
 |  * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC) | 
 |  * @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE | 
 |  * @command: Byte interpreted by slave, for protocols which use such bytes | 
 |  * @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL | 
 |  * @data: Data to be read or written | 
 |  * | 
 |  * This executes an SMBus protocol operation, and returns a negative | 
 |  * errno code else zero on success. | 
 |  */ | 
 | s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | 
 | 		   unsigned short flags, char read_write, | 
 | 		   u8 command, int protocol, union i2c_smbus_data *data) | 
 | { | 
 | 	s32 res; | 
 |  | 
 | 	res = __i2c_lock_bus_helper(adapter); | 
 | 	if (res) | 
 | 		return res; | 
 |  | 
 | 	res = __i2c_smbus_xfer(adapter, addr, flags, read_write, | 
 | 			       command, protocol, data); | 
 | 	i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); | 
 |  | 
 | 	return res; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_xfer); | 
 |  | 
 | s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | 
 | 		     unsigned short flags, char read_write, | 
 | 		     u8 command, int protocol, union i2c_smbus_data *data) | 
 | { | 
 | 	int (*xfer_func)(struct i2c_adapter *adap, u16 addr, | 
 | 			 unsigned short flags, char read_write, | 
 | 			 u8 command, int size, union i2c_smbus_data *data); | 
 | 	unsigned long orig_jiffies; | 
 | 	int try; | 
 | 	s32 res; | 
 |  | 
 | 	res = __i2c_check_suspended(adapter); | 
 | 	if (res) | 
 | 		return res; | 
 |  | 
 | 	/* If enabled, the following two tracepoints are conditional on | 
 | 	 * read_write and protocol. | 
 | 	 */ | 
 | 	trace_smbus_write(adapter, addr, flags, read_write, | 
 | 			  command, protocol, data); | 
 | 	trace_smbus_read(adapter, addr, flags, read_write, | 
 | 			 command, protocol); | 
 |  | 
 | 	flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; | 
 |  | 
 | 	xfer_func = adapter->algo->smbus_xfer; | 
 | 	if (i2c_in_atomic_xfer_mode()) { | 
 | 		if (adapter->algo->smbus_xfer_atomic) | 
 | 			xfer_func = adapter->algo->smbus_xfer_atomic; | 
 | 		else if (adapter->algo->master_xfer_atomic) | 
 | 			xfer_func = NULL; /* fallback to I2C emulation */ | 
 | 	} | 
 |  | 
 | 	if (xfer_func) { | 
 | 		/* Retry automatically on arbitration loss */ | 
 | 		orig_jiffies = jiffies; | 
 | 		for (res = 0, try = 0; try <= adapter->retries; try++) { | 
 | 			res = xfer_func(adapter, addr, flags, read_write, | 
 | 					command, protocol, data); | 
 | 			if (res != -EAGAIN) | 
 | 				break; | 
 | 			if (time_after(jiffies, | 
 | 				       orig_jiffies + adapter->timeout)) | 
 | 				break; | 
 | 		} | 
 |  | 
 | 		if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) | 
 | 			goto trace; | 
 | 		/* | 
 | 		 * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't | 
 | 		 * implement native support for the SMBus operation. | 
 | 		 */ | 
 | 	} | 
 |  | 
 | 	res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, | 
 | 				      command, protocol, data); | 
 |  | 
 | trace: | 
 | 	/* If enabled, the reply tracepoint is conditional on read_write. */ | 
 | 	trace_smbus_reply(adapter, addr, flags, read_write, | 
 | 			  command, protocol, data, res); | 
 | 	trace_smbus_result(adapter, addr, flags, read_write, | 
 | 			   command, protocol, res); | 
 |  | 
 | 	return res; | 
 | } | 
 | EXPORT_SYMBOL(__i2c_smbus_xfer); | 
 |  | 
 | /** | 
 |  * i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate | 
 |  * @client: Handle to slave device | 
 |  * @command: Byte interpreted by slave | 
 |  * @length: Size of data block; SMBus allows at most I2C_SMBUS_BLOCK_MAX bytes | 
 |  * @values: Byte array into which data will be read; big enough to hold | 
 |  *	the data returned by the slave.  SMBus allows at most | 
 |  *	I2C_SMBUS_BLOCK_MAX bytes. | 
 |  * | 
 |  * This executes the SMBus "block read" protocol if supported by the adapter. | 
 |  * If block read is not supported, it emulates it using either word or byte | 
 |  * read protocols depending on availability. | 
 |  * | 
 |  * The addresses of the I2C slave device that are accessed with this function | 
 |  * must be mapped to a linear region, so that a block read will have the same | 
 |  * effect as a byte read. Before using this function you must double-check | 
 |  * if the I2C slave does support exchanging a block transfer with a byte | 
 |  * transfer. | 
 |  */ | 
 | s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, | 
 | 					      u8 command, u8 length, u8 *values) | 
 | { | 
 | 	u8 i = 0; | 
 | 	int status; | 
 |  | 
 | 	if (length > I2C_SMBUS_BLOCK_MAX) | 
 | 		length = I2C_SMBUS_BLOCK_MAX; | 
 |  | 
 | 	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) | 
 | 		return i2c_smbus_read_i2c_block_data(client, command, length, values); | 
 |  | 
 | 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) | 
 | 		return -EOPNOTSUPP; | 
 |  | 
 | 	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) { | 
 | 		while ((i + 2) <= length) { | 
 | 			status = i2c_smbus_read_word_data(client, command + i); | 
 | 			if (status < 0) | 
 | 				return status; | 
 | 			values[i] = status & 0xff; | 
 | 			values[i + 1] = status >> 8; | 
 | 			i += 2; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	while (i < length) { | 
 | 		status = i2c_smbus_read_byte_data(client, command + i); | 
 | 		if (status < 0) | 
 | 			return status; | 
 | 		values[i] = status; | 
 | 		i++; | 
 | 	} | 
 |  | 
 | 	return i; | 
 | } | 
 | EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); | 
 |  | 
 | /** | 
 |  * i2c_new_smbus_alert_device - get ara client for SMBus alert support | 
 |  * @adapter: the target adapter | 
 |  * @setup: setup data for the SMBus alert handler | 
 |  * Context: can sleep | 
 |  * | 
 |  * Setup handling of the SMBus alert protocol on a given I2C bus segment. | 
 |  * | 
 |  * Handling can be done either through our IRQ handler, or by the | 
 |  * adapter (from its handler, periodic polling, or whatever). | 
 |  * | 
 |  * This returns the ara client, which should be saved for later use with | 
 |  * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or an | 
 |  * ERRPTR to indicate an error. | 
 |  */ | 
 | struct i2c_client *i2c_new_smbus_alert_device(struct i2c_adapter *adapter, | 
 | 					      struct i2c_smbus_alert_setup *setup) | 
 | { | 
 | 	struct i2c_board_info ara_board_info = { | 
 | 		I2C_BOARD_INFO("smbus_alert", 0x0c), | 
 | 		.platform_data = setup, | 
 | 	}; | 
 |  | 
 | 	return i2c_new_client_device(adapter, &ara_board_info); | 
 | } | 
 | EXPORT_SYMBOL_GPL(i2c_new_smbus_alert_device); | 
 |  | 
 | #if IS_ENABLED(CONFIG_I2C_SMBUS) | 
 | int i2c_setup_smbus_alert(struct i2c_adapter *adapter) | 
 | { | 
 | 	struct device *parent = adapter->dev.parent; | 
 | 	int irq; | 
 |  | 
 | 	/* Adapter instantiated without parent, skip the SMBus alert setup */ | 
 | 	if (!parent) | 
 | 		return 0; | 
 |  | 
 | 	/* Report serious errors */ | 
 | 	irq = device_property_match_string(parent, "interrupt-names", "smbus_alert"); | 
 | 	if (irq < 0 && irq != -EINVAL && irq != -ENODATA) | 
 | 		return irq; | 
 |  | 
 | 	/* Skip setup when no irq was found */ | 
 | 	if (irq < 0 && !device_property_present(parent, "smbalert-gpios")) | 
 | 		return 0; | 
 |  | 
 | 	return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); | 
 | } | 
 | #endif |