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