.. | .. |
---|
61 | 61 | #define SC230AI_REG_SEXPOSURE_L 0x3e05 |
---|
62 | 62 | #define SC230AI_EXPOSURE_MIN 1 |
---|
63 | 63 | #define SC230AI_EXPOSURE_STEP 1 |
---|
64 | | -#define SC230AI_EXPOSURE_LIN_MAX (2 * 0x465 - 9) |
---|
65 | | -#define SC230AI_EXPOSURE_HDR_MAX_S (2 * 0x465 - 9) |
---|
66 | | -#define SC230AI_EXPOSURE_HDR_MAX_L (2 * 0x465 - 9) |
---|
67 | 64 | #define SC230AI_VTS_MAX 0x7fff |
---|
68 | 65 | |
---|
69 | 66 | #define SC230AI_REG_DIG_GAIN 0x3e06 |
---|
.. | .. |
---|
74 | 71 | #define SC230AI_REG_SANA_GAIN 0x3e12 |
---|
75 | 72 | #define SC230AI_REG_SANA_FINE_GAIN 0x3e13 |
---|
76 | 73 | #define SC230AI_GAIN_MIN 1000 |
---|
77 | | -#define SC230AI_GAIN_MAX 1722628 //108.512*15.875*1000 |
---|
| 74 | +#define SC230AI_GAIN_MAX 1574800 // 99.2*15.875*1000 |
---|
78 | 75 | #define SC230AI_GAIN_STEP 1 |
---|
79 | 76 | #define SC230AI_GAIN_DEFAULT 1000 |
---|
80 | 77 | #define SC230AI_LGAIN 0 |
---|
.. | .. |
---|
176 | 173 | const char *module_facing; |
---|
177 | 174 | const char *module_name; |
---|
178 | 175 | const char *len_name; |
---|
| 176 | + enum rkmodule_sync_mode sync_mode; |
---|
179 | 177 | u32 cur_vts; |
---|
180 | 178 | bool has_init_exp; |
---|
181 | 179 | bool is_thunderboot; |
---|
.. | .. |
---|
537 | 535 | {REG_NULL, 0x00}, |
---|
538 | 536 | }; |
---|
539 | 537 | |
---|
| 538 | +static __maybe_unused const struct regval sc230ai_interal_sync_master_start_regs[] = { |
---|
| 539 | + {0x300a, 0x24}, //sync as output PAD |
---|
| 540 | + {0x3032, 0xa0}, |
---|
| 541 | + {0x3222, 0x00}, //master mode |
---|
| 542 | + {REG_NULL, 0x00}, |
---|
| 543 | +}; |
---|
| 544 | + |
---|
| 545 | +static __maybe_unused const struct regval sc230ai_interal_sync_master_stop_regs[] = { |
---|
| 546 | + {REG_NULL, 0x00}, |
---|
| 547 | +}; |
---|
| 548 | + |
---|
| 549 | +static __maybe_unused const struct regval sc230ai_interal_sync_slaver_start_regs[] = { |
---|
| 550 | + {0x300a, 0x20}, //sync as input PAD |
---|
| 551 | + {0x3222, 0x01}, //slave mode |
---|
| 552 | + {0x3224, 0x92}, //fsync trigger |
---|
| 553 | + {0x3614, 0x01}, |
---|
| 554 | + {REG_NULL, 0x00}, |
---|
| 555 | +}; |
---|
| 556 | + |
---|
| 557 | +static __maybe_unused const struct regval sc230ai_interal_sync_slaver_stop_regs[] = { |
---|
| 558 | + {REG_NULL, 0x00}, |
---|
| 559 | +}; |
---|
540 | 560 | |
---|
541 | 561 | static const struct sc230ai_mode supported_modes[] = { |
---|
542 | 562 | { |
---|
.. | .. |
---|
678 | 698 | *again = 0x00; |
---|
679 | 699 | *dgain = 0x00; |
---|
680 | 700 | *dgain_fine = total_gain * 128 / 1000; |
---|
681 | | - } else if (total_gain < 3391) { /* 2 ~ 3.391 gain*/ |
---|
| 701 | + } else if (total_gain < 3100) { /* 2 ~ 3.1 gain*/ |
---|
682 | 702 | *again = 0x01; |
---|
683 | 703 | *dgain = 0x00; |
---|
684 | 704 | *dgain_fine = total_gain * 128 / 1000 / 2; |
---|
685 | | - } else if (total_gain < 3391 * 2) { /* 3.391 ~ 6.782 gain*/ |
---|
| 705 | + } else if (total_gain < 3100 * 2) { /* 3.100 ~ 6.200 gain*/ |
---|
686 | 706 | *again = 0x40; |
---|
687 | 707 | *dgain = 0x00; |
---|
688 | | - *dgain_fine = total_gain * 128 / 3391; |
---|
689 | | - } else if (total_gain < 3391 * 4) { /* 6.782 ~ 13.564 gain*/ |
---|
| 708 | + *dgain_fine = total_gain * 128 / 3100; |
---|
| 709 | + } else if (total_gain < 3100 * 4) { /* 6.200 ~ 12.400 gain*/ |
---|
690 | 710 | *again = 0x48; |
---|
691 | 711 | *dgain = 0x00; |
---|
692 | | - *dgain_fine = total_gain * 128 / 3391 / 2; |
---|
693 | | - } else if (total_gain < 3391 * 8) { /* 13.564 ~ 27.128 gain*/ |
---|
| 712 | + *dgain_fine = total_gain * 128 / 3100 / 2; |
---|
| 713 | + } else if (total_gain < 3100 * 8) { /* 12.400 ~ 24.800 gain*/ |
---|
694 | 714 | *again = 0x49; |
---|
695 | 715 | *dgain = 0x00; |
---|
696 | | - *dgain_fine = total_gain * 128 / 3391 / 4; |
---|
697 | | - } else if (total_gain < 3391 * 16) { /* 27.128 ~ 54.256 gain*/ |
---|
| 716 | + *dgain_fine = total_gain * 128 / 3100 / 4; |
---|
| 717 | + } else if (total_gain < 3100 * 16) { /* 24.800 ~ 49.600 gain*/ |
---|
698 | 718 | *again = 0x4b; |
---|
699 | 719 | *dgain = 0x00; |
---|
700 | | - *dgain_fine = total_gain * 128 / 3391 / 8; |
---|
701 | | - } else if (total_gain < 3391 * 32) { /* 54.256 ~ 108.512 gain*/ |
---|
| 720 | + *dgain_fine = total_gain * 128 / 3100 / 8; |
---|
| 721 | + } else if (total_gain < 3100 * 32) { /* 49.600 ~ 99.200 gain*/ |
---|
702 | 722 | *again = 0x4f; |
---|
703 | 723 | *dgain = 0x00; |
---|
704 | | - *dgain_fine = total_gain * 128 / 3391 / 16; |
---|
705 | | - } else if (total_gain < 3391 * 64) { /* 108.512 ~ 217.024 gain*/ |
---|
| 724 | + *dgain_fine = total_gain * 128 / 3100 / 16; |
---|
| 725 | + } else if (total_gain < 3100 * 64) { /* 99.200 ~ 198.400 gain*/ |
---|
706 | 726 | *again = 0x5f; |
---|
707 | 727 | *dgain = 0x00; |
---|
708 | | - *dgain_fine = total_gain * 128 / 3391 / 32; |
---|
709 | | - } else if (total_gain < 3391 * 128) { /* 217.024 ~ 434.048 gain*/ |
---|
| 728 | + *dgain_fine = total_gain * 128 / 3100 / 32; |
---|
| 729 | + } else if (total_gain < 3100 * 128) { /* 198.400 ~ 396.800 gain*/ |
---|
710 | 730 | *again = 0x5f; |
---|
711 | 731 | *dgain = 0x01; |
---|
712 | | - *dgain_fine = total_gain * 128 / 3391 / 64; |
---|
713 | | - } else if (total_gain < 3391 * 256) { /* 434.048 ~ 868.096 gain*/ |
---|
| 732 | + *dgain_fine = total_gain * 128 / 3100 / 64; |
---|
| 733 | + } else if (total_gain < 3100 * 256) { /* 396.800 ~ 793.600 gain*/ |
---|
714 | 734 | *again = 0x5f; |
---|
715 | 735 | *dgain = 0x03; |
---|
716 | | - *dgain_fine = total_gain * 128 / 3391 / 128; |
---|
717 | | - } else if (total_gain < 3391 * 512) { /* 868.096 ~ 1736.192 gain*/ |
---|
| 736 | + *dgain_fine = total_gain * 128 / 3100 / 128; |
---|
| 737 | + } else { /* 793.600 ~ 1587.200 gain*/ |
---|
718 | 738 | *again = 0x5f; |
---|
719 | 739 | *dgain = 0x07; |
---|
720 | | - *dgain_fine = total_gain * 128 / 3391 / 128; |
---|
| 740 | + *dgain_fine = total_gain * 128 / 3100 / 128; |
---|
721 | 741 | } |
---|
722 | 742 | |
---|
723 | 743 | return ret; |
---|
.. | .. |
---|
933 | 953 | u32 i, h, w; |
---|
934 | 954 | long ret = 0; |
---|
935 | 955 | u32 stream = 0; |
---|
| 956 | + u32 *sync_mode = NULL; |
---|
936 | 957 | |
---|
937 | 958 | switch (cmd) { |
---|
938 | 959 | case RKMODULE_GET_MODULE_INFO: |
---|
.. | .. |
---|
983 | 1004 | ret = sc230ai_write_reg(sc230ai->client, SC230AI_REG_CTRL_MODE, |
---|
984 | 1005 | SC230AI_REG_VALUE_08BIT, SC230AI_MODE_SW_STANDBY); |
---|
985 | 1006 | break; |
---|
| 1007 | + case RKMODULE_GET_SYNC_MODE: |
---|
| 1008 | + sync_mode = (u32 *)arg; |
---|
| 1009 | + *sync_mode = sc230ai->sync_mode; |
---|
| 1010 | + break; |
---|
| 1011 | + case RKMODULE_SET_SYNC_MODE: |
---|
| 1012 | + sync_mode = (u32 *)arg; |
---|
| 1013 | + sc230ai->sync_mode = *sync_mode; |
---|
| 1014 | + break; |
---|
986 | 1015 | default: |
---|
987 | 1016 | ret = -ENOIOCTLCMD; |
---|
988 | 1017 | break; |
---|
.. | .. |
---|
1001 | 1030 | struct preisp_hdrae_exp_s *hdrae; |
---|
1002 | 1031 | long ret; |
---|
1003 | 1032 | u32 stream = 0; |
---|
| 1033 | + u32 sync_mode; |
---|
1004 | 1034 | |
---|
1005 | 1035 | switch (cmd) { |
---|
1006 | 1036 | case RKMODULE_GET_MODULE_INFO: |
---|
.. | .. |
---|
1069 | 1099 | |
---|
1070 | 1100 | ret = sc230ai_ioctl(sd, cmd, &stream); |
---|
1071 | 1101 | break; |
---|
| 1102 | + case RKMODULE_GET_SYNC_MODE: |
---|
| 1103 | + ret = sc230ai_ioctl(sd, cmd, &sync_mode); |
---|
| 1104 | + if (!ret) { |
---|
| 1105 | + ret = copy_to_user(up, &sync_mode, sizeof(u32)); |
---|
| 1106 | + if (ret) |
---|
| 1107 | + ret = -EFAULT; |
---|
| 1108 | + } |
---|
| 1109 | + break; |
---|
| 1110 | + case RKMODULE_SET_SYNC_MODE: |
---|
| 1111 | + ret = copy_from_user(&sync_mode, up, sizeof(u32)); |
---|
| 1112 | + if (!ret) |
---|
| 1113 | + ret = sc230ai_ioctl(sd, cmd, &sync_mode); |
---|
| 1114 | + else |
---|
| 1115 | + ret = -EFAULT; |
---|
| 1116 | + break; |
---|
1072 | 1117 | default: |
---|
1073 | 1118 | ret = -ENOIOCTLCMD; |
---|
1074 | 1119 | break; |
---|
.. | .. |
---|
1080 | 1125 | |
---|
1081 | 1126 | static int __sc230ai_start_stream(struct sc230ai *sc230ai) |
---|
1082 | 1127 | { |
---|
1083 | | - int ret; |
---|
| 1128 | + int ret = 0; |
---|
1084 | 1129 | |
---|
1085 | 1130 | if (!sc230ai->is_thunderboot) { |
---|
1086 | 1131 | ret = sc230ai_write_array(sc230ai->client, sc230ai->cur_mode->reg_list); |
---|
.. | .. |
---|
1099 | 1144 | return ret; |
---|
1100 | 1145 | } |
---|
1101 | 1146 | } |
---|
| 1147 | + if (sc230ai->sync_mode == INTERNAL_MASTER_MODE) |
---|
| 1148 | + ret |= sc230ai_write_array(sc230ai->client, |
---|
| 1149 | + sc230ai_interal_sync_master_start_regs); |
---|
| 1150 | + else if (sc230ai->sync_mode == SLAVE_MODE) |
---|
| 1151 | + ret |= sc230ai_write_array(sc230ai->client, |
---|
| 1152 | + sc230ai_interal_sync_slaver_start_regs); |
---|
1102 | 1153 | } |
---|
1103 | | - return sc230ai_write_reg(sc230ai->client, SC230AI_REG_CTRL_MODE, |
---|
| 1154 | + ret |= sc230ai_write_reg(sc230ai->client, SC230AI_REG_CTRL_MODE, |
---|
1104 | 1155 | SC230AI_REG_VALUE_08BIT, SC230AI_MODE_STREAMING); |
---|
| 1156 | + return ret; |
---|
1105 | 1157 | } |
---|
1106 | 1158 | |
---|
1107 | 1159 | static int __sc230ai_stop_stream(struct sc230ai *sc230ai) |
---|
1108 | 1160 | { |
---|
| 1161 | + int ret = 0; |
---|
1109 | 1162 | sc230ai->has_init_exp = false; |
---|
1110 | 1163 | if (sc230ai->is_thunderboot) { |
---|
1111 | 1164 | sc230ai->is_first_streamoff = true; |
---|
1112 | 1165 | pm_runtime_put(&sc230ai->client->dev); |
---|
| 1166 | + } else { |
---|
| 1167 | + if (sc230ai->sync_mode == INTERNAL_MASTER_MODE) |
---|
| 1168 | + ret |= sc230ai_write_array(sc230ai->client, |
---|
| 1169 | + sc230ai_interal_sync_master_stop_regs); |
---|
| 1170 | + else if (sc230ai->sync_mode == SLAVE_MODE) |
---|
| 1171 | + ret |= sc230ai_write_array(sc230ai->client, |
---|
| 1172 | + sc230ai_interal_sync_slaver_stop_regs); |
---|
1113 | 1173 | } |
---|
1114 | | - return sc230ai_write_reg(sc230ai->client, SC230AI_REG_CTRL_MODE, |
---|
| 1174 | + ret |= sc230ai_write_reg(sc230ai->client, SC230AI_REG_CTRL_MODE, |
---|
1115 | 1175 | SC230AI_REG_VALUE_08BIT, SC230AI_MODE_SW_STANDBY); |
---|
| 1176 | + return ret; |
---|
1116 | 1177 | } |
---|
1117 | 1178 | |
---|
1118 | 1179 | static int __sc230ai_power_on(struct sc230ai *sc230ai); |
---|
.. | .. |
---|
1406 | 1467 | switch (ctrl->id) { |
---|
1407 | 1468 | case V4L2_CID_VBLANK: |
---|
1408 | 1469 | /* Update max exposure while meeting expected vblanking */ |
---|
1409 | | - max = sc230ai->cur_mode->height + ctrl->val - 4; |
---|
| 1470 | + max = sc230ai->cur_mode->height + ctrl->val - 5; |
---|
1410 | 1471 | __v4l2_ctrl_modify_range(sc230ai->exposure, |
---|
1411 | 1472 | sc230ai->exposure->minimum, max, |
---|
1412 | 1473 | sc230ai->exposure->step, |
---|
.. | .. |
---|
1469 | 1530 | (ctrl->val + sc230ai->cur_mode->height) |
---|
1470 | 1531 | & 0xff); |
---|
1471 | 1532 | sc230ai->cur_vts = ctrl->val + sc230ai->cur_mode->height; |
---|
1472 | | - if (sc230ai->cur_vts != sc230ai->cur_mode->vts_def) |
---|
1473 | | - sc230ai_modify_fps_info(sc230ai); |
---|
| 1533 | + sc230ai_modify_fps_info(sc230ai); |
---|
1474 | 1534 | break; |
---|
1475 | 1535 | case V4L2_CID_TEST_PATTERN: |
---|
1476 | 1536 | ret = sc230ai_enable_test_pattern(sc230ai, ctrl->val); |
---|
.. | .. |
---|
1546 | 1606 | V4L2_CID_VBLANK, vblank_def, |
---|
1547 | 1607 | SC230AI_VTS_MAX - mode->height, |
---|
1548 | 1608 | 1, vblank_def); |
---|
1549 | | - exposure_max = SC230AI_EXPOSURE_LIN_MAX; |
---|
| 1609 | + exposure_max = mode->vts_def - 5; |
---|
1550 | 1610 | sc230ai->exposure = v4l2_ctrl_new_std(handler, &sc230ai_ctrl_ops, |
---|
1551 | 1611 | V4L2_CID_EXPOSURE, SC230AI_EXPOSURE_MIN, |
---|
1552 | 1612 | exposure_max, SC230AI_EXPOSURE_STEP, |
---|
.. | .. |
---|
1629 | 1689 | char facing[2]; |
---|
1630 | 1690 | int ret; |
---|
1631 | 1691 | u32 i, hdr_mode = 0; |
---|
| 1692 | + const char *sync_mode_name = NULL; |
---|
1632 | 1693 | |
---|
1633 | 1694 | dev_info(dev, "driver version: %02x.%02x.%02x", |
---|
1634 | 1695 | DRIVER_VERSION >> 16, |
---|
.. | .. |
---|
1652 | 1713 | dev_err(dev, "could not get module information!\n"); |
---|
1653 | 1714 | return -EINVAL; |
---|
1654 | 1715 | } |
---|
| 1716 | + |
---|
| 1717 | + ret = of_property_read_string(node, RKMODULE_CAMERA_SYNC_MODE, |
---|
| 1718 | + &sync_mode_name); |
---|
| 1719 | + if (ret) { |
---|
| 1720 | + sc230ai->sync_mode = NO_SYNC_MODE; |
---|
| 1721 | + dev_err(dev, "could not get sync mode!\n"); |
---|
| 1722 | + } else { |
---|
| 1723 | + if (strcmp(sync_mode_name, RKMODULE_EXTERNAL_MASTER_MODE) == 0) { |
---|
| 1724 | + sc230ai->sync_mode = EXTERNAL_MASTER_MODE; |
---|
| 1725 | + dev_info(dev, "external master mode\n"); |
---|
| 1726 | + } else if (strcmp(sync_mode_name, RKMODULE_INTERNAL_MASTER_MODE) == 0) { |
---|
| 1727 | + sc230ai->sync_mode = INTERNAL_MASTER_MODE; |
---|
| 1728 | + dev_info(dev, "internal master mode\n"); |
---|
| 1729 | + } else if (strcmp(sync_mode_name, RKMODULE_SLAVE_MODE) == 0) { |
---|
| 1730 | + sc230ai->sync_mode = SLAVE_MODE; |
---|
| 1731 | + dev_info(dev, "slave mode\n"); |
---|
| 1732 | + } |
---|
| 1733 | + } |
---|
| 1734 | + |
---|
1655 | 1735 | sc230ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); |
---|
1656 | 1736 | sc230ai->client = client; |
---|
1657 | 1737 | for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|