Shad Ansari | 2f7f9be | 2017-06-07 13:34:53 -0700 | [diff] [blame^] | 1 | /* |
| 2 | <:copyright-BRCM:2016:DUAL/GPL:standard |
| 3 | |
| 4 | Broadcom Proprietary and Confidential.(c) 2016 Broadcom |
| 5 | All Rights Reserved |
| 6 | |
| 7 | Unless you and Broadcom execute a separate written software license |
| 8 | agreement governing use of this software, this software is licensed |
| 9 | to you under the terms of the GNU General Public License version 2 |
| 10 | (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, |
| 11 | with the following added to such license: |
| 12 | |
| 13 | As a special exception, the copyright holders of this software give |
| 14 | you permission to link this software with independent modules, and |
| 15 | to copy and distribute the resulting executable under terms of your |
| 16 | choice, provided that you also meet, for each linked independent |
| 17 | module, the terms and conditions of the license of that module. |
| 18 | An independent module is a module which is not derived from this |
| 19 | software. The special exception does not apply to any modifications |
| 20 | of the software. |
| 21 | |
| 22 | Not withstanding the above, under no circumstances may you combine |
| 23 | this software in any way with any other Broadcom software provided |
| 24 | under a license other than the GPL, without Broadcom's express prior |
| 25 | written consent. |
| 26 | |
| 27 | :> |
| 28 | */ |
| 29 | |
| 30 | #include <linux/module.h> |
| 31 | #include <linux/init.h> |
| 32 | #include <linux/slab.h> |
| 33 | #include <linux/jiffies.h> |
| 34 | #include <linux/i2c.h> |
| 35 | #include <linux/err.h> |
| 36 | #include <linux/cdev.h> |
| 37 | #include <asm/uaccess.h> /*copy_from_user*/ |
| 38 | #include <linux/proc_fs.h> |
| 39 | #include "bcmos_system.h" |
| 40 | #include "bcmolt_i2c_devs.h" |
| 41 | #include "bcmolt_i2c_devs_ioctl.h" |
| 42 | |
| 43 | #define BCM_I2C_DEV_ADDR_START typedef enum { |
| 44 | #define BCM_I2C_DEV_ADDR(name, desc, val) name = val, |
| 45 | #define BCM_I2C_DEV_ADDR_END } bcm_i2c_dev_addr; |
| 46 | |
| 47 | #include "bcmolt_i2c_devs_addr.h" |
| 48 | |
| 49 | #define PROC_DIR_NAME "maple_i2c" |
| 50 | #define PROC_ENTRY_NAME "i2c" |
| 51 | #define MAX_EAGAIN_ITERS 200 /* 10ms per iter */ |
| 52 | |
| 53 | /* uncomment the next line to enable debug output to the kernel CLI */ |
| 54 | /* #define I2C_DEBUG_PRINTS 1 */ |
| 55 | #ifdef I2C_DEBUG_PRINTS |
| 56 | #define i2c_debug_print(fmt, args...) printk("%s#%d: " fmt, __FUNCTION__, __LINE__, ## args) |
| 57 | #else |
| 58 | #define i2c_debug_print(...) |
| 59 | #endif |
| 60 | |
| 61 | int maple_i2c_chrdev_major = 216; |
| 62 | module_param(maple_i2c_chrdev_major, int, S_IRUSR | S_IRGRP | S_IWGRP); |
| 63 | MODULE_PARM_DESC(maple_i2c_chrdev_major, "maple_i2c_major"); |
| 64 | |
| 65 | static struct proc_dir_entry *i2c_proc_dir; |
| 66 | static struct proc_dir_entry *i2c_proc_entry; |
| 67 | static char is_chrdev_reg; |
| 68 | static char is_cdev_add; |
| 69 | static int i2c_client_num; |
| 70 | static int i2c_num_clients; |
| 71 | |
| 72 | const unsigned short normal_i2c[] = { |
| 73 | I2C_SW0_I2C_ADDR, |
| 74 | I2C_SW1_I2C_ADDR, |
| 75 | I2C_SW2_I2C_ADDR, |
| 76 | I2C_SW3_I2C_ADDR, |
| 77 | I2C_SW4_I2C_ADDR, |
| 78 | SFP_I2C_ADDR1, |
| 79 | SFP_I2C_ADDR2, |
| 80 | FPGA_I2C_ADDR, |
| 81 | PON_DPLL_I2C_ADDR, |
| 82 | PM_DPLL_I2C_ADDR, |
| 83 | CXP_R_I2C_ADDR, |
| 84 | PCIE_SW_I2C_ADDR, |
| 85 | I2C_CLIENT_END |
| 86 | }; |
| 87 | |
| 88 | static unsigned char slave_valid[SLAVE_NUM_OF_SLAVES] = {0}; |
| 89 | |
| 90 | /* |
| 91 | * Driver data (common to all clients) |
| 92 | */ |
| 93 | |
| 94 | static const struct i2c_device_id maple_i2c_id_table[] = { |
| 95 | { "maple_i2c", 0 }, |
| 96 | { } |
| 97 | }; |
| 98 | MODULE_DEVICE_TABLE(i2c, maple_i2c_id_table); |
| 99 | |
| 100 | static void bcm_access_fpga(void); |
| 101 | |
| 102 | /* |
| 103 | * Client data (each client gets its own) |
| 104 | */ |
| 105 | struct maple_i2c_data { |
| 106 | struct i2c_client client; |
| 107 | }; |
| 108 | |
| 109 | static struct maple_i2c_data *pclient_data_ar[SLAVE_NUM_OF_SLAVES]; |
| 110 | |
| 111 | static int get_client(unsigned char client_num, struct i2c_client **client) |
| 112 | { |
| 113 | if ((client_num >= SLAVE_NUM_OF_SLAVES) || !slave_valid[client_num]) |
| 114 | { |
| 115 | i2c_debug_print("I2C error: Wrong client number 0x%x\n", client_num); |
| 116 | return -1; |
| 117 | } |
| 118 | *client = &pclient_data_ar[client_num]->client; |
| 119 | |
| 120 | return 0; |
| 121 | } |
| 122 | |
| 123 | |
| 124 | /* |
| 125 | * Helper functions which attempt I2C transfer until successful, or error code is other than -EAGAIN |
| 126 | */ |
| 127 | |
| 128 | static int maple_i2c_send(unsigned char client_num, u8 *buf, size_t count) |
| 129 | { |
| 130 | struct i2c_client *client; |
| 131 | int rc; |
| 132 | int niter = 0; |
| 133 | |
| 134 | if (get_client(client_num, &client)) |
| 135 | return -1; |
| 136 | |
| 137 | do { |
| 138 | rc = i2c_master_send(client, buf, count); |
| 139 | if (rc == -EAGAIN) |
| 140 | msleep(10); |
| 141 | } while (rc == -EAGAIN && ++niter < MAX_EAGAIN_ITERS); |
| 142 | rc = (rc == count) ? 0 : (rc < 0 ) ? rc : -1; |
| 143 | |
| 144 | return rc; |
| 145 | } |
| 146 | |
| 147 | static int maple_i2c_recv(unsigned char client_num, u8 *buf, size_t count) |
| 148 | { |
| 149 | struct i2c_client *client; |
| 150 | int rc; |
| 151 | int niter = 0; |
| 152 | |
| 153 | if (get_client(client_num, &client)) |
| 154 | return -1; |
| 155 | |
| 156 | do { |
| 157 | rc = i2c_master_recv(client, buf, count); |
| 158 | if (rc == -EAGAIN) |
| 159 | msleep(10); |
| 160 | } while (rc == -EAGAIN && ++niter < MAX_EAGAIN_ITERS); |
| 161 | rc = (rc == count) ? 0 : (rc < 0 ) ? rc : -1; |
| 162 | |
| 163 | return rc; |
| 164 | } |
| 165 | |
| 166 | |
| 167 | static int maple_i2c_read_with_offset(unsigned char client_num, u8 *offset, size_t offset_size, u8 *buf, size_t count) |
| 168 | { |
| 169 | struct i2c_client *client; |
| 170 | struct i2c_msg msg[2]; |
| 171 | int rc; |
| 172 | int niter = 0; |
| 173 | |
| 174 | if (get_client(client_num, &client)) |
| 175 | return -1; |
| 176 | |
| 177 | msg[0].addr = msg[1].addr = client->addr; |
| 178 | msg[0].flags = msg[1].flags = client->flags & I2C_M_TEN; |
| 179 | |
| 180 | msg[0].len = offset_size; |
| 181 | msg[0].buf = offset; |
| 182 | |
| 183 | msg[1].flags |= I2C_M_RD; |
| 184 | msg[1].len = count; |
| 185 | msg[1].buf = buf; |
| 186 | |
| 187 | do { |
| 188 | rc = i2c_transfer(client->adapter, msg, 2); |
| 189 | if (rc == -EAGAIN) |
| 190 | msleep(10); |
| 191 | } while (rc == -EAGAIN && ++niter < MAX_EAGAIN_ITERS); |
| 192 | |
| 193 | rc = (rc == 2) ? 0 : (rc < 0 ) ? rc : -1; |
| 194 | |
| 195 | return rc; |
| 196 | } |
| 197 | |
| 198 | ssize_t maple_i2c_write(unsigned char client_num, char *buf, size_t count) |
| 199 | { |
| 200 | int rc; |
| 201 | |
| 202 | i2c_debug_print("Write to switch: client=0x%x val = 0x%x\n", normal_i2c[client_num], *buf); |
| 203 | rc = maple_i2c_send(client_num, (u8 *)buf, count); |
| 204 | |
| 205 | if (rc < 0) |
| 206 | i2c_debug_print("Write Failed. rc=%d client=%u[%u]\n", rc, |
| 207 | normal_i2c[client_num], client_num); |
| 208 | else |
| 209 | i2c_debug_print("Write Successful client=%u[%u]\n", |
| 210 | normal_i2c[client_num], client_num); |
| 211 | return rc; |
| 212 | } |
| 213 | EXPORT_SYMBOL(maple_i2c_write); |
| 214 | |
| 215 | ssize_t maple_i2c_read(unsigned char client_num, char *buf, size_t count) |
| 216 | { |
| 217 | int rc; |
| 218 | |
| 219 | i2c_debug_print("Read from switch: client 0x%x\n", normal_i2c[client_num]); |
| 220 | rc = maple_i2c_recv(client_num, (u8 *)buf, count); |
| 221 | |
| 222 | if (rc < 0) |
| 223 | i2c_debug_print("Read Failed. rc=%d client=%u[%u]\n", rc, |
| 224 | normal_i2c[client_num], client_num); |
| 225 | else |
| 226 | i2c_debug_print("Read Successful: count=%u val = 0x%x\n", (unsigned)count, *buf); |
| 227 | return rc; |
| 228 | } |
| 229 | EXPORT_SYMBOL(maple_i2c_read); |
| 230 | |
| 231 | int maple_i2c_write_byte(unsigned char client_num, unsigned char offset, unsigned char val) |
| 232 | { |
| 233 | u8 buf[2]; |
| 234 | int rc; |
| 235 | |
| 236 | i2c_debug_print("Write Byte: client=0x%x offset = 0x%x, val = 0x%x\n", normal_i2c[client_num], offset, val); |
| 237 | |
| 238 | buf[0] = offset; |
| 239 | buf[1] = val; |
| 240 | rc = maple_i2c_send(client_num, buf, 2); |
| 241 | |
| 242 | if (rc < 0) |
| 243 | i2c_debug_print("Write Byte Failed. rc=%d offset=0x%x val=0x%x client=%u[%u]\n", |
| 244 | rc, offset, val, |
| 245 | normal_i2c[client_num], client_num); |
| 246 | else |
| 247 | i2c_debug_print("Write Byte: offset=0x%x val=0x%x client=%u/%u\n", |
| 248 | offset, val, |
| 249 | normal_i2c[client_num], client_num); |
| 250 | return rc; |
| 251 | } |
| 252 | EXPORT_SYMBOL(maple_i2c_write_byte); |
| 253 | |
| 254 | int maple_i2c_read_byte(unsigned char client_num, unsigned char offset, unsigned char *data) |
| 255 | { |
| 256 | u8 o = offset; |
| 257 | u8 val; |
| 258 | int rc; |
| 259 | |
| 260 | i2c_debug_print("Write Byte: client=0x%x offset = 0x%x, val = 0x%x\n", normal_i2c[client_num], offset, val); |
| 261 | |
| 262 | rc = maple_i2c_read_with_offset(client_num, &o, 1, &val, 1); |
| 263 | |
| 264 | if (rc < 0) |
| 265 | i2c_debug_print("Read Byte Failed. rc=%d client=%u[%u]\n", rc, |
| 266 | normal_i2c[client_num], client_num); |
| 267 | else |
| 268 | { |
| 269 | *data = val; |
| 270 | i2c_debug_print("Read Byte: client=0x%x offset = 0x%x, val = 0x%x\n", |
| 271 | normal_i2c[client_num], offset, *data); |
| 272 | } |
| 273 | return rc; |
| 274 | } |
| 275 | EXPORT_SYMBOL(maple_i2c_read_byte); |
| 276 | |
| 277 | |
| 278 | int maple_i2c_write_word(unsigned char client_num, unsigned char offset, unsigned short val) |
| 279 | { |
| 280 | u8 buf[3]; |
| 281 | int rc; |
| 282 | |
| 283 | i2c_debug_print("Write Word: offset = 0x%x, val = 0x%x\n", offset, val); |
| 284 | |
| 285 | /* The offset to be written should be the first byte in the I2C write */ |
| 286 | buf[0] = offset; |
| 287 | buf[1] = (char)(val&0xFF); |
| 288 | buf[2] = (char)(val>>8); |
| 289 | rc = maple_i2c_send(client_num, buf, sizeof(buf)); |
| 290 | |
| 291 | if (rc < 0) |
| 292 | i2c_debug_print("Write Word Failed. rc=%d offset=0x%x val=0x%x, client=%u[%u]\n", |
| 293 | rc, offset, val, |
| 294 | normal_i2c[client_num], client_num); |
| 295 | else |
| 296 | i2c_debug_print("Write Word: offset=0x%x val=0x%x, client=%u[%u]\n", |
| 297 | offset, val, |
| 298 | normal_i2c[client_num], client_num); |
| 299 | return rc; |
| 300 | } |
| 301 | EXPORT_SYMBOL(maple_i2c_write_word); |
| 302 | |
| 303 | int maple_i2c_read_word(unsigned char client_num, unsigned char offset, unsigned short *data) |
| 304 | { |
| 305 | u8 o = offset; |
| 306 | u8 buf[2]; |
| 307 | int rc; |
| 308 | |
| 309 | rc = maple_i2c_read_with_offset(client_num, &o, 1, buf, sizeof(buf)); |
| 310 | |
| 311 | if (rc < 0) |
| 312 | i2c_debug_print("Read Word Failed. rc=%d offset=0x%x client=%u[%u]\n", |
| 313 | rc, offset, |
| 314 | normal_i2c[client_num], client_num); |
| 315 | else |
| 316 | { |
| 317 | *data = (buf[1]<<8) | buf[0]; /* I2C data is LE */ |
| 318 | i2c_debug_print("Read Word: offset = 0x%x, val = 0x%x client=%u[%u]\n", |
| 319 | offset, *data, |
| 320 | normal_i2c[client_num], client_num); |
| 321 | } |
| 322 | return rc; |
| 323 | } |
| 324 | EXPORT_SYMBOL(maple_i2c_read_word); |
| 325 | |
| 326 | |
| 327 | int maple_i2c_write_reg(unsigned char client_num, unsigned char offset, int val) |
| 328 | { |
| 329 | u8 buf[5]; |
| 330 | int rc; |
| 331 | |
| 332 | i2c_debug_print("Write Register: offset = 0x%x, val = 0x%x\n", offset, val); |
| 333 | |
| 334 | /* Set the buf[0] to be the offset for write operation */ |
| 335 | buf[0] = offset; |
| 336 | |
| 337 | /* On the I2C bus, LS Byte should go first */ |
| 338 | buf[1] = val & 0xff; |
| 339 | buf[2] = (val >> 8) & 0xff; |
| 340 | buf[3] = (val >> 16) & 0xff; |
| 341 | buf[4] = (val >> 24) & 0xff; |
| 342 | rc = maple_i2c_send(client_num, buf, sizeof(buf)); |
| 343 | |
| 344 | if (rc < 0) |
| 345 | i2c_debug_print("Write Reg Failed. rc=%d offset=0x%x val=0x%x client=%u[%u]\n", |
| 346 | rc, offset, val, |
| 347 | normal_i2c[client_num], client_num); |
| 348 | else |
| 349 | i2c_debug_print("Write Reg Successful. offset=0x%x val=0x%x client=%u[%u]\n", |
| 350 | offset, val, |
| 351 | normal_i2c[client_num], client_num); |
| 352 | return rc; |
| 353 | } |
| 354 | EXPORT_SYMBOL(maple_i2c_write_reg); |
| 355 | |
| 356 | |
| 357 | int maple_i2c_read_reg(unsigned char client_num, unsigned char offset, unsigned int *data) |
| 358 | { |
| 359 | u8 o = offset; |
| 360 | u8 buf[4]; |
| 361 | int rc; |
| 362 | |
| 363 | rc = maple_i2c_read_with_offset(client_num, &o, 1, buf, sizeof(buf)); |
| 364 | |
| 365 | if (rc < 0) |
| 366 | i2c_debug_print("Read Reg Failed. rc=%d offset=0x%x client=%u[%u]\n", |
| 367 | rc, offset, |
| 368 | normal_i2c[client_num], client_num); |
| 369 | else |
| 370 | { |
| 371 | *data = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); /* LS byte is transferred first */ |
| 372 | i2c_debug_print("Read Register: client=0x%x offset = 0x%x, val = 0x%x\n", normal_i2c[client_num], offset, *data); |
| 373 | } |
| 374 | return rc; |
| 375 | } |
| 376 | EXPORT_SYMBOL(maple_i2c_read_reg); |
| 377 | |
| 378 | |
| 379 | int maple_i2c_write_fpga(unsigned char client_num, unsigned int offset, unsigned int val) |
| 380 | { |
| 381 | u8 buf[8]; |
| 382 | int rc; |
| 383 | |
| 384 | bcm_access_fpga(); |
| 385 | |
| 386 | i2c_debug_print("Write fpga: offset = 0x%x, val = 0x%x\n", offset, val); |
| 387 | |
| 388 | /* Set the offset for write operation */ |
| 389 | // offset = swab32(offset); |
| 390 | memcpy(&buf[0], (char*)&offset, 4); |
| 391 | |
| 392 | /* On the I2C bus, LS Byte should go first */ |
| 393 | // val = swab32(val); |
| 394 | memcpy(&buf[4], (char*)&val, 4); |
| 395 | |
| 396 | rc = maple_i2c_send(client_num, buf, sizeof(buf)); |
| 397 | |
| 398 | if (rc < 0) |
| 399 | i2c_debug_print("Write FPGA Failed. rc=%d offset=0x%x val=0x%x client=%u[%u]\n", |
| 400 | rc, offset, val, |
| 401 | normal_i2c[client_num], client_num); |
| 402 | else |
| 403 | i2c_debug_print("Write FPGA: offset=0x%x val=0x%x client=%u[%u]\n", |
| 404 | offset, val, |
| 405 | normal_i2c[client_num], client_num); |
| 406 | return rc; |
| 407 | } |
| 408 | EXPORT_SYMBOL(maple_i2c_write_fpga); |
| 409 | |
| 410 | int maple_i2c_read_fpga(unsigned char client_num, unsigned int offset, unsigned int *data) |
| 411 | { |
| 412 | u8 obuf[4]; |
| 413 | u8 buf[4]; |
| 414 | int rc; |
| 415 | |
| 416 | bcm_access_fpga(); |
| 417 | |
| 418 | /* FPGA expects 4 byte offset in BIG ENDIAN format */ |
| 419 | obuf[0] = (offset >> 24) & 0xff; |
| 420 | obuf[1] = (offset >> 16) & 0xff; |
| 421 | obuf[2] = (offset >> 8) & 0xff; |
| 422 | obuf[3] = offset & 0xff; |
| 423 | rc = maple_i2c_read_with_offset(client_num, obuf, sizeof(obuf), buf, sizeof(buf)); |
| 424 | |
| 425 | if (rc < 0) |
| 426 | i2c_debug_print("Read FPGA Failed. rc=%d offset=0x%x client=%u[%u]\n", |
| 427 | rc, offset, |
| 428 | normal_i2c[client_num], client_num); |
| 429 | else |
| 430 | { |
| 431 | *data = buf[3] | (buf[2] << 8) | (buf[1] << 16) | (buf[0] << 24); /* MS byte is transferred first */ |
| 432 | i2c_debug_print("Read FPGA: offset = 0x%x, val = 0x%x %02x %02x %02x %02x client=%u[%u]\n", |
| 433 | offset, *data, buf[0], buf[1], buf[2], buf[3], |
| 434 | normal_i2c[client_num], client_num); |
| 435 | } |
| 436 | return rc; |
| 437 | } |
| 438 | EXPORT_SYMBOL(maple_i2c_read_fpga); |
| 439 | |
| 440 | enum client_num maple_i2c_get_client(u32 addr) |
| 441 | { |
| 442 | enum client_num i = 0; |
| 443 | while (i < SLAVE_NUM_OF_SLAVES) |
| 444 | { |
| 445 | if (pclient_data_ar[i]) |
| 446 | { |
| 447 | if (slave_valid[i] && pclient_data_ar[i]->client.addr == addr) |
| 448 | { |
| 449 | break; |
| 450 | } |
| 451 | } |
| 452 | i++; |
| 453 | } |
| 454 | return i; |
| 455 | } |
| 456 | EXPORT_SYMBOL(maple_i2c_get_client); |
| 457 | |
| 458 | static int dev_change(u32 addr) |
| 459 | { |
| 460 | enum client_num i = maple_i2c_get_client(addr); |
| 461 | |
| 462 | if (i < SLAVE_NUM_OF_SLAVES) |
| 463 | { |
| 464 | i2c_client_num = i; |
| 465 | i2c_debug_print("Slave was set successfully i %d, addr 0x%x\n", i, addr); |
| 466 | } |
| 467 | else |
| 468 | { |
| 469 | i2c_debug_print("Failed to set slave i %d, addr 0x%x\n", i, addr); |
| 470 | } |
| 471 | |
| 472 | return 0; |
| 473 | } |
| 474 | |
| 475 | static void bcm_access_fpga(void) |
| 476 | { |
| 477 | static int access_enabled; |
| 478 | int fpga_client_num = maple_i2c_get_client(I2C_SW1_I2C_ADDR); |
| 479 | uint8_t b; |
| 480 | |
| 481 | if (access_enabled) |
| 482 | return; |
| 483 | b = 4; |
| 484 | maple_i2c_write(fpga_client_num, &b, 1); |
| 485 | access_enabled = 1; |
| 486 | } |
| 487 | #define BCM_FPGA_REG_RESETS 0x2 |
| 488 | #define BCM_FPGA_REG_FPGA_VERSION 0x0 |
| 489 | /* 1 = out of reset bcm_board_config_reset_value */ |
| 490 | void reset_maple(int bit,int param) |
| 491 | { |
| 492 | int fpga_client_num = maple_i2c_get_client(FPGA_I2C_ADDR); |
| 493 | int sw_client_num = maple_i2c_get_client(I2C_SW0_I2C_ADDR); |
| 494 | uint8_t b = 1; |
| 495 | uint32_t reset_values; |
| 496 | |
| 497 | maple_i2c_write(sw_client_num, &b, 1); |
| 498 | |
| 499 | /* Read-modify-write so we can set only the relevant bit */ |
| 500 | maple_i2c_read_fpga(fpga_client_num, BCM_FPGA_REG_RESETS, &reset_values); |
| 501 | |
| 502 | if (param) |
| 503 | reset_values |= 1 << bit; |
| 504 | else |
| 505 | reset_values &= ~(1 << bit); |
| 506 | maple_i2c_write_fpga(fpga_client_num, BCM_FPGA_REG_RESETS, reset_values); |
| 507 | } |
| 508 | EXPORT_SYMBOL(reset_maple); |
| 509 | |
| 510 | /* Calls the appropriate function based on user command */ |
| 511 | static int exec_command(const char *buf, size_t count) |
| 512 | { |
| 513 | #define MAX_ARGS 4 |
| 514 | #define MAX_ARG_SIZE 32 |
| 515 | int i, argc = 0, val = 0; |
| 516 | char cmd; |
| 517 | u32 offset = 0; |
| 518 | char arg[MAX_ARGS][MAX_ARG_SIZE]; |
| 519 | #define LOG_WR_KBUF_SIZE 128 |
| 520 | char kbuf[LOG_WR_KBUF_SIZE]; |
| 521 | |
| 522 | if ((count > LOG_WR_KBUF_SIZE-1) || (copy_from_user(kbuf, buf, count) != 0)) |
| 523 | return -EFAULT; |
| 524 | kbuf[count]=0; |
| 525 | argc = sscanf(kbuf, "%c %s %s %s %s", &cmd, arg[0], arg[1], arg[2], arg[3]); |
| 526 | |
| 527 | if (argc < 1) |
| 528 | { |
| 529 | printk("Need at-least 2 arguments\n"); |
| 530 | return -EFAULT; |
| 531 | } |
| 532 | |
| 533 | for (i=0; i<MAX_ARGS; ++i) { |
| 534 | arg[i][MAX_ARG_SIZE-1] = '\0'; |
| 535 | } |
| 536 | offset = (u32)simple_strtoul(arg[0], NULL, 0); |
| 537 | if (argc == 3) |
| 538 | val = (int)simple_strtoul(arg[1], NULL, 0); |
| 539 | |
| 540 | switch (cmd) |
| 541 | { |
| 542 | case 'm': |
| 543 | reset_maple(0,offset); // maple out of reset(1) | reset (0) |
| 544 | break; |
| 545 | case 'k': |
| 546 | reset_maple(4,offset); // katana2 out of reset(1) | reset (0) |
| 547 | break; |
| 548 | case 'b': |
| 549 | if (argc == 3) |
| 550 | maple_i2c_write_byte(i2c_client_num, (u8)offset, (u8)val); |
| 551 | else |
| 552 | { |
| 553 | u8 data; |
| 554 | maple_i2c_read_byte(i2c_client_num, (u8)offset, &data); |
| 555 | printk("client 0x%x, offset 0x%x, data=0x%x\n", normal_i2c[i2c_client_num], offset, data); |
| 556 | } |
| 557 | break; |
| 558 | |
| 559 | case 's': |
| 560 | if (argc == 2) |
| 561 | { |
| 562 | u8 data = (u8)offset; |
| 563 | maple_i2c_write(i2c_client_num, &data, 1); |
| 564 | } |
| 565 | else |
| 566 | { |
| 567 | u8 data = offset; |
| 568 | maple_i2c_read(i2c_client_num, &data, 1); |
| 569 | printk("client 0x%x, data=0x%x\n", normal_i2c[i2c_client_num], data); |
| 570 | } |
| 571 | break; |
| 572 | |
| 573 | case 'w': |
| 574 | if (argc == 3) |
| 575 | maple_i2c_write_word(i2c_client_num, (u8)offset, (u16)val); |
| 576 | else |
| 577 | { |
| 578 | u16 data; |
| 579 | maple_i2c_read_word(i2c_client_num, (u8)offset, &data); |
| 580 | printk("client 0x%x, offset 0x%x, data=0x%x\n", normal_i2c[i2c_client_num], offset, data); |
| 581 | } |
| 582 | break; |
| 583 | |
| 584 | case 'd': |
| 585 | if (argc == 3) |
| 586 | maple_i2c_write_reg(i2c_client_num, (u8)offset, val); |
| 587 | else |
| 588 | { |
| 589 | u32 data; |
| 590 | maple_i2c_read_reg(i2c_client_num, (u8)offset, &data); |
| 591 | printk("client 0x%x, offset 0x%x, data=0x%x\n", normal_i2c[i2c_client_num], offset, data); |
| 592 | } |
| 593 | break; |
| 594 | |
| 595 | case 'f': |
| 596 | if (argc == 3) |
| 597 | maple_i2c_write_fpga(i2c_client_num, offset, val); |
| 598 | else |
| 599 | { |
| 600 | u32 data; |
| 601 | maple_i2c_read_fpga(i2c_client_num, offset, &data); |
| 602 | printk("client 0x%x, offset 0x%x, data=0x%x\n", normal_i2c[i2c_client_num], offset, data); |
| 603 | } |
| 604 | break; |
| 605 | |
| 606 | case 'c': |
| 607 | dev_change(offset); |
| 608 | break; |
| 609 | |
| 610 | default: |
| 611 | printk("Invalid command.\n Valid commands:\n" |
| 612 | " Change I2C Addr: c addr\n" |
| 613 | " Write Reg: d offset val\n" |
| 614 | " Read Reg: d offset\n" |
| 615 | " Write Word: w offset val\n" |
| 616 | " Read Word: w offset\n" |
| 617 | " Write Byte: b offset val\n" |
| 618 | " Read Byte: b offset\n" |
| 619 | " Write fpga: f offset val\n" |
| 620 | " Read fpga: f offset\n" |
| 621 | " Write to switch: s val (one byte)\n" |
| 622 | " Read from switch:s\n" |
| 623 | " Maple: m <0|1>\n" |
| 624 | " Katana2: k <0|1>\n" |
| 625 | ); |
| 626 | break; |
| 627 | } |
| 628 | return count; |
| 629 | } |
| 630 | |
| 631 | |
| 632 | |
| 633 | /* Read Function of PROCFS attribute "maple_i2c/test" */ |
| 634 | static ssize_t maple_i2c_proc_test_read(struct file *f, char *buf, size_t count, |
| 635 | loff_t *pos) |
| 636 | { |
| 637 | printk(" Usage: echo command > " |
| 638 | " /proc/maple_i2c/test\n"); |
| 639 | printk(" supported commands:\n" |
| 640 | " Change I2C Addr: c addr\n" |
| 641 | " Write Reg: d offset val\n" |
| 642 | " Read Reg: d offset\n" |
| 643 | " Write Word: w offset val\n" |
| 644 | " Read Word: w offset\n" |
| 645 | " Write Byte: b offset val\n" |
| 646 | " Read Byte: b offset\n" |
| 647 | " Write fpga: f offset val\n" |
| 648 | " Read fpga: f offset\n" |
| 649 | " Write to switch: s val (one byte)\n" |
| 650 | " Read from switch:s\n" |
| 651 | ); |
| 652 | return 0; |
| 653 | } |
| 654 | |
| 655 | /* Write Function of PROCFS attribute "maple_i2c/test" */ |
| 656 | static ssize_t maple_i2c_proc_test_write(struct file *f, const char *buf, |
| 657 | size_t count, loff_t *pos) |
| 658 | { |
| 659 | return exec_command(buf, count); |
| 660 | } |
| 661 | |
| 662 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
| 663 | static int maple_i2c_dev_detect(struct i2c_client *client, struct i2c_board_info *info) |
| 664 | { |
| 665 | i2c_debug_print("detecting i2c device 0x%x\n", client->addr); |
| 666 | |
| 667 | /* TODO: detection and identification */ |
| 668 | |
| 669 | strcpy(info->type, "maple_i2c"); |
| 670 | info->flags = 0; |
| 671 | return 0; |
| 672 | } |
| 673 | |
| 674 | static struct file_operations maple_i2c_fops = |
| 675 | { |
| 676 | read: maple_i2c_proc_test_read, |
| 677 | write: maple_i2c_proc_test_write |
| 678 | }; |
| 679 | |
| 680 | static int maple_i2c_dev_create_proc(void) |
| 681 | { |
| 682 | i2c_proc_dir = proc_mkdir(PROC_DIR_NAME, NULL); |
| 683 | if (!i2c_proc_dir) |
| 684 | { |
| 685 | i2c_debug_print("fail to create proc dir\n"); |
| 686 | return -ENOMEM; |
| 687 | } |
| 688 | |
| 689 | i2c_proc_entry = create_proc_entry(PROC_ENTRY_NAME, 0, i2c_proc_dir); |
| 690 | if (!i2c_proc_entry) |
| 691 | { |
| 692 | remove_proc_entry(PROC_DIR_NAME, NULL); |
| 693 | return -ENOMEM; |
| 694 | } |
| 695 | |
| 696 | i2c_proc_entry->proc_fops = &maple_i2c_fops; |
| 697 | |
| 698 | return 0; |
| 699 | } |
| 700 | |
| 701 | static int maple_i2c_chrdev_open(struct inode *inode, struct file *filp) |
| 702 | { |
| 703 | return 0; |
| 704 | } |
| 705 | |
| 706 | static int maple_i2c_chrdev_release(struct inode *inode, struct file *filp) |
| 707 | { |
| 708 | return 0; |
| 709 | } |
| 710 | |
| 711 | static long maple_i2c_chrdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 712 | { |
| 713 | int linux_rc = 0; |
| 714 | int rc; |
| 715 | maple_i2c_ioctl_param params; |
| 716 | |
| 717 | /* don't even decode wrong cmds: better returning ENOTTY than EFAULT */ |
| 718 | if (_IOC_TYPE(cmd) != MAPLE_I2C_IOCTL_MAGIC) |
| 719 | return -ENOTTY; |
| 720 | |
| 721 | /* |
| 722 | * the type is a bitmask, and VERIFY_WRITE catches R/W |
| 723 | * transfers. Note that the type is user-oriented, while |
| 724 | * verify_area is kernel-oriented, so the concept of "read" and |
| 725 | * "write" is reversed |
| 726 | */ |
| 727 | if (_IOC_DIR(cmd) & _IOC_READ) |
| 728 | linux_rc = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); |
| 729 | else if (_IOC_DIR(cmd) & _IOC_WRITE) |
| 730 | linux_rc = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); |
| 731 | if (linux_rc) |
| 732 | return -EFAULT; |
| 733 | |
| 734 | switch (cmd) |
| 735 | { |
| 736 | case MAPLE_I2C_IOCTL_OP_DEV_CHANGE: |
| 737 | { |
| 738 | linux_rc = copy_from_user((char *)¶ms, (char *)arg, sizeof(params)); |
| 739 | if (linux_rc < 0) |
| 740 | break; |
| 741 | return dev_change(params.addr); |
| 742 | } |
| 743 | break; |
| 744 | case MAPLE_I2C_IOCTL_OP_DEV_WRITE: |
| 745 | { |
| 746 | linux_rc = copy_from_user((char *)¶ms, (char *)arg, sizeof(params)); |
| 747 | if (linux_rc < 0) |
| 748 | break; |
| 749 | switch (params.count) |
| 750 | { |
| 751 | case 8: |
| 752 | return maple_i2c_write_byte(i2c_client_num, params.addr, params.val); |
| 753 | case 16: |
| 754 | return maple_i2c_write_word(i2c_client_num, params.addr, params.val); |
| 755 | case 32: |
| 756 | return maple_i2c_write_reg(i2c_client_num, params.addr, params.val); |
| 757 | default: |
| 758 | return -EINVAL; |
| 759 | } |
| 760 | } |
| 761 | break; |
| 762 | case MAPLE_I2C_IOCTL_OP_DEV_READ: |
| 763 | { |
| 764 | unsigned char b; |
| 765 | unsigned short w; |
| 766 | unsigned int r; |
| 767 | |
| 768 | linux_rc = copy_from_user((char *)¶ms, (char *)arg, sizeof(params)); |
| 769 | if (linux_rc < 0) |
| 770 | break; |
| 771 | switch (params.count) |
| 772 | { |
| 773 | case 8: |
| 774 | linux_rc = maple_i2c_read_byte(i2c_client_num, params.addr, &b); |
| 775 | if (linux_rc < 0) |
| 776 | break; |
| 777 | params.val = b; |
| 778 | break; |
| 779 | case 16: |
| 780 | linux_rc = maple_i2c_read_word(i2c_client_num, params.addr, &w); |
| 781 | if (linux_rc < 0) |
| 782 | break; |
| 783 | params.val = w; |
| 784 | break; |
| 785 | case 32: |
| 786 | linux_rc = maple_i2c_read_reg(i2c_client_num, params.addr, &r); |
| 787 | if (linux_rc < 0) |
| 788 | break; |
| 789 | params.val = r; |
| 790 | break; |
| 791 | default: |
| 792 | return -EINVAL; |
| 793 | } |
| 794 | if (linux_rc < 0) |
| 795 | break; |
| 796 | return copy_to_user((char *)arg, (char *)¶ms, sizeof(params)); |
| 797 | } |
| 798 | case MAPLE_I2C_IOCTL_OP_SWITCH_WRITE: |
| 799 | { |
| 800 | char b; |
| 801 | |
| 802 | linux_rc = copy_from_user((char *)¶ms, (char *)arg, sizeof(params)); |
| 803 | if (linux_rc < 0) |
| 804 | break; |
| 805 | b = params.val; |
| 806 | return maple_i2c_write(i2c_client_num, &b, 1); |
| 807 | } |
| 808 | case MAPLE_I2C_IOCTL_OP_SWITCH_READ: |
| 809 | { |
| 810 | char b; |
| 811 | |
| 812 | linux_rc = maple_i2c_read(i2c_client_num, &b, 1); |
| 813 | if (linux_rc < 0) |
| 814 | break; |
| 815 | params.val = b; |
| 816 | return copy_to_user((char *)arg, (char *)¶ms, sizeof(params)); |
| 817 | } |
| 818 | case MAPLE_I2C_IOCTL_OP_FPGA_WRITE: |
| 819 | { |
| 820 | linux_rc = copy_from_user((char *)¶ms, (char *)arg, sizeof(params)); |
| 821 | if (linux_rc < 0) |
| 822 | break; |
| 823 | return maple_i2c_write_fpga(i2c_client_num, params.addr, params.val); |
| 824 | } |
| 825 | case MAPLE_I2C_IOCTL_OP_FPGA_READ: |
| 826 | { |
| 827 | linux_rc = copy_from_user((char *)¶ms, (char *)arg, sizeof(params)); |
| 828 | if (linux_rc < 0) |
| 829 | break; |
| 830 | linux_rc = maple_i2c_read_fpga(i2c_client_num, params.addr, ¶ms.val); |
| 831 | if (linux_rc < 0) |
| 832 | break; |
| 833 | return copy_to_user((char *)arg, (char *)¶ms, sizeof(params)); |
| 834 | } |
| 835 | default: |
| 836 | rc = -ENOTTY; |
| 837 | break; |
| 838 | } |
| 839 | |
| 840 | return linux_rc; |
| 841 | } |
| 842 | |
| 843 | static ssize_t maple_i2c_chrdev_write(struct file *filp, const char __user *buf, |
| 844 | size_t count, loff_t *f_pos) |
| 845 | { |
| 846 | return 0; |
| 847 | } |
| 848 | |
| 849 | static struct file_operations maple_i2c_chrdev_fops = |
| 850 | { |
| 851 | .owner = THIS_MODULE, |
| 852 | .open = maple_i2c_chrdev_open, |
| 853 | .release = maple_i2c_chrdev_release, |
| 854 | .write = maple_i2c_chrdev_write, |
| 855 | .unlocked_ioctl = maple_i2c_chrdev_ioctl |
| 856 | }; |
| 857 | |
| 858 | static struct cdev maple_i2c_chrdev_cdev; |
| 859 | |
| 860 | static int maple_i2c_dev_create_chrdev(void) |
| 861 | { |
| 862 | dev_t dev = MKDEV(maple_i2c_chrdev_major, 0); |
| 863 | int linux_rc; |
| 864 | |
| 865 | is_chrdev_reg = 0; |
| 866 | is_cdev_add = 0; |
| 867 | /* |
| 868 | * Register your major, and accept a dynamic number. |
| 869 | */ |
| 870 | if (!maple_i2c_chrdev_major) |
| 871 | return -1; |
| 872 | linux_rc = register_chrdev_region(dev, 0, "maple_i2c"); |
| 873 | if (linux_rc < 0) |
| 874 | { |
| 875 | i2c_debug_print("register_chrdev_region()->%d\n", linux_rc); |
| 876 | return -EIO; |
| 877 | } |
| 878 | is_chrdev_reg = 1; |
| 879 | |
| 880 | cdev_init(&maple_i2c_chrdev_cdev, &maple_i2c_chrdev_fops); |
| 881 | linux_rc = cdev_add(&maple_i2c_chrdev_cdev, dev, 1); |
| 882 | if (linux_rc < 0) |
| 883 | { |
| 884 | i2c_debug_print("cdev_add()->%d\n", linux_rc); |
| 885 | return -EIO; |
| 886 | } |
| 887 | is_cdev_add = 1; |
| 888 | |
| 889 | return 0; |
| 890 | } |
| 891 | |
| 892 | static int maple_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| 893 | { |
| 894 | int err = 0; |
| 895 | struct maple_i2c_data *pclient_data; |
| 896 | |
| 897 | i2c_debug_print("!!!! i2c device 0x%x probe\n", client->addr); |
| 898 | |
| 899 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) |
| 900 | goto exit; |
| 901 | |
| 902 | if (!(pclient_data = kzalloc(sizeof(struct maple_i2c_data), GFP_KERNEL))) |
| 903 | { |
| 904 | err = -ENOMEM; |
| 905 | goto exit; |
| 906 | } |
| 907 | |
| 908 | pclient_data->client.addr = client->addr; |
| 909 | pclient_data->client.adapter = client->adapter; |
| 910 | pclient_data->client.driver = client->driver; |
| 911 | pclient_data->client.flags = client->flags; |
| 912 | |
| 913 | i2c_set_clientdata(client, pclient_data); |
| 914 | |
| 915 | switch(client->addr) |
| 916 | { |
| 917 | case I2C_SW0_I2C_ADDR: |
| 918 | pclient_data_ar[SLAVE_SWITCH_70] = pclient_data; |
| 919 | slave_valid[SLAVE_SWITCH_70] = 1; |
| 920 | break; |
| 921 | case I2C_SW1_I2C_ADDR: |
| 922 | pclient_data_ar[SLAVE_SWITCH_71] = pclient_data; |
| 923 | slave_valid[SLAVE_SWITCH_71] = 1; |
| 924 | break; |
| 925 | case I2C_SW2_I2C_ADDR: |
| 926 | pclient_data_ar[SLAVE_SWITCH_72] = pclient_data; |
| 927 | slave_valid[SLAVE_SWITCH_72] = 1; |
| 928 | break; |
| 929 | case I2C_SW3_I2C_ADDR: |
| 930 | pclient_data_ar[SLAVE_SWITCH_73] = pclient_data; |
| 931 | slave_valid[SLAVE_SWITCH_73] = 1; |
| 932 | break; |
| 933 | case I2C_SW4_I2C_ADDR: |
| 934 | pclient_data_ar[SLAVE_SWITCH_74] = pclient_data; |
| 935 | slave_valid[SLAVE_SWITCH_74] = 1; |
| 936 | break; |
| 937 | case SFP_I2C_ADDR1: |
| 938 | pclient_data_ar[SLAVE_SFP_50] = pclient_data; |
| 939 | slave_valid[SLAVE_SFP_50] = 1; |
| 940 | break; |
| 941 | case SFP_I2C_ADDR2: |
| 942 | pclient_data_ar[SLAVE_SFP_51] = pclient_data; |
| 943 | slave_valid[SLAVE_SFP_51] = 1; |
| 944 | break; |
| 945 | case FPGA_I2C_ADDR: |
| 946 | pclient_data_ar[SLAVE_FPGA_40] = pclient_data; |
| 947 | slave_valid[SLAVE_FPGA_40] = 1; |
| 948 | break; |
| 949 | case PON_DPLL_I2C_ADDR: |
| 950 | pclient_data_ar[SLAVE_PON_DPLL_68] = pclient_data; |
| 951 | slave_valid[SLAVE_PON_DPLL_68] = 1; |
| 952 | break; |
| 953 | case PM_DPLL_I2C_ADDR: |
| 954 | pclient_data_ar[SLAVE_PM_DPLL_6A] = pclient_data; |
| 955 | slave_valid[SLAVE_PM_DPLL_6A] = 1; |
| 956 | break; |
| 957 | case CXP_R_I2C_ADDR: |
| 958 | pclient_data_ar[SLAVE_CXP_R_54] = pclient_data; |
| 959 | slave_valid[SLAVE_CXP_R_54] = 1; |
| 960 | break; |
| 961 | case PCIE_SW_I2C_ADDR: |
| 962 | pclient_data_ar[SLAVE_PCIE_SW_3C] = pclient_data; |
| 963 | slave_valid[SLAVE_PCIE_SW_3C] = 1; |
| 964 | break; |
| 965 | default: |
| 966 | i2c_debug_print("%s client addr out of range 0x%x\n", __FUNCTION__, client->addr); |
| 967 | goto exit_kfree; |
| 968 | } |
| 969 | |
| 970 | /* Create only once */ |
| 971 | if (i2c_proc_entry == NULL) |
| 972 | { |
| 973 | if (maple_i2c_dev_create_proc() < 0) |
| 974 | goto exit_kfree; |
| 975 | } |
| 976 | if (!is_cdev_add) |
| 977 | { |
| 978 | if (maple_i2c_dev_create_chrdev() < 0) |
| 979 | goto exit_kfree; |
| 980 | } |
| 981 | ++i2c_num_clients; |
| 982 | |
| 983 | return 0; |
| 984 | |
| 985 | exit_kfree: |
| 986 | kfree(pclient_data); |
| 987 | exit: |
| 988 | return err; |
| 989 | } |
| 990 | |
| 991 | static int maple_i2c_dev_remove(struct i2c_client *client) |
| 992 | { |
| 993 | kfree(i2c_get_clientdata(client)); |
| 994 | --i2c_num_clients; |
| 995 | if (!i2c_num_clients) |
| 996 | { |
| 997 | if (i2c_proc_entry != NULL) |
| 998 | { |
| 999 | remove_proc_entry(PROC_ENTRY_NAME, i2c_proc_dir); |
| 1000 | i2c_proc_entry = NULL; |
| 1001 | } |
| 1002 | if (i2c_proc_dir != NULL) |
| 1003 | { |
| 1004 | remove_proc_entry(PROC_DIR_NAME, NULL); |
| 1005 | i2c_proc_dir = NULL; |
| 1006 | } |
| 1007 | if (is_cdev_add) |
| 1008 | { |
| 1009 | cdev_del(&maple_i2c_chrdev_cdev); |
| 1010 | is_cdev_add = 0; |
| 1011 | } |
| 1012 | if (is_chrdev_reg) |
| 1013 | { |
| 1014 | unregister_chrdev_region(MKDEV(maple_i2c_chrdev_major, 0), 1); |
| 1015 | is_chrdev_reg = 0; |
| 1016 | } |
| 1017 | } |
| 1018 | |
| 1019 | return 0; |
| 1020 | } |
| 1021 | |
| 1022 | static struct i2c_driver maple_i2c_dev_driver = { |
| 1023 | .class = ~0, |
| 1024 | .driver = { |
| 1025 | .name = "maple_i2c", |
| 1026 | }, |
| 1027 | .probe = maple_i2c_dev_probe, |
| 1028 | .remove = maple_i2c_dev_remove, |
| 1029 | .id_table = maple_i2c_id_table, |
| 1030 | .detect = maple_i2c_dev_detect, |
| 1031 | .address_list = normal_i2c, |
| 1032 | }; |
| 1033 | |
| 1034 | module_i2c_driver(maple_i2c_dev_driver); |
| 1035 | |
| 1036 | MODULE_DESCRIPTION("maple i2c devices"); |
| 1037 | MODULE_LICENSE("GPL"); |
| 1038 | |