xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/mellanox/mlxsw/i2c.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/err.h>
5*4882a593Smuzhiyun #include <linux/i2c.h>
6*4882a593Smuzhiyun #include <linux/init.h>
7*4882a593Smuzhiyun #include <linux/jiffies.h>
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/mutex.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include "cmd.h"
15*4882a593Smuzhiyun #include "core.h"
16*4882a593Smuzhiyun #include "i2c.h"
17*4882a593Smuzhiyun #include "resources.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define MLXSW_I2C_CIR2_BASE		0x72000
20*4882a593Smuzhiyun #define MLXSW_I2C_CIR_STATUS_OFF	0x18
21*4882a593Smuzhiyun #define MLXSW_I2C_CIR2_OFF_STATUS	(MLXSW_I2C_CIR2_BASE + \
22*4882a593Smuzhiyun 					 MLXSW_I2C_CIR_STATUS_OFF)
23*4882a593Smuzhiyun #define MLXSW_I2C_OPMOD_SHIFT		12
24*4882a593Smuzhiyun #define MLXSW_I2C_EVENT_BIT_SHIFT	22
25*4882a593Smuzhiyun #define MLXSW_I2C_GO_BIT_SHIFT		23
26*4882a593Smuzhiyun #define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT	24
27*4882a593Smuzhiyun #define MLXSW_I2C_EVENT_BIT		BIT(MLXSW_I2C_EVENT_BIT_SHIFT)
28*4882a593Smuzhiyun #define MLXSW_I2C_GO_BIT		BIT(MLXSW_I2C_GO_BIT_SHIFT)
29*4882a593Smuzhiyun #define MLXSW_I2C_GO_OPMODE		BIT(MLXSW_I2C_OPMOD_SHIFT)
30*4882a593Smuzhiyun #define MLXSW_I2C_SET_IMM_CMD		(MLXSW_I2C_GO_OPMODE | \
31*4882a593Smuzhiyun 					 MLXSW_CMD_OPCODE_QUERY_FW)
32*4882a593Smuzhiyun #define MLXSW_I2C_PUSH_IMM_CMD		(MLXSW_I2C_GO_BIT | \
33*4882a593Smuzhiyun 					 MLXSW_I2C_SET_IMM_CMD)
34*4882a593Smuzhiyun #define MLXSW_I2C_SET_CMD		(MLXSW_CMD_OPCODE_ACCESS_REG)
35*4882a593Smuzhiyun #define MLXSW_I2C_PUSH_CMD		(MLXSW_I2C_GO_BIT | MLXSW_I2C_SET_CMD)
36*4882a593Smuzhiyun #define MLXSW_I2C_TLV_HDR_SIZE		0x10
37*4882a593Smuzhiyun #define MLXSW_I2C_ADDR_WIDTH		4
38*4882a593Smuzhiyun #define MLXSW_I2C_PUSH_CMD_SIZE		(MLXSW_I2C_ADDR_WIDTH + 4)
39*4882a593Smuzhiyun #define MLXSW_I2C_SET_EVENT_CMD		(MLXSW_I2C_EVENT_BIT)
40*4882a593Smuzhiyun #define MLXSW_I2C_PUSH_EVENT_CMD	(MLXSW_I2C_GO_BIT | \
41*4882a593Smuzhiyun 					 MLXSW_I2C_SET_EVENT_CMD)
42*4882a593Smuzhiyun #define MLXSW_I2C_READ_SEMA_SIZE	4
43*4882a593Smuzhiyun #define MLXSW_I2C_PREP_SIZE		(MLXSW_I2C_ADDR_WIDTH + 28)
44*4882a593Smuzhiyun #define MLXSW_I2C_MBOX_SIZE		20
45*4882a593Smuzhiyun #define MLXSW_I2C_MBOX_OUT_PARAM_OFF	12
46*4882a593Smuzhiyun #define MLXSW_I2C_MBOX_OFFSET_BITS	20
47*4882a593Smuzhiyun #define MLXSW_I2C_MBOX_SIZE_BITS	12
48*4882a593Smuzhiyun #define MLXSW_I2C_ADDR_BUF_SIZE		4
49*4882a593Smuzhiyun #define MLXSW_I2C_BLK_DEF		32
50*4882a593Smuzhiyun #define MLXSW_I2C_RETRY			5
51*4882a593Smuzhiyun #define MLXSW_I2C_TIMEOUT_MSECS		5000
52*4882a593Smuzhiyun #define MLXSW_I2C_MAX_DATA_SIZE		256
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /**
55*4882a593Smuzhiyun  * struct mlxsw_i2c - device private data:
56*4882a593Smuzhiyun  * @cmd: command attributes;
57*4882a593Smuzhiyun  * @cmd.mb_size_in: input mailbox size;
58*4882a593Smuzhiyun  * @cmd.mb_off_in: input mailbox offset in register space;
59*4882a593Smuzhiyun  * @cmd.mb_size_out: output mailbox size;
60*4882a593Smuzhiyun  * @cmd.mb_off_out: output mailbox offset in register space;
61*4882a593Smuzhiyun  * @cmd.lock: command execution lock;
62*4882a593Smuzhiyun  * @dev: I2C device;
63*4882a593Smuzhiyun  * @core: switch core pointer;
64*4882a593Smuzhiyun  * @bus_info: bus info block;
65*4882a593Smuzhiyun  * @block_size: maximum block size allowed to pass to under layer;
66*4882a593Smuzhiyun  */
67*4882a593Smuzhiyun struct mlxsw_i2c {
68*4882a593Smuzhiyun 	struct {
69*4882a593Smuzhiyun 		u32 mb_size_in;
70*4882a593Smuzhiyun 		u32 mb_off_in;
71*4882a593Smuzhiyun 		u32 mb_size_out;
72*4882a593Smuzhiyun 		u32 mb_off_out;
73*4882a593Smuzhiyun 		struct mutex lock;
74*4882a593Smuzhiyun 	} cmd;
75*4882a593Smuzhiyun 	struct device *dev;
76*4882a593Smuzhiyun 	struct mlxsw_core *core;
77*4882a593Smuzhiyun 	struct mlxsw_bus_info bus_info;
78*4882a593Smuzhiyun 	u16 block_size;
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) {	\
82*4882a593Smuzhiyun 	{ .addr = (_client)->addr,				\
83*4882a593Smuzhiyun 	  .buf = (_addr_buf),					\
84*4882a593Smuzhiyun 	  .len = MLXSW_I2C_ADDR_BUF_SIZE,			\
85*4882a593Smuzhiyun 	  .flags = 0 },						\
86*4882a593Smuzhiyun 	{ .addr = (_client)->addr,				\
87*4882a593Smuzhiyun 	  .buf = (_buf),					\
88*4882a593Smuzhiyun 	  .len = (_len),					\
89*4882a593Smuzhiyun 	  .flags = I2C_M_RD } }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun #define MLXSW_I2C_WRITE_MSG(_client, _buf, _len)		\
92*4882a593Smuzhiyun 	{ .addr = (_client)->addr,				\
93*4882a593Smuzhiyun 	  .buf = (u8 *)(_buf),					\
94*4882a593Smuzhiyun 	  .len = (_len),					\
95*4882a593Smuzhiyun 	  .flags = 0 }
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /* Routine converts in and out mail boxes offset and size. */
98*4882a593Smuzhiyun static inline void
mlxsw_i2c_convert_mbox(struct mlxsw_i2c * mlxsw_i2c,u8 * buf)99*4882a593Smuzhiyun mlxsw_i2c_convert_mbox(struct mlxsw_i2c *mlxsw_i2c, u8 *buf)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	u32 tmp;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	/* Local in/out mailboxes: 20 bits for offset, 12 for size */
104*4882a593Smuzhiyun 	tmp = be32_to_cpup((__be32 *) buf);
105*4882a593Smuzhiyun 	mlxsw_i2c->cmd.mb_off_in = tmp &
106*4882a593Smuzhiyun 				   GENMASK(MLXSW_I2C_MBOX_OFFSET_BITS - 1, 0);
107*4882a593Smuzhiyun 	mlxsw_i2c->cmd.mb_size_in = (tmp & GENMASK(31,
108*4882a593Smuzhiyun 					MLXSW_I2C_MBOX_OFFSET_BITS)) >>
109*4882a593Smuzhiyun 					MLXSW_I2C_MBOX_OFFSET_BITS;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	tmp = be32_to_cpup((__be32 *) (buf + MLXSW_I2C_ADDR_WIDTH));
112*4882a593Smuzhiyun 	mlxsw_i2c->cmd.mb_off_out = tmp &
113*4882a593Smuzhiyun 				    GENMASK(MLXSW_I2C_MBOX_OFFSET_BITS - 1, 0);
114*4882a593Smuzhiyun 	mlxsw_i2c->cmd.mb_size_out = (tmp & GENMASK(31,
115*4882a593Smuzhiyun 					MLXSW_I2C_MBOX_OFFSET_BITS)) >>
116*4882a593Smuzhiyun 					MLXSW_I2C_MBOX_OFFSET_BITS;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /* Routine obtains register size from mail box buffer. */
mlxsw_i2c_get_reg_size(u8 * in_mbox)120*4882a593Smuzhiyun static inline int mlxsw_i2c_get_reg_size(u8 *in_mbox)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	u16  tmp = be16_to_cpup((__be16 *) (in_mbox + MLXSW_I2C_TLV_HDR_SIZE));
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return (tmp & 0x7ff) * 4 + MLXSW_I2C_TLV_HDR_SIZE;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /* Routine sets I2C device internal offset in the transaction buffer. */
mlxsw_i2c_set_slave_addr(u8 * buf,u32 off)128*4882a593Smuzhiyun static inline void mlxsw_i2c_set_slave_addr(u8 *buf, u32 off)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	__be32 *val = (__be32 *) buf;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	*val = htonl(off);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /* Routine waits until go bit is cleared. */
mlxsw_i2c_wait_go_bit(struct i2c_client * client,struct mlxsw_i2c * mlxsw_i2c,u8 * p_status)136*4882a593Smuzhiyun static int mlxsw_i2c_wait_go_bit(struct i2c_client *client,
137*4882a593Smuzhiyun 				 struct mlxsw_i2c *mlxsw_i2c, u8 *p_status)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	u8 addr_buf[MLXSW_I2C_ADDR_BUF_SIZE];
140*4882a593Smuzhiyun 	u8 buf[MLXSW_I2C_READ_SEMA_SIZE];
141*4882a593Smuzhiyun 	int len = MLXSW_I2C_READ_SEMA_SIZE;
142*4882a593Smuzhiyun 	struct i2c_msg read_sema[] =
143*4882a593Smuzhiyun 		MLXSW_I2C_READ_MSG(client, addr_buf, buf, len);
144*4882a593Smuzhiyun 	bool wait_done = false;
145*4882a593Smuzhiyun 	unsigned long end;
146*4882a593Smuzhiyun 	int i = 0, err;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_OFF_STATUS);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	end = jiffies + msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS);
151*4882a593Smuzhiyun 	do {
152*4882a593Smuzhiyun 		u32 ctrl;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 		err = i2c_transfer(client->adapter, read_sema,
155*4882a593Smuzhiyun 				   ARRAY_SIZE(read_sema));
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 		ctrl = be32_to_cpu(*(__be32 *) buf);
158*4882a593Smuzhiyun 		if (err == ARRAY_SIZE(read_sema)) {
159*4882a593Smuzhiyun 			if (!(ctrl & MLXSW_I2C_GO_BIT)) {
160*4882a593Smuzhiyun 				wait_done = true;
161*4882a593Smuzhiyun 				*p_status = ctrl >>
162*4882a593Smuzhiyun 					    MLXSW_I2C_CIR_CTRL_STATUS_SHIFT;
163*4882a593Smuzhiyun 				break;
164*4882a593Smuzhiyun 			}
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 		cond_resched();
167*4882a593Smuzhiyun 	} while ((time_before(jiffies, end)) || (i++ < MLXSW_I2C_RETRY));
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (wait_done) {
170*4882a593Smuzhiyun 		if (*p_status)
171*4882a593Smuzhiyun 			err = -EIO;
172*4882a593Smuzhiyun 	} else {
173*4882a593Smuzhiyun 		return -ETIMEDOUT;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	return err > 0 ? 0 : err;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /* Routine posts a command to ASIC through mail box. */
mlxsw_i2c_write_cmd(struct i2c_client * client,struct mlxsw_i2c * mlxsw_i2c,int immediate)180*4882a593Smuzhiyun static int mlxsw_i2c_write_cmd(struct i2c_client *client,
181*4882a593Smuzhiyun 			       struct mlxsw_i2c *mlxsw_i2c,
182*4882a593Smuzhiyun 			       int immediate)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	__be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = {
185*4882a593Smuzhiyun 		0, cpu_to_be32(MLXSW_I2C_PUSH_IMM_CMD)
186*4882a593Smuzhiyun 	};
187*4882a593Smuzhiyun 	__be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = {
188*4882a593Smuzhiyun 		0, 0, 0, 0, 0, 0,
189*4882a593Smuzhiyun 		cpu_to_be32(client->adapter->nr & 0xffff),
190*4882a593Smuzhiyun 		cpu_to_be32(MLXSW_I2C_SET_IMM_CMD)
191*4882a593Smuzhiyun 	};
192*4882a593Smuzhiyun 	struct i2c_msg push_cmd =
193*4882a593Smuzhiyun 		MLXSW_I2C_WRITE_MSG(client, push_cmd_buf,
194*4882a593Smuzhiyun 				    MLXSW_I2C_PUSH_CMD_SIZE);
195*4882a593Smuzhiyun 	struct i2c_msg prep_cmd =
196*4882a593Smuzhiyun 		MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE);
197*4882a593Smuzhiyun 	int err;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (!immediate) {
200*4882a593Smuzhiyun 		push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_CMD);
201*4882a593Smuzhiyun 		prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_SET_CMD);
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 	mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf,
204*4882a593Smuzhiyun 				 MLXSW_I2C_CIR2_BASE);
205*4882a593Smuzhiyun 	mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf,
206*4882a593Smuzhiyun 				 MLXSW_I2C_CIR2_OFF_STATUS);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/* Prepare Command Interface Register for transaction */
209*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, &prep_cmd, 1);
210*4882a593Smuzhiyun 	if (err < 0)
211*4882a593Smuzhiyun 		return err;
212*4882a593Smuzhiyun 	else if (err != 1)
213*4882a593Smuzhiyun 		return -EIO;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	/* Write out Command Interface Register GO bit to push transaction */
216*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, &push_cmd, 1);
217*4882a593Smuzhiyun 	if (err < 0)
218*4882a593Smuzhiyun 		return err;
219*4882a593Smuzhiyun 	else if (err != 1)
220*4882a593Smuzhiyun 		return -EIO;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	return 0;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun /* Routine posts initialization command to ASIC through mail box. */
226*4882a593Smuzhiyun static int
mlxsw_i2c_write_init_cmd(struct i2c_client * client,struct mlxsw_i2c * mlxsw_i2c,u16 opcode,u32 in_mod)227*4882a593Smuzhiyun mlxsw_i2c_write_init_cmd(struct i2c_client *client,
228*4882a593Smuzhiyun 			 struct mlxsw_i2c *mlxsw_i2c, u16 opcode, u32 in_mod)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	__be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = {
231*4882a593Smuzhiyun 		0, cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD)
232*4882a593Smuzhiyun 	};
233*4882a593Smuzhiyun 	__be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = {
234*4882a593Smuzhiyun 		0, 0, 0, 0, 0, 0,
235*4882a593Smuzhiyun 		cpu_to_be32(client->adapter->nr & 0xffff),
236*4882a593Smuzhiyun 		cpu_to_be32(MLXSW_I2C_SET_EVENT_CMD)
237*4882a593Smuzhiyun 	};
238*4882a593Smuzhiyun 	struct i2c_msg push_cmd =
239*4882a593Smuzhiyun 		MLXSW_I2C_WRITE_MSG(client, push_cmd_buf,
240*4882a593Smuzhiyun 				    MLXSW_I2C_PUSH_CMD_SIZE);
241*4882a593Smuzhiyun 	struct i2c_msg prep_cmd =
242*4882a593Smuzhiyun 		MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE);
243*4882a593Smuzhiyun 	u8 status;
244*4882a593Smuzhiyun 	int err;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD | opcode);
247*4882a593Smuzhiyun 	prep_cmd_buf[3] = cpu_to_be32(in_mod);
248*4882a593Smuzhiyun 	prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_GO_BIT | opcode);
249*4882a593Smuzhiyun 	mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf,
250*4882a593Smuzhiyun 				 MLXSW_I2C_CIR2_BASE);
251*4882a593Smuzhiyun 	mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf,
252*4882a593Smuzhiyun 				 MLXSW_I2C_CIR2_OFF_STATUS);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* Prepare Command Interface Register for transaction */
255*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, &prep_cmd, 1);
256*4882a593Smuzhiyun 	if (err < 0)
257*4882a593Smuzhiyun 		return err;
258*4882a593Smuzhiyun 	else if (err != 1)
259*4882a593Smuzhiyun 		return -EIO;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	/* Write out Command Interface Register GO bit to push transaction */
262*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, &push_cmd, 1);
263*4882a593Smuzhiyun 	if (err < 0)
264*4882a593Smuzhiyun 		return err;
265*4882a593Smuzhiyun 	else if (err != 1)
266*4882a593Smuzhiyun 		return -EIO;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* Wait until go bit is cleared. */
269*4882a593Smuzhiyun 	err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status);
270*4882a593Smuzhiyun 	if (err) {
271*4882a593Smuzhiyun 		dev_err(&client->dev, "HW semaphore is not released");
272*4882a593Smuzhiyun 		return err;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	/* Validate transaction completion status. */
276*4882a593Smuzhiyun 	if (status) {
277*4882a593Smuzhiyun 		dev_err(&client->dev, "Bad transaction completion status %x\n",
278*4882a593Smuzhiyun 			status);
279*4882a593Smuzhiyun 		return -EIO;
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun /* Routine obtains mail box offsets from ASIC register space. */
mlxsw_i2c_get_mbox(struct i2c_client * client,struct mlxsw_i2c * mlxsw_i2c)286*4882a593Smuzhiyun static int mlxsw_i2c_get_mbox(struct i2c_client *client,
287*4882a593Smuzhiyun 			      struct mlxsw_i2c *mlxsw_i2c)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	u8 addr_buf[MLXSW_I2C_ADDR_BUF_SIZE];
290*4882a593Smuzhiyun 	u8 buf[MLXSW_I2C_MBOX_SIZE];
291*4882a593Smuzhiyun 	struct i2c_msg mbox_cmd[] =
292*4882a593Smuzhiyun 		MLXSW_I2C_READ_MSG(client, addr_buf, buf, MLXSW_I2C_MBOX_SIZE);
293*4882a593Smuzhiyun 	int err;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	/* Read mail boxes offsets. */
296*4882a593Smuzhiyun 	mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_BASE);
297*4882a593Smuzhiyun 	err = i2c_transfer(client->adapter, mbox_cmd, 2);
298*4882a593Smuzhiyun 	if (err != 2) {
299*4882a593Smuzhiyun 		dev_err(&client->dev, "Could not obtain mail boxes\n");
300*4882a593Smuzhiyun 		if (!err)
301*4882a593Smuzhiyun 			return -EIO;
302*4882a593Smuzhiyun 		else
303*4882a593Smuzhiyun 			return err;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* Convert mail boxes. */
307*4882a593Smuzhiyun 	mlxsw_i2c_convert_mbox(mlxsw_i2c, &buf[MLXSW_I2C_MBOX_OUT_PARAM_OFF]);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	return err;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun /* Routine sends I2C write transaction to ASIC device. */
313*4882a593Smuzhiyun static int
mlxsw_i2c_write(struct device * dev,size_t in_mbox_size,u8 * in_mbox,int num,u8 * p_status)314*4882a593Smuzhiyun mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,
315*4882a593Smuzhiyun 		u8 *p_status)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(dev);
318*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
319*4882a593Smuzhiyun 	unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS);
320*4882a593Smuzhiyun 	int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j;
321*4882a593Smuzhiyun 	unsigned long end;
322*4882a593Smuzhiyun 	u8 *tran_buf;
323*4882a593Smuzhiyun 	struct i2c_msg write_tran =
324*4882a593Smuzhiyun 		MLXSW_I2C_WRITE_MSG(client, NULL, MLXSW_I2C_PUSH_CMD_SIZE);
325*4882a593Smuzhiyun 	int err;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	tran_buf = kmalloc(mlxsw_i2c->block_size + MLXSW_I2C_ADDR_BUF_SIZE,
328*4882a593Smuzhiyun 			   GFP_KERNEL);
329*4882a593Smuzhiyun 	if (!tran_buf)
330*4882a593Smuzhiyun 		return -ENOMEM;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	write_tran.buf = tran_buf;
333*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
334*4882a593Smuzhiyun 		chunk_size = (in_mbox_size > mlxsw_i2c->block_size) ?
335*4882a593Smuzhiyun 			     mlxsw_i2c->block_size : in_mbox_size;
336*4882a593Smuzhiyun 		write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size;
337*4882a593Smuzhiyun 		mlxsw_i2c_set_slave_addr(tran_buf, off);
338*4882a593Smuzhiyun 		memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox +
339*4882a593Smuzhiyun 		       mlxsw_i2c->block_size * i, chunk_size);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		j = 0;
342*4882a593Smuzhiyun 		end = jiffies + timeout;
343*4882a593Smuzhiyun 		do {
344*4882a593Smuzhiyun 			err = i2c_transfer(client->adapter, &write_tran, 1);
345*4882a593Smuzhiyun 			if (err == 1)
346*4882a593Smuzhiyun 				break;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 			cond_resched();
349*4882a593Smuzhiyun 		} while ((time_before(jiffies, end)) ||
350*4882a593Smuzhiyun 			 (j++ < MLXSW_I2C_RETRY));
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 		if (err != 1) {
353*4882a593Smuzhiyun 			if (!err) {
354*4882a593Smuzhiyun 				err = -EIO;
355*4882a593Smuzhiyun 				goto mlxsw_i2c_write_exit;
356*4882a593Smuzhiyun 			}
357*4882a593Smuzhiyun 		}
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		off += chunk_size;
360*4882a593Smuzhiyun 		in_mbox_size -= chunk_size;
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	/* Prepare and write out Command Interface Register for transaction. */
364*4882a593Smuzhiyun 	err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0);
365*4882a593Smuzhiyun 	if (err) {
366*4882a593Smuzhiyun 		dev_err(&client->dev, "Could not start transaction");
367*4882a593Smuzhiyun 		err = -EIO;
368*4882a593Smuzhiyun 		goto mlxsw_i2c_write_exit;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/* Wait until go bit is cleared. */
372*4882a593Smuzhiyun 	err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status);
373*4882a593Smuzhiyun 	if (err) {
374*4882a593Smuzhiyun 		dev_err(&client->dev, "HW semaphore is not released");
375*4882a593Smuzhiyun 		goto mlxsw_i2c_write_exit;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/* Validate transaction completion status. */
379*4882a593Smuzhiyun 	if (*p_status) {
380*4882a593Smuzhiyun 		dev_err(&client->dev, "Bad transaction completion status %x\n",
381*4882a593Smuzhiyun 			*p_status);
382*4882a593Smuzhiyun 		err = -EIO;
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun mlxsw_i2c_write_exit:
386*4882a593Smuzhiyun 	kfree(tran_buf);
387*4882a593Smuzhiyun 	return err;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun /* Routine executes I2C command. */
391*4882a593Smuzhiyun static int
mlxsw_i2c_cmd(struct device * dev,u16 opcode,u32 in_mod,size_t in_mbox_size,u8 * in_mbox,size_t out_mbox_size,u8 * out_mbox,u8 * status)392*4882a593Smuzhiyun mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size,
393*4882a593Smuzhiyun 	      u8 *in_mbox, size_t out_mbox_size, u8 *out_mbox, u8 *status)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(dev);
396*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
397*4882a593Smuzhiyun 	unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS);
398*4882a593Smuzhiyun 	u8 tran_buf[MLXSW_I2C_ADDR_BUF_SIZE];
399*4882a593Smuzhiyun 	int num, chunk_size, reg_size, i, j;
400*4882a593Smuzhiyun 	int off = mlxsw_i2c->cmd.mb_off_out;
401*4882a593Smuzhiyun 	unsigned long end;
402*4882a593Smuzhiyun 	struct i2c_msg read_tran[] =
403*4882a593Smuzhiyun 		MLXSW_I2C_READ_MSG(client, tran_buf, NULL, 0);
404*4882a593Smuzhiyun 	int err;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32));
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (in_mbox) {
409*4882a593Smuzhiyun 		reg_size = mlxsw_i2c_get_reg_size(in_mbox);
410*4882a593Smuzhiyun 		num = reg_size / mlxsw_i2c->block_size;
411*4882a593Smuzhiyun 		if (reg_size % mlxsw_i2c->block_size)
412*4882a593Smuzhiyun 			num++;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 		if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
415*4882a593Smuzhiyun 			dev_err(&client->dev, "Could not acquire lock");
416*4882a593Smuzhiyun 			return -EINVAL;
417*4882a593Smuzhiyun 		}
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 		err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status);
420*4882a593Smuzhiyun 		if (err)
421*4882a593Smuzhiyun 			goto cmd_fail;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 		/* No out mailbox is case of write transaction. */
424*4882a593Smuzhiyun 		if (!out_mbox) {
425*4882a593Smuzhiyun 			mutex_unlock(&mlxsw_i2c->cmd.lock);
426*4882a593Smuzhiyun 			return 0;
427*4882a593Smuzhiyun 		}
428*4882a593Smuzhiyun 	} else {
429*4882a593Smuzhiyun 		/* No input mailbox is case of initialization query command. */
430*4882a593Smuzhiyun 		reg_size = MLXSW_I2C_MAX_DATA_SIZE;
431*4882a593Smuzhiyun 		num = reg_size / mlxsw_i2c->block_size;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 		if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
434*4882a593Smuzhiyun 			dev_err(&client->dev, "Could not acquire lock");
435*4882a593Smuzhiyun 			return -EINVAL;
436*4882a593Smuzhiyun 		}
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 		err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode,
439*4882a593Smuzhiyun 					       in_mod);
440*4882a593Smuzhiyun 		if (err)
441*4882a593Smuzhiyun 			goto cmd_fail;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	/* Send read transaction to get output mailbox content. */
445*4882a593Smuzhiyun 	read_tran[1].buf = out_mbox;
446*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
447*4882a593Smuzhiyun 		chunk_size = (reg_size > mlxsw_i2c->block_size) ?
448*4882a593Smuzhiyun 			     mlxsw_i2c->block_size : reg_size;
449*4882a593Smuzhiyun 		read_tran[1].len = chunk_size;
450*4882a593Smuzhiyun 		mlxsw_i2c_set_slave_addr(tran_buf, off);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 		j = 0;
453*4882a593Smuzhiyun 		end = jiffies + timeout;
454*4882a593Smuzhiyun 		do {
455*4882a593Smuzhiyun 			err = i2c_transfer(client->adapter, read_tran,
456*4882a593Smuzhiyun 					   ARRAY_SIZE(read_tran));
457*4882a593Smuzhiyun 			if (err == ARRAY_SIZE(read_tran))
458*4882a593Smuzhiyun 				break;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 			cond_resched();
461*4882a593Smuzhiyun 		} while ((time_before(jiffies, end)) ||
462*4882a593Smuzhiyun 			 (j++ < MLXSW_I2C_RETRY));
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 		if (err != ARRAY_SIZE(read_tran)) {
465*4882a593Smuzhiyun 			if (!err)
466*4882a593Smuzhiyun 				err = -EIO;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 			goto cmd_fail;
469*4882a593Smuzhiyun 		}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 		off += chunk_size;
472*4882a593Smuzhiyun 		reg_size -= chunk_size;
473*4882a593Smuzhiyun 		read_tran[1].buf += chunk_size;
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	mutex_unlock(&mlxsw_i2c->cmd.lock);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	return 0;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun cmd_fail:
481*4882a593Smuzhiyun 	mutex_unlock(&mlxsw_i2c->cmd.lock);
482*4882a593Smuzhiyun 	return err;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
mlxsw_i2c_cmd_exec(void * bus_priv,u16 opcode,u8 opcode_mod,u32 in_mod,bool out_mbox_direct,char * in_mbox,size_t in_mbox_size,char * out_mbox,size_t out_mbox_size,u8 * status)485*4882a593Smuzhiyun static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
486*4882a593Smuzhiyun 			      u32 in_mod, bool out_mbox_direct,
487*4882a593Smuzhiyun 			      char *in_mbox, size_t in_mbox_size,
488*4882a593Smuzhiyun 			      char *out_mbox, size_t out_mbox_size,
489*4882a593Smuzhiyun 			      u8 *status)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c = bus_priv;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	return mlxsw_i2c_cmd(mlxsw_i2c->dev, opcode, in_mod, in_mbox_size,
494*4882a593Smuzhiyun 			     in_mbox, out_mbox_size, out_mbox, status);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
mlxsw_i2c_skb_transmit_busy(void * bus_priv,const struct mlxsw_tx_info * tx_info)497*4882a593Smuzhiyun static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv,
498*4882a593Smuzhiyun 					const struct mlxsw_tx_info *tx_info)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun 	return false;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
mlxsw_i2c_skb_transmit(void * bus_priv,struct sk_buff * skb,const struct mlxsw_tx_info * tx_info)503*4882a593Smuzhiyun static int mlxsw_i2c_skb_transmit(void *bus_priv, struct sk_buff *skb,
504*4882a593Smuzhiyun 				  const struct mlxsw_tx_info *tx_info)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun 	return 0;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun static int
mlxsw_i2c_init(void * bus_priv,struct mlxsw_core * mlxsw_core,const struct mlxsw_config_profile * profile,struct mlxsw_res * res)510*4882a593Smuzhiyun mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
511*4882a593Smuzhiyun 	       const struct mlxsw_config_profile *profile,
512*4882a593Smuzhiyun 	       struct mlxsw_res *res)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c = bus_priv;
515*4882a593Smuzhiyun 	char *mbox;
516*4882a593Smuzhiyun 	int err;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	mlxsw_i2c->core = mlxsw_core;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	mbox = mlxsw_cmd_mbox_alloc();
521*4882a593Smuzhiyun 	if (!mbox)
522*4882a593Smuzhiyun 		return -ENOMEM;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	err = mlxsw_cmd_query_fw(mlxsw_core, mbox);
525*4882a593Smuzhiyun 	if (err)
526*4882a593Smuzhiyun 		goto mbox_put;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.fw_rev.major =
529*4882a593Smuzhiyun 		mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox);
530*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.fw_rev.minor =
531*4882a593Smuzhiyun 		mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox);
532*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.fw_rev.subminor =
533*4882a593Smuzhiyun 		mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox);
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	err = mlxsw_core_resources_query(mlxsw_core, mbox, res);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun mbox_put:
538*4882a593Smuzhiyun 	mlxsw_cmd_mbox_free(mbox);
539*4882a593Smuzhiyun 	return err;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
mlxsw_i2c_fini(void * bus_priv)542*4882a593Smuzhiyun static void mlxsw_i2c_fini(void *bus_priv)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c = bus_priv;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	mlxsw_i2c->core = NULL;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun static const struct mlxsw_bus mlxsw_i2c_bus = {
550*4882a593Smuzhiyun 	.kind			= "i2c",
551*4882a593Smuzhiyun 	.init			= mlxsw_i2c_init,
552*4882a593Smuzhiyun 	.fini			= mlxsw_i2c_fini,
553*4882a593Smuzhiyun 	.skb_transmit_busy	= mlxsw_i2c_skb_transmit_busy,
554*4882a593Smuzhiyun 	.skb_transmit		= mlxsw_i2c_skb_transmit,
555*4882a593Smuzhiyun 	.cmd_exec		= mlxsw_i2c_cmd_exec,
556*4882a593Smuzhiyun };
557*4882a593Smuzhiyun 
mlxsw_i2c_probe(struct i2c_client * client,const struct i2c_device_id * id)558*4882a593Smuzhiyun static int mlxsw_i2c_probe(struct i2c_client *client,
559*4882a593Smuzhiyun 			   const struct i2c_device_id *id)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	const struct i2c_adapter_quirks *quirks = client->adapter->quirks;
562*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c;
563*4882a593Smuzhiyun 	u8 status;
564*4882a593Smuzhiyun 	int err;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	mlxsw_i2c = devm_kzalloc(&client->dev, sizeof(*mlxsw_i2c), GFP_KERNEL);
567*4882a593Smuzhiyun 	if (!mlxsw_i2c)
568*4882a593Smuzhiyun 		return -ENOMEM;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	if (quirks) {
571*4882a593Smuzhiyun 		if ((quirks->max_read_len &&
572*4882a593Smuzhiyun 		     quirks->max_read_len < MLXSW_I2C_BLK_DEF) ||
573*4882a593Smuzhiyun 		    (quirks->max_write_len &&
574*4882a593Smuzhiyun 		     quirks->max_write_len < MLXSW_I2C_BLK_DEF)) {
575*4882a593Smuzhiyun 			dev_err(&client->dev, "Insufficient transaction buffer length\n");
576*4882a593Smuzhiyun 			return -EOPNOTSUPP;
577*4882a593Smuzhiyun 		}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 		mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF,
580*4882a593Smuzhiyun 					      min_t(u16, quirks->max_read_len,
581*4882a593Smuzhiyun 						    quirks->max_write_len));
582*4882a593Smuzhiyun 	} else {
583*4882a593Smuzhiyun 		mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	i2c_set_clientdata(client, mlxsw_i2c);
587*4882a593Smuzhiyun 	mutex_init(&mlxsw_i2c->cmd.lock);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	/* In order to use mailboxes through the i2c, special area is reserved
590*4882a593Smuzhiyun 	 * on the i2c address space that can be used for input and output
591*4882a593Smuzhiyun 	 * mailboxes. Such mailboxes are called local mailboxes. When using a
592*4882a593Smuzhiyun 	 * local mailbox, software should specify 0 as the Input/Output
593*4882a593Smuzhiyun 	 * parameters. The location of the Local Mailbox addresses on the i2c
594*4882a593Smuzhiyun 	 * space can be retrieved through the QUERY_FW command.
595*4882a593Smuzhiyun 	 * For this purpose QUERY_FW is to be issued with opcode modifier equal
596*4882a593Smuzhiyun 	 * 0x01. For such command the output parameter is an immediate value.
597*4882a593Smuzhiyun 	 * Here QUERY_FW command is invoked for ASIC probing and for getting
598*4882a593Smuzhiyun 	 * local mailboxes addresses from immedate output parameters.
599*4882a593Smuzhiyun 	 */
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	/* Prepare and write out Command Interface Register for transaction */
602*4882a593Smuzhiyun 	err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 1);
603*4882a593Smuzhiyun 	if (err) {
604*4882a593Smuzhiyun 		dev_err(&client->dev, "Could not start transaction");
605*4882a593Smuzhiyun 		goto errout;
606*4882a593Smuzhiyun 	}
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	/* Wait until go bit is cleared. */
609*4882a593Smuzhiyun 	err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status);
610*4882a593Smuzhiyun 	if (err) {
611*4882a593Smuzhiyun 		dev_err(&client->dev, "HW semaphore is not released");
612*4882a593Smuzhiyun 		goto errout;
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	/* Validate transaction completion status. */
616*4882a593Smuzhiyun 	if (status) {
617*4882a593Smuzhiyun 		dev_err(&client->dev, "Bad transaction completion status %x\n",
618*4882a593Smuzhiyun 			status);
619*4882a593Smuzhiyun 		err = -EIO;
620*4882a593Smuzhiyun 		goto errout;
621*4882a593Smuzhiyun 	}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	/* Get mailbox offsets. */
624*4882a593Smuzhiyun 	err = mlxsw_i2c_get_mbox(client, mlxsw_i2c);
625*4882a593Smuzhiyun 	if (err < 0) {
626*4882a593Smuzhiyun 		dev_err(&client->dev, "Fail to get mailboxes\n");
627*4882a593Smuzhiyun 		goto errout;
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	dev_info(&client->dev, "%s mb size=%x off=0x%08x out mb size=%x off=0x%08x\n",
631*4882a593Smuzhiyun 		 id->name, mlxsw_i2c->cmd.mb_size_in,
632*4882a593Smuzhiyun 		 mlxsw_i2c->cmd.mb_off_in, mlxsw_i2c->cmd.mb_size_out,
633*4882a593Smuzhiyun 		 mlxsw_i2c->cmd.mb_off_out);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	/* Register device bus. */
636*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.device_kind = id->name;
637*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.device_name = client->name;
638*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.dev = &client->dev;
639*4882a593Smuzhiyun 	mlxsw_i2c->bus_info.low_frequency = true;
640*4882a593Smuzhiyun 	mlxsw_i2c->dev = &client->dev;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
643*4882a593Smuzhiyun 					     &mlxsw_i2c_bus, mlxsw_i2c, false,
644*4882a593Smuzhiyun 					     NULL, NULL);
645*4882a593Smuzhiyun 	if (err) {
646*4882a593Smuzhiyun 		dev_err(&client->dev, "Fail to register core bus\n");
647*4882a593Smuzhiyun 		return err;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	return 0;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun errout:
653*4882a593Smuzhiyun 	mutex_destroy(&mlxsw_i2c->cmd.lock);
654*4882a593Smuzhiyun 	i2c_set_clientdata(client, NULL);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	return err;
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun 
mlxsw_i2c_remove(struct i2c_client * client)659*4882a593Smuzhiyun static int mlxsw_i2c_remove(struct i2c_client *client)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun 	struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false);
664*4882a593Smuzhiyun 	mutex_destroy(&mlxsw_i2c->cmd.lock);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return 0;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
mlxsw_i2c_driver_register(struct i2c_driver * i2c_driver)669*4882a593Smuzhiyun int mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun 	i2c_driver->probe = mlxsw_i2c_probe;
672*4882a593Smuzhiyun 	i2c_driver->remove = mlxsw_i2c_remove;
673*4882a593Smuzhiyun 	return i2c_add_driver(i2c_driver);
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun EXPORT_SYMBOL(mlxsw_i2c_driver_register);
676*4882a593Smuzhiyun 
mlxsw_i2c_driver_unregister(struct i2c_driver * i2c_driver)677*4882a593Smuzhiyun void mlxsw_i2c_driver_unregister(struct i2c_driver *i2c_driver)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun 	i2c_del_driver(i2c_driver);
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun EXPORT_SYMBOL(mlxsw_i2c_driver_unregister);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
684*4882a593Smuzhiyun MODULE_DESCRIPTION("Mellanox switch I2C interface driver");
685*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
686