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