| .. | .. |
|---|
| 9 | 9 | * 3. add version control. |
|---|
| 10 | 10 | * V0.0X01.0X02 |
|---|
| 11 | 11 | * 1. fix otp info null issue. |
|---|
| 12 | + * V0.0X01.0X03 |
|---|
| 13 | + * 1. add buf read optimize otp read speed. |
|---|
| 14 | + * 2. add mutex for otp read. |
|---|
| 12 | 15 | */ |
|---|
| 13 | | - |
|---|
| 16 | +//#define DEBUG |
|---|
| 14 | 17 | #include <linux/delay.h> |
|---|
| 15 | 18 | #include <linux/i2c.h> |
|---|
| 16 | 19 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 24 | 27 | #include <linux/version.h> |
|---|
| 25 | 28 | #include "otp_eeprom.h" |
|---|
| 26 | 29 | |
|---|
| 27 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02) |
|---|
| 30 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) |
|---|
| 28 | 31 | #define DEVICE_NAME "otp_eeprom" |
|---|
| 29 | 32 | |
|---|
| 30 | 33 | static inline struct eeprom_device |
|---|
| .. | .. |
|---|
| 64 | 67 | return -EIO; |
|---|
| 65 | 68 | |
|---|
| 66 | 69 | *val = be32_to_cpu(data_be); |
|---|
| 70 | + |
|---|
| 71 | + return 0; |
|---|
| 72 | +} |
|---|
| 73 | + |
|---|
| 74 | +/* Read registers buffers at a time */ |
|---|
| 75 | +static int read_reg_otp_buf(struct i2c_client *client, u16 reg, |
|---|
| 76 | + unsigned int len, u8 *buf) |
|---|
| 77 | +{ |
|---|
| 78 | + struct i2c_msg msgs[2]; |
|---|
| 79 | + __be16 reg_addr_be = cpu_to_be16(reg); |
|---|
| 80 | + int ret; |
|---|
| 81 | + |
|---|
| 82 | + /* Write register address */ |
|---|
| 83 | + msgs[0].addr = client->addr; |
|---|
| 84 | + msgs[0].flags = 0; |
|---|
| 85 | + msgs[0].len = 2; |
|---|
| 86 | + msgs[0].buf = (u8 *)®_addr_be; |
|---|
| 87 | + |
|---|
| 88 | + /* Read data from register */ |
|---|
| 89 | + msgs[1].addr = client->addr; |
|---|
| 90 | + msgs[1].flags = I2C_M_RD; |
|---|
| 91 | + msgs[1].len = len; |
|---|
| 92 | + msgs[1].buf = buf; |
|---|
| 93 | + |
|---|
| 94 | + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); |
|---|
| 95 | + if (ret != ARRAY_SIZE(msgs)) |
|---|
| 96 | + return -EIO; |
|---|
| 67 | 97 | |
|---|
| 68 | 98 | return 0; |
|---|
| 69 | 99 | } |
|---|
| .. | .. |
|---|
| 448 | 478 | struct i2c_client *client = eeprom_dev->client; |
|---|
| 449 | 479 | struct device *dev = &eeprom_dev->client->dev; |
|---|
| 450 | 480 | u32 checksum = 0; |
|---|
| 451 | | - u32 temp = 0; |
|---|
| 481 | + u8 *lsc_buf; |
|---|
| 452 | 482 | int i = 0; |
|---|
| 453 | 483 | int ret = 0; |
|---|
| 454 | 484 | #ifdef DEBUG |
|---|
| 455 | 485 | int w, h, j; |
|---|
| 456 | 486 | #endif |
|---|
| 487 | + |
|---|
| 488 | + lsc_buf = kzalloc(LSC_DATA_SIZE, GFP_KERNEL); |
|---|
| 489 | + if (!lsc_buf) { |
|---|
| 490 | + dev_err(dev, "%s ENOMEM!\n", __func__); |
|---|
| 491 | + return; |
|---|
| 492 | + } |
|---|
| 457 | 493 | |
|---|
| 458 | 494 | ret = read_reg_otp(client, base_addr, |
|---|
| 459 | 495 | 4, &otp_ptr->lsc_data.size); |
|---|
| .. | .. |
|---|
| 463 | 499 | 2, &otp_ptr->lsc_data.version); |
|---|
| 464 | 500 | checksum += otp_ptr->lsc_data.version; |
|---|
| 465 | 501 | base_addr += 2; |
|---|
| 502 | + |
|---|
| 503 | + ret |= read_reg_otp_buf(client, base_addr, |
|---|
| 504 | + LSC_DATA_SIZE, lsc_buf); |
|---|
| 505 | + base_addr += LSC_DATA_SIZE; |
|---|
| 506 | + |
|---|
| 466 | 507 | for (i = 0; i < LSC_DATA_SIZE; i++) { |
|---|
| 467 | | - ret |= read_reg_otp(client, base_addr, |
|---|
| 468 | | - 1, &temp); |
|---|
| 469 | | - otp_ptr->lsc_data.data[i] = temp; |
|---|
| 470 | | - checksum += temp; |
|---|
| 471 | | - base_addr += 1; |
|---|
| 508 | + otp_ptr->lsc_data.data[i] = lsc_buf[i]; |
|---|
| 509 | + checksum += lsc_buf[i]; |
|---|
| 472 | 510 | } |
|---|
| 473 | 511 | otp_ptr->lsc_data.table_size = LSC_DATA_SIZE; |
|---|
| 474 | 512 | #ifdef DEBUG |
|---|
| .. | .. |
|---|
| 482 | 520 | dev_info(dev, "\n"); |
|---|
| 483 | 521 | } |
|---|
| 484 | 522 | #endif |
|---|
| 523 | + |
|---|
| 524 | + memset(lsc_buf, 0, LSC_DATA_SIZE); |
|---|
| 525 | + ret |= read_reg_otp_buf(client, base_addr, |
|---|
| 526 | + RK_LSC_RESERVED_SIZE, lsc_buf); |
|---|
| 527 | + |
|---|
| 485 | 528 | for (i = 0; i < RK_LSC_RESERVED_SIZE; i++) { |
|---|
| 486 | | - ret |= read_reg_otp(client, base_addr, |
|---|
| 487 | | - 1, &temp); |
|---|
| 488 | | - checksum += temp; |
|---|
| 489 | | - base_addr += 1; |
|---|
| 529 | + checksum += lsc_buf[i]; |
|---|
| 490 | 530 | } |
|---|
| 531 | + base_addr += RK_LSC_RESERVED_SIZE; |
|---|
| 491 | 532 | ret |= read_reg_otp(client, base_addr, |
|---|
| 492 | 533 | 1, &otp_ptr->lsc_data.checksum); |
|---|
| 493 | 534 | if ((checksum % 255 + 1) == otp_ptr->lsc_data.checksum && (!ret)) { |
|---|
| .. | .. |
|---|
| 502 | 543 | (int)(checksum % 255 + 1), |
|---|
| 503 | 544 | (int)otp_ptr->lsc_data.checksum); |
|---|
| 504 | 545 | } |
|---|
| 546 | + kfree(lsc_buf); |
|---|
| 505 | 547 | } |
|---|
| 506 | 548 | |
|---|
| 507 | 549 | static void rkotp_read_pdaf(struct eeprom_device *eeprom_dev, |
|---|
| .. | .. |
|---|
| 511 | 553 | struct i2c_client *client = eeprom_dev->client; |
|---|
| 512 | 554 | struct device *dev = &eeprom_dev->client->dev; |
|---|
| 513 | 555 | u32 checksum = 0; |
|---|
| 514 | | - u32 temp = 0; |
|---|
| 556 | + u8 *pdaf_buf; |
|---|
| 515 | 557 | int i = 0; |
|---|
| 516 | 558 | int ret = 0; |
|---|
| 517 | 559 | #ifdef DEBUG |
|---|
| 518 | 560 | int w, h, j; |
|---|
| 519 | 561 | #endif |
|---|
| 562 | + |
|---|
| 563 | + pdaf_buf = kzalloc(RK_GAINMAP_SIZE, GFP_KERNEL); |
|---|
| 564 | + if (!pdaf_buf) { |
|---|
| 565 | + dev_err(dev, "%s ENOMEM!\n", __func__); |
|---|
| 566 | + return; |
|---|
| 567 | + } |
|---|
| 520 | 568 | |
|---|
| 521 | 569 | ret = read_reg_otp(client, base_addr, |
|---|
| 522 | 570 | 4, &otp_ptr->pdaf_data.size); |
|---|
| .. | .. |
|---|
| 534 | 582 | 1, &otp_ptr->pdaf_data.gainmap_height); |
|---|
| 535 | 583 | checksum += otp_ptr->pdaf_data.gainmap_height; |
|---|
| 536 | 584 | base_addr += 1; |
|---|
| 585 | + |
|---|
| 586 | + ret |= read_reg_otp_buf(client, base_addr, |
|---|
| 587 | + RK_GAINMAP_SIZE, pdaf_buf); |
|---|
| 588 | + base_addr += RK_GAINMAP_SIZE; |
|---|
| 589 | + |
|---|
| 537 | 590 | for (i = 0; i < RK_GAINMAP_SIZE; i++) { |
|---|
| 538 | | - ret |= read_reg_otp(client, base_addr, |
|---|
| 539 | | - 1, &otp_ptr->pdaf_data.gainmap[i]); |
|---|
| 591 | + otp_ptr->pdaf_data.gainmap[i] = pdaf_buf[i]; |
|---|
| 540 | 592 | checksum += otp_ptr->pdaf_data.gainmap[i]; |
|---|
| 541 | | - base_addr += 1; |
|---|
| 542 | 593 | } |
|---|
| 543 | 594 | #ifdef DEBUG |
|---|
| 544 | 595 | w = 64; |
|---|
| .. | .. |
|---|
| 571 | 622 | 1, &otp_ptr->pdaf_data.dccmap_height); |
|---|
| 572 | 623 | checksum += otp_ptr->pdaf_data.dccmap_height; |
|---|
| 573 | 624 | base_addr += 1; |
|---|
| 625 | + |
|---|
| 626 | + memset(pdaf_buf, 0, RK_DCCMAP_SIZE); |
|---|
| 627 | + ret |= read_reg_otp_buf(client, base_addr, |
|---|
| 628 | + RK_DCCMAP_SIZE, pdaf_buf); |
|---|
| 629 | + |
|---|
| 574 | 630 | for (i = 0; i < RK_DCCMAP_SIZE; i++) { |
|---|
| 575 | | - ret |= read_reg_otp(client, base_addr, |
|---|
| 576 | | - 1, &otp_ptr->pdaf_data.dccmap[i]); |
|---|
| 631 | + otp_ptr->pdaf_data.dccmap[i] = pdaf_buf[i]; |
|---|
| 577 | 632 | checksum += otp_ptr->pdaf_data.dccmap[i]; |
|---|
| 578 | | - base_addr += 1; |
|---|
| 579 | 633 | } |
|---|
| 634 | + base_addr += RK_DCCMAP_SIZE; |
|---|
| 635 | + |
|---|
| 580 | 636 | #ifdef DEBUG |
|---|
| 581 | 637 | w = 32; |
|---|
| 582 | 638 | h = 16; |
|---|
| .. | .. |
|---|
| 592 | 648 | 1, &otp_ptr->pdaf_data.dccmap_checksum); |
|---|
| 593 | 649 | checksum += otp_ptr->pdaf_data.dccmap_checksum; |
|---|
| 594 | 650 | base_addr += 1; |
|---|
| 651 | + |
|---|
| 652 | + ret |= read_reg_otp(client, base_addr, |
|---|
| 653 | + 2, &otp_ptr->pdaf_data.pd_offset); |
|---|
| 654 | + checksum += otp_ptr->pdaf_data.pd_offset; |
|---|
| 655 | + base_addr += 2; |
|---|
| 656 | + |
|---|
| 657 | + memset(pdaf_buf, 0, RK_PDAF_RESERVED_SIZE); |
|---|
| 658 | + ret |= read_reg_otp_buf(client, base_addr, |
|---|
| 659 | + RK_PDAF_RESERVED_SIZE, pdaf_buf); |
|---|
| 660 | + |
|---|
| 595 | 661 | for (i = 0; i < RK_PDAF_RESERVED_SIZE; i++) { |
|---|
| 596 | | - ret |= read_reg_otp(client, base_addr, |
|---|
| 597 | | - 1, &temp); |
|---|
| 598 | | - checksum += temp; |
|---|
| 599 | | - base_addr += 1; |
|---|
| 662 | + checksum += pdaf_buf[i]; |
|---|
| 600 | 663 | } |
|---|
| 664 | + base_addr += RK_PDAF_RESERVED_SIZE; |
|---|
| 665 | + |
|---|
| 601 | 666 | ret |= read_reg_otp(client, base_addr, |
|---|
| 602 | 667 | 1, &otp_ptr->pdaf_data.checksum); |
|---|
| 603 | 668 | if ((checksum % 255 + 1) == otp_ptr->pdaf_data.checksum && (!ret)) { |
|---|
| .. | .. |
|---|
| 612 | 677 | (int)(checksum % 255 + 1), |
|---|
| 613 | 678 | (int)otp_ptr->pdaf_data.checksum); |
|---|
| 614 | 679 | } |
|---|
| 680 | + kfree(pdaf_buf); |
|---|
| 615 | 681 | } |
|---|
| 616 | 682 | |
|---|
| 617 | 683 | static void rkotp_read_af(struct eeprom_device *eeprom_dev, |
|---|
| .. | .. |
|---|
| 738 | 804 | u8 vendor_flag = 0; |
|---|
| 739 | 805 | struct i2c_client *client = eeprom_dev->client; |
|---|
| 740 | 806 | |
|---|
| 807 | + mutex_lock(&eeprom_dev->mutex); |
|---|
| 741 | 808 | vendor_flag = get_vendor_flag(client); |
|---|
| 742 | 809 | if (vendor_flag == 0x80) |
|---|
| 743 | 810 | otp_read_data(eeprom_dev); |
|---|
| .. | .. |
|---|
| 745 | 812 | rkotp_read_data(eeprom_dev); |
|---|
| 746 | 813 | else { |
|---|
| 747 | 814 | dev_warn(&client->dev, "no vendor flag infos!\n"); |
|---|
| 815 | + mutex_unlock(&eeprom_dev->mutex); |
|---|
| 748 | 816 | return -1; |
|---|
| 749 | 817 | } |
|---|
| 818 | + |
|---|
| 819 | + mutex_unlock(&eeprom_dev->mutex); |
|---|
| 750 | 820 | return 0; |
|---|
| 751 | 821 | } |
|---|
| 752 | 822 | |
|---|
| .. | .. |
|---|
| 866 | 936 | seq_printf(p, "flag=%d;\n", dev->otp->pdaf_data.flag); |
|---|
| 867 | 937 | seq_printf(p, "gainmap_width=%d;\n", gainmap_w); |
|---|
| 868 | 938 | seq_printf(p, "gainmap_height=%d;\n", gainmap_h); |
|---|
| 869 | | - |
|---|
| 939 | + seq_printf(p, "pd_offset=%d\n", dev->otp->pdaf_data.pd_offset); |
|---|
| 870 | 940 | seq_printf(p, "gainmap_table=\n"); |
|---|
| 871 | 941 | for (i = 0; i < gainmap_h; i++) { |
|---|
| 872 | 942 | for (j = 0; j < gainmap_w; j++) { |
|---|
| .. | .. |
|---|
| 917 | 987 | return single_open(file, otp_eeprom_show, data); |
|---|
| 918 | 988 | } |
|---|
| 919 | 989 | |
|---|
| 920 | | -static const struct file_operations ops = { |
|---|
| 921 | | - .owner = THIS_MODULE, |
|---|
| 922 | | - .open = eeprom_open, |
|---|
| 923 | | - .read = seq_read, |
|---|
| 924 | | - .llseek = seq_lseek, |
|---|
| 925 | | - .release = single_release, |
|---|
| 990 | +static const struct proc_ops ops = { |
|---|
| 991 | + .proc_open = eeprom_open, |
|---|
| 992 | + .proc_read = seq_read, |
|---|
| 993 | + .proc_lseek = seq_lseek, |
|---|
| 994 | + .proc_release = single_release, |
|---|
| 926 | 995 | }; |
|---|
| 927 | 996 | |
|---|
| 928 | 997 | static int eeprom_proc_init(struct eeprom_device *dev) |
|---|
| .. | .. |
|---|
| 974 | 1043 | dev_err(&client->dev, "Probe failed\n"); |
|---|
| 975 | 1044 | return -ENOMEM; |
|---|
| 976 | 1045 | } |
|---|
| 1046 | + mutex_init(&eeprom_dev->mutex); |
|---|
| 977 | 1047 | v4l2_i2c_subdev_init(&eeprom_dev->sd, |
|---|
| 978 | 1048 | client, &eeprom_ops); |
|---|
| 979 | 1049 | eeprom_dev->client = client; |
|---|
| .. | .. |
|---|
| 995 | 1065 | struct eeprom_device *eeprom_dev = |
|---|
| 996 | 1066 | sd_to_eeprom(sd); |
|---|
| 997 | 1067 | kfree(eeprom_dev->otp); |
|---|
| 1068 | + mutex_destroy(&eeprom_dev->mutex); |
|---|
| 998 | 1069 | pm_runtime_disable(&client->dev); |
|---|
| 999 | 1070 | eeprom_subdev_cleanup(eeprom_dev); |
|---|
| 1000 | 1071 | eeprom_proc_cleanup(eeprom_dev); |
|---|