1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2016 T-Platforms. All Rights Reserved. |
4 | * |
5 | * IDT PCIe-switch NTB Linux driver |
6 | * |
7 | * Contact Information: |
8 | * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru> |
9 | */ |
10 | /* |
11 | * NOTE of the IDT 89HPESx SMBus-slave interface driver |
12 | * This driver primarily is developed to have an access to EEPROM device of |
13 | * IDT PCIe-switches. IDT provides a simple SMBus interface to perform IO- |
14 | * operations from/to EEPROM, which is located at private (so called Master) |
15 | * SMBus of switches. Using that interface this the driver creates a simple |
16 | * binary sysfs-file in the device directory: |
17 | * /sys/bus/i2c/devices/<bus>-<devaddr>/eeprom |
18 | * In case if read-only flag is specified in the dts-node of device desription, |
19 | * User-space applications won't be able to write to the EEPROM sysfs-node. |
20 | * Additionally IDT 89HPESx SMBus interface has an ability to write/read |
21 | * data of device CSRs. This driver exposes debugf-file to perform simple IO |
22 | * operations using that ability for just basic debug purpose. Particularly |
23 | * next file is created in the specific debugfs-directory: |
24 | * /sys/kernel/debug/idt_csr/ |
25 | * Format of the debugfs-node is: |
26 | * $ cat /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>; |
27 | * <CSR address>:<CSR value> |
28 | * So reading the content of the file gives current CSR address and it value. |
29 | * If User-space application wishes to change current CSR address, |
30 | * it can just write a proper value to the sysfs-file: |
31 | * $ echo "<CSR address>" > /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname> |
32 | * If it wants to change the CSR value as well, the format of the write |
33 | * operation is: |
34 | * $ echo "<CSR address>:<CSR value>" > \ |
35 | * /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>; |
36 | * CSR address and value can be any of hexadecimal, decimal or octal format. |
37 | */ |
38 | |
39 | #include <linux/kernel.h> |
40 | #include <linux/init.h> |
41 | #include <linux/module.h> |
42 | #include <linux/types.h> |
43 | #include <linux/sizes.h> |
44 | #include <linux/slab.h> |
45 | #include <linux/mutex.h> |
46 | #include <linux/sysfs.h> |
47 | #include <linux/debugfs.h> |
48 | #include <linux/mod_devicetable.h> |
49 | #include <linux/property.h> |
50 | #include <linux/i2c.h> |
51 | #include <linux/pci_ids.h> |
52 | #include <linux/delay.h> |
53 | |
54 | #define IDT_NAME "89hpesx" |
55 | #define IDT_89HPESX_DESC "IDT 89HPESx SMBus-slave interface driver" |
56 | #define IDT_89HPESX_VER "1.0" |
57 | |
58 | MODULE_DESCRIPTION(IDT_89HPESX_DESC); |
59 | MODULE_VERSION(IDT_89HPESX_VER); |
60 | MODULE_LICENSE("GPL v2" ); |
61 | MODULE_AUTHOR("T-platforms" ); |
62 | |
63 | /* |
64 | * csr_dbgdir - CSR read/write operations Debugfs directory |
65 | */ |
66 | static struct dentry *csr_dbgdir; |
67 | |
68 | /* |
69 | * struct idt_89hpesx_dev - IDT 89HPESx device data structure |
70 | * @eesize: Size of EEPROM in bytes (calculated from "idt,eecompatible") |
71 | * @eero: EEPROM Read-only flag |
72 | * @eeaddr: EEPROM custom address |
73 | * |
74 | * @inieecmd: Initial cmd value for EEPROM read/write operations |
75 | * @inicsrcmd: Initial cmd value for CSR read/write operations |
76 | * @iniccode: Initialial command code value for IO-operations |
77 | * |
78 | * @csr: CSR address to perform read operation |
79 | * |
80 | * @smb_write: SMBus write method |
81 | * @smb_read: SMBus read method |
82 | * @smb_mtx: SMBus mutex |
83 | * |
84 | * @client: i2c client used to perform IO operations |
85 | * |
86 | * @ee_file: EEPROM read/write sysfs-file |
87 | */ |
88 | struct idt_smb_seq; |
89 | struct idt_89hpesx_dev { |
90 | u32 eesize; |
91 | bool eero; |
92 | u8 eeaddr; |
93 | |
94 | u8 inieecmd; |
95 | u8 inicsrcmd; |
96 | u8 iniccode; |
97 | |
98 | u16 csr; |
99 | |
100 | int (*smb_write)(struct idt_89hpesx_dev *, const struct idt_smb_seq *); |
101 | int (*smb_read)(struct idt_89hpesx_dev *, struct idt_smb_seq *); |
102 | struct mutex smb_mtx; |
103 | |
104 | struct i2c_client *client; |
105 | |
106 | struct bin_attribute *ee_file; |
107 | struct dentry *csr_dir; |
108 | }; |
109 | |
110 | /* |
111 | * struct idt_smb_seq - sequence of data to be read/written from/to IDT 89HPESx |
112 | * @ccode: SMBus command code |
113 | * @bytecnt: Byte count of operation |
114 | * @data: Data to by written |
115 | */ |
116 | struct idt_smb_seq { |
117 | u8 ccode; |
118 | u8 bytecnt; |
119 | u8 *data; |
120 | }; |
121 | |
122 | /* |
123 | * struct idt_eeprom_seq - sequence of data to be read/written from/to EEPROM |
124 | * @cmd: Transaction CMD |
125 | * @eeaddr: EEPROM custom address |
126 | * @memaddr: Internal memory address of EEPROM |
127 | * @data: Data to be written at the memory address |
128 | */ |
129 | struct idt_eeprom_seq { |
130 | u8 cmd; |
131 | u8 eeaddr; |
132 | __le16 memaddr; |
133 | u8 data; |
134 | } __packed; |
135 | |
136 | /* |
137 | * struct idt_csr_seq - sequence of data to be read/written from/to CSR |
138 | * @cmd: Transaction CMD |
139 | * @csraddr: Internal IDT device CSR address |
140 | * @data: Data to be read/written from/to the CSR address |
141 | */ |
142 | struct idt_csr_seq { |
143 | u8 cmd; |
144 | __le16 csraddr; |
145 | __le32 data; |
146 | } __packed; |
147 | |
148 | /* |
149 | * SMBus command code macros |
150 | * @CCODE_END: Indicates the end of transaction |
151 | * @CCODE_START: Indicates the start of transaction |
152 | * @CCODE_CSR: CSR read/write transaction |
153 | * @CCODE_EEPROM: EEPROM read/write transaction |
154 | * @CCODE_BYTE: Supplied data has BYTE length |
155 | * @CCODE_WORD: Supplied data has WORD length |
156 | * @CCODE_BLOCK: Supplied data has variable length passed in bytecnt |
157 | * byte right following CCODE byte |
158 | */ |
159 | #define CCODE_END ((u8)0x01) |
160 | #define CCODE_START ((u8)0x02) |
161 | #define CCODE_CSR ((u8)0x00) |
162 | #define CCODE_EEPROM ((u8)0x04) |
163 | #define CCODE_BYTE ((u8)0x00) |
164 | #define CCODE_WORD ((u8)0x20) |
165 | #define CCODE_BLOCK ((u8)0x40) |
166 | #define CCODE_PEC ((u8)0x80) |
167 | |
168 | /* |
169 | * EEPROM command macros |
170 | * @EEPROM_OP_WRITE: EEPROM write operation |
171 | * @EEPROM_OP_READ: EEPROM read operation |
172 | * @EEPROM_USA: Use specified address of EEPROM |
173 | * @EEPROM_NAERR: EEPROM device is not ready to respond |
174 | * @EEPROM_LAERR: EEPROM arbitration loss error |
175 | * @EEPROM_MSS: EEPROM misplace start & stop bits error |
176 | * @EEPROM_WR_CNT: Bytes count to perform write operation |
177 | * @EEPROM_WRRD_CNT: Bytes count to write before reading |
178 | * @EEPROM_RD_CNT: Bytes count to perform read operation |
179 | * @EEPROM_DEF_SIZE: Fall back size of EEPROM |
180 | * @EEPROM_DEF_ADDR: Defatul EEPROM address |
181 | * @EEPROM_TOUT: Timeout before retry read operation if eeprom is busy |
182 | */ |
183 | #define EEPROM_OP_WRITE ((u8)0x00) |
184 | #define EEPROM_OP_READ ((u8)0x01) |
185 | #define EEPROM_USA ((u8)0x02) |
186 | #define EEPROM_NAERR ((u8)0x08) |
187 | #define EEPROM_LAERR ((u8)0x10) |
188 | #define EEPROM_MSS ((u8)0x20) |
189 | #define EEPROM_WR_CNT ((u8)5) |
190 | #define EEPROM_WRRD_CNT ((u8)4) |
191 | #define EEPROM_RD_CNT ((u8)5) |
192 | #define EEPROM_DEF_SIZE ((u16)4096) |
193 | #define EEPROM_DEF_ADDR ((u8)0x50) |
194 | #define EEPROM_TOUT (100) |
195 | |
196 | /* |
197 | * CSR command macros |
198 | * @CSR_DWE: Enable all four bytes of the operation |
199 | * @CSR_OP_WRITE: CSR write operation |
200 | * @CSR_OP_READ: CSR read operation |
201 | * @CSR_RERR: Read operation error |
202 | * @CSR_WERR: Write operation error |
203 | * @CSR_WR_CNT: Bytes count to perform write operation |
204 | * @CSR_WRRD_CNT: Bytes count to write before reading |
205 | * @CSR_RD_CNT: Bytes count to perform read operation |
206 | * @CSR_MAX: Maximum CSR address |
207 | * @CSR_DEF: Default CSR address |
208 | * @CSR_REAL_ADDR: CSR real unshifted address |
209 | */ |
210 | #define CSR_DWE ((u8)0x0F) |
211 | #define CSR_OP_WRITE ((u8)0x00) |
212 | #define CSR_OP_READ ((u8)0x10) |
213 | #define CSR_RERR ((u8)0x40) |
214 | #define CSR_WERR ((u8)0x80) |
215 | #define CSR_WR_CNT ((u8)7) |
216 | #define CSR_WRRD_CNT ((u8)3) |
217 | #define CSR_RD_CNT ((u8)7) |
218 | #define CSR_MAX ((u32)0x3FFFF) |
219 | #define CSR_DEF ((u16)0x0000) |
220 | #define CSR_REAL_ADDR(val) ((unsigned int)val << 2) |
221 | |
222 | /* |
223 | * IDT 89HPESx basic register |
224 | * @IDT_VIDDID_CSR: PCIe VID and DID of IDT 89HPESx |
225 | * @IDT_VID_MASK: Mask of VID |
226 | */ |
227 | #define IDT_VIDDID_CSR ((u32)0x0000) |
228 | #define IDT_VID_MASK ((u32)0xFFFF) |
229 | |
230 | /* |
231 | * IDT 89HPESx can send NACK when new command is sent before previous one |
232 | * fininshed execution. In this case driver retries operation |
233 | * certain times. |
234 | * @RETRY_CNT: Number of retries before giving up and fail |
235 | * @idt_smb_safe: Generate a retry loop on corresponding SMBus method |
236 | */ |
237 | #define RETRY_CNT (128) |
238 | #define idt_smb_safe(ops, args...) ({ \ |
239 | int __retry = RETRY_CNT; \ |
240 | s32 __sts; \ |
241 | do { \ |
242 | __sts = i2c_smbus_ ## ops ## _data(args); \ |
243 | } while (__retry-- && __sts < 0); \ |
244 | __sts; \ |
245 | }) |
246 | |
247 | /*=========================================================================== |
248 | * i2c bus level IO-operations |
249 | *=========================================================================== |
250 | */ |
251 | |
252 | /* |
253 | * idt_smb_write_byte() - SMBus write method when I2C_SMBUS_BYTE_DATA operation |
254 | * is only available |
255 | * @pdev: Pointer to the driver data |
256 | * @seq: Sequence of data to be written |
257 | */ |
258 | static int idt_smb_write_byte(struct idt_89hpesx_dev *pdev, |
259 | const struct idt_smb_seq *seq) |
260 | { |
261 | s32 sts; |
262 | u8 ccode; |
263 | int idx; |
264 | |
265 | /* Loop over the supplied data sending byte one-by-one */ |
266 | for (idx = 0; idx < seq->bytecnt; idx++) { |
267 | /* Collect the command code byte */ |
268 | ccode = seq->ccode | CCODE_BYTE; |
269 | if (idx == 0) |
270 | ccode |= CCODE_START; |
271 | if (idx == seq->bytecnt - 1) |
272 | ccode |= CCODE_END; |
273 | |
274 | /* Send data to the device */ |
275 | sts = idt_smb_safe(write_byte, pdev->client, ccode, |
276 | seq->data[idx]); |
277 | if (sts != 0) |
278 | return (int)sts; |
279 | } |
280 | |
281 | return 0; |
282 | } |
283 | |
284 | /* |
285 | * idt_smb_read_byte() - SMBus read method when I2C_SMBUS_BYTE_DATA operation |
286 | * is only available |
287 | * @pdev: Pointer to the driver data |
288 | * @seq: Buffer to read data to |
289 | */ |
290 | static int idt_smb_read_byte(struct idt_89hpesx_dev *pdev, |
291 | struct idt_smb_seq *seq) |
292 | { |
293 | s32 sts; |
294 | u8 ccode; |
295 | int idx; |
296 | |
297 | /* Loop over the supplied buffer receiving byte one-by-one */ |
298 | for (idx = 0; idx < seq->bytecnt; idx++) { |
299 | /* Collect the command code byte */ |
300 | ccode = seq->ccode | CCODE_BYTE; |
301 | if (idx == 0) |
302 | ccode |= CCODE_START; |
303 | if (idx == seq->bytecnt - 1) |
304 | ccode |= CCODE_END; |
305 | |
306 | /* Read data from the device */ |
307 | sts = idt_smb_safe(read_byte, pdev->client, ccode); |
308 | if (sts < 0) |
309 | return (int)sts; |
310 | |
311 | seq->data[idx] = (u8)sts; |
312 | } |
313 | |
314 | return 0; |
315 | } |
316 | |
317 | /* |
318 | * idt_smb_write_word() - SMBus write method when I2C_SMBUS_BYTE_DATA and |
319 | * I2C_FUNC_SMBUS_WORD_DATA operations are available |
320 | * @pdev: Pointer to the driver data |
321 | * @seq: Sequence of data to be written |
322 | */ |
323 | static int idt_smb_write_word(struct idt_89hpesx_dev *pdev, |
324 | const struct idt_smb_seq *seq) |
325 | { |
326 | s32 sts; |
327 | u8 ccode; |
328 | int idx, evencnt; |
329 | |
330 | /* Calculate the even count of data to send */ |
331 | evencnt = seq->bytecnt - (seq->bytecnt % 2); |
332 | |
333 | /* Loop over the supplied data sending two bytes at a time */ |
334 | for (idx = 0; idx < evencnt; idx += 2) { |
335 | /* Collect the command code byte */ |
336 | ccode = seq->ccode | CCODE_WORD; |
337 | if (idx == 0) |
338 | ccode |= CCODE_START; |
339 | if (idx == evencnt - 2) |
340 | ccode |= CCODE_END; |
341 | |
342 | /* Send word data to the device */ |
343 | sts = idt_smb_safe(write_word, pdev->client, ccode, |
344 | *(u16 *)&seq->data[idx]); |
345 | if (sts != 0) |
346 | return (int)sts; |
347 | } |
348 | |
349 | /* If there is odd number of bytes then send just one last byte */ |
350 | if (seq->bytecnt != evencnt) { |
351 | /* Collect the command code byte */ |
352 | ccode = seq->ccode | CCODE_BYTE | CCODE_END; |
353 | if (idx == 0) |
354 | ccode |= CCODE_START; |
355 | |
356 | /* Send byte data to the device */ |
357 | sts = idt_smb_safe(write_byte, pdev->client, ccode, |
358 | seq->data[idx]); |
359 | if (sts != 0) |
360 | return (int)sts; |
361 | } |
362 | |
363 | return 0; |
364 | } |
365 | |
366 | /* |
367 | * idt_smb_read_word() - SMBus read method when I2C_SMBUS_BYTE_DATA and |
368 | * I2C_FUNC_SMBUS_WORD_DATA operations are available |
369 | * @pdev: Pointer to the driver data |
370 | * @seq: Buffer to read data to |
371 | */ |
372 | static int idt_smb_read_word(struct idt_89hpesx_dev *pdev, |
373 | struct idt_smb_seq *seq) |
374 | { |
375 | s32 sts; |
376 | u8 ccode; |
377 | int idx, evencnt; |
378 | |
379 | /* Calculate the even count of data to send */ |
380 | evencnt = seq->bytecnt - (seq->bytecnt % 2); |
381 | |
382 | /* Loop over the supplied data reading two bytes at a time */ |
383 | for (idx = 0; idx < evencnt; idx += 2) { |
384 | /* Collect the command code byte */ |
385 | ccode = seq->ccode | CCODE_WORD; |
386 | if (idx == 0) |
387 | ccode |= CCODE_START; |
388 | if (idx == evencnt - 2) |
389 | ccode |= CCODE_END; |
390 | |
391 | /* Read word data from the device */ |
392 | sts = idt_smb_safe(read_word, pdev->client, ccode); |
393 | if (sts < 0) |
394 | return (int)sts; |
395 | |
396 | *(u16 *)&seq->data[idx] = (u16)sts; |
397 | } |
398 | |
399 | /* If there is odd number of bytes then receive just one last byte */ |
400 | if (seq->bytecnt != evencnt) { |
401 | /* Collect the command code byte */ |
402 | ccode = seq->ccode | CCODE_BYTE | CCODE_END; |
403 | if (idx == 0) |
404 | ccode |= CCODE_START; |
405 | |
406 | /* Read last data byte from the device */ |
407 | sts = idt_smb_safe(read_byte, pdev->client, ccode); |
408 | if (sts < 0) |
409 | return (int)sts; |
410 | |
411 | seq->data[idx] = (u8)sts; |
412 | } |
413 | |
414 | return 0; |
415 | } |
416 | |
417 | /* |
418 | * idt_smb_write_block() - SMBus write method when I2C_SMBUS_BLOCK_DATA |
419 | * operation is available |
420 | * @pdev: Pointer to the driver data |
421 | * @seq: Sequence of data to be written |
422 | */ |
423 | static int idt_smb_write_block(struct idt_89hpesx_dev *pdev, |
424 | const struct idt_smb_seq *seq) |
425 | { |
426 | u8 ccode; |
427 | |
428 | /* Return error if too much data passed to send */ |
429 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) |
430 | return -EINVAL; |
431 | |
432 | /* Collect the command code byte */ |
433 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; |
434 | |
435 | /* Send block of data to the device */ |
436 | return idt_smb_safe(write_block, pdev->client, ccode, seq->bytecnt, |
437 | seq->data); |
438 | } |
439 | |
440 | /* |
441 | * idt_smb_read_block() - SMBus read method when I2C_SMBUS_BLOCK_DATA |
442 | * operation is available |
443 | * @pdev: Pointer to the driver data |
444 | * @seq: Buffer to read data to |
445 | */ |
446 | static int idt_smb_read_block(struct idt_89hpesx_dev *pdev, |
447 | struct idt_smb_seq *seq) |
448 | { |
449 | s32 sts; |
450 | u8 ccode; |
451 | |
452 | /* Return error if too much data passed to send */ |
453 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) |
454 | return -EINVAL; |
455 | |
456 | /* Collect the command code byte */ |
457 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; |
458 | |
459 | /* Read block of data from the device */ |
460 | sts = idt_smb_safe(read_block, pdev->client, ccode, seq->data); |
461 | if (sts != seq->bytecnt) |
462 | return (sts < 0 ? sts : -ENODATA); |
463 | |
464 | return 0; |
465 | } |
466 | |
467 | /* |
468 | * idt_smb_write_i2c_block() - SMBus write method when I2C_SMBUS_I2C_BLOCK_DATA |
469 | * operation is available |
470 | * @pdev: Pointer to the driver data |
471 | * @seq: Sequence of data to be written |
472 | * |
473 | * NOTE It's usual SMBus write block operation, except the actual data length is |
474 | * sent as first byte of data |
475 | */ |
476 | static int idt_smb_write_i2c_block(struct idt_89hpesx_dev *pdev, |
477 | const struct idt_smb_seq *seq) |
478 | { |
479 | u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1]; |
480 | |
481 | /* Return error if too much data passed to send */ |
482 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) |
483 | return -EINVAL; |
484 | |
485 | /* Collect the data to send. Length byte must be added prior the data */ |
486 | buf[0] = seq->bytecnt; |
487 | memcpy(&buf[1], seq->data, seq->bytecnt); |
488 | |
489 | /* Collect the command code byte */ |
490 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; |
491 | |
492 | /* Send length and block of data to the device */ |
493 | return idt_smb_safe(write_i2c_block, pdev->client, ccode, |
494 | seq->bytecnt + 1, buf); |
495 | } |
496 | |
497 | /* |
498 | * idt_smb_read_i2c_block() - SMBus read method when I2C_SMBUS_I2C_BLOCK_DATA |
499 | * operation is available |
500 | * @pdev: Pointer to the driver data |
501 | * @seq: Buffer to read data to |
502 | * |
503 | * NOTE It's usual SMBus read block operation, except the actual data length is |
504 | * retrieved as first byte of data |
505 | */ |
506 | static int idt_smb_read_i2c_block(struct idt_89hpesx_dev *pdev, |
507 | struct idt_smb_seq *seq) |
508 | { |
509 | u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1]; |
510 | s32 sts; |
511 | |
512 | /* Return error if too much data passed to send */ |
513 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) |
514 | return -EINVAL; |
515 | |
516 | /* Collect the command code byte */ |
517 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; |
518 | |
519 | /* Read length and block of data from the device */ |
520 | sts = idt_smb_safe(read_i2c_block, pdev->client, ccode, |
521 | seq->bytecnt + 1, buf); |
522 | if (sts != seq->bytecnt + 1) |
523 | return (sts < 0 ? sts : -ENODATA); |
524 | if (buf[0] != seq->bytecnt) |
525 | return -ENODATA; |
526 | |
527 | /* Copy retrieved data to the output data buffer */ |
528 | memcpy(seq->data, &buf[1], seq->bytecnt); |
529 | |
530 | return 0; |
531 | } |
532 | |
533 | /*=========================================================================== |
534 | * EEPROM IO-operations |
535 | *=========================================================================== |
536 | */ |
537 | |
538 | /* |
539 | * idt_eeprom_read_byte() - read just one byte from EEPROM |
540 | * @pdev: Pointer to the driver data |
541 | * @memaddr: Start EEPROM memory address |
542 | * @data: Data to be written to EEPROM |
543 | */ |
544 | static int idt_eeprom_read_byte(struct idt_89hpesx_dev *pdev, u16 memaddr, |
545 | u8 *data) |
546 | { |
547 | struct device *dev = &pdev->client->dev; |
548 | struct idt_eeprom_seq eeseq; |
549 | struct idt_smb_seq smbseq; |
550 | int ret, retry; |
551 | |
552 | /* Initialize SMBus sequence fields */ |
553 | smbseq.ccode = pdev->iniccode | CCODE_EEPROM; |
554 | smbseq.data = (u8 *)&eeseq; |
555 | |
556 | /* |
557 | * Sometimes EEPROM may respond with NACK if it's busy with previous |
558 | * operation, so we need to perform a few attempts of read cycle |
559 | */ |
560 | retry = RETRY_CNT; |
561 | do { |
562 | /* Send EEPROM memory address to read data from */ |
563 | smbseq.bytecnt = EEPROM_WRRD_CNT; |
564 | eeseq.cmd = pdev->inieecmd | EEPROM_OP_READ; |
565 | eeseq.eeaddr = pdev->eeaddr; |
566 | eeseq.memaddr = cpu_to_le16(memaddr); |
567 | ret = pdev->smb_write(pdev, &smbseq); |
568 | if (ret != 0) { |
569 | dev_err(dev, "Failed to init eeprom addr 0x%02x" , |
570 | memaddr); |
571 | break; |
572 | } |
573 | |
574 | /* Perform read operation */ |
575 | smbseq.bytecnt = EEPROM_RD_CNT; |
576 | ret = pdev->smb_read(pdev, &smbseq); |
577 | if (ret != 0) { |
578 | dev_err(dev, "Failed to read eeprom data 0x%02x" , |
579 | memaddr); |
580 | break; |
581 | } |
582 | |
583 | /* Restart read operation if the device is busy */ |
584 | if (retry && (eeseq.cmd & EEPROM_NAERR)) { |
585 | dev_dbg(dev, "EEPROM busy, retry reading after %d ms" , |
586 | EEPROM_TOUT); |
587 | msleep(EEPROM_TOUT); |
588 | continue; |
589 | } |
590 | |
591 | /* Check whether IDT successfully read data from EEPROM */ |
592 | if (eeseq.cmd & (EEPROM_NAERR | EEPROM_LAERR | EEPROM_MSS)) { |
593 | dev_err(dev, |
594 | "Communication with eeprom failed, cmd 0x%hhx" , |
595 | eeseq.cmd); |
596 | ret = -EREMOTEIO; |
597 | break; |
598 | } |
599 | |
600 | /* Save retrieved data and exit the loop */ |
601 | *data = eeseq.data; |
602 | break; |
603 | } while (retry--); |
604 | |
605 | /* Return the status of operation */ |
606 | return ret; |
607 | } |
608 | |
609 | /* |
610 | * idt_eeprom_write() - EEPROM write operation |
611 | * @pdev: Pointer to the driver data |
612 | * @memaddr: Start EEPROM memory address |
613 | * @len: Length of data to be written |
614 | * @data: Data to be written to EEPROM |
615 | */ |
616 | static int idt_eeprom_write(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len, |
617 | const u8 *data) |
618 | { |
619 | struct device *dev = &pdev->client->dev; |
620 | struct idt_eeprom_seq eeseq; |
621 | struct idt_smb_seq smbseq; |
622 | int ret; |
623 | u16 idx; |
624 | |
625 | /* Initialize SMBus sequence fields */ |
626 | smbseq.ccode = pdev->iniccode | CCODE_EEPROM; |
627 | smbseq.data = (u8 *)&eeseq; |
628 | |
629 | /* Send data byte-by-byte, checking if it is successfully written */ |
630 | for (idx = 0; idx < len; idx++, memaddr++) { |
631 | /* Lock IDT SMBus device */ |
632 | mutex_lock(&pdev->smb_mtx); |
633 | |
634 | /* Perform write operation */ |
635 | smbseq.bytecnt = EEPROM_WR_CNT; |
636 | eeseq.cmd = pdev->inieecmd | EEPROM_OP_WRITE; |
637 | eeseq.eeaddr = pdev->eeaddr; |
638 | eeseq.memaddr = cpu_to_le16(memaddr); |
639 | eeseq.data = data[idx]; |
640 | ret = pdev->smb_write(pdev, &smbseq); |
641 | if (ret != 0) { |
642 | dev_err(dev, |
643 | "Failed to write 0x%04hx:0x%02hhx to eeprom" , |
644 | memaddr, data[idx]); |
645 | goto err_mutex_unlock; |
646 | } |
647 | |
648 | /* |
649 | * Check whether the data is successfully written by reading |
650 | * from the same EEPROM memory address. |
651 | */ |
652 | eeseq.data = ~data[idx]; |
653 | ret = idt_eeprom_read_byte(pdev, memaddr, data: &eeseq.data); |
654 | if (ret != 0) |
655 | goto err_mutex_unlock; |
656 | |
657 | /* Check whether the read byte is the same as written one */ |
658 | if (eeseq.data != data[idx]) { |
659 | dev_err(dev, "Values don't match 0x%02hhx != 0x%02hhx" , |
660 | eeseq.data, data[idx]); |
661 | ret = -EREMOTEIO; |
662 | goto err_mutex_unlock; |
663 | } |
664 | |
665 | /* Unlock IDT SMBus device */ |
666 | err_mutex_unlock: |
667 | mutex_unlock(lock: &pdev->smb_mtx); |
668 | if (ret != 0) |
669 | return ret; |
670 | } |
671 | |
672 | return 0; |
673 | } |
674 | |
675 | /* |
676 | * idt_eeprom_read() - EEPROM read operation |
677 | * @pdev: Pointer to the driver data |
678 | * @memaddr: Start EEPROM memory address |
679 | * @len: Length of data to read |
680 | * @buf: Buffer to read data to |
681 | */ |
682 | static int idt_eeprom_read(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len, |
683 | u8 *buf) |
684 | { |
685 | int ret; |
686 | u16 idx; |
687 | |
688 | /* Read data byte-by-byte, retrying if it wasn't successful */ |
689 | for (idx = 0; idx < len; idx++, memaddr++) { |
690 | /* Lock IDT SMBus device */ |
691 | mutex_lock(&pdev->smb_mtx); |
692 | |
693 | /* Just read the byte to the buffer */ |
694 | ret = idt_eeprom_read_byte(pdev, memaddr, data: &buf[idx]); |
695 | |
696 | /* Unlock IDT SMBus device */ |
697 | mutex_unlock(lock: &pdev->smb_mtx); |
698 | |
699 | /* Return error if read operation failed */ |
700 | if (ret != 0) |
701 | return ret; |
702 | } |
703 | |
704 | return 0; |
705 | } |
706 | |
707 | /*=========================================================================== |
708 | * CSR IO-operations |
709 | *=========================================================================== |
710 | */ |
711 | |
712 | /* |
713 | * idt_csr_write() - CSR write operation |
714 | * @pdev: Pointer to the driver data |
715 | * @csraddr: CSR address (with no two LS bits) |
716 | * @data: Data to be written to CSR |
717 | */ |
718 | static int idt_csr_write(struct idt_89hpesx_dev *pdev, u16 csraddr, |
719 | const u32 data) |
720 | { |
721 | struct device *dev = &pdev->client->dev; |
722 | struct idt_csr_seq csrseq; |
723 | struct idt_smb_seq smbseq; |
724 | int ret; |
725 | |
726 | /* Initialize SMBus sequence fields */ |
727 | smbseq.ccode = pdev->iniccode | CCODE_CSR; |
728 | smbseq.data = (u8 *)&csrseq; |
729 | |
730 | /* Lock IDT SMBus device */ |
731 | mutex_lock(&pdev->smb_mtx); |
732 | |
733 | /* Perform write operation */ |
734 | smbseq.bytecnt = CSR_WR_CNT; |
735 | csrseq.cmd = pdev->inicsrcmd | CSR_OP_WRITE; |
736 | csrseq.csraddr = cpu_to_le16(csraddr); |
737 | csrseq.data = cpu_to_le32(data); |
738 | ret = pdev->smb_write(pdev, &smbseq); |
739 | if (ret != 0) { |
740 | dev_err(dev, "Failed to write 0x%04x: 0x%04x to csr" , |
741 | CSR_REAL_ADDR(csraddr), data); |
742 | goto err_mutex_unlock; |
743 | } |
744 | |
745 | /* Send CSR address to read data from */ |
746 | smbseq.bytecnt = CSR_WRRD_CNT; |
747 | csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ; |
748 | ret = pdev->smb_write(pdev, &smbseq); |
749 | if (ret != 0) { |
750 | dev_err(dev, "Failed to init csr address 0x%04x" , |
751 | CSR_REAL_ADDR(csraddr)); |
752 | goto err_mutex_unlock; |
753 | } |
754 | |
755 | /* Perform read operation */ |
756 | smbseq.bytecnt = CSR_RD_CNT; |
757 | ret = pdev->smb_read(pdev, &smbseq); |
758 | if (ret != 0) { |
759 | dev_err(dev, "Failed to read csr 0x%04x" , |
760 | CSR_REAL_ADDR(csraddr)); |
761 | goto err_mutex_unlock; |
762 | } |
763 | |
764 | /* Check whether IDT successfully retrieved CSR data */ |
765 | if (csrseq.cmd & (CSR_RERR | CSR_WERR)) { |
766 | dev_err(dev, "IDT failed to perform CSR r/w" ); |
767 | ret = -EREMOTEIO; |
768 | goto err_mutex_unlock; |
769 | } |
770 | |
771 | /* Unlock IDT SMBus device */ |
772 | err_mutex_unlock: |
773 | mutex_unlock(lock: &pdev->smb_mtx); |
774 | |
775 | return ret; |
776 | } |
777 | |
778 | /* |
779 | * idt_csr_read() - CSR read operation |
780 | * @pdev: Pointer to the driver data |
781 | * @csraddr: CSR address (with no two LS bits) |
782 | * @data: Data to be written to CSR |
783 | */ |
784 | static int idt_csr_read(struct idt_89hpesx_dev *pdev, u16 csraddr, u32 *data) |
785 | { |
786 | struct device *dev = &pdev->client->dev; |
787 | struct idt_csr_seq csrseq; |
788 | struct idt_smb_seq smbseq; |
789 | int ret; |
790 | |
791 | /* Initialize SMBus sequence fields */ |
792 | smbseq.ccode = pdev->iniccode | CCODE_CSR; |
793 | smbseq.data = (u8 *)&csrseq; |
794 | |
795 | /* Lock IDT SMBus device */ |
796 | mutex_lock(&pdev->smb_mtx); |
797 | |
798 | /* Send CSR register address before reading it */ |
799 | smbseq.bytecnt = CSR_WRRD_CNT; |
800 | csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ; |
801 | csrseq.csraddr = cpu_to_le16(csraddr); |
802 | ret = pdev->smb_write(pdev, &smbseq); |
803 | if (ret != 0) { |
804 | dev_err(dev, "Failed to init csr address 0x%04x" , |
805 | CSR_REAL_ADDR(csraddr)); |
806 | goto err_mutex_unlock; |
807 | } |
808 | |
809 | /* Perform read operation */ |
810 | smbseq.bytecnt = CSR_RD_CNT; |
811 | ret = pdev->smb_read(pdev, &smbseq); |
812 | if (ret != 0) { |
813 | dev_err(dev, "Failed to read csr 0x%04x" , |
814 | CSR_REAL_ADDR(csraddr)); |
815 | goto err_mutex_unlock; |
816 | } |
817 | |
818 | /* Check whether IDT successfully retrieved CSR data */ |
819 | if (csrseq.cmd & (CSR_RERR | CSR_WERR)) { |
820 | dev_err(dev, "IDT failed to perform CSR r/w" ); |
821 | ret = -EREMOTEIO; |
822 | goto err_mutex_unlock; |
823 | } |
824 | |
825 | /* Save data retrieved from IDT */ |
826 | *data = le32_to_cpu(csrseq.data); |
827 | |
828 | /* Unlock IDT SMBus device */ |
829 | err_mutex_unlock: |
830 | mutex_unlock(lock: &pdev->smb_mtx); |
831 | |
832 | return ret; |
833 | } |
834 | |
835 | /*=========================================================================== |
836 | * Sysfs/debugfs-nodes IO-operations |
837 | *=========================================================================== |
838 | */ |
839 | |
840 | /* |
841 | * eeprom_write() - EEPROM sysfs-node write callback |
842 | * @filep: Pointer to the file system node |
843 | * @kobj: Pointer to the kernel object related to the sysfs-node |
844 | * @attr: Attributes of the file |
845 | * @buf: Buffer to write data to |
846 | * @off: Offset at which data should be written to |
847 | * @count: Number of bytes to write |
848 | */ |
849 | static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, |
850 | struct bin_attribute *attr, |
851 | char *buf, loff_t off, size_t count) |
852 | { |
853 | struct idt_89hpesx_dev *pdev; |
854 | int ret; |
855 | |
856 | /* Retrieve driver data */ |
857 | pdev = dev_get_drvdata(kobj_to_dev(kobj)); |
858 | |
859 | /* Perform EEPROM write operation */ |
860 | ret = idt_eeprom_write(pdev, memaddr: (u16)off, len: (u16)count, data: (u8 *)buf); |
861 | return (ret != 0 ? ret : count); |
862 | } |
863 | |
864 | /* |
865 | * eeprom_read() - EEPROM sysfs-node read callback |
866 | * @filep: Pointer to the file system node |
867 | * @kobj: Pointer to the kernel object related to the sysfs-node |
868 | * @attr: Attributes of the file |
869 | * @buf: Buffer to write data to |
870 | * @off: Offset at which data should be written to |
871 | * @count: Number of bytes to write |
872 | */ |
873 | static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, |
874 | struct bin_attribute *attr, |
875 | char *buf, loff_t off, size_t count) |
876 | { |
877 | struct idt_89hpesx_dev *pdev; |
878 | int ret; |
879 | |
880 | /* Retrieve driver data */ |
881 | pdev = dev_get_drvdata(kobj_to_dev(kobj)); |
882 | |
883 | /* Perform EEPROM read operation */ |
884 | ret = idt_eeprom_read(pdev, memaddr: (u16)off, len: (u16)count, buf: (u8 *)buf); |
885 | return (ret != 0 ? ret : count); |
886 | } |
887 | |
888 | /* |
889 | * idt_dbgfs_csr_write() - CSR debugfs-node write callback |
890 | * @filep: Pointer to the file system file descriptor |
891 | * @buf: Buffer to read data from |
892 | * @count: Size of the buffer |
893 | * @offp: Offset within the file |
894 | * |
895 | * It accepts either "0x<reg addr>:0x<value>" for saving register address |
896 | * and writing value to specified DWORD register or "0x<reg addr>" for |
897 | * just saving register address in order to perform next read operation. |
898 | * |
899 | * WARNING No spaces are allowed. Incoming string must be strictly formated as: |
900 | * "<reg addr>:<value>". Register address must be aligned within 4 bytes |
901 | * (one DWORD). |
902 | */ |
903 | static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, |
904 | size_t count, loff_t *offp) |
905 | { |
906 | struct idt_89hpesx_dev *pdev = filep->private_data; |
907 | char *colon_ch, *csraddr_str, *csrval_str; |
908 | int ret; |
909 | u32 csraddr, csrval; |
910 | char *buf; |
911 | |
912 | if (*offp) |
913 | return 0; |
914 | |
915 | /* Copy data from User-space */ |
916 | buf = memdup_user_nul(ubuf, count); |
917 | if (IS_ERR(ptr: buf)) |
918 | return PTR_ERR(ptr: buf); |
919 | |
920 | /* Find position of colon in the buffer */ |
921 | colon_ch = strnchr(buf, count, ':'); |
922 | |
923 | /* |
924 | * If there is colon passed then new CSR value should be parsed as |
925 | * well, so allocate buffer for CSR address substring. |
926 | * If no colon is found, then string must have just one number with |
927 | * no new CSR value |
928 | */ |
929 | if (colon_ch != NULL) { |
930 | /* Copy the register address to the substring buffer */ |
931 | csraddr_str = kmemdup_nul(s: buf, len: colon_ch - buf, GFP_KERNEL); |
932 | if (csraddr_str == NULL) { |
933 | ret = -ENOMEM; |
934 | goto free_buf; |
935 | } |
936 | /* Register value must follow the colon */ |
937 | csrval_str = colon_ch + 1; |
938 | } else /* if (str_colon == NULL) */ { |
939 | csraddr_str = (char *)buf; /* Just to shut warning up */ |
940 | csrval_str = NULL; |
941 | } |
942 | |
943 | /* Convert CSR address to u32 value */ |
944 | ret = kstrtou32(s: csraddr_str, base: 0, res: &csraddr); |
945 | if (ret != 0) |
946 | goto free_csraddr_str; |
947 | |
948 | /* Check whether passed register address is valid */ |
949 | if (csraddr > CSR_MAX || !IS_ALIGNED(csraddr, SZ_4)) { |
950 | ret = -EINVAL; |
951 | goto free_csraddr_str; |
952 | } |
953 | |
954 | /* Shift register address to the right so to have u16 address */ |
955 | pdev->csr = (csraddr >> 2); |
956 | |
957 | /* Parse new CSR value and send it to IDT, if colon has been found */ |
958 | if (colon_ch != NULL) { |
959 | ret = kstrtou32(s: csrval_str, base: 0, res: &csrval); |
960 | if (ret != 0) |
961 | goto free_csraddr_str; |
962 | |
963 | ret = idt_csr_write(pdev, csraddr: pdev->csr, data: csrval); |
964 | if (ret != 0) |
965 | goto free_csraddr_str; |
966 | } |
967 | |
968 | /* Free memory only if colon has been found */ |
969 | free_csraddr_str: |
970 | if (colon_ch != NULL) |
971 | kfree(objp: csraddr_str); |
972 | |
973 | /* Free buffer allocated for data retrieved from User-space */ |
974 | free_buf: |
975 | kfree(objp: buf); |
976 | |
977 | return (ret != 0 ? ret : count); |
978 | } |
979 | |
980 | /* |
981 | * idt_dbgfs_csr_read() - CSR debugfs-node read callback |
982 | * @filep: Pointer to the file system file descriptor |
983 | * @buf: Buffer to write data to |
984 | * @count: Size of the buffer |
985 | * @offp: Offset within the file |
986 | * |
987 | * It just prints the pair "0x<reg addr>:0x<value>" to passed buffer. |
988 | */ |
989 | #define CSRBUF_SIZE ((size_t)32) |
990 | static ssize_t idt_dbgfs_csr_read(struct file *filep, char __user *ubuf, |
991 | size_t count, loff_t *offp) |
992 | { |
993 | struct idt_89hpesx_dev *pdev = filep->private_data; |
994 | u32 csraddr, csrval; |
995 | char buf[CSRBUF_SIZE]; |
996 | int ret, size; |
997 | |
998 | /* Perform CSR read operation */ |
999 | ret = idt_csr_read(pdev, csraddr: pdev->csr, data: &csrval); |
1000 | if (ret != 0) |
1001 | return ret; |
1002 | |
1003 | /* Shift register address to the left so to have real address */ |
1004 | csraddr = ((u32)pdev->csr << 2); |
1005 | |
1006 | /* Print the "0x<reg addr>:0x<value>" to buffer */ |
1007 | size = snprintf(buf, CSRBUF_SIZE, fmt: "0x%05x:0x%08x\n" , |
1008 | (unsigned int)csraddr, (unsigned int)csrval); |
1009 | |
1010 | /* Copy data to User-space */ |
1011 | return simple_read_from_buffer(to: ubuf, count, ppos: offp, from: buf, available: size); |
1012 | } |
1013 | |
1014 | /* |
1015 | * eeprom_attribute - EEPROM sysfs-node attributes |
1016 | * |
1017 | * NOTE Size will be changed in compliance with OF node. EEPROM attribute will |
1018 | * be read-only as well if the corresponding flag is specified in OF node. |
1019 | */ |
1020 | static BIN_ATTR_RW(eeprom, EEPROM_DEF_SIZE); |
1021 | |
1022 | /* |
1023 | * csr_dbgfs_ops - CSR debugfs-node read/write operations |
1024 | */ |
1025 | static const struct file_operations csr_dbgfs_ops = { |
1026 | .owner = THIS_MODULE, |
1027 | .open = simple_open, |
1028 | .write = idt_dbgfs_csr_write, |
1029 | .read = idt_dbgfs_csr_read |
1030 | }; |
1031 | |
1032 | /*=========================================================================== |
1033 | * Driver init/deinit methods |
1034 | *=========================================================================== |
1035 | */ |
1036 | |
1037 | /* |
1038 | * idt_set_defval() - disable EEPROM access by default |
1039 | * @pdev: Pointer to the driver data |
1040 | */ |
1041 | static void idt_set_defval(struct idt_89hpesx_dev *pdev) |
1042 | { |
1043 | /* If OF info is missing then use next values */ |
1044 | pdev->eesize = 0; |
1045 | pdev->eero = true; |
1046 | pdev->inieecmd = 0; |
1047 | pdev->eeaddr = 0; |
1048 | } |
1049 | |
1050 | static const struct i2c_device_id ee_ids[]; |
1051 | |
1052 | /* |
1053 | * idt_ee_match_id() - check whether the node belongs to compatible EEPROMs |
1054 | */ |
1055 | static const struct i2c_device_id *idt_ee_match_id(struct fwnode_handle *fwnode) |
1056 | { |
1057 | const struct i2c_device_id *id = ee_ids; |
1058 | const char *compatible, *p; |
1059 | char devname[I2C_NAME_SIZE]; |
1060 | int ret; |
1061 | |
1062 | ret = fwnode_property_read_string(fwnode, propname: "compatible" , val: &compatible); |
1063 | if (ret) |
1064 | return NULL; |
1065 | |
1066 | p = strchr(compatible, ','); |
1067 | strscpy(devname, p ? p + 1 : compatible, sizeof(devname)); |
1068 | /* Search through the device name */ |
1069 | while (id->name[0]) { |
1070 | if (strcmp(devname, id->name) == 0) |
1071 | return id; |
1072 | id++; |
1073 | } |
1074 | return NULL; |
1075 | } |
1076 | |
1077 | /* |
1078 | * idt_get_fw_data() - get IDT i2c-device parameters from device tree |
1079 | * @pdev: Pointer to the driver data |
1080 | */ |
1081 | static void idt_get_fw_data(struct idt_89hpesx_dev *pdev) |
1082 | { |
1083 | struct device *dev = &pdev->client->dev; |
1084 | struct fwnode_handle *fwnode; |
1085 | const struct i2c_device_id *ee_id = NULL; |
1086 | u32 eeprom_addr; |
1087 | int ret; |
1088 | |
1089 | device_for_each_child_node(dev, fwnode) { |
1090 | ee_id = idt_ee_match_id(fwnode); |
1091 | if (ee_id) |
1092 | break; |
1093 | |
1094 | dev_warn(dev, "Skip unsupported EEPROM device %pfw\n" , fwnode); |
1095 | } |
1096 | |
1097 | /* If there is no fwnode EEPROM device, then set zero size */ |
1098 | if (!ee_id) { |
1099 | dev_warn(dev, "No fwnode, EEPROM access disabled" ); |
1100 | idt_set_defval(pdev); |
1101 | return; |
1102 | } |
1103 | |
1104 | /* Retrieve EEPROM size */ |
1105 | pdev->eesize = (u32)ee_id->driver_data; |
1106 | |
1107 | /* Get custom EEPROM address from 'reg' attribute */ |
1108 | ret = fwnode_property_read_u32(fwnode, propname: "reg" , val: &eeprom_addr); |
1109 | if (ret || (eeprom_addr == 0)) { |
1110 | dev_warn(dev, "No EEPROM reg found, use default address 0x%x" , |
1111 | EEPROM_DEF_ADDR); |
1112 | pdev->inieecmd = 0; |
1113 | pdev->eeaddr = EEPROM_DEF_ADDR << 1; |
1114 | } else { |
1115 | pdev->inieecmd = EEPROM_USA; |
1116 | pdev->eeaddr = eeprom_addr << 1; |
1117 | } |
1118 | |
1119 | /* Check EEPROM 'read-only' flag */ |
1120 | if (fwnode_property_read_bool(fwnode, propname: "read-only" )) |
1121 | pdev->eero = true; |
1122 | else /* if (!fwnode_property_read_bool(node, "read-only")) */ |
1123 | pdev->eero = false; |
1124 | |
1125 | fwnode_handle_put(fwnode); |
1126 | dev_info(dev, "EEPROM of %d bytes found by 0x%x" , |
1127 | pdev->eesize, pdev->eeaddr); |
1128 | } |
1129 | |
1130 | /* |
1131 | * idt_create_pdev() - create and init data structure of the driver |
1132 | * @client: i2c client of IDT PCIe-switch device |
1133 | */ |
1134 | static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client) |
1135 | { |
1136 | struct idt_89hpesx_dev *pdev; |
1137 | |
1138 | /* Allocate memory for driver data */ |
1139 | pdev = devm_kmalloc(dev: &client->dev, size: sizeof(struct idt_89hpesx_dev), |
1140 | GFP_KERNEL); |
1141 | if (pdev == NULL) |
1142 | return ERR_PTR(error: -ENOMEM); |
1143 | |
1144 | /* Initialize basic fields of the data */ |
1145 | pdev->client = client; |
1146 | i2c_set_clientdata(client, data: pdev); |
1147 | |
1148 | /* Read firmware nodes information */ |
1149 | idt_get_fw_data(pdev); |
1150 | |
1151 | /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */ |
1152 | pdev->inicsrcmd = CSR_DWE; |
1153 | pdev->csr = CSR_DEF; |
1154 | |
1155 | /* Enable Packet Error Checking if it's supported by adapter */ |
1156 | if (i2c_check_functionality(adap: client->adapter, I2C_FUNC_SMBUS_PEC)) { |
1157 | pdev->iniccode = CCODE_PEC; |
1158 | client->flags |= I2C_CLIENT_PEC; |
1159 | } else /* PEC is unsupported */ { |
1160 | pdev->iniccode = 0; |
1161 | } |
1162 | |
1163 | return pdev; |
1164 | } |
1165 | |
1166 | /* |
1167 | * idt_free_pdev() - free data structure of the driver |
1168 | * @pdev: Pointer to the driver data |
1169 | */ |
1170 | static void idt_free_pdev(struct idt_89hpesx_dev *pdev) |
1171 | { |
1172 | /* Clear driver data from device private field */ |
1173 | i2c_set_clientdata(client: pdev->client, NULL); |
1174 | } |
1175 | |
1176 | /* |
1177 | * idt_set_smbus_ops() - set supported SMBus operations |
1178 | * @pdev: Pointer to the driver data |
1179 | * Return status of smbus check operations |
1180 | */ |
1181 | static int idt_set_smbus_ops(struct idt_89hpesx_dev *pdev) |
1182 | { |
1183 | struct i2c_adapter *adapter = pdev->client->adapter; |
1184 | struct device *dev = &pdev->client->dev; |
1185 | |
1186 | /* Check i2c adapter read functionality */ |
1187 | if (i2c_check_functionality(adap: adapter, |
1188 | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { |
1189 | pdev->smb_read = idt_smb_read_block; |
1190 | dev_dbg(dev, "SMBus block-read op chosen" ); |
1191 | } else if (i2c_check_functionality(adap: adapter, |
1192 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { |
1193 | pdev->smb_read = idt_smb_read_i2c_block; |
1194 | dev_dbg(dev, "SMBus i2c-block-read op chosen" ); |
1195 | } else if (i2c_check_functionality(adap: adapter, |
1196 | I2C_FUNC_SMBUS_READ_WORD_DATA) && |
1197 | i2c_check_functionality(adap: adapter, |
1198 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { |
1199 | pdev->smb_read = idt_smb_read_word; |
1200 | dev_warn(dev, "Use slow word/byte SMBus read ops" ); |
1201 | } else if (i2c_check_functionality(adap: adapter, |
1202 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { |
1203 | pdev->smb_read = idt_smb_read_byte; |
1204 | dev_warn(dev, "Use slow byte SMBus read op" ); |
1205 | } else /* no supported smbus read operations */ { |
1206 | dev_err(dev, "No supported SMBus read op" ); |
1207 | return -EPFNOSUPPORT; |
1208 | } |
1209 | |
1210 | /* Check i2c adapter write functionality */ |
1211 | if (i2c_check_functionality(adap: adapter, |
1212 | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) { |
1213 | pdev->smb_write = idt_smb_write_block; |
1214 | dev_dbg(dev, "SMBus block-write op chosen" ); |
1215 | } else if (i2c_check_functionality(adap: adapter, |
1216 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { |
1217 | pdev->smb_write = idt_smb_write_i2c_block; |
1218 | dev_dbg(dev, "SMBus i2c-block-write op chosen" ); |
1219 | } else if (i2c_check_functionality(adap: adapter, |
1220 | I2C_FUNC_SMBUS_WRITE_WORD_DATA) && |
1221 | i2c_check_functionality(adap: adapter, |
1222 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { |
1223 | pdev->smb_write = idt_smb_write_word; |
1224 | dev_warn(dev, "Use slow word/byte SMBus write op" ); |
1225 | } else if (i2c_check_functionality(adap: adapter, |
1226 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { |
1227 | pdev->smb_write = idt_smb_write_byte; |
1228 | dev_warn(dev, "Use slow byte SMBus write op" ); |
1229 | } else /* no supported smbus write operations */ { |
1230 | dev_err(dev, "No supported SMBus write op" ); |
1231 | return -EPFNOSUPPORT; |
1232 | } |
1233 | |
1234 | /* Initialize IDT SMBus slave interface mutex */ |
1235 | mutex_init(&pdev->smb_mtx); |
1236 | |
1237 | return 0; |
1238 | } |
1239 | |
1240 | /* |
1241 | * idt_check_dev() - check whether it's really IDT 89HPESx device |
1242 | * @pdev: Pointer to the driver data |
1243 | * Return status of i2c adapter check operation |
1244 | */ |
1245 | static int idt_check_dev(struct idt_89hpesx_dev *pdev) |
1246 | { |
1247 | struct device *dev = &pdev->client->dev; |
1248 | u32 viddid; |
1249 | int ret; |
1250 | |
1251 | /* Read VID and DID directly from IDT memory space */ |
1252 | ret = idt_csr_read(pdev, IDT_VIDDID_CSR, data: &viddid); |
1253 | if (ret != 0) { |
1254 | dev_err(dev, "Failed to read VID/DID" ); |
1255 | return ret; |
1256 | } |
1257 | |
1258 | /* Check whether it's IDT device */ |
1259 | if ((viddid & IDT_VID_MASK) != PCI_VENDOR_ID_IDT) { |
1260 | dev_err(dev, "Got unsupported VID/DID: 0x%08x" , viddid); |
1261 | return -ENODEV; |
1262 | } |
1263 | |
1264 | dev_info(dev, "Found IDT 89HPES device VID:0x%04x, DID:0x%04x" , |
1265 | (viddid & IDT_VID_MASK), (viddid >> 16)); |
1266 | |
1267 | return 0; |
1268 | } |
1269 | |
1270 | /* |
1271 | * idt_create_sysfs_files() - create sysfs attribute files |
1272 | * @pdev: Pointer to the driver data |
1273 | * Return status of operation |
1274 | */ |
1275 | static int idt_create_sysfs_files(struct idt_89hpesx_dev *pdev) |
1276 | { |
1277 | struct device *dev = &pdev->client->dev; |
1278 | int ret; |
1279 | |
1280 | /* Don't do anything if EEPROM isn't accessible */ |
1281 | if (pdev->eesize == 0) { |
1282 | dev_dbg(dev, "Skip creating sysfs-files" ); |
1283 | return 0; |
1284 | } |
1285 | |
1286 | /* |
1287 | * Allocate memory for attribute file and copy the declared EEPROM attr |
1288 | * structure to change some of fields |
1289 | */ |
1290 | pdev->ee_file = devm_kmemdup(dev, src: &bin_attr_eeprom, |
1291 | len: sizeof(*pdev->ee_file), GFP_KERNEL); |
1292 | if (!pdev->ee_file) |
1293 | return -ENOMEM; |
1294 | |
1295 | /* In case of read-only EEPROM get rid of write ability */ |
1296 | if (pdev->eero) { |
1297 | pdev->ee_file->attr.mode &= ~0200; |
1298 | pdev->ee_file->write = NULL; |
1299 | } |
1300 | /* Create EEPROM sysfs file */ |
1301 | pdev->ee_file->size = pdev->eesize; |
1302 | ret = sysfs_create_bin_file(kobj: &dev->kobj, attr: pdev->ee_file); |
1303 | if (ret != 0) { |
1304 | dev_err(dev, "Failed to create EEPROM sysfs-node" ); |
1305 | return ret; |
1306 | } |
1307 | |
1308 | return 0; |
1309 | } |
1310 | |
1311 | /* |
1312 | * idt_remove_sysfs_files() - remove sysfs attribute files |
1313 | * @pdev: Pointer to the driver data |
1314 | */ |
1315 | static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev) |
1316 | { |
1317 | struct device *dev = &pdev->client->dev; |
1318 | |
1319 | /* Don't do anything if EEPROM wasn't accessible */ |
1320 | if (pdev->eesize == 0) |
1321 | return; |
1322 | |
1323 | /* Remove EEPROM sysfs file */ |
1324 | sysfs_remove_bin_file(kobj: &dev->kobj, attr: pdev->ee_file); |
1325 | } |
1326 | |
1327 | /* |
1328 | * idt_create_dbgfs_files() - create debugfs files |
1329 | * @pdev: Pointer to the driver data |
1330 | */ |
1331 | #define CSRNAME_LEN ((size_t)32) |
1332 | static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev) |
1333 | { |
1334 | struct i2c_client *cli = pdev->client; |
1335 | char fname[CSRNAME_LEN]; |
1336 | |
1337 | /* Create Debugfs directory for CSR file */ |
1338 | snprintf(buf: fname, CSRNAME_LEN, fmt: "%d-%04hx" , cli->adapter->nr, cli->addr); |
1339 | pdev->csr_dir = debugfs_create_dir(name: fname, parent: csr_dbgdir); |
1340 | |
1341 | /* Create Debugfs file for CSR read/write operations */ |
1342 | debugfs_create_file(name: cli->name, mode: 0600, parent: pdev->csr_dir, data: pdev, |
1343 | fops: &csr_dbgfs_ops); |
1344 | } |
1345 | |
1346 | /* |
1347 | * idt_remove_dbgfs_files() - remove debugfs files |
1348 | * @pdev: Pointer to the driver data |
1349 | */ |
1350 | static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev) |
1351 | { |
1352 | /* Remove CSR directory and it sysfs-node */ |
1353 | debugfs_remove_recursive(dentry: pdev->csr_dir); |
1354 | } |
1355 | |
1356 | /* |
1357 | * idt_probe() - IDT 89HPESx driver probe() callback method |
1358 | */ |
1359 | static int idt_probe(struct i2c_client *client) |
1360 | { |
1361 | struct idt_89hpesx_dev *pdev; |
1362 | int ret; |
1363 | |
1364 | /* Create driver data */ |
1365 | pdev = idt_create_pdev(client); |
1366 | if (IS_ERR(ptr: pdev)) |
1367 | return PTR_ERR(ptr: pdev); |
1368 | |
1369 | /* Set SMBus operations */ |
1370 | ret = idt_set_smbus_ops(pdev); |
1371 | if (ret != 0) |
1372 | goto err_free_pdev; |
1373 | |
1374 | /* Check whether it is truly IDT 89HPESx device */ |
1375 | ret = idt_check_dev(pdev); |
1376 | if (ret != 0) |
1377 | goto err_free_pdev; |
1378 | |
1379 | /* Create sysfs files */ |
1380 | ret = idt_create_sysfs_files(pdev); |
1381 | if (ret != 0) |
1382 | goto err_free_pdev; |
1383 | |
1384 | /* Create debugfs files */ |
1385 | idt_create_dbgfs_files(pdev); |
1386 | |
1387 | return 0; |
1388 | |
1389 | err_free_pdev: |
1390 | idt_free_pdev(pdev); |
1391 | |
1392 | return ret; |
1393 | } |
1394 | |
1395 | /* |
1396 | * idt_remove() - IDT 89HPESx driver remove() callback method |
1397 | */ |
1398 | static void idt_remove(struct i2c_client *client) |
1399 | { |
1400 | struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client); |
1401 | |
1402 | /* Remove debugfs files first */ |
1403 | idt_remove_dbgfs_files(pdev); |
1404 | |
1405 | /* Remove sysfs files */ |
1406 | idt_remove_sysfs_files(pdev); |
1407 | |
1408 | /* Discard driver data structure */ |
1409 | idt_free_pdev(pdev); |
1410 | } |
1411 | |
1412 | /* |
1413 | * ee_ids - array of supported EEPROMs |
1414 | */ |
1415 | static const struct i2c_device_id ee_ids[] = { |
1416 | { "24c32" , 4096}, |
1417 | { "24c64" , 8192}, |
1418 | { "24c128" , 16384}, |
1419 | { "24c256" , 32768}, |
1420 | { "24c512" , 65536}, |
1421 | {} |
1422 | }; |
1423 | MODULE_DEVICE_TABLE(i2c, ee_ids); |
1424 | |
1425 | /* |
1426 | * idt_ids - supported IDT 89HPESx devices |
1427 | */ |
1428 | static const struct i2c_device_id idt_ids[] = { |
1429 | { "89hpes8nt2" , 0 }, |
1430 | { "89hpes12nt3" , 0 }, |
1431 | |
1432 | { "89hpes24nt6ag2" , 0 }, |
1433 | { "89hpes32nt8ag2" , 0 }, |
1434 | { "89hpes32nt8bg2" , 0 }, |
1435 | { "89hpes12nt12g2" , 0 }, |
1436 | { "89hpes16nt16g2" , 0 }, |
1437 | { "89hpes24nt24g2" , 0 }, |
1438 | { "89hpes32nt24ag2" , 0 }, |
1439 | { "89hpes32nt24bg2" , 0 }, |
1440 | |
1441 | { "89hpes12n3" , 0 }, |
1442 | { "89hpes12n3a" , 0 }, |
1443 | { "89hpes24n3" , 0 }, |
1444 | { "89hpes24n3a" , 0 }, |
1445 | |
1446 | { "89hpes32h8" , 0 }, |
1447 | { "89hpes32h8g2" , 0 }, |
1448 | { "89hpes48h12" , 0 }, |
1449 | { "89hpes48h12g2" , 0 }, |
1450 | { "89hpes48h12ag2" , 0 }, |
1451 | { "89hpes16h16" , 0 }, |
1452 | { "89hpes22h16" , 0 }, |
1453 | { "89hpes22h16g2" , 0 }, |
1454 | { "89hpes34h16" , 0 }, |
1455 | { "89hpes34h16g2" , 0 }, |
1456 | { "89hpes64h16" , 0 }, |
1457 | { "89hpes64h16g2" , 0 }, |
1458 | { "89hpes64h16ag2" , 0 }, |
1459 | |
1460 | /* { "89hpes3t3", 0 }, // No SMBus-slave iface */ |
1461 | { "89hpes12t3g2" , 0 }, |
1462 | { "89hpes24t3g2" , 0 }, |
1463 | /* { "89hpes4t4", 0 }, // No SMBus-slave iface */ |
1464 | { "89hpes16t4" , 0 }, |
1465 | { "89hpes4t4g2" , 0 }, |
1466 | { "89hpes10t4g2" , 0 }, |
1467 | { "89hpes16t4g2" , 0 }, |
1468 | { "89hpes16t4ag2" , 0 }, |
1469 | { "89hpes5t5" , 0 }, |
1470 | { "89hpes6t5" , 0 }, |
1471 | { "89hpes8t5" , 0 }, |
1472 | { "89hpes8t5a" , 0 }, |
1473 | { "89hpes24t6" , 0 }, |
1474 | { "89hpes6t6g2" , 0 }, |
1475 | { "89hpes24t6g2" , 0 }, |
1476 | { "89hpes16t7" , 0 }, |
1477 | { "89hpes32t8" , 0 }, |
1478 | { "89hpes32t8g2" , 0 }, |
1479 | { "89hpes48t12" , 0 }, |
1480 | { "89hpes48t12g2" , 0 }, |
1481 | { /* END OF LIST */ } |
1482 | }; |
1483 | MODULE_DEVICE_TABLE(i2c, idt_ids); |
1484 | |
1485 | static const struct of_device_id idt_of_match[] = { |
1486 | { .compatible = "idt,89hpes8nt2" , }, |
1487 | { .compatible = "idt,89hpes12nt3" , }, |
1488 | |
1489 | { .compatible = "idt,89hpes24nt6ag2" , }, |
1490 | { .compatible = "idt,89hpes32nt8ag2" , }, |
1491 | { .compatible = "idt,89hpes32nt8bg2" , }, |
1492 | { .compatible = "idt,89hpes12nt12g2" , }, |
1493 | { .compatible = "idt,89hpes16nt16g2" , }, |
1494 | { .compatible = "idt,89hpes24nt24g2" , }, |
1495 | { .compatible = "idt,89hpes32nt24ag2" , }, |
1496 | { .compatible = "idt,89hpes32nt24bg2" , }, |
1497 | |
1498 | { .compatible = "idt,89hpes12n3" , }, |
1499 | { .compatible = "idt,89hpes12n3a" , }, |
1500 | { .compatible = "idt,89hpes24n3" , }, |
1501 | { .compatible = "idt,89hpes24n3a" , }, |
1502 | |
1503 | { .compatible = "idt,89hpes32h8" , }, |
1504 | { .compatible = "idt,89hpes32h8g2" , }, |
1505 | { .compatible = "idt,89hpes48h12" , }, |
1506 | { .compatible = "idt,89hpes48h12g2" , }, |
1507 | { .compatible = "idt,89hpes48h12ag2" , }, |
1508 | { .compatible = "idt,89hpes16h16" , }, |
1509 | { .compatible = "idt,89hpes22h16" , }, |
1510 | { .compatible = "idt,89hpes22h16g2" , }, |
1511 | { .compatible = "idt,89hpes34h16" , }, |
1512 | { .compatible = "idt,89hpes34h16g2" , }, |
1513 | { .compatible = "idt,89hpes64h16" , }, |
1514 | { .compatible = "idt,89hpes64h16g2" , }, |
1515 | { .compatible = "idt,89hpes64h16ag2" , }, |
1516 | |
1517 | { .compatible = "idt,89hpes12t3g2" , }, |
1518 | { .compatible = "idt,89hpes24t3g2" , }, |
1519 | |
1520 | { .compatible = "idt,89hpes16t4" , }, |
1521 | { .compatible = "idt,89hpes4t4g2" , }, |
1522 | { .compatible = "idt,89hpes10t4g2" , }, |
1523 | { .compatible = "idt,89hpes16t4g2" , }, |
1524 | { .compatible = "idt,89hpes16t4ag2" , }, |
1525 | { .compatible = "idt,89hpes5t5" , }, |
1526 | { .compatible = "idt,89hpes6t5" , }, |
1527 | { .compatible = "idt,89hpes8t5" , }, |
1528 | { .compatible = "idt,89hpes8t5a" , }, |
1529 | { .compatible = "idt,89hpes24t6" , }, |
1530 | { .compatible = "idt,89hpes6t6g2" , }, |
1531 | { .compatible = "idt,89hpes24t6g2" , }, |
1532 | { .compatible = "idt,89hpes16t7" , }, |
1533 | { .compatible = "idt,89hpes32t8" , }, |
1534 | { .compatible = "idt,89hpes32t8g2" , }, |
1535 | { .compatible = "idt,89hpes48t12" , }, |
1536 | { .compatible = "idt,89hpes48t12g2" , }, |
1537 | { }, |
1538 | }; |
1539 | MODULE_DEVICE_TABLE(of, idt_of_match); |
1540 | |
1541 | /* |
1542 | * idt_driver - IDT 89HPESx driver structure |
1543 | */ |
1544 | static struct i2c_driver idt_driver = { |
1545 | .driver = { |
1546 | .name = IDT_NAME, |
1547 | .of_match_table = idt_of_match, |
1548 | }, |
1549 | .probe = idt_probe, |
1550 | .remove = idt_remove, |
1551 | .id_table = idt_ids, |
1552 | }; |
1553 | |
1554 | /* |
1555 | * idt_init() - IDT 89HPESx driver init() callback method |
1556 | */ |
1557 | static int __init idt_init(void) |
1558 | { |
1559 | int ret; |
1560 | |
1561 | /* Create Debugfs directory first */ |
1562 | if (debugfs_initialized()) |
1563 | csr_dbgdir = debugfs_create_dir(name: "idt_csr" , NULL); |
1564 | |
1565 | /* Add new i2c-device driver */ |
1566 | ret = i2c_add_driver(&idt_driver); |
1567 | if (ret) { |
1568 | debugfs_remove_recursive(dentry: csr_dbgdir); |
1569 | return ret; |
1570 | } |
1571 | |
1572 | return 0; |
1573 | } |
1574 | module_init(idt_init); |
1575 | |
1576 | /* |
1577 | * idt_exit() - IDT 89HPESx driver exit() callback method |
1578 | */ |
1579 | static void __exit idt_exit(void) |
1580 | { |
1581 | /* Discard debugfs directory and all files if any */ |
1582 | debugfs_remove_recursive(dentry: csr_dbgdir); |
1583 | |
1584 | /* Unregister i2c-device driver */ |
1585 | i2c_del_driver(driver: &idt_driver); |
1586 | } |
1587 | module_exit(idt_exit); |
1588 | |