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/gc2053.c | 396 +++++++++++++++++++++++-------------------------------- 1 files changed, 166 insertions(+), 230 deletions(-) diff --git a/kernel/drivers/media/i2c/gc2053.c b/kernel/drivers/media/i2c/gc2053.c index 1b027fd..8475b67 100644 --- a/kernel/drivers/media/i2c/gc2053.c +++ b/kernel/drivers/media/i2c/gc2053.c @@ -6,6 +6,7 @@ * * V0.0X01.0X00 first version. * V0.0X01.0X01 add quick stream on/off + * V0.0X01.0X02 support slave mode */ #include <linux/clk.h> @@ -35,8 +36,9 @@ #include <media/v4l2-mediabus.h> #include <media/v4l2-subdev.h> -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02) #define GC2053_NAME "gc2053" +#define GC2053_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG10_1X10 #define MIPI_FREQ_297M 297000000 #define GC2053_XVCLK_FREQ 24000000 @@ -53,6 +55,8 @@ #define GC2053_REG_VTS_L 0x42 #define GC2053_REG_CTRL_MODE 0x3E +#define GC2053_MODE_SW_STANDBY 0x11 +#define GC2053_MODE_STREAMING 0x91 #define REG_NULL 0xFF @@ -91,23 +95,6 @@ #define GC2053_NUM_SUPPLIES ARRAY_SIZE(gc2053_supply_names) #define to_gc2053(sd) container_of(sd, struct gc2053, subdev) - -#define USE_DVP_INTERFACE 0 - -#if USE_DVP_INTERFACE - #define GC2053_MEDIA_BUS_FMT MEDIA_BUS_FMT_SRGGB8_1X8 - #define GC2053_MODE_SW_STANDBY 0x00 - #define GC2053_MODE_STREAMING 0x40 -#else - #define GC2053_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG10_1X10 - #define GC2053_MODE_SW_STANDBY 0x11 - #define GC2053_MODE_STREAMING 0x91 -#endif - -enum gc2053_max_pad { - PAD0, - PAD_MAX, -}; struct regval { u8 addr; @@ -154,11 +141,12 @@ unsigned int lane_num; unsigned int cfg_num; unsigned int pixel_rate; - u32 cur_vts; + u32 module_index; const char *module_facing; const char *module_name; const char *len_name; + enum rkmodule_sync_mode sync_mode; struct rkmodule_awb_cfg awb_cfg; struct rkmodule_lsc_cfg lsc_cfg; u8 flip; @@ -316,173 +304,26 @@ {REG_NULL, 0x00}, }; -/* - * window_size=1920*1080 - * mclk=24mhz,pclk=74.25mhz - * pixel_line_total=2200,line_frame_total=1125 - * row_time=29.629us,frame_rate=30fps - */ -static const struct regval __maybe_unused gc2053_1920x1080_regs_dvp[] = { - /****system****/ - {0xfe, 0x80}, - {0xfe, 0x80}, - {0xfe, 0x80}, +static __maybe_unused const struct regval gc2053_master_mode_regs[] = { {0xfe, 0x00}, - {0xf2, 0x00}, - {0xf3, 0x0f}, - {0xf4, 0x36}, - {0xf5, 0xc0}, - {0xf6, 0x44}, - {0xf7, 0x01}, - {0xf8, 0x63}, - {0xf9, 0x40}, - {0xfc, 0x8e}, - /****CISCTL & ANALOG****/ + {0x7f, 0x09}, + {0x82, 0x01}, + {0x83, 0x0c}, + {0x84, 0x80}, + {REG_NULL, 0x00}, +}; + +static __maybe_unused const struct regval gc2053_slave_mode_regs[] = { {0xfe, 0x00}, - {0x87, 0x18}, - {0xee, 0x30}, - {0xd0, 0xb7}, - {0x03, 0x04}, - {0x04, 0x60}, - {0x05, 0x04}, - {0x06, 0x4c}, - {0x07, 0x00}, - {0x08, 0x11}, - {0x09, 0x00}, - {0x0a, 0x02}, - {0x0b, 0x00}, - {0x0c, 0x02}, - {0x0d, 0x04}, - {0x0e, 0x40}, - {0x12, 0xe2}, - {0x13, 0x16}, - {0x19, 0x0a}, - {0x21, 0x1c}, - {0x28, 0x0a}, - {0x29, 0x24}, - {0x2b, 0x04}, - {0x32, 0xf8}, - {0x37, 0x03}, - {0x39, 0x15}, - {0x43, 0x07}, - {0x44, 0x40}, - {0x46, 0x0b}, - {0x4b, 0x20}, - {0x4e, 0x08}, - {0x55, 0x20}, - {0x66, 0x05}, - {0x67, 0x05}, - {0x77, 0x01}, - {0x78, 0x00}, - {0x7c, 0x93}, - {0x8c, 0x12}, - {0x8d, 0x92}, - {0x90, 0x00}, - {0x9d, 0x10}, - {0xce, 0x7c}, - {0xd2, 0x41}, - {0xd3, 0xdc}, - {0xe6, 0x50}, - /*gain*/ - {0xb6, 0xc0}, - {0xb0, 0x70}, - {0xb1, 0x01}, - {0xb2, 0x00}, - {0xb3, 0x00}, - {0xb4, 0x00}, - {0xb8, 0x01}, - {0xb9, 0x00}, - /*blk*/ - {0x26, 0x30}, - {0xfe, 0x01}, - {0x40, 0x23}, - {0x55, 0x07}, - {0x60, 0x40}, - {0xfe, 0x04}, - {0x14, 0x78}, - {0x15, 0x78}, - {0x16, 0x78}, - {0x17, 0x78}, - /*window*/ - {0xfe, 0x01}, - {0x92, 0x00}, - {0x94, 0x03}, - {0x95, 0x04}, - {0x96, 0x38}, - {0x97, 0x07}, - {0x98, 0x80}, - /*ISP*/ - {0xfe, 0x01}, - {0x01, 0x05}, - {0x02, 0x89}, - {0x04, 0x01}, - {0x07, 0xa6}, - {0x08, 0xa9}, - {0x09, 0xa8}, - {0x0a, 0xa7}, - {0x0b, 0xff}, - {0x0c, 0xff}, - {0x0f, 0x00}, - {0x50, 0x1c}, - {0x89, 0x03}, - {0xfe, 0x04}, - {0x28, 0x86}, - {0x29, 0x86}, - {0x2a, 0x86}, - {0x2b, 0x68}, - {0x2c, 0x68}, - {0x2d, 0x68}, - {0x2e, 0x68}, - {0x2f, 0x68}, - {0x30, 0x4f}, - {0x31, 0x68}, - {0x32, 0x67}, - {0x33, 0x66}, - {0x34, 0x66}, - {0x35, 0x66}, - {0x36, 0x66}, - {0x37, 0x66}, - {0x38, 0x62}, - {0x39, 0x62}, - {0x3a, 0x62}, - {0x3b, 0x62}, - {0x3c, 0x62}, - {0x3d, 0x62}, - {0x3e, 0x62}, - {0x3f, 0x62}, - /****DVP & MIPI****/ - {0xfe, 0x01}, - {0x9a, 0x06}, - {0xfe, 0x00}, - {0x7b, 0x2a}, - {0x23, 0x2d}, - {0xfe, 0x03}, - {0x01, 0x20}, - {0x02, 0x56}, - {0x03, 0xb2}, - {0x12, 0x80}, - {0x13, 0x07}, - {0xfe, 0x00}, + {0x7f, 0x09}, + {0x82, 0x0a}, + {0x83, 0x0b}, + {0x84, 0x80}, + {0x85, 0x51}, {REG_NULL, 0x00}, }; static const struct gc2053_mode supported_modes[] = { -#if USE_DVP_INTERFACE - { - .width = 1920, - .height = 1080, - .max_fps = { - .numerator = 10000, - .denominator = 300000, - }, - .exp_def = 0x0010, - .hts_def = 0x0898, - .vts_def = 0x0465, - .reg_list = gc2053_1920x1080_regs_dvp, - .hdr_mode = NO_HDR, - .vc[PAD0] = 0, - }, -#endif { .width = 1920, .height = 1080, @@ -499,11 +340,9 @@ }, }; -#if !USE_DVP_INTERFACE static const s64 link_freq_menu_items[] = { MIPI_FREQ_297M }; -#endif /* sensor register write */ static int gc2053_write_reg(struct i2c_client *client, u8 reg, u8 val) @@ -606,7 +445,7 @@ return &supported_modes[cur_best_fit]; } -static uint8_t gain_reg_table[29][4] = { +static const uint8_t gain_reg_table[29][4] = { {0x00, 0x00, 0x01, 0x00}, {0x00, 0x10, 0x01, 0x0c}, {0x00, 0x20, 0x01, 0x1b}, @@ -638,7 +477,7 @@ {0x00, 0xce, 0x3f, 0x3f}, }; -static uint32_t gain_level_table[29] = { +static const uint32_t gain_level_table[30] = { 64, 76, 91, @@ -668,6 +507,7 @@ 5572, 6552, 7713, + 0xffffffff }; static int gc2053_set_gain(struct gc2053 *gc2053, u32 gain) @@ -675,13 +515,16 @@ int ret; uint8_t i = 0; uint8_t total = 0; - uint8_t temp = 0; + uint32_t temp = 0; total = sizeof(gain_level_table) / sizeof(u32) - 1; - for (i = 0; i < total; i++) { + for (i = 0; i <= total; i++) { if ((gain_level_table[i] <= gain) && (gain < gain_level_table[i+1])) break; } + + if (i > total) + i = total; ret = gc2053_write_reg(gc2053->client, 0xb4, gain_reg_table[i][0]); ret |= gc2053_write_reg(gc2053->client, 0xb3, gain_reg_table[i][1]); @@ -731,8 +574,13 @@ break; case V4L2_CID_VBLANK: vts = ctrl->val + gc2053->cur_mode->height; + /* Note: In master-slave mode, Galaxycore request slave sensor frame rate bigger than master. */ + if (gc2053->sync_mode == INTERNAL_MASTER_MODE) + vts += 10; ret = gc2053_write_reg(gc2053->client, GC2053_REG_VTS_H, (vts >> 8) & 0x3f); ret |= gc2053_write_reg(gc2053->client, GC2053_REG_VTS_L, vts & 0xff); + /* TBD: master and slave not sync to streaming, but except sleep 20ms below */ + usleep_range(20000, 50000); break; case V4L2_CID_HFLIP: if (ctrl->val) @@ -772,7 +620,7 @@ gc2053->supplies); } -static int __maybe_unused gc2053_parse_of_mipi(struct gc2053 *gc2053) +static int gc2053_parse_of(struct gc2053 *gc2053) { struct device *dev = &gc2053->client->dev; struct device_node *endpoint; @@ -795,7 +643,6 @@ if (2 == gc2053->lane_num) { gc2053->cur_mode = &supported_modes[0]; gc2053->cfg_num = ARRAY_SIZE(supported_modes); - gc2053->cur_vts = gc2053->cur_mode->vts_def; /*pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ gc2053->pixel_rate = MIPI_FREQ_297M * 2U * (gc2053->lane_num) / 10U; @@ -811,7 +658,7 @@ { const struct gc2053_mode *mode; struct v4l2_ctrl_handler *handler; - struct v4l2_ctrl __maybe_unused *ctrl; + struct v4l2_ctrl *ctrl; s64 exposure_max, vblank_def; u32 h_blank; int ret; @@ -823,12 +670,10 @@ return ret; handler->lock = &gc2053->mutex; -#if !USE_DVP_INTERFACE ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, link_freq_menu_items); if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -#endif v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, gc2053->pixel_rate, 1, gc2053->pixel_rate); @@ -1013,22 +858,41 @@ static int __gc2053_start_stream(struct gc2053 *gc2053) { + struct i2c_client *client = gc2053->client; int ret; - ret = gc2053_write_array(gc2053->client, gc2053->cur_mode->reg_list); + ret = gc2053_write_array(client, gc2053->cur_mode->reg_list); if (ret) return ret; /* In case these controls are set before streaming */ mutex_unlock(&gc2053->mutex); - v4l2_ctrl_handler_setup(&gc2053->ctrl_handler); + ret = v4l2_ctrl_handler_setup(&gc2053->ctrl_handler); mutex_lock(&gc2053->mutex); - ret = gc2053_set_flip(gc2053, gc2053->flip); + ret |= gc2053_set_flip(gc2053, gc2053->flip); if (ret) return ret; - return gc2053_write_reg(gc2053->client, GC2053_REG_CTRL_MODE, + if (gc2053->sync_mode == INTERNAL_MASTER_MODE) { + ret = gc2053_write_array(client, gc2053_master_mode_regs); + if (ret) + dev_err(&client->dev, + "write internal master mode reg failed %d\n", ret); + } else if (gc2053->sync_mode == EXTERNAL_MASTER_MODE) { + ret = gc2053_write_array(client, gc2053_slave_mode_regs); + if (ret) + dev_err(&client->dev, + "write external master mode reg failed %d\n", ret); + } else if (gc2053->sync_mode == SLAVE_MODE) { + ret = gc2053_write_array(gc2053->client, gc2053_slave_mode_regs); + if (ret) + dev_err(&client->dev, "write slave mode reg failed %d\n", ret); + } + + ret = gc2053_write_reg(gc2053->client, GC2053_REG_CTRL_MODE, GC2053_MODE_STREAMING); + + return ret; } static int __gc2053_stop_stream(struct gc2053 *gc2053) @@ -1041,10 +905,26 @@ struct rkmodule_inf *inf) { memset(inf, 0, sizeof(*inf)); - strscpy(inf->base.sensor, GC2053_NAME, sizeof(inf->base.sensor)); - strscpy(inf->base.module, gc2053->module_name, + strlcpy(inf->base.sensor, GC2053_NAME, sizeof(inf->base.sensor)); + strlcpy(inf->base.module, gc2053->module_name, sizeof(inf->base.module)); - strscpy(inf->base.lens, gc2053->len_name, sizeof(inf->base.lens)); + strlcpy(inf->base.lens, gc2053->len_name, sizeof(inf->base.lens)); +} + +static void gc2053_set_awb_cfg(struct gc2053 *gc2053, + struct rkmodule_awb_cfg *cfg) +{ + mutex_lock(&gc2053->mutex); + memcpy(&gc2053->awb_cfg, cfg, sizeof(*cfg)); + mutex_unlock(&gc2053->mutex); +} + +static void gc2053_set_lsc_cfg(struct gc2053 *gc2053, + struct rkmodule_lsc_cfg *cfg) +{ + mutex_lock(&gc2053->mutex); + memcpy(&gc2053->lsc_cfg, cfg, sizeof(*cfg)); + mutex_unlock(&gc2053->mutex); } static long gc2053_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) @@ -1053,6 +933,7 @@ long ret = 0; struct rkmodule_hdr_cfg *hdr_cfg; u32 stream = 0; + u32 *sync_mode = NULL; switch (cmd) { case RKMODULE_GET_HDR_CFG: @@ -1060,12 +941,14 @@ hdr_cfg->esp.mode = HDR_NORMAL_VC; hdr_cfg->hdr_mode = gc2053->cur_mode->hdr_mode; break; - case RKMODULE_SET_HDR_CFG: - ret = -EINVAL; - dev_err(&gc2053->client->dev, "gc2053 not support hdr mode\n"); - break; case RKMODULE_GET_MODULE_INFO: gc2053_get_module_inf(gc2053, (struct rkmodule_inf *)arg); + break; + case RKMODULE_AWB_CFG: + gc2053_set_awb_cfg(gc2053, (struct rkmodule_awb_cfg *)arg); + break; + case RKMODULE_LSC_CFG: + gc2053_set_lsc_cfg(gc2053, (struct rkmodule_lsc_cfg *)arg); break; case RKMODULE_SET_QUICK_STREAM: @@ -1077,6 +960,14 @@ else ret = gc2053_write_reg(gc2053->client, GC2053_REG_CTRL_MODE, GC2053_MODE_SW_STANDBY); + break; + case RKMODULE_GET_SYNC_MODE: + sync_mode = (u32 *)arg; + *sync_mode = gc2053->sync_mode; + break; + case RKMODULE_SET_SYNC_MODE: + sync_mode = (u32 *)arg; + gc2053->sync_mode = *sync_mode; break; default: ret = -ENOTTY; @@ -1091,9 +982,12 @@ { void __user *up = compat_ptr(arg); struct rkmodule_inf *inf; + struct rkmodule_awb_cfg *awb_cfg; + struct rkmodule_lsc_cfg *lsc_cfg; struct rkmodule_hdr_cfg *hdr; long ret = 0; u32 stream = 0; + u32 sync_mode; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -1110,6 +1004,36 @@ ret = -EFAULT; } kfree(inf); + break; + case RKMODULE_AWB_CFG: + awb_cfg = kzalloc(sizeof(*awb_cfg), GFP_KERNEL); + if (!awb_cfg) { + ret = -ENOMEM; + return ret; + } + + if (copy_from_user(awb_cfg, up, sizeof(*awb_cfg))) { + kfree(awb_cfg); + return -EFAULT; + } + + ret = gc2053_ioctl(sd, cmd, awb_cfg); + kfree(awb_cfg); + break; + case RKMODULE_LSC_CFG: + lsc_cfg = kzalloc(sizeof(*lsc_cfg), GFP_KERNEL); + if (!lsc_cfg) { + ret = -ENOMEM; + return ret; + } + + if (copy_from_user(lsc_cfg, up, sizeof(*lsc_cfg))) { + kfree(lsc_cfg); + return -EFAULT; + } + + ret = gc2053_ioctl(sd, cmd, lsc_cfg); + kfree(lsc_cfg); break; case RKMODULE_GET_HDR_CFG: hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); @@ -1133,8 +1057,10 @@ return ret; } - if (copy_from_user(hdr, up, sizeof(*hdr))) + if (copy_from_user(hdr, up, sizeof(*hdr))) { + kfree(hdr); return -EFAULT; + } ret = gc2053_ioctl(sd, cmd, hdr); kfree(hdr); @@ -1145,8 +1071,23 @@ ret = gc2053_ioctl(sd, cmd, &stream); break; + case RKMODULE_GET_SYNC_MODE: + ret = gc2053_ioctl(sd, cmd, &sync_mode); + if (!ret) { + ret = copy_to_user(up, &sync_mode, sizeof(u32)); + if (ret) + ret = -EFAULT; + } + break; + case RKMODULE_SET_SYNC_MODE: + ret = copy_from_user(&sync_mode, up, sizeof(u32)); + if (!ret) + ret = gc2053_ioctl(sd, cmd, &sync_mode); + else + ret = -EFAULT; + break; default: - ret = -ENOIOCTLCMD; + ret = -ENOTTY; break; } return ret; @@ -1195,22 +1136,14 @@ struct gc2053 *gc2053 = to_gc2053(sd); const struct gc2053_mode *mode = gc2053->cur_mode; - mutex_lock(&gc2053->mutex); fi->interval = mode->max_fps; - mutex_unlock(&gc2053->mutex); return 0; } -static int gc2053_g_mbus_config(struct v4l2_subdev *sd, +static int gc2053_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *config) { -#if USE_DVP_INTERFACE - config->type = V4L2_MBUS_PARALLEL; - config->flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_VSYNC_ACTIVE_LOW | - V4L2_MBUS_PCLK_SAMPLE_RISING; -#else struct gc2053 *gc2053 = to_gc2053(sd); const struct gc2053_mode *mode = gc2053->cur_mode; u32 val = 0; @@ -1220,9 +1153,8 @@ V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - config->type = V4L2_MBUS_CSI2; + config->type = V4L2_MBUS_CSI2_DPHY; config->flags = val; -#endif return 0; } static int gc2053_enum_mbus_code(struct v4l2_subdev *sd, @@ -1409,7 +1341,6 @@ static const struct v4l2_subdev_video_ops gc2053_video_ops = { .s_stream = gc2053_s_stream, .g_frame_interval = gc2053_g_frame_interval, - .g_mbus_config = gc2053_g_mbus_config, }; static const struct v4l2_subdev_pad_ops gc2053_pad_ops = { @@ -1418,6 +1349,7 @@ .enum_frame_interval = gc2053_enum_frame_interval, .get_fmt = gc2053_get_fmt, .set_fmt = gc2053_set_fmt, + .get_mbus_config = gc2053_g_mbus_config, }; static const struct v4l2_subdev_ops gc2053_subdev_ops = { @@ -1426,7 +1358,7 @@ .pad = &gc2053_pad_ops, }; -static int gc2053_runtime_resume(struct device *dev) +static int __maybe_unused gc2053_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -1436,7 +1368,7 @@ return 0; } -static int gc2053_runtime_suspend(struct device *dev) +static int __maybe_unused gc2053_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -1460,6 +1392,7 @@ struct v4l2_subdev *sd; char facing[2]; int ret; + const char *sync_mode_name = NULL; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, @@ -1483,6 +1416,20 @@ dev_err(dev, "could not get module information!\n"); return -EINVAL; + } + + ret = of_property_read_string(node, RKMODULE_CAMERA_SYNC_MODE, + &sync_mode_name); + if (ret) { + gc2053->sync_mode = NO_SYNC_MODE; + dev_err(dev, "could not get sync mode!\n"); + } else { + if (strcmp(sync_mode_name, RKMODULE_EXTERNAL_MASTER_MODE) == 0) + gc2053->sync_mode = EXTERNAL_MASTER_MODE; + else if (strcmp(sync_mode_name, RKMODULE_INTERNAL_MASTER_MODE) == 0) + gc2053->sync_mode = INTERNAL_MASTER_MODE; + else if (strcmp(sync_mode_name, RKMODULE_SLAVE_MODE) == 0) + gc2053->sync_mode = SLAVE_MODE; } gc2053->xvclk = devm_clk_get(&client->dev, "xvclk"); @@ -1509,20 +1456,9 @@ return ret; } -#if USE_DVP_INTERFACE - gc2053->cur_mode = &supported_modes[0]; - gc2053->cfg_num = 1; - gc2053->cur_vts = gc2053->cur_mode->vts_def; - - gc2053->pixel_rate = gc2053->cur_mode->width * - gc2053->cur_mode->height * 8 * 30 / 8; - -#else - ret = gc2053_parse_of_mipi(gc2053); + ret = gc2053_parse_of(gc2053); if (ret != 0) return -EINVAL; - -#endif gc2053->pinctrl = devm_pinctrl_get(dev); if (!IS_ERR(gc2053->pinctrl)) { -- Gitblit v1.6.2