18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux I2C core SMBus and SMBus emulation code 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains the SMBus functions which are always included in the I2C 68c2ecf20Sopenharmony_ci * core because they can be emulated via I2C. SMBus specific extensions 78c2ecf20Sopenharmony_ci * (e.g. smbalert) are handled in a separate i2c-smbus module. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> 108c2ecf20Sopenharmony_ci * SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and 118c2ecf20Sopenharmony_ci * Jean Delvare <jdelvare@suse.de> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c-smbus.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "i2c-core.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 228c2ecf20Sopenharmony_ci#include <trace/events/smbus.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* The SMBus parts */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define POLY (0x1070U << 3) 288c2ecf20Sopenharmony_cistatic u8 crc8(u16 data) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci int i; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 338c2ecf20Sopenharmony_ci if (data & 0x8000) 348c2ecf20Sopenharmony_ci data = data ^ POLY; 358c2ecf20Sopenharmony_ci data = data << 1; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci return (u8)(data >> 8); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Incremental CRC8 over count bytes in the array pointed to by p */ 418c2ecf20Sopenharmony_cistatic u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int i; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 468c2ecf20Sopenharmony_ci crc = crc8((crc ^ p[i]) << 8); 478c2ecf20Sopenharmony_ci return crc; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* Assume a 7-bit address, which is reasonable for SMBus */ 518c2ecf20Sopenharmony_cistatic u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci /* The address will be sent first */ 548c2ecf20Sopenharmony_ci u8 addr = i2c_8bit_addr_from_msg(msg); 558c2ecf20Sopenharmony_ci pec = i2c_smbus_pec(pec, &addr, 1); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* The data buffer follows */ 588c2ecf20Sopenharmony_ci return i2c_smbus_pec(pec, msg->buf, msg->len); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* Used for write only transactions */ 628c2ecf20Sopenharmony_cistatic inline void i2c_smbus_add_pec(struct i2c_msg *msg) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); 658c2ecf20Sopenharmony_ci msg->len++; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Return <0 on CRC error 698c2ecf20Sopenharmony_ci If there was a write before this read (most cases) we need to take the 708c2ecf20Sopenharmony_ci partial CRC from the write part into account. 718c2ecf20Sopenharmony_ci Note that this function does modify the message (we need to decrease the 728c2ecf20Sopenharmony_ci message length to hide the CRC byte from the caller). */ 738c2ecf20Sopenharmony_cistatic int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci u8 rpec = msg->buf[--msg->len]; 768c2ecf20Sopenharmony_ci cpec = i2c_smbus_msg_pec(cpec, msg); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (rpec != cpec) { 798c2ecf20Sopenharmony_ci pr_debug("Bad PEC 0x%02x vs. 0x%02x\n", 808c2ecf20Sopenharmony_ci rpec, cpec); 818c2ecf20Sopenharmony_ci return -EBADMSG; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * i2c_smbus_read_byte - SMBus "receive byte" protocol 888c2ecf20Sopenharmony_ci * @client: Handle to slave device 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * This executes the SMBus "receive byte" protocol, returning negative errno 918c2ecf20Sopenharmony_ci * else the byte received from the device. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cis32 i2c_smbus_read_byte(const struct i2c_client *client) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci union i2c_smbus_data data; 968c2ecf20Sopenharmony_ci int status; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, 998c2ecf20Sopenharmony_ci I2C_SMBUS_READ, 0, 1008c2ecf20Sopenharmony_ci I2C_SMBUS_BYTE, &data); 1018c2ecf20Sopenharmony_ci return (status < 0) ? status : data.byte; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_read_byte); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/** 1068c2ecf20Sopenharmony_ci * i2c_smbus_write_byte - SMBus "send byte" protocol 1078c2ecf20Sopenharmony_ci * @client: Handle to slave device 1088c2ecf20Sopenharmony_ci * @value: Byte to be sent 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * This executes the SMBus "send byte" protocol, returning negative errno 1118c2ecf20Sopenharmony_ci * else zero on success. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_cis32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 1168c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_write_byte); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * i2c_smbus_read_byte_data - SMBus "read byte" protocol 1228c2ecf20Sopenharmony_ci * @client: Handle to slave device 1238c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * This executes the SMBus "read byte" protocol, returning negative errno 1268c2ecf20Sopenharmony_ci * else a data byte received from the device. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_cis32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci union i2c_smbus_data data; 1318c2ecf20Sopenharmony_ci int status; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, 1348c2ecf20Sopenharmony_ci I2C_SMBUS_READ, command, 1358c2ecf20Sopenharmony_ci I2C_SMBUS_BYTE_DATA, &data); 1368c2ecf20Sopenharmony_ci return (status < 0) ? status : data.byte; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_read_byte_data); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/** 1418c2ecf20Sopenharmony_ci * i2c_smbus_write_byte_data - SMBus "write byte" protocol 1428c2ecf20Sopenharmony_ci * @client: Handle to slave device 1438c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 1448c2ecf20Sopenharmony_ci * @value: Byte being written 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * This executes the SMBus "write byte" protocol, returning negative errno 1478c2ecf20Sopenharmony_ci * else zero on success. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cis32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, 1508c2ecf20Sopenharmony_ci u8 value) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci union i2c_smbus_data data; 1538c2ecf20Sopenharmony_ci data.byte = value; 1548c2ecf20Sopenharmony_ci return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 1558c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, command, 1568c2ecf20Sopenharmony_ci I2C_SMBUS_BYTE_DATA, &data); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_write_byte_data); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * i2c_smbus_read_word_data - SMBus "read word" protocol 1628c2ecf20Sopenharmony_ci * @client: Handle to slave device 1638c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * This executes the SMBus "read word" protocol, returning negative errno 1668c2ecf20Sopenharmony_ci * else a 16-bit unsigned "word" received from the device. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cis32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci union i2c_smbus_data data; 1718c2ecf20Sopenharmony_ci int status; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, 1748c2ecf20Sopenharmony_ci I2C_SMBUS_READ, command, 1758c2ecf20Sopenharmony_ci I2C_SMBUS_WORD_DATA, &data); 1768c2ecf20Sopenharmony_ci return (status < 0) ? status : data.word; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_read_word_data); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/** 1818c2ecf20Sopenharmony_ci * i2c_smbus_write_word_data - SMBus "write word" protocol 1828c2ecf20Sopenharmony_ci * @client: Handle to slave device 1838c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 1848c2ecf20Sopenharmony_ci * @value: 16-bit "word" being written 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * This executes the SMBus "write word" protocol, returning negative errno 1878c2ecf20Sopenharmony_ci * else zero on success. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cis32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, 1908c2ecf20Sopenharmony_ci u16 value) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci union i2c_smbus_data data; 1938c2ecf20Sopenharmony_ci data.word = value; 1948c2ecf20Sopenharmony_ci return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 1958c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, command, 1968c2ecf20Sopenharmony_ci I2C_SMBUS_WORD_DATA, &data); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_write_word_data); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci/** 2018c2ecf20Sopenharmony_ci * i2c_smbus_read_block_data - SMBus "block read" protocol 2028c2ecf20Sopenharmony_ci * @client: Handle to slave device 2038c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 2048c2ecf20Sopenharmony_ci * @values: Byte array into which data will be read; big enough to hold 2058c2ecf20Sopenharmony_ci * the data returned by the slave. SMBus allows at most 32 bytes. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * This executes the SMBus "block read" protocol, returning negative errno 2088c2ecf20Sopenharmony_ci * else the number of data bytes in the slave's response. 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Note that using this function requires that the client's adapter support 2118c2ecf20Sopenharmony_ci * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers 2128c2ecf20Sopenharmony_ci * support this; its emulation through I2C messaging relies on a specific 2138c2ecf20Sopenharmony_ci * mechanism (I2C_M_RECV_LEN) which may not be implemented. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_cis32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, 2168c2ecf20Sopenharmony_ci u8 *values) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci union i2c_smbus_data data; 2198c2ecf20Sopenharmony_ci int status; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, 2228c2ecf20Sopenharmony_ci I2C_SMBUS_READ, command, 2238c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_DATA, &data); 2248c2ecf20Sopenharmony_ci if (status) 2258c2ecf20Sopenharmony_ci return status; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci memcpy(values, &data.block[1], data.block[0]); 2288c2ecf20Sopenharmony_ci return data.block[0]; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_read_block_data); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/** 2338c2ecf20Sopenharmony_ci * i2c_smbus_write_block_data - SMBus "block write" protocol 2348c2ecf20Sopenharmony_ci * @client: Handle to slave device 2358c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 2368c2ecf20Sopenharmony_ci * @length: Size of data block; SMBus allows at most 32 bytes 2378c2ecf20Sopenharmony_ci * @values: Byte array which will be written. 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * This executes the SMBus "block write" protocol, returning negative errno 2408c2ecf20Sopenharmony_ci * else zero on success. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_cis32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, 2438c2ecf20Sopenharmony_ci u8 length, const u8 *values) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci union i2c_smbus_data data; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (length > I2C_SMBUS_BLOCK_MAX) 2488c2ecf20Sopenharmony_ci length = I2C_SMBUS_BLOCK_MAX; 2498c2ecf20Sopenharmony_ci data.block[0] = length; 2508c2ecf20Sopenharmony_ci memcpy(&data.block[1], values, length); 2518c2ecf20Sopenharmony_ci return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 2528c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, command, 2538c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_DATA, &data); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_write_block_data); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* Returns the number of read bytes */ 2588c2ecf20Sopenharmony_cis32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, 2598c2ecf20Sopenharmony_ci u8 length, u8 *values) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci union i2c_smbus_data data; 2628c2ecf20Sopenharmony_ci int status; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (length > I2C_SMBUS_BLOCK_MAX) 2658c2ecf20Sopenharmony_ci length = I2C_SMBUS_BLOCK_MAX; 2668c2ecf20Sopenharmony_ci data.block[0] = length; 2678c2ecf20Sopenharmony_ci status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, 2688c2ecf20Sopenharmony_ci I2C_SMBUS_READ, command, 2698c2ecf20Sopenharmony_ci I2C_SMBUS_I2C_BLOCK_DATA, &data); 2708c2ecf20Sopenharmony_ci if (status < 0) 2718c2ecf20Sopenharmony_ci return status; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci memcpy(values, &data.block[1], data.block[0]); 2748c2ecf20Sopenharmony_ci return data.block[0]; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cis32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, 2798c2ecf20Sopenharmony_ci u8 length, const u8 *values) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci union i2c_smbus_data data; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (length > I2C_SMBUS_BLOCK_MAX) 2848c2ecf20Sopenharmony_ci length = I2C_SMBUS_BLOCK_MAX; 2858c2ecf20Sopenharmony_ci data.block[0] = length; 2868c2ecf20Sopenharmony_ci memcpy(data.block + 1, values, length); 2878c2ecf20Sopenharmony_ci return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 2888c2ecf20Sopenharmony_ci I2C_SMBUS_WRITE, command, 2898c2ecf20Sopenharmony_ci I2C_SMBUS_I2C_BLOCK_DATA, &data); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci bool is_read = msg->flags & I2C_M_RD; 2968c2ecf20Sopenharmony_ci unsigned char *dma_buf; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL); 2998c2ecf20Sopenharmony_ci if (!dma_buf) 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci msg->buf = dma_buf; 3038c2ecf20Sopenharmony_ci msg->flags |= I2C_M_DMA_SAFE; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (init_val) 3068c2ecf20Sopenharmony_ci msg->buf[0] = init_val; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* 3108c2ecf20Sopenharmony_ci * Simulate a SMBus command using the I2C protocol. 3118c2ecf20Sopenharmony_ci * No checking of parameters is done! 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_cistatic s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, 3148c2ecf20Sopenharmony_ci unsigned short flags, 3158c2ecf20Sopenharmony_ci char read_write, u8 command, int size, 3168c2ecf20Sopenharmony_ci union i2c_smbus_data *data) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * So we need to generate a series of msgs. In the case of writing, we 3208c2ecf20Sopenharmony_ci * need to use only one message; when reading, we need two. We 3218c2ecf20Sopenharmony_ci * initialize most things with sane defaults, to keep the code below 3228c2ecf20Sopenharmony_ci * somewhat simpler. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; 3258c2ecf20Sopenharmony_ci unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; 3268c2ecf20Sopenharmony_ci int num = read_write == I2C_SMBUS_READ ? 2 : 1; 3278c2ecf20Sopenharmony_ci int i; 3288c2ecf20Sopenharmony_ci u8 partial_pec = 0; 3298c2ecf20Sopenharmony_ci int status; 3308c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 3318c2ecf20Sopenharmony_ci { 3328c2ecf20Sopenharmony_ci .addr = addr, 3338c2ecf20Sopenharmony_ci .flags = flags, 3348c2ecf20Sopenharmony_ci .len = 1, 3358c2ecf20Sopenharmony_ci .buf = msgbuf0, 3368c2ecf20Sopenharmony_ci }, { 3378c2ecf20Sopenharmony_ci .addr = addr, 3388c2ecf20Sopenharmony_ci .flags = flags | I2C_M_RD, 3398c2ecf20Sopenharmony_ci .len = 0, 3408c2ecf20Sopenharmony_ci .buf = msgbuf1, 3418c2ecf20Sopenharmony_ci }, 3428c2ecf20Sopenharmony_ci }; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci msgbuf0[0] = command; 3458c2ecf20Sopenharmony_ci switch (size) { 3468c2ecf20Sopenharmony_ci case I2C_SMBUS_QUICK: 3478c2ecf20Sopenharmony_ci msg[0].len = 0; 3488c2ecf20Sopenharmony_ci /* Special case: The read/write field is used as data */ 3498c2ecf20Sopenharmony_ci msg[0].flags = flags | (read_write == I2C_SMBUS_READ ? 3508c2ecf20Sopenharmony_ci I2C_M_RD : 0); 3518c2ecf20Sopenharmony_ci num = 1; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 3548c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 3558c2ecf20Sopenharmony_ci /* Special case: only a read! */ 3568c2ecf20Sopenharmony_ci msg[0].flags = I2C_M_RD | flags; 3578c2ecf20Sopenharmony_ci num = 1; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 3618c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) 3628c2ecf20Sopenharmony_ci msg[1].len = 1; 3638c2ecf20Sopenharmony_ci else { 3648c2ecf20Sopenharmony_ci msg[0].len = 2; 3658c2ecf20Sopenharmony_ci msgbuf0[1] = data->byte; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 3698c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) 3708c2ecf20Sopenharmony_ci msg[1].len = 2; 3718c2ecf20Sopenharmony_ci else { 3728c2ecf20Sopenharmony_ci msg[0].len = 3; 3738c2ecf20Sopenharmony_ci msgbuf0[1] = data->word & 0xff; 3748c2ecf20Sopenharmony_ci msgbuf0[2] = data->word >> 8; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case I2C_SMBUS_PROC_CALL: 3788c2ecf20Sopenharmony_ci num = 2; /* Special case */ 3798c2ecf20Sopenharmony_ci read_write = I2C_SMBUS_READ; 3808c2ecf20Sopenharmony_ci msg[0].len = 3; 3818c2ecf20Sopenharmony_ci msg[1].len = 2; 3828c2ecf20Sopenharmony_ci msgbuf0[1] = data->word & 0xff; 3838c2ecf20Sopenharmony_ci msgbuf0[2] = data->word >> 8; 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 3868c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 3878c2ecf20Sopenharmony_ci msg[1].flags |= I2C_M_RECV_LEN; 3888c2ecf20Sopenharmony_ci msg[1].len = 1; /* block length will be added by 3898c2ecf20Sopenharmony_ci the underlying bus driver */ 3908c2ecf20Sopenharmony_ci i2c_smbus_try_get_dmabuf(&msg[1], 0); 3918c2ecf20Sopenharmony_ci } else { 3928c2ecf20Sopenharmony_ci msg[0].len = data->block[0] + 2; 3938c2ecf20Sopenharmony_ci if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { 3948c2ecf20Sopenharmony_ci dev_err(&adapter->dev, 3958c2ecf20Sopenharmony_ci "Invalid block write size %d\n", 3968c2ecf20Sopenharmony_ci data->block[0]); 3978c2ecf20Sopenharmony_ci return -EINVAL; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci i2c_smbus_try_get_dmabuf(&msg[0], command); 4018c2ecf20Sopenharmony_ci for (i = 1; i < msg[0].len; i++) 4028c2ecf20Sopenharmony_ci msg[0].buf[i] = data->block[i - 1]; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_PROC_CALL: 4068c2ecf20Sopenharmony_ci num = 2; /* Another special case */ 4078c2ecf20Sopenharmony_ci read_write = I2C_SMBUS_READ; 4088c2ecf20Sopenharmony_ci if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { 4098c2ecf20Sopenharmony_ci dev_err(&adapter->dev, 4108c2ecf20Sopenharmony_ci "Invalid block write size %d\n", 4118c2ecf20Sopenharmony_ci data->block[0]); 4128c2ecf20Sopenharmony_ci return -EINVAL; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci msg[0].len = data->block[0] + 2; 4168c2ecf20Sopenharmony_ci i2c_smbus_try_get_dmabuf(&msg[0], command); 4178c2ecf20Sopenharmony_ci for (i = 1; i < msg[0].len; i++) 4188c2ecf20Sopenharmony_ci msg[0].buf[i] = data->block[i - 1]; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci msg[1].flags |= I2C_M_RECV_LEN; 4218c2ecf20Sopenharmony_ci msg[1].len = 1; /* block length will be added by 4228c2ecf20Sopenharmony_ci the underlying bus driver */ 4238c2ecf20Sopenharmony_ci i2c_smbus_try_get_dmabuf(&msg[1], 0); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci case I2C_SMBUS_I2C_BLOCK_DATA: 4268c2ecf20Sopenharmony_ci if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { 4278c2ecf20Sopenharmony_ci dev_err(&adapter->dev, "Invalid block %s size %d\n", 4288c2ecf20Sopenharmony_ci read_write == I2C_SMBUS_READ ? "read" : "write", 4298c2ecf20Sopenharmony_ci data->block[0]); 4308c2ecf20Sopenharmony_ci return -EINVAL; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) { 4348c2ecf20Sopenharmony_ci msg[1].len = data->block[0]; 4358c2ecf20Sopenharmony_ci i2c_smbus_try_get_dmabuf(&msg[1], 0); 4368c2ecf20Sopenharmony_ci } else { 4378c2ecf20Sopenharmony_ci msg[0].len = data->block[0] + 1; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci i2c_smbus_try_get_dmabuf(&msg[0], command); 4408c2ecf20Sopenharmony_ci for (i = 1; i <= data->block[0]; i++) 4418c2ecf20Sopenharmony_ci msg[0].buf[i] = data->block[i]; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci default: 4458c2ecf20Sopenharmony_ci dev_err(&adapter->dev, "Unsupported transaction %d\n", size); 4468c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK 4508c2ecf20Sopenharmony_ci && size != I2C_SMBUS_I2C_BLOCK_DATA); 4518c2ecf20Sopenharmony_ci if (i) { 4528c2ecf20Sopenharmony_ci /* Compute PEC if first message is a write */ 4538c2ecf20Sopenharmony_ci if (!(msg[0].flags & I2C_M_RD)) { 4548c2ecf20Sopenharmony_ci if (num == 1) /* Write only */ 4558c2ecf20Sopenharmony_ci i2c_smbus_add_pec(&msg[0]); 4568c2ecf20Sopenharmony_ci else /* Write followed by read */ 4578c2ecf20Sopenharmony_ci partial_pec = i2c_smbus_msg_pec(0, &msg[0]); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci /* Ask for PEC if last message is a read */ 4608c2ecf20Sopenharmony_ci if (msg[num-1].flags & I2C_M_RD) 4618c2ecf20Sopenharmony_ci msg[num-1].len++; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci status = __i2c_transfer(adapter, msg, num); 4658c2ecf20Sopenharmony_ci if (status < 0) 4668c2ecf20Sopenharmony_ci goto cleanup; 4678c2ecf20Sopenharmony_ci if (status != num) { 4688c2ecf20Sopenharmony_ci status = -EIO; 4698c2ecf20Sopenharmony_ci goto cleanup; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci status = 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Check PEC if last message is a read */ 4748c2ecf20Sopenharmony_ci if (i && (msg[num-1].flags & I2C_M_RD)) { 4758c2ecf20Sopenharmony_ci status = i2c_smbus_check_pec(partial_pec, &msg[num-1]); 4768c2ecf20Sopenharmony_ci if (status < 0) 4778c2ecf20Sopenharmony_ci goto cleanup; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (read_write == I2C_SMBUS_READ) 4818c2ecf20Sopenharmony_ci switch (size) { 4828c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 4838c2ecf20Sopenharmony_ci data->byte = msgbuf0[0]; 4848c2ecf20Sopenharmony_ci break; 4858c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 4868c2ecf20Sopenharmony_ci data->byte = msgbuf1[0]; 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 4898c2ecf20Sopenharmony_ci case I2C_SMBUS_PROC_CALL: 4908c2ecf20Sopenharmony_ci data->word = msgbuf1[0] | (msgbuf1[1] << 8); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case I2C_SMBUS_I2C_BLOCK_DATA: 4938c2ecf20Sopenharmony_ci for (i = 0; i < data->block[0]; i++) 4948c2ecf20Sopenharmony_ci data->block[i + 1] = msg[1].buf[i]; 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 4978c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_PROC_CALL: 4988c2ecf20Sopenharmony_ci if (msg[1].buf[0] > I2C_SMBUS_BLOCK_MAX) { 4998c2ecf20Sopenharmony_ci dev_err(&adapter->dev, 5008c2ecf20Sopenharmony_ci "Invalid block size returned: %d\n", 5018c2ecf20Sopenharmony_ci msg[1].buf[0]); 5028c2ecf20Sopenharmony_ci status = -EPROTO; 5038c2ecf20Sopenharmony_ci goto cleanup; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci for (i = 0; i < msg[1].buf[0] + 1; i++) 5068c2ecf20Sopenharmony_ci data->block[i] = msg[1].buf[i]; 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cicleanup: 5118c2ecf20Sopenharmony_ci if (msg[0].flags & I2C_M_DMA_SAFE) 5128c2ecf20Sopenharmony_ci kfree(msg[0].buf); 5138c2ecf20Sopenharmony_ci if (msg[1].flags & I2C_M_DMA_SAFE) 5148c2ecf20Sopenharmony_ci kfree(msg[1].buf); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return status; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/** 5208c2ecf20Sopenharmony_ci * i2c_smbus_xfer - execute SMBus protocol operations 5218c2ecf20Sopenharmony_ci * @adapter: Handle to I2C bus 5228c2ecf20Sopenharmony_ci * @addr: Address of SMBus slave on that bus 5238c2ecf20Sopenharmony_ci * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC) 5248c2ecf20Sopenharmony_ci * @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE 5258c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave, for protocols which use such bytes 5268c2ecf20Sopenharmony_ci * @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL 5278c2ecf20Sopenharmony_ci * @data: Data to be read or written 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * This executes an SMBus protocol operation, and returns a negative 5308c2ecf20Sopenharmony_ci * errno code else zero on success. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_cis32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 5338c2ecf20Sopenharmony_ci unsigned short flags, char read_write, 5348c2ecf20Sopenharmony_ci u8 command, int protocol, union i2c_smbus_data *data) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci s32 res; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci res = __i2c_lock_bus_helper(adapter); 5398c2ecf20Sopenharmony_ci if (res) 5408c2ecf20Sopenharmony_ci return res; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci res = __i2c_smbus_xfer(adapter, addr, flags, read_write, 5438c2ecf20Sopenharmony_ci command, protocol, data); 5448c2ecf20Sopenharmony_ci i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return res; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_xfer); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cis32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 5518c2ecf20Sopenharmony_ci unsigned short flags, char read_write, 5528c2ecf20Sopenharmony_ci u8 command, int protocol, union i2c_smbus_data *data) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci int (*xfer_func)(struct i2c_adapter *adap, u16 addr, 5558c2ecf20Sopenharmony_ci unsigned short flags, char read_write, 5568c2ecf20Sopenharmony_ci u8 command, int size, union i2c_smbus_data *data); 5578c2ecf20Sopenharmony_ci unsigned long orig_jiffies; 5588c2ecf20Sopenharmony_ci int try; 5598c2ecf20Sopenharmony_ci s32 res; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci res = __i2c_check_suspended(adapter); 5628c2ecf20Sopenharmony_ci if (res) 5638c2ecf20Sopenharmony_ci return res; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* If enabled, the following two tracepoints are conditional on 5668c2ecf20Sopenharmony_ci * read_write and protocol. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci trace_smbus_write(adapter, addr, flags, read_write, 5698c2ecf20Sopenharmony_ci command, protocol, data); 5708c2ecf20Sopenharmony_ci trace_smbus_read(adapter, addr, flags, read_write, 5718c2ecf20Sopenharmony_ci command, protocol); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci xfer_func = adapter->algo->smbus_xfer; 5768c2ecf20Sopenharmony_ci if (i2c_in_atomic_xfer_mode()) { 5778c2ecf20Sopenharmony_ci if (adapter->algo->smbus_xfer_atomic) 5788c2ecf20Sopenharmony_ci xfer_func = adapter->algo->smbus_xfer_atomic; 5798c2ecf20Sopenharmony_ci else if (adapter->algo->master_xfer_atomic) 5808c2ecf20Sopenharmony_ci xfer_func = NULL; /* fallback to I2C emulation */ 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (xfer_func) { 5848c2ecf20Sopenharmony_ci /* Retry automatically on arbitration loss */ 5858c2ecf20Sopenharmony_ci orig_jiffies = jiffies; 5868c2ecf20Sopenharmony_ci for (res = 0, try = 0; try <= adapter->retries; try++) { 5878c2ecf20Sopenharmony_ci res = xfer_func(adapter, addr, flags, read_write, 5888c2ecf20Sopenharmony_ci command, protocol, data); 5898c2ecf20Sopenharmony_ci if (res != -EAGAIN) 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci if (time_after(jiffies, 5928c2ecf20Sopenharmony_ci orig_jiffies + adapter->timeout)) 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) 5978c2ecf20Sopenharmony_ci goto trace; 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't 6008c2ecf20Sopenharmony_ci * implement native support for the SMBus operation. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, 6058c2ecf20Sopenharmony_ci command, protocol, data); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_citrace: 6088c2ecf20Sopenharmony_ci /* If enabled, the reply tracepoint is conditional on read_write. */ 6098c2ecf20Sopenharmony_ci trace_smbus_reply(adapter, addr, flags, read_write, 6108c2ecf20Sopenharmony_ci command, protocol, data, res); 6118c2ecf20Sopenharmony_ci trace_smbus_result(adapter, addr, flags, read_write, 6128c2ecf20Sopenharmony_ci command, protocol, res); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return res; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__i2c_smbus_xfer); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/** 6198c2ecf20Sopenharmony_ci * i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate 6208c2ecf20Sopenharmony_ci * @client: Handle to slave device 6218c2ecf20Sopenharmony_ci * @command: Byte interpreted by slave 6228c2ecf20Sopenharmony_ci * @length: Size of data block; SMBus allows at most I2C_SMBUS_BLOCK_MAX bytes 6238c2ecf20Sopenharmony_ci * @values: Byte array into which data will be read; big enough to hold 6248c2ecf20Sopenharmony_ci * the data returned by the slave. SMBus allows at most 6258c2ecf20Sopenharmony_ci * I2C_SMBUS_BLOCK_MAX bytes. 6268c2ecf20Sopenharmony_ci * 6278c2ecf20Sopenharmony_ci * This executes the SMBus "block read" protocol if supported by the adapter. 6288c2ecf20Sopenharmony_ci * If block read is not supported, it emulates it using either word or byte 6298c2ecf20Sopenharmony_ci * read protocols depending on availability. 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * The addresses of the I2C slave device that are accessed with this function 6328c2ecf20Sopenharmony_ci * must be mapped to a linear region, so that a block read will have the same 6338c2ecf20Sopenharmony_ci * effect as a byte read. Before using this function you must double-check 6348c2ecf20Sopenharmony_ci * if the I2C slave does support exchanging a block transfer with a byte 6358c2ecf20Sopenharmony_ci * transfer. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_cis32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, 6388c2ecf20Sopenharmony_ci u8 command, u8 length, u8 *values) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci u8 i = 0; 6418c2ecf20Sopenharmony_ci int status; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (length > I2C_SMBUS_BLOCK_MAX) 6448c2ecf20Sopenharmony_ci length = I2C_SMBUS_BLOCK_MAX; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) 6478c2ecf20Sopenharmony_ci return i2c_smbus_read_i2c_block_data(client, command, length, values); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) 6508c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) { 6538c2ecf20Sopenharmony_ci while ((i + 2) <= length) { 6548c2ecf20Sopenharmony_ci status = i2c_smbus_read_word_data(client, command + i); 6558c2ecf20Sopenharmony_ci if (status < 0) 6568c2ecf20Sopenharmony_ci return status; 6578c2ecf20Sopenharmony_ci values[i] = status & 0xff; 6588c2ecf20Sopenharmony_ci values[i + 1] = status >> 8; 6598c2ecf20Sopenharmony_ci i += 2; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci while (i < length) { 6648c2ecf20Sopenharmony_ci status = i2c_smbus_read_byte_data(client, command + i); 6658c2ecf20Sopenharmony_ci if (status < 0) 6668c2ecf20Sopenharmony_ci return status; 6678c2ecf20Sopenharmony_ci values[i] = status; 6688c2ecf20Sopenharmony_ci i++; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return i; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci/** 6768c2ecf20Sopenharmony_ci * i2c_new_smbus_alert_device - get ara client for SMBus alert support 6778c2ecf20Sopenharmony_ci * @adapter: the target adapter 6788c2ecf20Sopenharmony_ci * @setup: setup data for the SMBus alert handler 6798c2ecf20Sopenharmony_ci * Context: can sleep 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * Setup handling of the SMBus alert protocol on a given I2C bus segment. 6828c2ecf20Sopenharmony_ci * 6838c2ecf20Sopenharmony_ci * Handling can be done either through our IRQ handler, or by the 6848c2ecf20Sopenharmony_ci * adapter (from its handler, periodic polling, or whatever). 6858c2ecf20Sopenharmony_ci * 6868c2ecf20Sopenharmony_ci * This returns the ara client, which should be saved for later use with 6878c2ecf20Sopenharmony_ci * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or an 6888c2ecf20Sopenharmony_ci * ERRPTR to indicate an error. 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_cistruct i2c_client *i2c_new_smbus_alert_device(struct i2c_adapter *adapter, 6918c2ecf20Sopenharmony_ci struct i2c_smbus_alert_setup *setup) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct i2c_board_info ara_board_info = { 6948c2ecf20Sopenharmony_ci I2C_BOARD_INFO("smbus_alert", 0x0c), 6958c2ecf20Sopenharmony_ci .platform_data = setup, 6968c2ecf20Sopenharmony_ci }; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return i2c_new_client_device(adapter, &ara_board_info); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(i2c_new_smbus_alert_device); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) 7038c2ecf20Sopenharmony_ciint of_i2c_setup_smbus_alert(struct i2c_adapter *adapter) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci int irq; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci irq = of_property_match_string(adapter->dev.of_node, "interrupt-names", 7088c2ecf20Sopenharmony_ci "smbus_alert"); 7098c2ecf20Sopenharmony_ci if (irq == -EINVAL || irq == -ENODATA) 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci else if (irq < 0) 7128c2ecf20Sopenharmony_ci return irq; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert); 7178c2ecf20Sopenharmony_ci#endif 718