From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/media/i2c/sc530ai.c | 399 ++++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 256 insertions(+), 143 deletions(-) diff --git a/kernel/drivers/media/i2c/sc530ai.c b/kernel/drivers/media/i2c/sc530ai.c index 4ffffda..d8e3548 100644 --- a/kernel/drivers/media/i2c/sc530ai.c +++ b/kernel/drivers/media/i2c/sc530ai.c @@ -8,6 +8,7 @@ * V0.0X01.0X01 fix set vflip/hflip failed bug. */ +//#define DEBUG #include <linux/clk.h> #include <linux/device.h> #include <linux/delay.h> @@ -42,6 +43,7 @@ #include <linux/printk.h> #include <linux/rk-camera-module.h> +#include "../platform/rockchip/isp/rkisp_tb_helper.h" #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) #ifndef V4L2_CID_DIGITAL_GAIN @@ -51,6 +53,7 @@ #define SC530AI_LINK_FREQ_396M 198000000 // 396Mbps #define SC530AI_LINK_FREQ_792M 396000000 // 792Mbps #define SC530AI_LINK_FREQ_792M_2LANE 396000000 // 792Mbps +#define SC530AI_LINK_FREQ_936M_2LANE 468000000 // 936Mbps #define SC530AI_LINEAR_PIXEL_RATES (SC530AI_LINK_FREQ_396M / 10 * 2 * 4) #define SC530AI_HDR_PIXEL_RATES (SC530AI_LINK_FREQ_792M / 10 * 2 * 4) @@ -59,7 +62,7 @@ #define SC530AI_XVCLK_FREQ 27000000 -#define SC530AI_CHIP_ID 0x9e39 +#define SC530AI_CHIP_ID 0x8e39 #define SC530AI_REG_CHIP_ID 0x3107 #define SC530AI_REG_CTRL_MODE 0x0100 @@ -77,10 +80,10 @@ #define SC530AI_REG_DIG_FINE_GAIN 0x3e07 #define SC530AI_REG_ANA_GAIN 0x3e09 -#define SC530AI_GAIN_MIN 0x800 -#define SC530AI_GAIN_MAX 0xa3300 +#define SC530AI_GAIN_MIN 0x20 +#define SC530AI_GAIN_MAX (32 * 326) #define SC530AI_GAIN_STEP 1 -#define SC530AI_GAIN_DEFAULT 0x800 +#define SC530AI_GAIN_DEFAULT 0x20 #define SC530AI_REG_VTS_H 0x320e #define SC530AI_REG_VTS_L 0x320f @@ -139,14 +142,6 @@ #define sc530ai_NUM_SUPPLIES ARRAY_SIZE(sc530ai_supply_names) -enum sc530ai_max_pad { - PAD0, /* link to isp */ - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ - PAD2, /* link to csi wr1 | hdr x3:L */ - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ - PAD_MAX, -}; - struct regval { u16 addr; u8 val; @@ -177,7 +172,8 @@ struct pinctrl *pinctrl; struct pinctrl_state *pins_default; struct pinctrl_state *pins_sleep; - + struct v4l2_fract cur_fps; + u32 cur_vts; struct v4l2_subdev subdev; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -191,13 +187,17 @@ struct mutex mutex; bool streaming; bool power_on; + const struct sc530ai_mode *support_modes; const struct sc530ai_mode *cur_mode; + u32 support_modes_num; unsigned int lane_num; u32 module_index; const char *module_facing; const char *module_name; const char *len_name; bool has_init_exp; + bool is_thunderboot; + bool is_first_streamoff; struct preisp_hdrae_exp_s init_hdrae_exp; }; @@ -208,7 +208,7 @@ * max_framerate 30fps * mipi_datarate per lane 1008Mbps, 4lane */ -static const struct regval sc530ai_linear_10_30fps_2880x1620_regs[] = { +static const struct regval sc530ai_linear_10_30fps_2880x1620_4lane_regs[] = { {0x0103, 0x01}, {0x0100, 0x00}, {0x36e9, 0x80}, @@ -317,6 +317,7 @@ {0x3e02, 0xa0}, {0x440e, 0x02}, {0x4509, 0x20}, + {0x4800, 0x04}, {0x4837, 0x28}, {0x5010, 0x10}, {0x5799, 0x06}, @@ -356,7 +357,7 @@ {REG_NULL, 0x00}, }; -static const struct regval sc530ai_hdr_10_30fps_2880x1620_regs[] = { +static const struct regval sc530ai_hdr_10_30fps_2880x1620_4lane_regs[] = { {0x0103, 0x01}, {0x0100, 0x00}, {0x36e9, 0x80}, @@ -471,6 +472,7 @@ {0x3e24, 0xc8}, {0x440e, 0x02}, {0x4509, 0x20}, + {0x4800, 0x04}, {0x4816, 0x11}, {0x5010, 0x10}, {0x5799, 0x06}, @@ -522,18 +524,22 @@ {0x37f9, 0x80}, {0x3018, 0x32}, {0x3019, 0x0c}, - {0x301f, 0x18}, + {0x301f, 0x42}, + {0x320c, 0x06}, + {0x320d, 0x27}, + {0x320e, 0x07}, + {0x320f, 0xbc}, {0x3250, 0x40}, {0x3251, 0x98}, {0x3253, 0x0c}, {0x325f, 0x20}, {0x3301, 0x08}, {0x3304, 0x50}, - {0x3306, 0x78}, + {0x3306, 0x88}, {0x3308, 0x14}, {0x3309, 0x70}, {0x330a, 0x00}, - {0x330b, 0xd8}, + {0x330b, 0xf8}, {0x330d, 0x10}, {0x331e, 0x41}, {0x331f, 0x61}, @@ -562,18 +568,18 @@ {0x33ae, 0x30}, {0x33af, 0x50}, {0x33b1, 0x80}, - {0x33b2, 0x80}, - {0x33b3, 0x40}, + {0x33b2, 0x48}, + {0x33b3, 0x30}, {0x349f, 0x02}, {0x34a6, 0x48}, - {0x34a7, 0x49}, - {0x34a8, 0x40}, - {0x34a9, 0x30}, - {0x34f8, 0x4b}, - {0x34f9, 0x30}, + {0x34a7, 0x4b}, + {0x34a8, 0x30}, + {0x34a9, 0x18}, + {0x34f8, 0x5f}, + {0x34f9, 0x08}, {0x3632, 0x48}, {0x3633, 0x32}, - {0x3637, 0x2b}, + {0x3637, 0x29}, {0x3638, 0xc1}, {0x363b, 0x20}, {0x363d, 0x02}, @@ -584,7 +590,7 @@ {0x367c, 0x40}, {0x367d, 0x48}, {0x3690, 0x32}, - {0x3691, 0x32}, + {0x3691, 0x43}, {0x3692, 0x33}, {0x3693, 0x40}, {0x3694, 0x4b}, @@ -596,7 +602,10 @@ {0x36a3, 0x4b}, {0x36a4, 0x4f}, {0x36d0, 0x01}, + {0x36ea, 0x0d}, + {0x36eb, 0x04}, {0x36ec, 0x03}, + {0x36ed, 0x14}, {0x370f, 0x01}, {0x3722, 0x00}, {0x3728, 0x10}, @@ -605,8 +614,10 @@ {0x37b2, 0x83}, {0x37b3, 0x48}, {0x37b4, 0x49}, - {0x37fb, 0x25}, + {0x37fa, 0x0d}, + {0x37fb, 0x24}, {0x37fc, 0x01}, + {0x37fd, 0x14}, {0x3901, 0x00}, {0x3902, 0xc5}, {0x3904, 0x08}, @@ -616,18 +627,20 @@ {0x391f, 0x44}, {0x3926, 0x21}, {0x3929, 0x18}, - {0x3933, 0x81}, - {0x3934, 0x81}, - {0x3937, 0x69}, + {0x3933, 0x82}, + {0x3934, 0x0a}, + {0x3937, 0x5f}, {0x3939, 0x00}, {0x393a, 0x00}, {0x39dc, 0x02}, - {0x3e01, 0xcd}, - {0x3e02, 0xa0}, + {0x3e01, 0xf6}, + {0x3e02, 0xe0}, {0x440e, 0x02}, {0x4509, 0x20}, - {0x4837, 0x14}, + {0x4837, 0x22}, {0x5010, 0x10}, + {0x5780, 0x66}, + {0x578d, 0x40}, {0x5799, 0x06}, {0x57ad, 0x00}, {0x5ae0, 0xfe}, @@ -659,12 +672,11 @@ {0x5afe, 0x30}, {0x5aff, 0x28}, {0x36e9, 0x44}, - {0x37f9, 0x34}, -// {0x0100, 0x01}, + {0x37f9, 0x44}, {REG_NULL, 0x00}, }; -static const struct sc530ai_mode supported_modes[] = { +static const struct sc530ai_mode supported_modes_4lane[] = { { .width = 2880, .height = 1620, @@ -676,7 +688,7 @@ .hts_def = 0xb40, .vts_def = 0x0672, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .reg_list = sc530ai_linear_10_30fps_2880x1620_regs, + .reg_list = sc530ai_linear_10_30fps_2880x1620_4lane_regs, .mipi_freq_idx = 0, .bpp = 10, .hdr_mode = NO_HDR, @@ -693,7 +705,7 @@ .hts_def = 0xb40, .vts_def = 0x0ce4, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .reg_list = sc530ai_hdr_10_30fps_2880x1620_regs, + .reg_list = sc530ai_hdr_10_30fps_2880x1620_4lane_regs, .mipi_freq_idx = 1, .bpp = 10, .hdr_mode = HDR_X2, @@ -702,7 +714,10 @@ .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 }, - { +}; + +static const struct sc530ai_mode supported_modes_2lane[] = { +{ .width = 2880, .height = 1620, .max_fps = { @@ -711,10 +726,10 @@ }, .exp_def = 0xcda / 2, .hts_def = 0xb40, - .vts_def = 0x0672, + .vts_def = 0x07bc, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, .reg_list = sc530ai_10_30fps_2880x1620_2lane_regs, - .mipi_freq_idx = 2, + .mipi_freq_idx = 3, .bpp = 10, .hdr_mode = NO_HDR, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, @@ -725,6 +740,7 @@ SC530AI_LINK_FREQ_396M, SC530AI_LINK_FREQ_792M, SC530AI_LINK_FREQ_792M_2LANE, + SC530AI_LINK_FREQ_936M_2LANE, }; /* Write registers up to 4 at a time */ @@ -812,7 +828,7 @@ } static const struct sc530ai_mode * -sc530ai_find_best_fit(struct v4l2_subdev_format *fmt) +sc530ai_find_best_fit(struct sc530ai *sc530ai, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt = &fmt->format; int dist; @@ -820,15 +836,15 @@ int cur_best_fit_dist = -1; unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - dist = sc530ai_get_reso_dist(&supported_modes[i], framefmt); + for (i = 0; i < sc530ai->support_modes_num; i++) { + dist = sc530ai_get_reso_dist(&sc530ai->support_modes[i], framefmt); if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { cur_best_fit_dist = dist; cur_best_fit = i; } } - return &supported_modes[cur_best_fit]; + return &sc530ai->support_modes[cur_best_fit]; } static int sc530ai_set_fmt(struct v4l2_subdev *sd, @@ -842,7 +858,7 @@ mutex_lock(&sc530ai->mutex); - mode = sc530ai_find_best_fit(fmt); + mode = sc530ai_find_best_fit(sc530ai, fmt); fmt->format.code = mode->bus_fmt; fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -869,6 +885,8 @@ pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * sc530ai->lane_num; __v4l2_ctrl_s_ctrl_int64(sc530ai->pixel_rate, pixel_rate); + sc530ai->cur_vts = mode->vts_def; + sc530ai->cur_fps = mode->max_fps; } mutex_unlock(&sc530ai->mutex); @@ -924,16 +942,18 @@ struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { - if (fse->index >= ARRAY_SIZE(supported_modes)) + struct sc530ai *sc530ai = to_sc530ai(sd); + + if (fse->index >= sc530ai->support_modes_num) return -EINVAL; - if (fse->code != supported_modes[0].bus_fmt) + if (fse->code != sc530ai->support_modes[fse->index].bus_fmt) return -EINVAL; - fse->min_width = supported_modes[fse->index].width; - fse->max_width = supported_modes[fse->index].width; - fse->max_height = supported_modes[fse->index].height; - fse->min_height = supported_modes[fse->index].height; + fse->min_width = sc530ai->support_modes[fse->index].width; + fse->max_width = sc530ai->support_modes[fse->index].width; + fse->max_height = sc530ai->support_modes[fse->index].height; + fse->min_height = sc530ai->support_modes[fse->index].height; return 0; } @@ -944,14 +964,15 @@ struct sc530ai *sc530ai = to_sc530ai(sd); const struct sc530ai_mode *mode = sc530ai->cur_mode; - mutex_lock(&sc530ai->mutex); - fi->interval = mode->max_fps; - mutex_unlock(&sc530ai->mutex); + if (sc530ai->streaming) + fi->interval = sc530ai->cur_fps; + else + fi->interval = mode->max_fps; return 0; } -static int sc530ai_g_mbus_config(struct v4l2_subdev *sd, +static int sc530ai_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *config) { struct sc530ai *sc530ai = to_sc530ai(sd); @@ -965,7 +986,7 @@ if (mode->hdr_mode == HDR_X3) val |= V4L2_MBUS_CSI2_CHANNEL_2; - config->type = V4L2_MBUS_CSI2; + config->type = V4L2_MBUS_CSI2_DPHY; config->flags = val; return 0; @@ -984,42 +1005,50 @@ static void sc530ai_get_gain_reg(u32 total_gain, u32 *again, u32 *dgain, u32 *dgain_fine) { - if (total_gain < 0x1000) { /* 1 - 2x gain */ + u32 gain_factor = 0; + + if (total_gain < SC530AI_GAIN_MIN) + total_gain = SC530AI_GAIN_MIN; + else if (total_gain > SC530AI_GAIN_MAX) + total_gain = SC530AI_GAIN_MAX; + + gain_factor = total_gain * 1000 / 32; + if (gain_factor < 2000) { /* 1 - 2x gain */ *again = 0x00; *dgain = 0x00; - *dgain_fine = total_gain >> 4; - } else if (total_gain < 0x1466) { /* 2x - 2.55x gain */ + *dgain_fine = gain_factor * 128 / 1000; + } else if (gain_factor < 2550) { /* 2x - 2.55x gain */ *again = 0x01; *dgain = 0x00; - *dgain_fine = total_gain >> 5; - } else if (total_gain < 0x28cc) { /* 2.55x - 5.1x gain */ + *dgain_fine = gain_factor * 128 / 2000; + } else if (gain_factor < 2550 * 2) { /* 2.55x - 5.1x gain */ *again = 0x40; *dgain = 0x00; - *dgain_fine = total_gain * 0x80 / 0x1466; - } else if (total_gain < 0x5198) { /* 5.1x - 10.2x gain */ + *dgain_fine = gain_factor * 128 / 2550; + } else if (gain_factor < 2550 * 4) { /* 5.1x - 10.2x gain */ *again = 0x48; *dgain = 0x00; - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 1; - } else if (total_gain < 0xa330) { /* 10.2x - 20.4x gain */ + *dgain_fine = gain_factor * 128 / 5110; + } else if (gain_factor < 2550 * 8) { /* 10.2x - 20.4x gain */ *again = 0x49; *dgain = 0x00; - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 2; - } else if (total_gain < 0x14660) { /* 20.4x - 40.8x gain */ + *dgain_fine = gain_factor * 128 / 10200; + } else if (gain_factor < 2550 * 16) { /* 20.4x - 40.8x gain */ *again = 0x4B; *dgain = 0x00; - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 3; - } else if (total_gain < 0x28cc0) { /* 40.8x - 81.6x gain */ + *dgain_fine = gain_factor * 128 / 20400; + } else if (gain_factor < 2550 * 32) { /* 40.8x - 81.6x gain */ *again = 0x4f; *dgain = 0x00; - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 4; - } else if (total_gain < 0x51980) { /* 81.6x - 163.2x gain */ + *dgain_fine = gain_factor * 128 / 40800; + } else if (gain_factor < 2550 * 64) { /* 81.6x - 163.2x gain */ *again = 0x5f; *dgain = 0x00; - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 5; - } else if (total_gain < 0xa3300) { /* 163.2x - 326.4x gain */ + *dgain_fine = gain_factor * 128 / 40800 / 2; + } else if (gain_factor < 2550 * 128) { /* 163.2x - 326.4x gain */ *again = 0x5f; *dgain = 0x01; - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 6; + *dgain_fine = gain_factor * 128 / 40800 / 4; } } @@ -1114,11 +1143,23 @@ return ret; } +static int sc530ai_get_channel_info(struct sc530ai *sc530ai, struct rkmodule_channel_info *ch_info) +{ + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) + return -EINVAL; + ch_info->vc = sc530ai->cur_mode->vc[ch_info->index]; + ch_info->width = sc530ai->cur_mode->width; + ch_info->height = sc530ai->cur_mode->height; + ch_info->bus_fmt = sc530ai->cur_mode->bus_fmt; + return 0; +} + static long sc530ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct sc530ai *sc530ai = to_sc530ai(sd); struct rkmodule_hdr_cfg *hdr; const struct sc530ai_mode *mode; + struct rkmodule_channel_info *ch_info; long ret = 0; u32 i, h = 0, w; @@ -1136,15 +1177,17 @@ break; case RKMODULE_SET_HDR_CFG: hdr = (struct rkmodule_hdr_cfg *)arg; - w = sc530ai->cur_mode->mipi_freq_idx; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - if (w == supported_modes[i].mipi_freq_idx && - supported_modes[i].hdr_mode == hdr->hdr_mode) { - sc530ai->cur_mode = &supported_modes[i]; + w = sc530ai->cur_mode->width; + h = sc530ai->cur_mode->height; + for (i = 0; i < sc530ai->support_modes_num; i++) { + if (w == sc530ai->support_modes[i].width && + h == sc530ai->support_modes[i].height && + sc530ai->support_modes[i].hdr_mode == hdr->hdr_mode) { + sc530ai->cur_mode = &sc530ai->support_modes[i]; break; } } - if (i == ARRAY_SIZE(supported_modes)) { + if (i == sc530ai->support_modes_num) { dev_err(&sc530ai->client->dev, "not find hdr mode:%d %dx%d config\n", hdr->hdr_mode, w, h); @@ -1169,7 +1212,8 @@ __v4l2_ctrl_s_ctrl_int64(sc530ai->pixel_rate, pixel_rate); - + sc530ai->cur_vts = mode->vts_def; + sc530ai->cur_fps = mode->max_fps; dev_info(&sc530ai->client->dev, "sensor mode: %d\n", sc530ai->cur_mode->hdr_mode); } @@ -1191,6 +1235,10 @@ SC530AI_REG_VALUE_08BIT, SC530AI_MODE_SW_STANDBY); break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = (struct rkmodule_channel_info *)arg; + ret = sc530ai_get_channel_info(sc530ai, ch_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -1207,6 +1255,7 @@ struct rkmodule_inf *inf; struct rkmodule_hdr_cfg *hdr; struct preisp_hdrae_exp_s *hdrae; + struct rkmodule_channel_info *ch_info; long ret = 0; u32 stream = 0; @@ -1277,6 +1326,21 @@ ret = sc530ai_ioctl(sd, cmd, &stream); break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + return ret; + } + + ret = sc530ai_ioctl(sd, cmd, ch_info); + if (!ret) { + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); + if (ret) + ret = -EFAULT; + } + kfree(ch_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -1290,21 +1354,23 @@ { int ret; - ret = sc530ai_write_array(sc530ai->client, sc530ai->cur_mode->reg_list); - if (ret) - return ret; - - /* In case these controls are set before streaming */ - ret = __v4l2_ctrl_handler_setup(&sc530ai->ctrl_handler); - if (ret) - return ret; - if (sc530ai->has_init_exp && sc530ai->cur_mode->hdr_mode != NO_HDR) { - ret = sc530ai_ioctl(&sc530ai->subdev, PREISP_CMD_SET_HDRAE_EXP, - &sc530ai->init_hdrae_exp); - if (ret) { - dev_err(&sc530ai->client->dev, - "init exp fail in hdr mode\n"); + if (!sc530ai->is_thunderboot) { + ret = sc530ai_write_array(sc530ai->client, sc530ai->cur_mode->reg_list); + if (ret) return ret; + + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&sc530ai->ctrl_handler); + if (ret) + return ret; + if (sc530ai->has_init_exp && sc530ai->cur_mode->hdr_mode != NO_HDR) { + ret = sc530ai_ioctl(&sc530ai->subdev, PREISP_CMD_SET_HDRAE_EXP, + &sc530ai->init_hdrae_exp); + if (ret) { + dev_err(&sc530ai->client->dev, + "init exp fail in hdr mode\n"); + return ret; + } } } return sc530ai_write_reg(sc530ai->client, SC530AI_REG_CTRL_MODE, @@ -1315,11 +1381,16 @@ static int __sc530ai_stop_stream(struct sc530ai *sc530ai) { sc530ai->has_init_exp = false; + if (sc530ai->is_thunderboot) { + sc530ai->is_first_streamoff = true; + pm_runtime_put(&sc530ai->client->dev); + } return sc530ai_write_reg(sc530ai->client, SC530AI_REG_CTRL_MODE, SC530AI_REG_VALUE_08BIT, SC530AI_MODE_SW_STANDBY); } +static int __sc530ai_power_on(struct sc530ai *sc530ai); static int sc530ai_s_stream(struct v4l2_subdev *sd, int on) { struct sc530ai *sc530ai = to_sc530ai(sd); @@ -1331,6 +1402,10 @@ if (on == sc530ai->streaming) goto unlock_and_return; if (on) { + if (sc530ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { + sc530ai->is_thunderboot = false; + __sc530ai_power_on(sc530ai); + } ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { pm_runtime_put_noidle(&client->dev); @@ -1373,13 +1448,18 @@ pm_runtime_put_noidle(&client->dev); goto unlock_and_return; } - - ret |= sc530ai_write_reg(sc530ai->client, - SC530AI_SOFTWARE_RESET_REG, - SC530AI_REG_VALUE_08BIT, - 0x01); - usleep_range(100, 200); - + if (!sc530ai->is_thunderboot) { + ret |= sc530ai_write_reg(sc530ai->client, + SC530AI_SOFTWARE_RESET_REG, + SC530AI_REG_VALUE_08BIT, + 0x01); + if (ret) { + v4l2_err(sd, "could not set init registers\n"); + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + usleep_range(100, 200); + } sc530ai->power_on = true; } else { pm_runtime_put(&client->dev); @@ -1413,6 +1493,10 @@ dev_err(dev, "Failed to enable xvclk\n"); return ret; } + + if (sc530ai->is_thunderboot) + return 0; + if (!IS_ERR(sc530ai->reset_gpio)) gpiod_set_value_cansleep(sc530ai->reset_gpio, 0); @@ -1443,6 +1527,15 @@ int ret; struct device *dev = &sc530ai->client->dev; + if (sc530ai->is_thunderboot) { + if (sc530ai->is_first_streamoff) { + sc530ai->is_thunderboot = false; + sc530ai->is_first_streamoff = false; + } else { + return; + } + } + if (!IS_ERR(sc530ai->pwdn_gpio)) gpiod_set_value_cansleep(sc530ai->pwdn_gpio, 0); clk_disable_unprepare(sc530ai->xvclk); @@ -1457,7 +1550,7 @@ regulator_bulk_disable(sc530ai_NUM_SUPPLIES, sc530ai->supplies); } -static int sc530ai_runtime_resume(struct device *dev) +static int __maybe_unused sc530ai_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -1466,7 +1559,7 @@ return __sc530ai_power_on(sc530ai); } -static int sc530ai_runtime_suspend(struct device *dev) +static int __maybe_unused sc530ai_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -1483,7 +1576,7 @@ struct sc530ai *sc530ai = to_sc530ai(sd); struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0); - const struct sc530ai_mode *def_mode = &supported_modes[0]; + const struct sc530ai_mode *def_mode = &sc530ai->support_modes[0]; mutex_lock(&sc530ai->mutex); /* Initialize try_fmt */ @@ -1529,14 +1622,16 @@ struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { - if (fie->index >= ARRAY_SIZE(supported_modes)) + struct sc530ai *sc530ai = to_sc530ai(sd); + + if (fie->index >= sc530ai->support_modes_num) return -EINVAL; - fie->code = supported_modes[fie->index].bus_fmt; - fie->width = supported_modes[fie->index].width; - fie->height = supported_modes[fie->index].height; - fie->interval = supported_modes[fie->index].max_fps; - fie->reserved[0] = supported_modes[fie->index].hdr_mode; + fie->code = sc530ai->support_modes[fie->index].bus_fmt; + fie->width = sc530ai->support_modes[fie->index].width; + fie->height = sc530ai->support_modes[fie->index].height; + fie->interval = sc530ai->support_modes[fie->index].max_fps; + fie->reserved[0] = sc530ai->support_modes[fie->index].hdr_mode; return 0; } @@ -1562,7 +1657,6 @@ static const struct v4l2_subdev_video_ops sc530ai_video_ops = { .s_stream = sc530ai_s_stream, .g_frame_interval = sc530ai_g_frame_interval, - .g_mbus_config = sc530ai_g_mbus_config, }; static const struct v4l2_subdev_pad_ops sc530ai_pad_ops = { @@ -1572,6 +1666,7 @@ .get_fmt = sc530ai_get_fmt, .set_fmt = sc530ai_set_fmt, .get_selection = sc530ai_get_selection, + .get_mbus_config = sc530ai_g_mbus_config, }; static const struct v4l2_subdev_ops sc530ai_subdev_ops = { @@ -1579,6 +1674,14 @@ .video = &sc530ai_video_ops, .pad = &sc530ai_pad_ops, }; + +static void sc530ai_modify_fps_info(struct sc530ai *sc5330ai) +{ + const struct sc530ai_mode *mode = sc5330ai->cur_mode; + + sc5330ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc5330ai->cur_vts; +} static int sc530ai_set_ctrl(struct v4l2_ctrl *ctrl) { @@ -1608,7 +1711,7 @@ switch (ctrl->id) { case V4L2_CID_EXPOSURE: if (sc530ai->cur_mode->hdr_mode != NO_HDR) - return ret; + goto ctrl_end; val = ctrl->val << 1; ret = sc530ai_write_reg(sc530ai->client, SC530AI_REG_EXPOSURE_H, @@ -1627,7 +1730,7 @@ break; case V4L2_CID_ANALOGUE_GAIN: if (sc530ai->cur_mode->hdr_mode != NO_HDR) - return ret; + goto ctrl_end; sc530ai_get_gain_reg(ctrl->val, &again, &dgain, &dgain_fine); ret = sc530ai_write_reg(sc530ai->client, @@ -1642,7 +1745,7 @@ SC530AI_REG_ANA_GAIN, SC530AI_REG_VALUE_08BIT, again); - + dev_dbg(&client->dev, "set gain 0x%x\n", ctrl->val); break; case V4L2_CID_VBLANK: vts = ctrl->val + sc530ai->cur_mode->height; @@ -1654,6 +1757,10 @@ SC530AI_REG_VTS_L, SC530AI_REG_VALUE_08BIT, vts & 0xff); + if (!ret) + sc530ai->cur_vts = vts; + sc530ai_modify_fps_info(sc530ai); + dev_dbg(&client->dev, "set vblank 0x%x\n", ctrl->val); break; case V4L2_CID_HFLIP: ret = sc530ai_read_reg(sc530ai->client, SC530AI_FLIP_MIRROR_REG, @@ -1691,6 +1798,7 @@ break; } +ctrl_end: pm_runtime_put(&client->dev); return ret; @@ -1715,22 +1823,23 @@ fwnode = of_fwnode_handle(endpoint); rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); if (rval <= 0) { - dev_warn(dev, " Get mipi lane num failed!\n"); - return -1; + dev_err(dev, " Get mipi lane num failed!\n"); + return -EINVAL; } sc530ai->lane_num = rval; + dev_info(dev, "lane_num = %d\n", sc530ai->lane_num); if (sc530ai->lane_num == 2) { - sc530ai->cur_mode = &supported_modes[2]; - dev_info(dev, "lane_num(%d)\n", sc530ai->lane_num); - } else if (sc530ai->lane_num == 2) { - sc530ai->cur_mode = &supported_modes[0]; - dev_info(dev, "lane_num(%d)\n", sc530ai->lane_num); - } else { - dev_err(dev, "unsupported lane_num(%d)\n", sc530ai->lane_num); - return -1; + sc530ai->support_modes = supported_modes_2lane; + sc530ai->support_modes_num = ARRAY_SIZE(supported_modes_2lane); + } else if (sc530ai->lane_num == 4) { + sc530ai->support_modes = supported_modes_4lane; + sc530ai->support_modes_num = ARRAY_SIZE(supported_modes_4lane); } + + sc530ai->cur_mode = &sc530ai->support_modes[0]; + return 0; } @@ -1809,6 +1918,8 @@ } sc530ai->subdev.ctrl_handler = handler; sc530ai->has_init_exp = false; + sc530ai->cur_vts = mode->vts_def; + sc530ai->cur_fps = mode->max_fps; return 0; @@ -1824,6 +1935,10 @@ u32 id = 0; int ret; + if (sc530ai->is_thunderboot) { + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); + return 0; + } ret = sc530ai_read_reg(client, SC530AI_REG_CHIP_ID, SC530AI_REG_VALUE_16BIT, &id); if (id != SC530AI_CHIP_ID) { @@ -1857,7 +1972,7 @@ struct v4l2_subdev *sd; char facing[2]; int ret; - u32 i, hdr_mode = 0; + u32 hdr_mode = 0; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, @@ -1882,15 +1997,12 @@ return -EINVAL; } + sc530ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); sc530ai->client = client; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - if (hdr_mode == supported_modes[i].hdr_mode) { - sc530ai->cur_mode = &supported_modes[i]; - break; - } - } - if (i == ARRAY_SIZE(supported_modes)) - sc530ai->cur_mode = &supported_modes[0]; + + ret = sc530ai_parse_of(sc530ai); + if (ret) + return -EINVAL; sc530ai->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(sc530ai->xvclk)) { @@ -1898,11 +2010,13 @@ return -EINVAL; } - sc530ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + sc530ai->reset_gpio = devm_gpiod_get(dev, "reset", + sc530ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); if (IS_ERR(sc530ai->reset_gpio)) dev_warn(dev, "Failed to get reset-gpios\n"); - sc530ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); + sc530ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", + sc530ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); if (IS_ERR(sc530ai->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios\n"); @@ -1928,10 +2042,6 @@ dev_err(dev, "Failed to get power regulators\n"); return ret; } - - ret = sc530ai_parse_of(sc530ai); - if (ret != 0) - return -EINVAL; mutex_init(&sc530ai->mutex); @@ -1980,7 +2090,10 @@ pm_runtime_set_active(dev); pm_runtime_enable(dev); - pm_runtime_idle(dev); + if (sc530ai->is_thunderboot) + pm_runtime_get_sync(dev); + else + pm_runtime_idle(dev); return 0; -- Gitblit v1.6.2