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