media: i2c: gc2053 support slave mode

Signed-off-by: Yiqing Zeng <zack.zeng@rock-chips.com>
Change-Id: Ia851a9de5443c835be9c1c2b1d89625062742682
This commit is contained in:
Yiqing Zeng
2023-02-24 17:42:05 +08:00
committed by Tao Huang
parent ee38b2089a
commit 9a3e2b4d71

View File

@@ -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,7 +36,7 @@
#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
@@ -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");