| .. | .. |
|---|
| 5 | 5 | * Copyright (C) 2020 Rockchip Electronics Co., Ltd. |
|---|
| 6 | 6 | * |
|---|
| 7 | 7 | * V0.0X01.0X01 first version |
|---|
| 8 | + * V0.0X01.0X02 support fastboot |
|---|
| 8 | 9 | */ |
|---|
| 9 | 10 | |
|---|
| 10 | 11 | //#define DEBUG |
|---|
| .. | .. |
|---|
| 26 | 27 | #include <media/v4l2-ctrls.h> |
|---|
| 27 | 28 | #include <media/v4l2-subdev.h> |
|---|
| 28 | 29 | #include <linux/pinctrl/consumer.h> |
|---|
| 30 | +#include "../platform/rockchip/isp/rkisp_tb_helper.h" |
|---|
| 29 | 31 | |
|---|
| 30 | 32 | #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) |
|---|
| 31 | 33 | |
|---|
| .. | .. |
|---|
| 110 | 112 | u8 val; |
|---|
| 111 | 113 | }; |
|---|
| 112 | 114 | |
|---|
| 113 | | -enum sc4336_max_pad { |
|---|
| 114 | | - PAD0, /* link to isp */ |
|---|
| 115 | | - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ |
|---|
| 116 | | - PAD2, /* link to csi wr1 | hdr x3:L */ |
|---|
| 117 | | - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ |
|---|
| 118 | | - PAD_MAX, |
|---|
| 119 | | -}; |
|---|
| 120 | | - |
|---|
| 121 | 115 | struct sc4336_mode { |
|---|
| 122 | 116 | u32 bus_fmt; |
|---|
| 123 | 117 | u32 width; |
|---|
| .. | .. |
|---|
| 155 | 149 | bool streaming; |
|---|
| 156 | 150 | bool power_on; |
|---|
| 157 | 151 | const struct sc4336_mode *cur_mode; |
|---|
| 152 | + struct v4l2_fract cur_fps; |
|---|
| 158 | 153 | u32 module_index; |
|---|
| 159 | 154 | const char *module_facing; |
|---|
| 160 | 155 | const char *module_name; |
|---|
| 161 | 156 | const char *len_name; |
|---|
| 162 | 157 | u32 cur_vts; |
|---|
| 158 | + bool is_thunderboot; |
|---|
| 159 | + bool is_first_streamoff; |
|---|
| 163 | 160 | }; |
|---|
| 164 | 161 | |
|---|
| 165 | 162 | #define to_sc4336(sd) container_of(sd, struct sc4336, subdev) |
|---|
| .. | .. |
|---|
| 314 | 311 | {0x5aed, 0x2c}, |
|---|
| 315 | 312 | {0x36e9, 0x53}, |
|---|
| 316 | 313 | {0x37f9, 0x23}, |
|---|
| 314 | + {0x320e, 0x07}, |
|---|
| 315 | + {0x320f, 0x08}, |
|---|
| 317 | 316 | {REG_NULL, 0x00}, |
|---|
| 318 | 317 | }; |
|---|
| 319 | 318 | |
|---|
| .. | .. |
|---|
| 323 | 322 | .height = 1440, |
|---|
| 324 | 323 | .max_fps = { |
|---|
| 325 | 324 | .numerator = 10000, |
|---|
| 326 | | - .denominator = 300000, |
|---|
| 325 | + .denominator = 250000, |
|---|
| 327 | 326 | }, |
|---|
| 328 | 327 | .exp_def = 0x0080, |
|---|
| 329 | 328 | .hts_def = 0x0578 * 2, |
|---|
| 330 | | - .vts_def = 0x05dc, |
|---|
| 329 | + .vts_def = 0x0708, |
|---|
| 331 | 330 | .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
|---|
| 332 | 331 | .reg_list = sc4336_linear_10_2560x1440_regs, |
|---|
| 333 | 332 | .hdr_mode = NO_HDR, |
|---|
| .. | .. |
|---|
| 552 | 551 | __v4l2_ctrl_modify_range(sc4336->vblank, vblank_def, |
|---|
| 553 | 552 | SC4336_VTS_MAX - mode->height, |
|---|
| 554 | 553 | 1, vblank_def); |
|---|
| 554 | + sc4336->cur_fps = mode->max_fps; |
|---|
| 555 | 555 | } |
|---|
| 556 | 556 | |
|---|
| 557 | 557 | mutex_unlock(&sc4336->mutex); |
|---|
| .. | .. |
|---|
| 644 | 644 | struct sc4336 *sc4336 = to_sc4336(sd); |
|---|
| 645 | 645 | const struct sc4336_mode *mode = sc4336->cur_mode; |
|---|
| 646 | 646 | |
|---|
| 647 | | - mutex_lock(&sc4336->mutex); |
|---|
| 648 | | - fi->interval = mode->max_fps; |
|---|
| 649 | | - mutex_unlock(&sc4336->mutex); |
|---|
| 647 | + if (sc4336->streaming) |
|---|
| 648 | + fi->interval = sc4336->cur_fps; |
|---|
| 649 | + else |
|---|
| 650 | + fi->interval = mode->max_fps; |
|---|
| 650 | 651 | |
|---|
| 651 | 652 | return 0; |
|---|
| 652 | 653 | } |
|---|
| 653 | 654 | |
|---|
| 654 | 655 | static int sc4336_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 656 | + unsigned int pad_id, |
|---|
| 655 | 657 | struct v4l2_mbus_config *config) |
|---|
| 656 | 658 | { |
|---|
| 657 | 659 | struct sc4336 *sc4336 = to_sc4336(sd); |
|---|
| .. | .. |
|---|
| 665 | 667 | if (mode->hdr_mode == HDR_X3) |
|---|
| 666 | 668 | val |= V4L2_MBUS_CSI2_CHANNEL_2; |
|---|
| 667 | 669 | |
|---|
| 668 | | - config->type = V4L2_MBUS_CSI2; |
|---|
| 670 | + config->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 669 | 671 | config->flags = val; |
|---|
| 670 | 672 | |
|---|
| 671 | 673 | return 0; |
|---|
| .. | .. |
|---|
| 831 | 833 | static int __sc4336_start_stream(struct sc4336 *sc4336) |
|---|
| 832 | 834 | { |
|---|
| 833 | 835 | int ret; |
|---|
| 836 | + if (!sc4336->is_thunderboot) { |
|---|
| 837 | + ret = sc4336_write_array(sc4336->client, sc4336->cur_mode->reg_list); |
|---|
| 838 | + if (ret) |
|---|
| 839 | + return ret; |
|---|
| 834 | 840 | |
|---|
| 835 | | - ret = sc4336_write_array(sc4336->client, sc4336->cur_mode->reg_list); |
|---|
| 836 | | - if (ret) |
|---|
| 837 | | - return ret; |
|---|
| 838 | | - |
|---|
| 839 | | - /* In case these controls are set before streaming */ |
|---|
| 840 | | - ret = __v4l2_ctrl_handler_setup(&sc4336->ctrl_handler); |
|---|
| 841 | | - if (ret) |
|---|
| 842 | | - return ret; |
|---|
| 841 | + /* In case these controls are set before streaming */ |
|---|
| 842 | + ret = __v4l2_ctrl_handler_setup(&sc4336->ctrl_handler); |
|---|
| 843 | + if (ret) |
|---|
| 844 | + return ret; |
|---|
| 845 | + } |
|---|
| 843 | 846 | |
|---|
| 844 | 847 | return sc4336_write_reg(sc4336->client, SC4336_REG_CTRL_MODE, |
|---|
| 845 | 848 | SC4336_REG_VALUE_08BIT, SC4336_MODE_STREAMING); |
|---|
| .. | .. |
|---|
| 847 | 850 | |
|---|
| 848 | 851 | static int __sc4336_stop_stream(struct sc4336 *sc4336) |
|---|
| 849 | 852 | { |
|---|
| 853 | + if (sc4336->is_thunderboot) { |
|---|
| 854 | + sc4336->is_first_streamoff = true; |
|---|
| 855 | + pm_runtime_put(&sc4336->client->dev); |
|---|
| 856 | + } |
|---|
| 850 | 857 | return sc4336_write_reg(sc4336->client, SC4336_REG_CTRL_MODE, |
|---|
| 851 | 858 | SC4336_REG_VALUE_08BIT, SC4336_MODE_SW_STANDBY); |
|---|
| 852 | 859 | } |
|---|
| 853 | 860 | |
|---|
| 861 | +static int __sc4336_power_on(struct sc4336 *sc4336); |
|---|
| 854 | 862 | static int sc4336_s_stream(struct v4l2_subdev *sd, int on) |
|---|
| 855 | 863 | { |
|---|
| 856 | 864 | struct sc4336 *sc4336 = to_sc4336(sd); |
|---|
| .. | .. |
|---|
| 863 | 871 | goto unlock_and_return; |
|---|
| 864 | 872 | |
|---|
| 865 | 873 | if (on) { |
|---|
| 874 | + if (sc4336->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { |
|---|
| 875 | + sc4336->is_thunderboot = false; |
|---|
| 876 | + __sc4336_power_on(sc4336); |
|---|
| 877 | + } |
|---|
| 878 | + |
|---|
| 866 | 879 | ret = pm_runtime_get_sync(&client->dev); |
|---|
| 867 | 880 | if (ret < 0) { |
|---|
| 868 | 881 | pm_runtime_put_noidle(&client->dev); |
|---|
| .. | .. |
|---|
| 907 | 920 | goto unlock_and_return; |
|---|
| 908 | 921 | } |
|---|
| 909 | 922 | |
|---|
| 910 | | - ret = sc4336_write_array(sc4336->client, sc4336_global_regs); |
|---|
| 911 | | - if (ret) { |
|---|
| 912 | | - v4l2_err(sd, "could not set init registers\n"); |
|---|
| 913 | | - pm_runtime_put_noidle(&client->dev); |
|---|
| 914 | | - goto unlock_and_return; |
|---|
| 923 | + if (!sc4336->is_thunderboot) { |
|---|
| 924 | + ret = sc4336_write_array(sc4336->client, sc4336_global_regs); |
|---|
| 925 | + if (ret) { |
|---|
| 926 | + v4l2_err(sd, "could not set init registers\n"); |
|---|
| 927 | + pm_runtime_put_noidle(&client->dev); |
|---|
| 928 | + goto unlock_and_return; |
|---|
| 929 | + } |
|---|
| 915 | 930 | } |
|---|
| 916 | 931 | |
|---|
| 917 | 932 | sc4336->power_on = true; |
|---|
| .. | .. |
|---|
| 954 | 969 | dev_err(dev, "Failed to enable xvclk\n"); |
|---|
| 955 | 970 | return ret; |
|---|
| 956 | 971 | } |
|---|
| 972 | + if (sc4336->is_thunderboot) |
|---|
| 973 | + return 0; |
|---|
| 974 | + |
|---|
| 957 | 975 | if (!IS_ERR(sc4336->reset_gpio)) |
|---|
| 958 | 976 | gpiod_set_value_cansleep(sc4336->reset_gpio, 0); |
|---|
| 959 | 977 | |
|---|
| .. | .. |
|---|
| 992 | 1010 | int ret; |
|---|
| 993 | 1011 | struct device *dev = &sc4336->client->dev; |
|---|
| 994 | 1012 | |
|---|
| 1013 | + clk_disable_unprepare(sc4336->xvclk); |
|---|
| 1014 | + if (sc4336->is_thunderboot) { |
|---|
| 1015 | + if (sc4336->is_first_streamoff) { |
|---|
| 1016 | + sc4336->is_thunderboot = false; |
|---|
| 1017 | + sc4336->is_first_streamoff = false; |
|---|
| 1018 | + } else { |
|---|
| 1019 | + return; |
|---|
| 1020 | + } |
|---|
| 1021 | + } |
|---|
| 1022 | + |
|---|
| 995 | 1023 | if (!IS_ERR(sc4336->pwdn_gpio)) |
|---|
| 996 | 1024 | gpiod_set_value_cansleep(sc4336->pwdn_gpio, 0); |
|---|
| 997 | | - clk_disable_unprepare(sc4336->xvclk); |
|---|
| 998 | 1025 | if (!IS_ERR(sc4336->reset_gpio)) |
|---|
| 999 | 1026 | gpiod_set_value_cansleep(sc4336->reset_gpio, 0); |
|---|
| 1000 | 1027 | if (!IS_ERR_OR_NULL(sc4336->pins_sleep)) { |
|---|
| .. | .. |
|---|
| 1006 | 1033 | regulator_bulk_disable(SC4336_NUM_SUPPLIES, sc4336->supplies); |
|---|
| 1007 | 1034 | } |
|---|
| 1008 | 1035 | |
|---|
| 1009 | | -static int sc4336_runtime_resume(struct device *dev) |
|---|
| 1036 | +static int __maybe_unused sc4336_runtime_resume(struct device *dev) |
|---|
| 1010 | 1037 | { |
|---|
| 1011 | 1038 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| 1012 | 1039 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| .. | .. |
|---|
| 1015 | 1042 | return __sc4336_power_on(sc4336); |
|---|
| 1016 | 1043 | } |
|---|
| 1017 | 1044 | |
|---|
| 1018 | | -static int sc4336_runtime_suspend(struct device *dev) |
|---|
| 1045 | +static int __maybe_unused sc4336_runtime_suspend(struct device *dev) |
|---|
| 1019 | 1046 | { |
|---|
| 1020 | 1047 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| 1021 | 1048 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| .. | .. |
|---|
| 1085 | 1112 | static const struct v4l2_subdev_video_ops sc4336_video_ops = { |
|---|
| 1086 | 1113 | .s_stream = sc4336_s_stream, |
|---|
| 1087 | 1114 | .g_frame_interval = sc4336_g_frame_interval, |
|---|
| 1088 | | - .g_mbus_config = sc4336_g_mbus_config, |
|---|
| 1089 | 1115 | }; |
|---|
| 1090 | 1116 | |
|---|
| 1091 | 1117 | static const struct v4l2_subdev_pad_ops sc4336_pad_ops = { |
|---|
| .. | .. |
|---|
| 1094 | 1120 | .enum_frame_interval = sc4336_enum_frame_interval, |
|---|
| 1095 | 1121 | .get_fmt = sc4336_get_fmt, |
|---|
| 1096 | 1122 | .set_fmt = sc4336_set_fmt, |
|---|
| 1123 | + .get_mbus_config = sc4336_g_mbus_config, |
|---|
| 1097 | 1124 | }; |
|---|
| 1098 | 1125 | |
|---|
| 1099 | 1126 | static const struct v4l2_subdev_ops sc4336_subdev_ops = { |
|---|
| .. | .. |
|---|
| 1101 | 1128 | .video = &sc4336_video_ops, |
|---|
| 1102 | 1129 | .pad = &sc4336_pad_ops, |
|---|
| 1103 | 1130 | }; |
|---|
| 1131 | + |
|---|
| 1132 | +static void sc4336_modify_fps_info(struct sc4336 *sc4336) |
|---|
| 1133 | +{ |
|---|
| 1134 | + const struct sc4336_mode *mode = sc4336->cur_mode; |
|---|
| 1135 | + |
|---|
| 1136 | + sc4336->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
|---|
| 1137 | + sc4336->cur_vts; |
|---|
| 1138 | +} |
|---|
| 1104 | 1139 | |
|---|
| 1105 | 1140 | static int sc4336_set_ctrl(struct v4l2_ctrl *ctrl) |
|---|
| 1106 | 1141 | { |
|---|
| .. | .. |
|---|
| 1164 | 1199 | (ctrl->val + sc4336->cur_mode->height) |
|---|
| 1165 | 1200 | & 0xff); |
|---|
| 1166 | 1201 | sc4336->cur_vts = ctrl->val + sc4336->cur_mode->height; |
|---|
| 1202 | + sc4336_modify_fps_info(sc4336); |
|---|
| 1167 | 1203 | break; |
|---|
| 1168 | 1204 | case V4L2_CID_TEST_PATTERN: |
|---|
| 1169 | 1205 | ret = sc4336_enable_test_pattern(sc4336, ctrl->val); |
|---|
| .. | .. |
|---|
| 1231 | 1267 | V4L2_CID_VBLANK, vblank_def, |
|---|
| 1232 | 1268 | SC4336_VTS_MAX - mode->height, |
|---|
| 1233 | 1269 | 1, vblank_def); |
|---|
| 1270 | + sc4336->cur_fps = mode->max_fps; |
|---|
| 1234 | 1271 | exposure_max = mode->vts_def - 8; |
|---|
| 1235 | 1272 | sc4336->exposure = v4l2_ctrl_new_std(handler, &sc4336_ctrl_ops, |
|---|
| 1236 | 1273 | V4L2_CID_EXPOSURE, SC4336_EXPOSURE_MIN, |
|---|
| .. | .. |
|---|
| 1272 | 1309 | struct device *dev = &sc4336->client->dev; |
|---|
| 1273 | 1310 | u32 id = 0; |
|---|
| 1274 | 1311 | int ret; |
|---|
| 1312 | + |
|---|
| 1313 | + if (sc4336->is_thunderboot) { |
|---|
| 1314 | + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); |
|---|
| 1315 | + return 0; |
|---|
| 1316 | + } |
|---|
| 1275 | 1317 | |
|---|
| 1276 | 1318 | ret = sc4336_read_reg(client, SC4336_REG_CHIP_ID, |
|---|
| 1277 | 1319 | SC4336_REG_VALUE_16BIT, &id); |
|---|
| .. | .. |
|---|
| 1329 | 1371 | return -EINVAL; |
|---|
| 1330 | 1372 | } |
|---|
| 1331 | 1373 | |
|---|
| 1374 | + sc4336->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); |
|---|
| 1332 | 1375 | sc4336->client = client; |
|---|
| 1333 | 1376 | sc4336->cur_mode = &supported_modes[0]; |
|---|
| 1334 | 1377 | |
|---|
| .. | .. |
|---|
| 1338 | 1381 | return -EINVAL; |
|---|
| 1339 | 1382 | } |
|---|
| 1340 | 1383 | |
|---|
| 1341 | | - sc4336->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
|---|
| 1342 | | - if (IS_ERR(sc4336->reset_gpio)) |
|---|
| 1343 | | - dev_warn(dev, "Failed to get reset-gpios\n"); |
|---|
| 1384 | + if (sc4336->is_thunderboot) { |
|---|
| 1385 | + sc4336->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); |
|---|
| 1386 | + if (IS_ERR(sc4336->reset_gpio)) |
|---|
| 1387 | + dev_warn(dev, "Failed to get reset-gpios\n"); |
|---|
| 1344 | 1388 | |
|---|
| 1345 | | - sc4336->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
|---|
| 1346 | | - if (IS_ERR(sc4336->pwdn_gpio)) |
|---|
| 1347 | | - dev_warn(dev, "Failed to get pwdn-gpios\n"); |
|---|
| 1389 | + sc4336->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); |
|---|
| 1390 | + if (IS_ERR(sc4336->pwdn_gpio)) |
|---|
| 1391 | + dev_warn(dev, "Failed to get pwdn-gpios\n"); |
|---|
| 1392 | + } else { |
|---|
| 1393 | + sc4336->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
|---|
| 1394 | + if (IS_ERR(sc4336->reset_gpio)) |
|---|
| 1395 | + dev_warn(dev, "Failed to get reset-gpios\n"); |
|---|
| 1348 | 1396 | |
|---|
| 1397 | + sc4336->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
|---|
| 1398 | + if (IS_ERR(sc4336->pwdn_gpio)) |
|---|
| 1399 | + dev_warn(dev, "Failed to get pwdn-gpios\n"); |
|---|
| 1400 | + } |
|---|
| 1349 | 1401 | sc4336->pinctrl = devm_pinctrl_get(dev); |
|---|
| 1350 | 1402 | if (!IS_ERR(sc4336->pinctrl)) { |
|---|
| 1351 | 1403 | sc4336->pins_default = |
|---|
| .. | .. |
|---|
| 1415 | 1467 | |
|---|
| 1416 | 1468 | pm_runtime_set_active(dev); |
|---|
| 1417 | 1469 | pm_runtime_enable(dev); |
|---|
| 1418 | | - pm_runtime_idle(dev); |
|---|
| 1470 | + if (sc4336->is_thunderboot) |
|---|
| 1471 | + pm_runtime_get_sync(dev); |
|---|
| 1472 | + else |
|---|
| 1473 | + pm_runtime_idle(dev); |
|---|
| 1419 | 1474 | |
|---|
| 1420 | 1475 | return 0; |
|---|
| 1421 | 1476 | |
|---|
| .. | .. |
|---|
| 1487 | 1542 | i2c_del_driver(&sc4336_i2c_driver); |
|---|
| 1488 | 1543 | } |
|---|
| 1489 | 1544 | |
|---|
| 1545 | +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) |
|---|
| 1546 | +subsys_initcall(sensor_mod_init); |
|---|
| 1547 | +#else |
|---|
| 1490 | 1548 | device_initcall_sync(sensor_mod_init); |
|---|
| 1549 | +#endif |
|---|
| 1491 | 1550 | module_exit(sensor_mod_exit); |
|---|
| 1492 | 1551 | |
|---|
| 1493 | 1552 | MODULE_DESCRIPTION("smartsens sc4336 sensor driver"); |
|---|