diff --git a/drivers/media/i2c/os04a10.c b/drivers/media/i2c/os04a10.c index a2923aa2d624..5cd5dd9ad2dd 100644 --- a/drivers/media/i2c/os04a10.c +++ b/drivers/media/i2c/os04a10.c @@ -9,6 +9,7 @@ * V0.0X01.0X02 add debug interface for conversion gain switch. * V0.0X01.0X03 support enum sensor fmt * V0.0X01.0X04 add quick stream on/off + * V0.0X01.0X05 support get dcg ratio from sensor */ #include @@ -31,7 +32,7 @@ #include #include "../platform/rockchip/isp/rkisp_tb_helper.h" -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x04) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x05) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN @@ -190,6 +191,7 @@ struct os04a10 { bool is_thunderboot_ng; bool is_first_streamoff; u8 flip; + u32 dcg_ratio; }; #define to_os04a10(sd) container_of(sd, struct os04a10, subdev) @@ -1223,6 +1225,10 @@ static int os04a10_set_hdrae(struct os04a10 *os04a10, if (!os04a10->has_init_exp && !os04a10->streaming) { os04a10->init_hdrae_exp = *ae; os04a10->has_init_exp = true; + if (os04a10->init_hdrae_exp.short_exp_reg >= 0x90) { + dev_err(&os04a10->client->dev, "short exposure must less than 0x90 before start stream!\n"); + return -EINVAL; + } dev_dbg(&os04a10->client->dev, "os04a10 don't stream, record exp for hdr!\n"); return ret; } @@ -1445,6 +1451,7 @@ static long os04a10_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct os04a10 *os04a10 = to_os04a10(sd); struct rkmodule_hdr_cfg *hdr_cfg; + struct rkmodule_dcg_ratio *dcg; long ret = 0; u32 i, h, w; u32 stream = 0; @@ -1503,6 +1510,17 @@ static long os04a10_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ret = os04a10_write_reg(os04a10->client, OS04A10_REG_CTRL_MODE, OS04A10_REG_VALUE_08BIT, OS04A10_MODE_SW_STANDBY); break; + case RKMODULE_GET_DCG_RATIO: + if (os04a10->dcg_ratio == 0) + return -EINVAL; + dcg = (struct rkmodule_dcg_ratio *)arg; + dcg->integer = (os04a10->dcg_ratio >> 8) & 0xff; + dcg->decimal = os04a10->dcg_ratio & 0xff; + dcg->div_coeff = 256; + dev_info(&os04a10->client->dev, + "get dcg ratio integer %d, decimal %d div_coeff %d\n", + dcg->integer, dcg->decimal, dcg->div_coeff); + break; default: ret = -ENOIOCTLCMD; break; @@ -1520,6 +1538,7 @@ static long os04a10_compat_ioctl32(struct v4l2_subdev *sd, struct rkmodule_awb_cfg *cfg; struct rkmodule_hdr_cfg *hdr; struct preisp_hdrae_exp_s *hdrae; + struct rkmodule_dcg_ratio *dcg; long ret; u32 cg = 0; u32 stream = 0; @@ -1595,6 +1614,18 @@ static long os04a10_compat_ioctl32(struct v4l2_subdev *sd, if (!ret) ret = os04a10_ioctl(sd, cmd, &stream); break; + case RKMODULE_GET_DCG_RATIO: + dcg = kzalloc(sizeof(*dcg), GFP_KERNEL); + if (!dcg) { + ret = -ENOMEM; + return ret; + } + + ret = os04a10_ioctl(sd, cmd, dcg); + if (!ret) + ret = copy_to_user(up, dcg, sizeof(*dcg)); + kfree(dcg); + break; default: ret = -ENOIOCTLCMD; break; @@ -2184,6 +2215,36 @@ static int os04a10_configure_regulators(struct os04a10 *os04a10) os04a10->supplies); } +static int os04a10_get_dcg_ratio(struct os04a10 *os04a10) +{ + struct device *dev = &os04a10->client->dev; + u32 val = 0; + int ret = 0; + + if (os04a10->is_thunderboot) { + ret = os04a10_read_reg(os04a10->client, 0x77fe, + OS04A10_REG_VALUE_16BIT, &val); + } else { + ret = os04a10_write_reg(os04a10->client, OS04A10_REG_CTRL_MODE, + OS04A10_REG_VALUE_08BIT, OS04A10_MODE_STREAMING); + usleep_range(5000, 6000); + ret |= os04a10_read_reg(os04a10->client, 0x77fe, + OS04A10_REG_VALUE_16BIT, &val); + ret |= os04a10_write_reg(os04a10->client, OS04A10_REG_CTRL_MODE, + OS04A10_REG_VALUE_08BIT, OS04A10_MODE_SW_STANDBY); + } + + if (ret != 0 || val == 0) { + os04a10->dcg_ratio = 0; + dev_err(dev, "get dcg ratio fail, ret %d, dcg ratio %d\n", ret, val); + } else { + os04a10->dcg_ratio = val; + dev_info(dev, "get dcg ratio reg val 0x%04x\n", val); + } + + return ret; +} + static int os04a10_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2285,6 +2346,7 @@ static int os04a10_probe(struct i2c_client *client, ret = os04a10_check_sensor_id(os04a10, client); if (ret) goto err_power_off; + ret = os04a10_get_dcg_ratio(os04a10); #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &os04a10_internal_ops; diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index 14b8dce4d94e..526eb75f3652 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -96,6 +96,10 @@ #define RKMODULE_GET_BT656_MBUS_INFO \ _IOR('V', BASE_VIDIOC_PRIVATE + 17, struct rkmodule_bt656_mbus_info) + +#define RKMODULE_GET_DCG_RATIO \ + _IOR('V', BASE_VIDIOC_PRIVATE + 18, struct rkmodule_dcg_ratio) + /** * struct rkmodule_base_inf - module base information * @@ -419,5 +423,11 @@ struct rkmodule_bt656_mbus_info { __u32 id_en_bits; } __attribute__ ((packed)); +/* DCG ratio (float) = integer + decimal / div_coeff */ +struct rkmodule_dcg_ratio { + u32 integer; + u32 decimal; + u32 div_coeff; +}; #endif /* _UAPI_RKMODULE_CAMERA_H */