From b6601c35fd89a89a70af1368dd3be713fb7e9528 Mon Sep 17 00:00:00 2001 From: Su Yuefu Date: Thu, 15 Sep 2022 08:08:47 +0800 Subject: [PATCH] media: i2c: sc200ai support fastboot Signed-off-by: Su Yuefu Change-Id: I521c53b826c485231aa4c59b310a0352d6cdf428 Signed-off-by: Zefa Chen --- drivers/media/i2c/sc200ai.c | 210 +++++++++++++++++++++++++++++++----- 1 file changed, 184 insertions(+), 26 deletions(-) diff --git a/drivers/media/i2c/sc200ai.c b/drivers/media/i2c/sc200ai.c index 2b1c1a49fb9e..26fbea10893b 100644 --- a/drivers/media/i2c/sc200ai.c +++ b/drivers/media/i2c/sc200ai.c @@ -33,6 +33,7 @@ #include #include #include +#include "../platform/rockchip/isp/rkisp_tb_helper.h" #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x07) @@ -46,6 +47,7 @@ #define PIXEL_RATE_WITH_371M_10BIT (SC200AI_LINK_FREQ_371 * 2 * \ SC200AI_LANES / SC200AI_BITS_PER_SAMPLE) + #define SC200AI_XVCLK_FREQ 27000000 #define CHIP_ID 0xcb1c @@ -174,6 +176,8 @@ struct sc200ai { const char *len_name; u32 cur_vts; bool has_init_exp; + bool is_thunderboot; + bool is_first_streamoff; struct preisp_hdrae_exp_s init_hdrae_exp; }; @@ -188,10 +192,10 @@ static const struct regval sc200ai_global_regs[] = { /* * Xclk 24Mhz - * max_framerate 90fps + * max_framerate 60fps * mipi_datarate per lane 1008Mbps, 4lane */ -static const struct regval sc200ai_linear_10_1920x1080_regs[] = { +static const struct regval sc200ai_linear_10_1920x1080_60fps_regs[] = { {0x0103, 0x01}, {0x0100, 0x00}, {0x36e9, 0x80}, @@ -328,6 +332,113 @@ static const struct regval sc200ai_linear_10_1920x1080_regs[] = { {REG_NULL, 0x00}, }; +/* + * Xclk 27Mhz + * max_framerate 30fps + * mipi_datarate per lane 371.25Mbps, 2lane + */ +static const struct regval sc200ai_linear_10_1920x1080_30fps_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x36e9, 0x80}, + {0x36f9, 0x80}, + {0x301f, 0x03}, + //HTS=1100*2=2200 + {0x320c, 0x04}, + {0x320d, 0x4c}, + //VTS=1125 + {0x320e, 0x04}, + {0x320f, 0x65}, + {0x3243, 0x01}, + {0x3248, 0x02}, + {0x3249, 0x09}, + {0x3253, 0x08}, + {0x3271, 0x0a}, + {0x3301, 0x20}, + {0x3304, 0x40}, + {0x3306, 0x32}, + {0x330b, 0x88}, + {0x330f, 0x02}, + {0x331e, 0x39}, + {0x3333, 0x10}, + {0x3621, 0xe8}, + {0x3622, 0x16}, + {0x3637, 0x1b}, + {0x363a, 0x1f}, + {0x363b, 0xc6}, + {0x363c, 0x0e}, + {0x3670, 0x0a}, + {0x3674, 0x82}, + {0x3675, 0x76}, + {0x3676, 0x78}, + {0x367c, 0x48}, + {0x367d, 0x58}, + {0x3690, 0x34}, + {0x3691, 0x33}, + {0x3692, 0x44}, + {0x369c, 0x40}, + {0x369d, 0x48}, + {0x3901, 0x02}, + {0x3904, 0x04}, + {0x3908, 0x41}, + {0x391d, 0x14}, + {0x391f, 0x18}, + {0x3e01, 0x8c}, + {0x3e02, 0x20}, + {0x3e16, 0x00}, + {0x3e17, 0x80}, + {0x3f09, 0x48}, + {0x5787, 0x10}, + {0x5788, 0x06}, + {0x578a, 0x10}, + {0x578b, 0x06}, + {0x5790, 0x10}, + {0x5791, 0x10}, + {0x5792, 0x00}, + {0x5793, 0x10}, + {0x5794, 0x10}, + {0x5795, 0x00}, + {0x5799, 0x00}, + {0x57c7, 0x10}, + {0x57c8, 0x06}, + {0x57ca, 0x10}, + {0x57cb, 0x06}, + {0x57d1, 0x10}, + {0x57d4, 0x10}, + {0x57d9, 0x00}, + {0x59e0, 0x60}, + {0x59e1, 0x08}, + {0x59e2, 0x3f}, + {0x59e3, 0x18}, + {0x59e4, 0x18}, + {0x59e5, 0x3f}, + {0x59e6, 0x06}, + {0x59e7, 0x02}, + {0x59e8, 0x38}, + {0x59e9, 0x10}, + {0x59ea, 0x0c}, + {0x59eb, 0x10}, + {0x59ec, 0x04}, + {0x59ed, 0x02}, + {0x59ee, 0xa0}, + {0x59ef, 0x08}, + {0x59f4, 0x18}, + {0x59f5, 0x10}, + {0x59f6, 0x0c}, + {0x59f7, 0x10}, + {0x59f8, 0x06}, + {0x59f9, 0x02}, + {0x59fa, 0x18}, + {0x59fb, 0x10}, + {0x59fc, 0x0c}, + {0x59fd, 0x10}, + {0x59fe, 0x04}, + {0x59ff, 0x02}, + {0x36e9, 0x20}, + {0x36f9, 0x27}, + {REG_NULL, 0x00}, +}; + /* * Xclk 27Mhz * max_framerate 30fps @@ -490,6 +601,20 @@ static const struct regval sc200ai_hdr_10_1920x1080_regs[] = { static const struct sc200ai_mode supported_modes[] = { { + .width = 1920, + .height = 1080, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = 0x0080, + .hts_def = 0x44C * 2, + .vts_def = 0x0465, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, + .reg_list = sc200ai_linear_10_1920x1080_30fps_regs, + .hdr_mode = NO_HDR, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + }, { .width = 1920, .height = 1080, .max_fps = { @@ -500,7 +625,7 @@ static const struct sc200ai_mode supported_modes[] = { .hts_def = 0x44C * 2, .vts_def = 0x0465, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .reg_list = sc200ai_linear_10_1920x1080_regs, + .reg_list = sc200ai_linear_10_1920x1080_60fps_regs, .hdr_mode = NO_HDR, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, }, { @@ -1230,21 +1355,23 @@ static int __sc200ai_start_stream(struct sc200ai *sc200ai) { int ret; - ret = sc200ai_write_array(sc200ai->client, sc200ai->cur_mode->reg_list); - if (ret) - return ret; - - /* In case these controls are set before streaming */ - ret = __v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler); - if (ret) - return ret; - if (sc200ai->has_init_exp && sc200ai->cur_mode->hdr_mode != NO_HDR) { - ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP, - &sc200ai->init_hdrae_exp); - if (ret) { - dev_err(&sc200ai->client->dev, - "init exp fail in hdr mode\n"); + if (!sc200ai->is_thunderboot) { + ret = sc200ai_write_array(sc200ai->client, sc200ai->cur_mode->reg_list); + if (ret) return ret; + + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler); + if (ret) + return ret; + if (sc200ai->has_init_exp && sc200ai->cur_mode->hdr_mode != NO_HDR) { + ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP, + &sc200ai->init_hdrae_exp); + if (ret) { + dev_err(&sc200ai->client->dev, + "init exp fail in hdr mode\n"); + return ret; + } } } @@ -1255,10 +1382,13 @@ static int __sc200ai_start_stream(struct sc200ai *sc200ai) static int __sc200ai_stop_stream(struct sc200ai *sc200ai) { sc200ai->has_init_exp = false; + if (sc200ai->is_thunderboot) + sc200ai->is_first_streamoff = true; return sc200ai_write_reg(sc200ai->client, SC200AI_REG_CTRL_MODE, SC200AI_REG_VALUE_08BIT, SC200AI_MODE_SW_STANDBY); } +static int __sc200ai_power_on(struct sc200ai *sc200ai); static int sc200ai_s_stream(struct v4l2_subdev *sd, int on) { struct sc200ai *sc200ai = to_sc200ai(sd); @@ -1271,6 +1401,10 @@ static int sc200ai_s_stream(struct v4l2_subdev *sd, int on) goto unlock_and_return; if (on) { + if (sc200ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { + sc200ai->is_thunderboot = false; + __sc200ai_power_on(sc200ai); + } ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { pm_runtime_put_noidle(&client->dev); @@ -1315,11 +1449,13 @@ static int sc200ai_s_power(struct v4l2_subdev *sd, int on) goto unlock_and_return; } - ret = sc200ai_write_array(sc200ai->client, sc200ai_global_regs); - if (ret) { - v4l2_err(sd, "could not set init registers\n"); - pm_runtime_put_noidle(&client->dev); - goto unlock_and_return; + if (!sc200ai->is_thunderboot) { + ret = sc200ai_write_array(sc200ai->client, sc200ai_global_regs); + if (ret) { + v4l2_err(sd, "could not set init registers\n"); + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } } sc200ai->power_on = true; @@ -1362,6 +1498,9 @@ static int __sc200ai_power_on(struct sc200ai *sc200ai) dev_err(dev, "Failed to enable xvclk\n"); return ret; } + if (sc200ai->is_thunderboot) + return 0; + if (!IS_ERR(sc200ai->reset_gpio)) gpiod_set_value_cansleep(sc200ai->reset_gpio, 0); @@ -1400,6 +1539,15 @@ static void __sc200ai_power_off(struct sc200ai *sc200ai) int ret; struct device *dev = &sc200ai->client->dev; + clk_disable_unprepare(sc200ai->xvclk); + if (sc200ai->is_thunderboot) { + if (sc200ai->is_first_streamoff) { + sc200ai->is_thunderboot = false; + sc200ai->is_first_streamoff = false; + } else { + return; + } + } if (!IS_ERR(sc200ai->pwdn_gpio)) gpiod_set_value_cansleep(sc200ai->pwdn_gpio, 0); clk_disable_unprepare(sc200ai->xvclk); @@ -1651,7 +1799,7 @@ static int sc200ai_initialize_controls(struct sc200ai *sc200ai) V4L2_CID_VBLANK, vblank_def, SC200AI_VTS_MAX - mode->height, 1, vblank_def); - exposure_max = mode->vts_def - 4; + exposure_max = 2 * mode->vts_def - 8; sc200ai->exposure = v4l2_ctrl_new_std(handler, &sc200ai_ctrl_ops, V4L2_CID_EXPOSURE, SC200AI_EXPOSURE_MIN, exposure_max, SC200AI_EXPOSURE_STEP, @@ -1698,6 +1846,11 @@ static int sc200ai_check_sensor_id(struct sc200ai *sc200ai, u32 id = 0; int ret; + if (sc200ai->is_thunderboot) { + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); + return 0; + } + ret = sc200ai_read_reg(client, SC200AI_REG_CHIP_ID, SC200AI_REG_VALUE_16BIT, &id); if (id != CHIP_ID) { @@ -1756,6 +1909,7 @@ static int sc200ai_probe(struct i2c_client *client, return -EINVAL; } + sc200ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); sc200ai->client = client; for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { if (hdr_mode == supported_modes[i].hdr_mode) { @@ -1772,11 +1926,11 @@ static int sc200ai_probe(struct i2c_client *client, return -EINVAL; } - sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); if (IS_ERR(sc200ai->reset_gpio)) dev_warn(dev, "Failed to get reset-gpios\n"); - sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); + sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); if (IS_ERR(sc200ai->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios\n"); @@ -1921,8 +2075,12 @@ static void __exit sensor_mod_exit(void) i2c_del_driver(&sc200ai_i2c_driver); } +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) +subsys_initcall(sensor_mod_init); +#else device_initcall_sync(sensor_mod_init); +#endif module_exit(sensor_mod_exit); MODULE_DESCRIPTION("smartsens sc200ai sensor driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL");