mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
media: i2c: gc2053 support slave mode
Signed-off-by: Yiqing Zeng <zack.zeng@rock-chips.com> Change-Id: Ia851a9de5443c835be9c1c2b1d89625062742682
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user