19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 29948a064SJiri Pirko /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ 36882b0aeSVadim Pasternak 46882b0aeSVadim Pasternak #include <linux/err.h> 56882b0aeSVadim Pasternak #include <linux/i2c.h> 66882b0aeSVadim Pasternak #include <linux/init.h> 76882b0aeSVadim Pasternak #include <linux/jiffies.h> 86882b0aeSVadim Pasternak #include <linux/kernel.h> 96882b0aeSVadim Pasternak #include <linux/mutex.h> 106882b0aeSVadim Pasternak #include <linux/module.h> 116882b0aeSVadim Pasternak #include <linux/mod_devicetable.h> 126882b0aeSVadim Pasternak #include <linux/slab.h> 136882b0aeSVadim Pasternak 146882b0aeSVadim Pasternak #include "cmd.h" 156882b0aeSVadim Pasternak #include "core.h" 166882b0aeSVadim Pasternak #include "i2c.h" 17*6a986993SVadim Pasternak #include "resources.h" 186882b0aeSVadim Pasternak 196882b0aeSVadim Pasternak #define MLXSW_I2C_CIR2_BASE 0x72000 206882b0aeSVadim Pasternak #define MLXSW_I2C_CIR_STATUS_OFF 0x18 216882b0aeSVadim Pasternak #define MLXSW_I2C_CIR2_OFF_STATUS (MLXSW_I2C_CIR2_BASE + \ 226882b0aeSVadim Pasternak MLXSW_I2C_CIR_STATUS_OFF) 236882b0aeSVadim Pasternak #define MLXSW_I2C_OPMOD_SHIFT 12 2495b75cbdSVadim Pasternak #define MLXSW_I2C_EVENT_BIT_SHIFT 22 256882b0aeSVadim Pasternak #define MLXSW_I2C_GO_BIT_SHIFT 23 266882b0aeSVadim Pasternak #define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT 24 2795b75cbdSVadim Pasternak #define MLXSW_I2C_EVENT_BIT BIT(MLXSW_I2C_EVENT_BIT_SHIFT) 286882b0aeSVadim Pasternak #define MLXSW_I2C_GO_BIT BIT(MLXSW_I2C_GO_BIT_SHIFT) 296882b0aeSVadim Pasternak #define MLXSW_I2C_GO_OPMODE BIT(MLXSW_I2C_OPMOD_SHIFT) 306882b0aeSVadim Pasternak #define MLXSW_I2C_SET_IMM_CMD (MLXSW_I2C_GO_OPMODE | \ 316882b0aeSVadim Pasternak MLXSW_CMD_OPCODE_QUERY_FW) 326882b0aeSVadim Pasternak #define MLXSW_I2C_PUSH_IMM_CMD (MLXSW_I2C_GO_BIT | \ 336882b0aeSVadim Pasternak MLXSW_I2C_SET_IMM_CMD) 346882b0aeSVadim Pasternak #define MLXSW_I2C_SET_CMD (MLXSW_CMD_OPCODE_ACCESS_REG) 356882b0aeSVadim Pasternak #define MLXSW_I2C_PUSH_CMD (MLXSW_I2C_GO_BIT | MLXSW_I2C_SET_CMD) 366882b0aeSVadim Pasternak #define MLXSW_I2C_TLV_HDR_SIZE 0x10 376882b0aeSVadim Pasternak #define MLXSW_I2C_ADDR_WIDTH 4 386882b0aeSVadim Pasternak #define MLXSW_I2C_PUSH_CMD_SIZE (MLXSW_I2C_ADDR_WIDTH + 4) 3995b75cbdSVadim Pasternak #define MLXSW_I2C_SET_EVENT_CMD (MLXSW_I2C_EVENT_BIT) 4095b75cbdSVadim Pasternak #define MLXSW_I2C_PUSH_EVENT_CMD (MLXSW_I2C_GO_BIT | \ 4195b75cbdSVadim Pasternak MLXSW_I2C_SET_EVENT_CMD) 426882b0aeSVadim Pasternak #define MLXSW_I2C_READ_SEMA_SIZE 4 436882b0aeSVadim Pasternak #define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28) 446882b0aeSVadim Pasternak #define MLXSW_I2C_MBOX_SIZE 20 456882b0aeSVadim Pasternak #define MLXSW_I2C_MBOX_OUT_PARAM_OFF 12 466882b0aeSVadim Pasternak #define MLXSW_I2C_MAX_BUFF_SIZE 32 476882b0aeSVadim Pasternak #define MLXSW_I2C_MBOX_OFFSET_BITS 20 486882b0aeSVadim Pasternak #define MLXSW_I2C_MBOX_SIZE_BITS 12 496882b0aeSVadim Pasternak #define MLXSW_I2C_ADDR_BUF_SIZE 4 506882b0aeSVadim Pasternak #define MLXSW_I2C_BLK_MAX 32 516882b0aeSVadim Pasternak #define MLXSW_I2C_RETRY 5 526882b0aeSVadim Pasternak #define MLXSW_I2C_TIMEOUT_MSECS 5000 5395b75cbdSVadim Pasternak #define MLXSW_I2C_MAX_DATA_SIZE 256 546882b0aeSVadim Pasternak 556882b0aeSVadim Pasternak /** 566882b0aeSVadim Pasternak * struct mlxsw_i2c - device private data: 576882b0aeSVadim Pasternak * @cmd.mb_size_in: input mailbox size; 586882b0aeSVadim Pasternak * @cmd.mb_off_in: input mailbox offset in register space; 596882b0aeSVadim Pasternak * @cmd.mb_size_out: output mailbox size; 606882b0aeSVadim Pasternak * @cmd.mb_off_out: output mailbox offset in register space; 616882b0aeSVadim Pasternak * @cmd.lock: command execution lock; 626882b0aeSVadim Pasternak * @dev: I2C device; 636882b0aeSVadim Pasternak * @core: switch core pointer; 646882b0aeSVadim Pasternak * @bus_info: bus info block; 656882b0aeSVadim Pasternak */ 666882b0aeSVadim Pasternak struct mlxsw_i2c { 676882b0aeSVadim Pasternak struct { 686882b0aeSVadim Pasternak u32 mb_size_in; 696882b0aeSVadim Pasternak u32 mb_off_in; 706882b0aeSVadim Pasternak u32 mb_size_out; 716882b0aeSVadim Pasternak u32 mb_off_out; 726882b0aeSVadim Pasternak struct mutex lock; 736882b0aeSVadim Pasternak } cmd; 746882b0aeSVadim Pasternak struct device *dev; 756882b0aeSVadim Pasternak struct mlxsw_core *core; 766882b0aeSVadim Pasternak struct mlxsw_bus_info bus_info; 776882b0aeSVadim Pasternak }; 786882b0aeSVadim Pasternak 796882b0aeSVadim Pasternak #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ 806882b0aeSVadim Pasternak { .addr = (_client)->addr, \ 816882b0aeSVadim Pasternak .buf = (_addr_buf), \ 826882b0aeSVadim Pasternak .len = MLXSW_I2C_ADDR_BUF_SIZE, \ 836882b0aeSVadim Pasternak .flags = 0 }, \ 846882b0aeSVadim Pasternak { .addr = (_client)->addr, \ 856882b0aeSVadim Pasternak .buf = (_buf), \ 866882b0aeSVadim Pasternak .len = (_len), \ 876882b0aeSVadim Pasternak .flags = I2C_M_RD } } 886882b0aeSVadim Pasternak 896882b0aeSVadim Pasternak #define MLXSW_I2C_WRITE_MSG(_client, _buf, _len) \ 906882b0aeSVadim Pasternak { .addr = (_client)->addr, \ 916882b0aeSVadim Pasternak .buf = (u8 *)(_buf), \ 926882b0aeSVadim Pasternak .len = (_len), \ 936882b0aeSVadim Pasternak .flags = 0 } 946882b0aeSVadim Pasternak 956882b0aeSVadim Pasternak /* Routine converts in and out mail boxes offset and size. */ 966882b0aeSVadim Pasternak static inline void 976882b0aeSVadim Pasternak mlxsw_i2c_convert_mbox(struct mlxsw_i2c *mlxsw_i2c, u8 *buf) 986882b0aeSVadim Pasternak { 996882b0aeSVadim Pasternak u32 tmp; 1006882b0aeSVadim Pasternak 1016882b0aeSVadim Pasternak /* Local in/out mailboxes: 20 bits for offset, 12 for size */ 1026882b0aeSVadim Pasternak tmp = be32_to_cpup((__be32 *) buf); 1036882b0aeSVadim Pasternak mlxsw_i2c->cmd.mb_off_in = tmp & 1046882b0aeSVadim Pasternak GENMASK(MLXSW_I2C_MBOX_OFFSET_BITS - 1, 0); 1056882b0aeSVadim Pasternak mlxsw_i2c->cmd.mb_size_in = (tmp & GENMASK(31, 1066882b0aeSVadim Pasternak MLXSW_I2C_MBOX_OFFSET_BITS)) >> 1076882b0aeSVadim Pasternak MLXSW_I2C_MBOX_OFFSET_BITS; 1086882b0aeSVadim Pasternak 1096882b0aeSVadim Pasternak tmp = be32_to_cpup((__be32 *) (buf + MLXSW_I2C_ADDR_WIDTH)); 1106882b0aeSVadim Pasternak mlxsw_i2c->cmd.mb_off_out = tmp & 1116882b0aeSVadim Pasternak GENMASK(MLXSW_I2C_MBOX_OFFSET_BITS - 1, 0); 1126882b0aeSVadim Pasternak mlxsw_i2c->cmd.mb_size_out = (tmp & GENMASK(31, 1136882b0aeSVadim Pasternak MLXSW_I2C_MBOX_OFFSET_BITS)) >> 1146882b0aeSVadim Pasternak MLXSW_I2C_MBOX_OFFSET_BITS; 1156882b0aeSVadim Pasternak } 1166882b0aeSVadim Pasternak 1176882b0aeSVadim Pasternak /* Routine obtains register size from mail box buffer. */ 1186882b0aeSVadim Pasternak static inline int mlxsw_i2c_get_reg_size(u8 *in_mbox) 1196882b0aeSVadim Pasternak { 1206882b0aeSVadim Pasternak u16 tmp = be16_to_cpup((__be16 *) (in_mbox + MLXSW_I2C_TLV_HDR_SIZE)); 1216882b0aeSVadim Pasternak 1226882b0aeSVadim Pasternak return (tmp & 0x7ff) * 4 + MLXSW_I2C_TLV_HDR_SIZE; 1236882b0aeSVadim Pasternak } 1246882b0aeSVadim Pasternak 1256882b0aeSVadim Pasternak /* Routine sets I2C device internal offset in the transaction buffer. */ 1266882b0aeSVadim Pasternak static inline void mlxsw_i2c_set_slave_addr(u8 *buf, u32 off) 1276882b0aeSVadim Pasternak { 1286882b0aeSVadim Pasternak __be32 *val = (__be32 *) buf; 1296882b0aeSVadim Pasternak 1306882b0aeSVadim Pasternak *val = htonl(off); 1316882b0aeSVadim Pasternak } 1326882b0aeSVadim Pasternak 1336882b0aeSVadim Pasternak /* Routine waits until go bit is cleared. */ 1346882b0aeSVadim Pasternak static int mlxsw_i2c_wait_go_bit(struct i2c_client *client, 1356882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c, u8 *p_status) 1366882b0aeSVadim Pasternak { 1376882b0aeSVadim Pasternak u8 addr_buf[MLXSW_I2C_ADDR_BUF_SIZE]; 1386882b0aeSVadim Pasternak u8 buf[MLXSW_I2C_READ_SEMA_SIZE]; 1396882b0aeSVadim Pasternak int len = MLXSW_I2C_READ_SEMA_SIZE; 1406882b0aeSVadim Pasternak struct i2c_msg read_sema[] = 1416882b0aeSVadim Pasternak MLXSW_I2C_READ_MSG(client, addr_buf, buf, len); 1426882b0aeSVadim Pasternak bool wait_done = false; 1436882b0aeSVadim Pasternak unsigned long end; 1446882b0aeSVadim Pasternak int i = 0, err; 1456882b0aeSVadim Pasternak 1466882b0aeSVadim Pasternak mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_OFF_STATUS); 1476882b0aeSVadim Pasternak 1486882b0aeSVadim Pasternak end = jiffies + msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); 1496882b0aeSVadim Pasternak do { 1506882b0aeSVadim Pasternak u32 ctrl; 1516882b0aeSVadim Pasternak 1526882b0aeSVadim Pasternak err = i2c_transfer(client->adapter, read_sema, 1536882b0aeSVadim Pasternak ARRAY_SIZE(read_sema)); 1546882b0aeSVadim Pasternak 1556882b0aeSVadim Pasternak ctrl = be32_to_cpu(*(__be32 *) buf); 1566882b0aeSVadim Pasternak if (err == ARRAY_SIZE(read_sema)) { 1576882b0aeSVadim Pasternak if (!(ctrl & MLXSW_I2C_GO_BIT)) { 1586882b0aeSVadim Pasternak wait_done = true; 1596882b0aeSVadim Pasternak *p_status = ctrl >> 1606882b0aeSVadim Pasternak MLXSW_I2C_CIR_CTRL_STATUS_SHIFT; 1616882b0aeSVadim Pasternak break; 1626882b0aeSVadim Pasternak } 1636882b0aeSVadim Pasternak } 1646882b0aeSVadim Pasternak cond_resched(); 1656882b0aeSVadim Pasternak } while ((time_before(jiffies, end)) || (i++ < MLXSW_I2C_RETRY)); 1666882b0aeSVadim Pasternak 1676882b0aeSVadim Pasternak if (wait_done) { 1686882b0aeSVadim Pasternak if (*p_status) 1696882b0aeSVadim Pasternak err = -EIO; 1706882b0aeSVadim Pasternak } else { 1716882b0aeSVadim Pasternak return -ETIMEDOUT; 1726882b0aeSVadim Pasternak } 1736882b0aeSVadim Pasternak 1746882b0aeSVadim Pasternak return err > 0 ? 0 : err; 1756882b0aeSVadim Pasternak } 1766882b0aeSVadim Pasternak 17727758c80SVadim Pasternak /* Routine posts a command to ASIC through mail box. */ 1786882b0aeSVadim Pasternak static int mlxsw_i2c_write_cmd(struct i2c_client *client, 1796882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c, 1806882b0aeSVadim Pasternak int immediate) 1816882b0aeSVadim Pasternak { 1826882b0aeSVadim Pasternak __be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = { 1836882b0aeSVadim Pasternak 0, cpu_to_be32(MLXSW_I2C_PUSH_IMM_CMD) 1846882b0aeSVadim Pasternak }; 1856882b0aeSVadim Pasternak __be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = { 1866882b0aeSVadim Pasternak 0, 0, 0, 0, 0, 0, 1876882b0aeSVadim Pasternak cpu_to_be32(client->adapter->nr & 0xffff), 1886882b0aeSVadim Pasternak cpu_to_be32(MLXSW_I2C_SET_IMM_CMD) 1896882b0aeSVadim Pasternak }; 1906882b0aeSVadim Pasternak struct i2c_msg push_cmd = 1916882b0aeSVadim Pasternak MLXSW_I2C_WRITE_MSG(client, push_cmd_buf, 1926882b0aeSVadim Pasternak MLXSW_I2C_PUSH_CMD_SIZE); 1936882b0aeSVadim Pasternak struct i2c_msg prep_cmd = 1946882b0aeSVadim Pasternak MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE); 1956882b0aeSVadim Pasternak int err; 1966882b0aeSVadim Pasternak 1976882b0aeSVadim Pasternak if (!immediate) { 1986882b0aeSVadim Pasternak push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_CMD); 1996882b0aeSVadim Pasternak prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_SET_CMD); 2006882b0aeSVadim Pasternak } 2016882b0aeSVadim Pasternak mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf, 2026882b0aeSVadim Pasternak MLXSW_I2C_CIR2_BASE); 2036882b0aeSVadim Pasternak mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf, 2046882b0aeSVadim Pasternak MLXSW_I2C_CIR2_OFF_STATUS); 2056882b0aeSVadim Pasternak 2066882b0aeSVadim Pasternak /* Prepare Command Interface Register for transaction */ 2076882b0aeSVadim Pasternak err = i2c_transfer(client->adapter, &prep_cmd, 1); 2086882b0aeSVadim Pasternak if (err < 0) 2096882b0aeSVadim Pasternak return err; 2106882b0aeSVadim Pasternak else if (err != 1) 2116882b0aeSVadim Pasternak return -EIO; 2126882b0aeSVadim Pasternak 2136882b0aeSVadim Pasternak /* Write out Command Interface Register GO bit to push transaction */ 2146882b0aeSVadim Pasternak err = i2c_transfer(client->adapter, &push_cmd, 1); 2156882b0aeSVadim Pasternak if (err < 0) 2166882b0aeSVadim Pasternak return err; 2176882b0aeSVadim Pasternak else if (err != 1) 2186882b0aeSVadim Pasternak return -EIO; 2196882b0aeSVadim Pasternak 2206882b0aeSVadim Pasternak return 0; 2216882b0aeSVadim Pasternak } 2226882b0aeSVadim Pasternak 22395b75cbdSVadim Pasternak /* Routine posts initialization command to ASIC through mail box. */ 22495b75cbdSVadim Pasternak static int 22595b75cbdSVadim Pasternak mlxsw_i2c_write_init_cmd(struct i2c_client *client, 22695b75cbdSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c, u16 opcode, u32 in_mod) 22795b75cbdSVadim Pasternak { 22895b75cbdSVadim Pasternak __be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = { 22995b75cbdSVadim Pasternak 0, cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD) 23095b75cbdSVadim Pasternak }; 23195b75cbdSVadim Pasternak __be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = { 23295b75cbdSVadim Pasternak 0, 0, 0, 0, 0, 0, 23395b75cbdSVadim Pasternak cpu_to_be32(client->adapter->nr & 0xffff), 23495b75cbdSVadim Pasternak cpu_to_be32(MLXSW_I2C_SET_EVENT_CMD) 23595b75cbdSVadim Pasternak }; 23695b75cbdSVadim Pasternak struct i2c_msg push_cmd = 23795b75cbdSVadim Pasternak MLXSW_I2C_WRITE_MSG(client, push_cmd_buf, 23895b75cbdSVadim Pasternak MLXSW_I2C_PUSH_CMD_SIZE); 23995b75cbdSVadim Pasternak struct i2c_msg prep_cmd = 24095b75cbdSVadim Pasternak MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE); 24195b75cbdSVadim Pasternak u8 status; 24295b75cbdSVadim Pasternak int err; 24395b75cbdSVadim Pasternak 24495b75cbdSVadim Pasternak push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD | opcode); 24595b75cbdSVadim Pasternak prep_cmd_buf[3] = cpu_to_be32(in_mod); 24695b75cbdSVadim Pasternak prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_GO_BIT | opcode); 24795b75cbdSVadim Pasternak mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf, 24895b75cbdSVadim Pasternak MLXSW_I2C_CIR2_BASE); 24995b75cbdSVadim Pasternak mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf, 25095b75cbdSVadim Pasternak MLXSW_I2C_CIR2_OFF_STATUS); 25195b75cbdSVadim Pasternak 25295b75cbdSVadim Pasternak /* Prepare Command Interface Register for transaction */ 25395b75cbdSVadim Pasternak err = i2c_transfer(client->adapter, &prep_cmd, 1); 25495b75cbdSVadim Pasternak if (err < 0) 25595b75cbdSVadim Pasternak return err; 25695b75cbdSVadim Pasternak else if (err != 1) 25795b75cbdSVadim Pasternak return -EIO; 25895b75cbdSVadim Pasternak 25995b75cbdSVadim Pasternak /* Write out Command Interface Register GO bit to push transaction */ 26095b75cbdSVadim Pasternak err = i2c_transfer(client->adapter, &push_cmd, 1); 26195b75cbdSVadim Pasternak if (err < 0) 26295b75cbdSVadim Pasternak return err; 26395b75cbdSVadim Pasternak else if (err != 1) 26495b75cbdSVadim Pasternak return -EIO; 26595b75cbdSVadim Pasternak 26695b75cbdSVadim Pasternak /* Wait until go bit is cleared. */ 26795b75cbdSVadim Pasternak err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status); 26895b75cbdSVadim Pasternak if (err) { 26995b75cbdSVadim Pasternak dev_err(&client->dev, "HW semaphore is not released"); 27095b75cbdSVadim Pasternak return err; 27195b75cbdSVadim Pasternak } 27295b75cbdSVadim Pasternak 27395b75cbdSVadim Pasternak /* Validate transaction completion status. */ 27495b75cbdSVadim Pasternak if (status) { 27595b75cbdSVadim Pasternak dev_err(&client->dev, "Bad transaction completion status %x\n", 27695b75cbdSVadim Pasternak status); 27795b75cbdSVadim Pasternak return -EIO; 27895b75cbdSVadim Pasternak } 27995b75cbdSVadim Pasternak 28095b75cbdSVadim Pasternak return 0; 28195b75cbdSVadim Pasternak } 28295b75cbdSVadim Pasternak 2836882b0aeSVadim Pasternak /* Routine obtains mail box offsets from ASIC register space. */ 2846882b0aeSVadim Pasternak static int mlxsw_i2c_get_mbox(struct i2c_client *client, 2856882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c) 2866882b0aeSVadim Pasternak { 2876882b0aeSVadim Pasternak u8 addr_buf[MLXSW_I2C_ADDR_BUF_SIZE]; 2886882b0aeSVadim Pasternak u8 buf[MLXSW_I2C_MBOX_SIZE]; 2896882b0aeSVadim Pasternak struct i2c_msg mbox_cmd[] = 2906882b0aeSVadim Pasternak MLXSW_I2C_READ_MSG(client, addr_buf, buf, MLXSW_I2C_MBOX_SIZE); 2916882b0aeSVadim Pasternak int err; 2926882b0aeSVadim Pasternak 2936882b0aeSVadim Pasternak /* Read mail boxes offsets. */ 2946882b0aeSVadim Pasternak mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_BASE); 2956882b0aeSVadim Pasternak err = i2c_transfer(client->adapter, mbox_cmd, 2); 2966882b0aeSVadim Pasternak if (err != 2) { 2976882b0aeSVadim Pasternak dev_err(&client->dev, "Could not obtain mail boxes\n"); 2986882b0aeSVadim Pasternak if (!err) 2996882b0aeSVadim Pasternak return -EIO; 3006882b0aeSVadim Pasternak else 3016882b0aeSVadim Pasternak return err; 3026882b0aeSVadim Pasternak } 3036882b0aeSVadim Pasternak 3046882b0aeSVadim Pasternak /* Convert mail boxes. */ 3056882b0aeSVadim Pasternak mlxsw_i2c_convert_mbox(mlxsw_i2c, &buf[MLXSW_I2C_MBOX_OUT_PARAM_OFF]); 3066882b0aeSVadim Pasternak 3076882b0aeSVadim Pasternak return err; 3086882b0aeSVadim Pasternak } 3096882b0aeSVadim Pasternak 3106882b0aeSVadim Pasternak /* Routine sends I2C write transaction to ASIC device. */ 3116882b0aeSVadim Pasternak static int 3126882b0aeSVadim Pasternak mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, 3136882b0aeSVadim Pasternak u8 *p_status) 3146882b0aeSVadim Pasternak { 3156882b0aeSVadim Pasternak struct i2c_client *client = to_i2c_client(dev); 3166882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); 3176882b0aeSVadim Pasternak unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); 3186882b0aeSVadim Pasternak u8 tran_buf[MLXSW_I2C_MAX_BUFF_SIZE + MLXSW_I2C_ADDR_BUF_SIZE]; 3196882b0aeSVadim Pasternak int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j; 3206882b0aeSVadim Pasternak unsigned long end; 3216882b0aeSVadim Pasternak struct i2c_msg write_tran = 3226882b0aeSVadim Pasternak MLXSW_I2C_WRITE_MSG(client, tran_buf, MLXSW_I2C_PUSH_CMD_SIZE); 3236882b0aeSVadim Pasternak int err; 3246882b0aeSVadim Pasternak 3256882b0aeSVadim Pasternak for (i = 0; i < num; i++) { 3266882b0aeSVadim Pasternak chunk_size = (in_mbox_size > MLXSW_I2C_BLK_MAX) ? 3276882b0aeSVadim Pasternak MLXSW_I2C_BLK_MAX : in_mbox_size; 3286882b0aeSVadim Pasternak write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size; 3296882b0aeSVadim Pasternak mlxsw_i2c_set_slave_addr(tran_buf, off); 3306882b0aeSVadim Pasternak memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox + 331d70eaa38SVadim Pasternak MLXSW_I2C_BLK_MAX * i, chunk_size); 3326882b0aeSVadim Pasternak 3336882b0aeSVadim Pasternak j = 0; 3346882b0aeSVadim Pasternak end = jiffies + timeout; 3356882b0aeSVadim Pasternak do { 3366882b0aeSVadim Pasternak err = i2c_transfer(client->adapter, &write_tran, 1); 3376882b0aeSVadim Pasternak if (err == 1) 3386882b0aeSVadim Pasternak break; 3396882b0aeSVadim Pasternak 3406882b0aeSVadim Pasternak cond_resched(); 3416882b0aeSVadim Pasternak } while ((time_before(jiffies, end)) || 3426882b0aeSVadim Pasternak (j++ < MLXSW_I2C_RETRY)); 3436882b0aeSVadim Pasternak 3446882b0aeSVadim Pasternak if (err != 1) { 3456882b0aeSVadim Pasternak if (!err) 3466882b0aeSVadim Pasternak err = -EIO; 3476882b0aeSVadim Pasternak return err; 3486882b0aeSVadim Pasternak } 3496882b0aeSVadim Pasternak 3506882b0aeSVadim Pasternak off += chunk_size; 3516882b0aeSVadim Pasternak in_mbox_size -= chunk_size; 3526882b0aeSVadim Pasternak } 3536882b0aeSVadim Pasternak 3546882b0aeSVadim Pasternak /* Prepare and write out Command Interface Register for transaction. */ 3556882b0aeSVadim Pasternak err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0); 3566882b0aeSVadim Pasternak if (err) { 3576882b0aeSVadim Pasternak dev_err(&client->dev, "Could not start transaction"); 3586882b0aeSVadim Pasternak return -EIO; 3596882b0aeSVadim Pasternak } 3606882b0aeSVadim Pasternak 3616882b0aeSVadim Pasternak /* Wait until go bit is cleared. */ 3626882b0aeSVadim Pasternak err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status); 3636882b0aeSVadim Pasternak if (err) { 3646882b0aeSVadim Pasternak dev_err(&client->dev, "HW semaphore is not released"); 3656882b0aeSVadim Pasternak return err; 3666882b0aeSVadim Pasternak } 3676882b0aeSVadim Pasternak 3686882b0aeSVadim Pasternak /* Validate transaction completion status. */ 3696882b0aeSVadim Pasternak if (*p_status) { 3706882b0aeSVadim Pasternak dev_err(&client->dev, "Bad transaction completion status %x\n", 3716882b0aeSVadim Pasternak *p_status); 3726882b0aeSVadim Pasternak return -EIO; 3736882b0aeSVadim Pasternak } 3746882b0aeSVadim Pasternak 37536ca68bfSElad Raz return 0; 3766882b0aeSVadim Pasternak } 3776882b0aeSVadim Pasternak 3786882b0aeSVadim Pasternak /* Routine executes I2C command. */ 3796882b0aeSVadim Pasternak static int 38095b75cbdSVadim Pasternak mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, 38195b75cbdSVadim Pasternak u8 *in_mbox, size_t out_mbox_size, u8 *out_mbox, u8 *status) 3826882b0aeSVadim Pasternak { 3836882b0aeSVadim Pasternak struct i2c_client *client = to_i2c_client(dev); 3846882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); 3856882b0aeSVadim Pasternak unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); 3866882b0aeSVadim Pasternak u8 tran_buf[MLXSW_I2C_ADDR_BUF_SIZE]; 3876882b0aeSVadim Pasternak int num, chunk_size, reg_size, i, j; 3886882b0aeSVadim Pasternak int off = mlxsw_i2c->cmd.mb_off_out; 3896882b0aeSVadim Pasternak unsigned long end; 3906882b0aeSVadim Pasternak struct i2c_msg read_tran[] = 3916882b0aeSVadim Pasternak MLXSW_I2C_READ_MSG(client, tran_buf, NULL, 0); 3926882b0aeSVadim Pasternak int err; 3936882b0aeSVadim Pasternak 3946882b0aeSVadim Pasternak WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); 3956882b0aeSVadim Pasternak 39695b75cbdSVadim Pasternak if (in_mbox) { 3976882b0aeSVadim Pasternak reg_size = mlxsw_i2c_get_reg_size(in_mbox); 3986882b0aeSVadim Pasternak num = reg_size / MLXSW_I2C_BLK_MAX; 3996882b0aeSVadim Pasternak if (reg_size % MLXSW_I2C_BLK_MAX) 4006882b0aeSVadim Pasternak num++; 4016882b0aeSVadim Pasternak 4026882b0aeSVadim Pasternak if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { 4036882b0aeSVadim Pasternak dev_err(&client->dev, "Could not acquire lock"); 4046882b0aeSVadim Pasternak return -EINVAL; 4056882b0aeSVadim Pasternak } 4066882b0aeSVadim Pasternak 4076882b0aeSVadim Pasternak err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); 4086882b0aeSVadim Pasternak if (err) 4096882b0aeSVadim Pasternak goto cmd_fail; 4106882b0aeSVadim Pasternak 4116882b0aeSVadim Pasternak /* No out mailbox is case of write transaction. */ 4126882b0aeSVadim Pasternak if (!out_mbox) { 4136882b0aeSVadim Pasternak mutex_unlock(&mlxsw_i2c->cmd.lock); 4146882b0aeSVadim Pasternak return 0; 4156882b0aeSVadim Pasternak } 41695b75cbdSVadim Pasternak } else { 41795b75cbdSVadim Pasternak /* No input mailbox is case of initialization query command. */ 41895b75cbdSVadim Pasternak reg_size = MLXSW_I2C_MAX_DATA_SIZE; 41995b75cbdSVadim Pasternak num = reg_size / MLXSW_I2C_BLK_MAX; 42095b75cbdSVadim Pasternak 42195b75cbdSVadim Pasternak if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { 42295b75cbdSVadim Pasternak dev_err(&client->dev, "Could not acquire lock"); 42395b75cbdSVadim Pasternak return -EINVAL; 42495b75cbdSVadim Pasternak } 42595b75cbdSVadim Pasternak 42695b75cbdSVadim Pasternak err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode, 42795b75cbdSVadim Pasternak in_mod); 42895b75cbdSVadim Pasternak if (err) 42995b75cbdSVadim Pasternak goto cmd_fail; 43095b75cbdSVadim Pasternak } 4316882b0aeSVadim Pasternak 4326882b0aeSVadim Pasternak /* Send read transaction to get output mailbox content. */ 4336882b0aeSVadim Pasternak read_tran[1].buf = out_mbox; 4346882b0aeSVadim Pasternak for (i = 0; i < num; i++) { 4356882b0aeSVadim Pasternak chunk_size = (reg_size > MLXSW_I2C_BLK_MAX) ? 4366882b0aeSVadim Pasternak MLXSW_I2C_BLK_MAX : reg_size; 4376882b0aeSVadim Pasternak read_tran[1].len = chunk_size; 4386882b0aeSVadim Pasternak mlxsw_i2c_set_slave_addr(tran_buf, off); 4396882b0aeSVadim Pasternak 4406882b0aeSVadim Pasternak j = 0; 4416882b0aeSVadim Pasternak end = jiffies + timeout; 4426882b0aeSVadim Pasternak do { 4436882b0aeSVadim Pasternak err = i2c_transfer(client->adapter, read_tran, 4446882b0aeSVadim Pasternak ARRAY_SIZE(read_tran)); 4456882b0aeSVadim Pasternak if (err == ARRAY_SIZE(read_tran)) 4466882b0aeSVadim Pasternak break; 4476882b0aeSVadim Pasternak 4486882b0aeSVadim Pasternak cond_resched(); 4496882b0aeSVadim Pasternak } while ((time_before(jiffies, end)) || 4506882b0aeSVadim Pasternak (j++ < MLXSW_I2C_RETRY)); 4516882b0aeSVadim Pasternak 4526882b0aeSVadim Pasternak if (err != ARRAY_SIZE(read_tran)) { 4536882b0aeSVadim Pasternak if (!err) 4546882b0aeSVadim Pasternak err = -EIO; 4556882b0aeSVadim Pasternak 4566882b0aeSVadim Pasternak goto cmd_fail; 4576882b0aeSVadim Pasternak } 4586882b0aeSVadim Pasternak 4596882b0aeSVadim Pasternak off += chunk_size; 4606882b0aeSVadim Pasternak reg_size -= chunk_size; 4616882b0aeSVadim Pasternak read_tran[1].buf += chunk_size; 4626882b0aeSVadim Pasternak } 4636882b0aeSVadim Pasternak 4646882b0aeSVadim Pasternak mutex_unlock(&mlxsw_i2c->cmd.lock); 4656882b0aeSVadim Pasternak 4666882b0aeSVadim Pasternak return 0; 4676882b0aeSVadim Pasternak 4686882b0aeSVadim Pasternak cmd_fail: 4696882b0aeSVadim Pasternak mutex_unlock(&mlxsw_i2c->cmd.lock); 4706882b0aeSVadim Pasternak return err; 4716882b0aeSVadim Pasternak } 4726882b0aeSVadim Pasternak 4736882b0aeSVadim Pasternak static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, 4746882b0aeSVadim Pasternak u32 in_mod, bool out_mbox_direct, 4756882b0aeSVadim Pasternak char *in_mbox, size_t in_mbox_size, 4766882b0aeSVadim Pasternak char *out_mbox, size_t out_mbox_size, 4776882b0aeSVadim Pasternak u8 *status) 4786882b0aeSVadim Pasternak { 4796882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c = bus_priv; 4806882b0aeSVadim Pasternak 48195b75cbdSVadim Pasternak return mlxsw_i2c_cmd(mlxsw_i2c->dev, opcode, in_mod, in_mbox_size, 48295b75cbdSVadim Pasternak in_mbox, out_mbox_size, out_mbox, status); 4836882b0aeSVadim Pasternak } 4846882b0aeSVadim Pasternak 4856882b0aeSVadim Pasternak static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv, 4866882b0aeSVadim Pasternak const struct mlxsw_tx_info *tx_info) 4876882b0aeSVadim Pasternak { 4886882b0aeSVadim Pasternak return false; 4896882b0aeSVadim Pasternak } 4906882b0aeSVadim Pasternak 4916882b0aeSVadim Pasternak static int mlxsw_i2c_skb_transmit(void *bus_priv, struct sk_buff *skb, 4926882b0aeSVadim Pasternak const struct mlxsw_tx_info *tx_info) 4936882b0aeSVadim Pasternak { 4946882b0aeSVadim Pasternak return 0; 4956882b0aeSVadim Pasternak } 4966882b0aeSVadim Pasternak 4976882b0aeSVadim Pasternak static int 4986882b0aeSVadim Pasternak mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core, 4996882b0aeSVadim Pasternak const struct mlxsw_config_profile *profile, 500f43d9d9bSVadim Pasternak struct mlxsw_res *res) 5016882b0aeSVadim Pasternak { 5026882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c = bus_priv; 503*6a986993SVadim Pasternak char *mbox; 504*6a986993SVadim Pasternak int err; 5056882b0aeSVadim Pasternak 5066882b0aeSVadim Pasternak mlxsw_i2c->core = mlxsw_core; 5076882b0aeSVadim Pasternak 508*6a986993SVadim Pasternak mbox = mlxsw_cmd_mbox_alloc(); 509*6a986993SVadim Pasternak if (!mbox) 510*6a986993SVadim Pasternak return -ENOMEM; 511*6a986993SVadim Pasternak 512*6a986993SVadim Pasternak err = mlxsw_core_resources_query(mlxsw_core, mbox, res); 513*6a986993SVadim Pasternak 514*6a986993SVadim Pasternak mlxsw_cmd_mbox_free(mbox); 515*6a986993SVadim Pasternak return err; 5166882b0aeSVadim Pasternak } 5176882b0aeSVadim Pasternak 5186882b0aeSVadim Pasternak static void mlxsw_i2c_fini(void *bus_priv) 5196882b0aeSVadim Pasternak { 5206882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c = bus_priv; 5216882b0aeSVadim Pasternak 5226882b0aeSVadim Pasternak mlxsw_i2c->core = NULL; 5236882b0aeSVadim Pasternak } 5246882b0aeSVadim Pasternak 5256882b0aeSVadim Pasternak static const struct mlxsw_bus mlxsw_i2c_bus = { 5266882b0aeSVadim Pasternak .kind = "i2c", 5276882b0aeSVadim Pasternak .init = mlxsw_i2c_init, 5286882b0aeSVadim Pasternak .fini = mlxsw_i2c_fini, 5296882b0aeSVadim Pasternak .skb_transmit_busy = mlxsw_i2c_skb_transmit_busy, 5306882b0aeSVadim Pasternak .skb_transmit = mlxsw_i2c_skb_transmit, 5316882b0aeSVadim Pasternak .cmd_exec = mlxsw_i2c_cmd_exec, 5326882b0aeSVadim Pasternak }; 5336882b0aeSVadim Pasternak 5346882b0aeSVadim Pasternak static int mlxsw_i2c_probe(struct i2c_client *client, 5356882b0aeSVadim Pasternak const struct i2c_device_id *id) 5366882b0aeSVadim Pasternak { 5376882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c; 5386882b0aeSVadim Pasternak u8 status; 5396882b0aeSVadim Pasternak int err; 5406882b0aeSVadim Pasternak 5416882b0aeSVadim Pasternak mlxsw_i2c = devm_kzalloc(&client->dev, sizeof(*mlxsw_i2c), GFP_KERNEL); 5426882b0aeSVadim Pasternak if (!mlxsw_i2c) 5436882b0aeSVadim Pasternak return -ENOMEM; 5446882b0aeSVadim Pasternak 5456882b0aeSVadim Pasternak i2c_set_clientdata(client, mlxsw_i2c); 5466882b0aeSVadim Pasternak mutex_init(&mlxsw_i2c->cmd.lock); 5476882b0aeSVadim Pasternak 5486882b0aeSVadim Pasternak /* In order to use mailboxes through the i2c, special area is reserved 5496882b0aeSVadim Pasternak * on the i2c address space that can be used for input and output 5506882b0aeSVadim Pasternak * mailboxes. Such mailboxes are called local mailboxes. When using a 5516882b0aeSVadim Pasternak * local mailbox, software should specify 0 as the Input/Output 5526882b0aeSVadim Pasternak * parameters. The location of the Local Mailbox addresses on the i2c 5536882b0aeSVadim Pasternak * space can be retrieved through the QUERY_FW command. 5546882b0aeSVadim Pasternak * For this purpose QUERY_FW is to be issued with opcode modifier equal 5556882b0aeSVadim Pasternak * 0x01. For such command the output parameter is an immediate value. 5566882b0aeSVadim Pasternak * Here QUERY_FW command is invoked for ASIC probing and for getting 5576882b0aeSVadim Pasternak * local mailboxes addresses from immedate output parameters. 5586882b0aeSVadim Pasternak */ 5596882b0aeSVadim Pasternak 5606882b0aeSVadim Pasternak /* Prepare and write out Command Interface Register for transaction */ 5616882b0aeSVadim Pasternak err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 1); 5626882b0aeSVadim Pasternak if (err) { 5636882b0aeSVadim Pasternak dev_err(&client->dev, "Could not start transaction"); 5646882b0aeSVadim Pasternak goto errout; 5656882b0aeSVadim Pasternak } 5666882b0aeSVadim Pasternak 5676882b0aeSVadim Pasternak /* Wait until go bit is cleared. */ 5686882b0aeSVadim Pasternak err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status); 5696882b0aeSVadim Pasternak if (err) { 5706882b0aeSVadim Pasternak dev_err(&client->dev, "HW semaphore is not released"); 5716882b0aeSVadim Pasternak goto errout; 5726882b0aeSVadim Pasternak } 5736882b0aeSVadim Pasternak 5746882b0aeSVadim Pasternak /* Validate transaction completion status. */ 5756882b0aeSVadim Pasternak if (status) { 5766882b0aeSVadim Pasternak dev_err(&client->dev, "Bad transaction completion status %x\n", 5776882b0aeSVadim Pasternak status); 5786882b0aeSVadim Pasternak err = -EIO; 5796882b0aeSVadim Pasternak goto errout; 5806882b0aeSVadim Pasternak } 5816882b0aeSVadim Pasternak 5826882b0aeSVadim Pasternak /* Get mailbox offsets. */ 5836882b0aeSVadim Pasternak err = mlxsw_i2c_get_mbox(client, mlxsw_i2c); 5846882b0aeSVadim Pasternak if (err < 0) { 5856882b0aeSVadim Pasternak dev_err(&client->dev, "Fail to get mailboxes\n"); 5866882b0aeSVadim Pasternak goto errout; 5876882b0aeSVadim Pasternak } 5886882b0aeSVadim Pasternak 5896882b0aeSVadim Pasternak dev_info(&client->dev, "%s mb size=%x off=0x%08x out mb size=%x off=0x%08x\n", 5906882b0aeSVadim Pasternak id->name, mlxsw_i2c->cmd.mb_size_in, 5916882b0aeSVadim Pasternak mlxsw_i2c->cmd.mb_off_in, mlxsw_i2c->cmd.mb_size_out, 5926882b0aeSVadim Pasternak mlxsw_i2c->cmd.mb_off_out); 5936882b0aeSVadim Pasternak 5946882b0aeSVadim Pasternak /* Register device bus. */ 5956882b0aeSVadim Pasternak mlxsw_i2c->bus_info.device_kind = id->name; 5966882b0aeSVadim Pasternak mlxsw_i2c->bus_info.device_name = client->name; 5976882b0aeSVadim Pasternak mlxsw_i2c->bus_info.dev = &client->dev; 5983dcfe179SVadim Pasternak mlxsw_i2c->bus_info.low_frequency = true; 5996882b0aeSVadim Pasternak mlxsw_i2c->dev = &client->dev; 6006882b0aeSVadim Pasternak 6016882b0aeSVadim Pasternak err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, 60224cc68adSArkadi Sharshevsky &mlxsw_i2c_bus, mlxsw_i2c, false, 60324cc68adSArkadi Sharshevsky NULL); 6046882b0aeSVadim Pasternak if (err) { 6056882b0aeSVadim Pasternak dev_err(&client->dev, "Fail to register core bus\n"); 6066882b0aeSVadim Pasternak return err; 6076882b0aeSVadim Pasternak } 6086882b0aeSVadim Pasternak 6096882b0aeSVadim Pasternak return 0; 6106882b0aeSVadim Pasternak 6116882b0aeSVadim Pasternak errout: 6126882b0aeSVadim Pasternak i2c_set_clientdata(client, NULL); 6136882b0aeSVadim Pasternak 6146882b0aeSVadim Pasternak return err; 6156882b0aeSVadim Pasternak } 6166882b0aeSVadim Pasternak 6176882b0aeSVadim Pasternak static int mlxsw_i2c_remove(struct i2c_client *client) 6186882b0aeSVadim Pasternak { 6196882b0aeSVadim Pasternak struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); 6206882b0aeSVadim Pasternak 62124cc68adSArkadi Sharshevsky mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false); 6226882b0aeSVadim Pasternak mutex_destroy(&mlxsw_i2c->cmd.lock); 6236882b0aeSVadim Pasternak 6246882b0aeSVadim Pasternak return 0; 6256882b0aeSVadim Pasternak } 6266882b0aeSVadim Pasternak 6276882b0aeSVadim Pasternak int mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver) 6286882b0aeSVadim Pasternak { 6296882b0aeSVadim Pasternak i2c_driver->probe = mlxsw_i2c_probe; 6306882b0aeSVadim Pasternak i2c_driver->remove = mlxsw_i2c_remove; 6316882b0aeSVadim Pasternak return i2c_add_driver(i2c_driver); 6326882b0aeSVadim Pasternak } 6336882b0aeSVadim Pasternak EXPORT_SYMBOL(mlxsw_i2c_driver_register); 6346882b0aeSVadim Pasternak 6356882b0aeSVadim Pasternak void mlxsw_i2c_driver_unregister(struct i2c_driver *i2c_driver) 6366882b0aeSVadim Pasternak { 6376882b0aeSVadim Pasternak i2c_del_driver(i2c_driver); 6386882b0aeSVadim Pasternak } 6396882b0aeSVadim Pasternak EXPORT_SYMBOL(mlxsw_i2c_driver_unregister); 6406882b0aeSVadim Pasternak 6416882b0aeSVadim Pasternak MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 6426882b0aeSVadim Pasternak MODULE_DESCRIPTION("Mellanox switch I2C interface driver"); 6436882b0aeSVadim Pasternak MODULE_LICENSE("Dual BSD/GPL"); 644