From 9a3e2b4d7157609e9c33d6868baaa5baea101693 Mon Sep 17 00:00:00 2001 From: Yiqing Zeng Date: Fri, 24 Feb 2023 17:42:05 +0800 Subject: [PATCH] media: i2c: gc2053 support slave mode Signed-off-by: Yiqing Zeng Change-Id: Ia851a9de5443c835be9c1c2b1d89625062742682 --- drivers/media/i2c/gc2053.c | 141 ++++++++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 26 deletions(-) diff --git a/drivers/media/i2c/gc2053.c b/drivers/media/i2c/gc2053.c index a5074362277d..65df80934211 100644 --- a/drivers/media/i2c/gc2053.c +++ b/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 @@ -35,7 +36,7 @@ #include #include -#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 @@ -145,6 +146,7 @@ struct gc2053 { 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; @@ -302,6 +304,25 @@ static const struct regval gc2053_1920x1080_regs_2lane[] = { {REG_NULL, 0x00}, }; +static __maybe_unused const struct regval gc2053_master_mode_regs[] = { + {0xfe, 0x00}, + {0x7f, 0x09}, + {0x82, 0x01}, + {0x83, 0x0c}, + {0x84, 0x80}, + {REG_NULL, 0x00}, +}; + +static __maybe_unused const struct regval gc2053_slave_mode_regs[] = { + {0xfe, 0x00}, + {0x7f, 0x09}, + {0x82, 0x0a}, + {0x83, 0x0b}, + {0x84, 0x80}, + {0x85, 0x51}, + {REG_NULL, 0x00}, +}; + static const struct gc2053_mode supported_modes[] = { { .width = 1920, @@ -555,6 +576,8 @@ static int gc2053_set_ctrl(struct v4l2_ctrl *ctrl) vts = ctrl->val + gc2053->cur_mode->height; 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); + if (gc2053->sync_mode == INTERNAL_MASTER_MODE) + gc2053_write_reg(gc2053->client, GC2053_REG_VTS_L, (vts & 0xff) + 5); break; case V4L2_CID_HFLIP: if (ctrl->val) @@ -832,9 +855,10 @@ static int gc2053_set_flip(struct gc2053 *gc2053, u8 mode) 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; @@ -843,11 +867,29 @@ static int __gc2053_start_stream(struct gc2053 *gc2053) 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) @@ -888,6 +930,7 @@ static long gc2053_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) long ret = 0; struct rkmodule_hdr_cfg *hdr_cfg; u32 stream = 0; + u32 *sync_mode = NULL; switch (cmd) { case RKMODULE_GET_HDR_CFG: @@ -895,9 +938,6 @@ static long gc2053_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) hdr_cfg->esp.mode = HDR_NORMAL_VC; hdr_cfg->hdr_mode = gc2053->cur_mode->hdr_mode; break; - case RKMODULE_SET_HDR_CFG: - case RKMODULE_SET_CONVERSION_GAIN: - break; case RKMODULE_GET_MODULE_INFO: gc2053_get_module_inf(gc2053, (struct rkmodule_inf *)arg); break; @@ -918,6 +958,14 @@ static long gc2053_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 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; break; @@ -935,8 +983,8 @@ static long gc2053_compat_ioctl32(struct v4l2_subdev *sd, struct rkmodule_lsc_cfg *lsc_cfg; struct rkmodule_hdr_cfg *hdr; long ret = 0; - u32 cg = 0; u32 stream = 0; + u32 sync_mode; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -947,8 +995,11 @@ static long gc2053_compat_ioctl32(struct v4l2_subdev *sd, } ret = gc2053_ioctl(sd, cmd, inf); - if (!ret) + if (!ret) { ret = copy_to_user(up, inf, sizeof(*inf)); + if (ret) + ret = -EFAULT; + } kfree(inf); break; case RKMODULE_AWB_CFG: @@ -958,9 +1009,12 @@ static long gc2053_compat_ioctl32(struct v4l2_subdev *sd, return ret; } - ret = copy_from_user(awb_cfg, up, sizeof(*awb_cfg)); - if (!ret) - ret = gc2053_ioctl(sd, cmd, awb_cfg); + 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: @@ -970,9 +1024,12 @@ static long gc2053_compat_ioctl32(struct v4l2_subdev *sd, return ret; } - ret = copy_from_user(lsc_cfg, up, sizeof(*lsc_cfg)); - if (!ret) - ret = gc2053_ioctl(sd, cmd, lsc_cfg); + 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: @@ -983,8 +1040,11 @@ static long gc2053_compat_ioctl32(struct v4l2_subdev *sd, } ret = gc2053_ioctl(sd, cmd, hdr); - if (!ret) + if (!ret) { ret = copy_to_user(up, hdr, sizeof(*hdr)); + if (ret) + ret = -EFAULT; + } kfree(hdr); break; case RKMODULE_SET_HDR_CFG: @@ -994,20 +1054,34 @@ static long gc2053_compat_ioctl32(struct v4l2_subdev *sd, return ret; } - ret = copy_from_user(hdr, up, sizeof(*hdr)); - if (!ret) - ret = gc2053_ioctl(sd, cmd, hdr); + if (copy_from_user(hdr, up, sizeof(*hdr))) { + kfree(hdr); + return -EFAULT; + } + + ret = gc2053_ioctl(sd, cmd, hdr); kfree(hdr); break; - case RKMODULE_SET_CONVERSION_GAIN: - ret = copy_from_user(&cg, up, sizeof(cg)); - if (!ret) - ret = gc2053_ioctl(sd, cmd, &cg); - break; case RKMODULE_SET_QUICK_STREAM: - ret = copy_from_user(&stream, up, sizeof(u32)); + if (copy_from_user(&stream, up, sizeof(u32))) + return -EFAULT; + + 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, &stream); + ret = gc2053_ioctl(sd, cmd, &sync_mode); + else + ret = -EFAULT; break; default: ret = -ENOTTY; @@ -1315,6 +1389,7 @@ static int gc2053_probe(struct i2c_client *client, 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, @@ -1340,6 +1415,20 @@ static int gc2053_probe(struct i2c_client *client, 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"); if (IS_ERR(gc2053->xvclk)) { dev_err(&client->dev, "Failed to get xvclk\n");