From 1138b3704124eb67e4e6362afebcf0ede972d7af Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Tue, 11 Jun 2024 19:38:58 +0800 Subject: [PATCH] media: i2c: maxim: driver version v3.06.00 Signed-off-by: Cai Wenzhong Change-Id: If0c75766e3a8eaf6ad6921931c526454ca8b0511 --- .../i2c/maxim/local/maxim2c/maxim2c_drv.c | 7 +- .../i2c/maxim/local/maxim2c/maxim2c_drv.h | 16 +++ .../i2c/maxim/local/maxim2c/maxim2c_v4l2.c | 106 +++++++++++++++++ .../i2c/maxim/local/maxim4c/maxim4c_drv.c | 7 +- .../i2c/maxim/local/maxim4c/maxim4c_drv.h | 16 +++ .../i2c/maxim/local/maxim4c/maxim4c_v4l2.c | 107 ++++++++++++++++++ 6 files changed, 257 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c index 4588ce8edf41..ae4ebd53c28d 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c @@ -47,6 +47,11 @@ * 1. unified use __v4l2_ctrl_handler_setup in the xxx_start_stream * 2. support subscribe hot plug detect v4l2 event * + * V3.06.00 + * 1. support multi-channel information configuration + * 2. mode vc initialization when vc-array isn't configured + * 3. fix the issue of mutex deadlock during hot plug + * */ #include #include @@ -74,7 +79,7 @@ #include "maxim2c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x05, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00) #define MAXIM2C_NAME "maxim2c" diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h index c7dc362bef75..b961cb0f0750 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h @@ -49,6 +49,21 @@ struct maxim2c_hot_plug_work { u32 hot_plug_state; }; +struct maxim2c_vc_info { + u32 enable; // 0: disable, !0: enable + + u32 width; + u32 height; + u32 bus_fmt; + + /* + * the following are optional parameters, user-defined data types + * default 0: invalid parameter + */ + u32 data_type; + u32 data_bit; +}; + struct maxim2c_mode { u32 width; u32 height; @@ -61,6 +76,7 @@ struct maxim2c_mode { u32 bpp; const struct regval *reg_list; u32 vc[PAD_MAX]; + struct maxim2c_vc_info vc_info[PAD_MAX]; struct v4l2_rect crop_rect; }; diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c index 00dbef3bd341..09f46e9db148 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c @@ -103,6 +103,7 @@ static int maxim2c_support_mode_init(maxim2c_t *maxim2c) struct device_node *node = NULL; struct maxim2c_mode *mode = NULL; u32 value = 0, vc_array[PAD_MAX], crop_array[4]; + struct maxim2c_vc_info vc_info[PAD_MAX]; int ret = 0, i = 0, array_size = 0; dev_info(dev, "=== maxim2c support mode init ===\n"); @@ -239,6 +240,41 @@ static int maxim2c_support_mode_init(maxim2c_t *maxim2c) for (i = 0; i < PAD_MAX; i++) dev_info(dev, "support mode: vc[%d] = 0x%x\n", i, mode->vc[i]); + /* vc info */ + array_size = of_property_count_u32_elems(node, "vc-info"); + if ((array_size > 0) && + (array_size % sizeof(struct maxim2c_vc_info) == 0) && + (array_size <= sizeof(struct maxim2c_vc_info) * PAD_MAX)) { + + memset((char *)vc_info, 0, sizeof(vc_info)); + + ret = of_property_read_u32_array(node, "vc-info", (u32 *)vc_info, array_size); + if (ret == 0) { + /* */ + for (i = 0; i < PAD_MAX; i++) { + dev_info(dev, "vc-info[%d] property:\n", i); + dev_info(dev, " vc-info[%d].enable = %d:\n", i, vc_info[i].enable); + + dev_info(dev, " vc-info[%d].width = %d:\n", i, vc_info[i].width); + dev_info(dev, " vc-info[%d].height = %d:\n", i, vc_info[i].height); + dev_info(dev, " vc-info[%d].bus_fmt = %d:\n", i, vc_info[i].bus_fmt); + + dev_info(dev, " vc-info[%d].data_type = %d:\n", i, vc_info[i].data_type); + dev_info(dev, " vc-info[%d].data_bit = %d:\n", i, vc_info[i].data_bit); + + mode->vc_info[i].enable = vc_info[i].enable; + + mode->vc_info[i].width = vc_info[i].width; + mode->vc_info[i].height = vc_info[i].height; + mode->vc_info[i].bus_fmt = vc_info[i].bus_fmt; + + mode->vc_info[i].data_type = vc_info[i].data_type; + mode->vc_info[i].data_bit = vc_info[i].data_bit; + + } + } + } + /* crop rect */ array_size = of_property_read_variable_u32_array(node, "crop-rect", crop_array, 1, 4); @@ -354,11 +390,52 @@ static void maxim2c_set_vicap_rst_inf(maxim2c_t *maxim2c, maxim2c->is_reset = rst_info.is_reset; } +static int maxim2c_get_channel_info(maxim2c_t *maxim2c, struct rkmodule_channel_info *ch_info) +{ + const struct maxim2c_mode *mode = maxim2c->cur_mode; + struct device *dev = &maxim2c->client->dev; + + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) + return -EINVAL; + + if (mode->vc_info[ch_info->index].enable) { + ch_info->vc = mode->vc[ch_info->index]; + + ch_info->width = mode->vc_info[ch_info->index].width; + ch_info->height = mode->vc_info[ch_info->index].height; + ch_info->bus_fmt = mode->vc_info[ch_info->index].bus_fmt; + + /* optional parameters, default 0: invalid parameter */ + ch_info->data_type = mode->vc_info[ch_info->index].data_type; + ch_info->data_bit = mode->vc_info[ch_info->index].data_bit; + } else { + ch_info->vc = mode->vc[ch_info->index]; + + ch_info->width = mode->width; + ch_info->height = mode->height; + ch_info->bus_fmt = mode->bus_fmt; + } + + dev_info(dev, "get channel info, ch_info->index = %d\n", ch_info->index); + + dev_info(dev, " ch_info->vc = 0x%x\n", ch_info->vc); + + dev_info(dev, " ch_info->width = %d\n", ch_info->width); + dev_info(dev, " ch_info->height = %d\n", ch_info->height); + dev_info(dev, " ch_info->bus_fmt = 0x%x\n", ch_info->bus_fmt); + + dev_info(dev, " ch_info->data_type = 0x%x:\n", ch_info->data_type); + dev_info(dev, " ch_info->data_bit = %d\n", ch_info->data_bit); + + return 0; +} + static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { maxim2c_t *maxim2c = v4l2_get_subdevdata(sd); struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; + struct rkmodule_channel_info *ch_info; long ret = 0; dev_dbg(&maxim2c->client->dev, "ioctl cmd = 0x%08x\n", cmd); @@ -392,6 +469,10 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) else capture_info->mode = RKMODULE_CAPTURE_MODE_NONE; break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = (struct rkmodule_channel_info *)arg; + ret = maxim2c_get_channel_info(maxim2c, ch_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -409,6 +490,7 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, struct rkmodule_vicap_reset_info *vicap_rst_inf; struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; + struct rkmodule_channel_info *ch_info; long ret = 0; switch (cmd) { @@ -501,6 +583,21 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, } kfree(capture_info); break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + return ret; + } + + ret = maxim2c_ioctl(sd, cmd, ch_info); + if (!ret) { + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); + if (ret) + ret = -EFAULT; + } + kfree(ch_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -914,8 +1011,17 @@ static int maxim2c_get_selection(struct v4l2_subdev *sd, #endif { maxim2c_t *maxim2c = v4l2_get_subdevdata(sd); + int i = 0; if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) { + /* if multiple channel info enable, get_selection isn't support */ + for (i = 0; i < PAD_MAX; i++) { + if (maxim2c->cur_mode->vc_info[i].enable) { + v4l2_warn(sd, "Multi-channel enable, get_selection isn't support\n"); + return -EINVAL; + } + } + sel->r.left = maxim2c->cur_mode->crop_rect.left; sel->r.width = maxim2c->cur_mode->crop_rect.width; sel->r.top = maxim2c->cur_mode->crop_rect.top; diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c index dcfb335a487b..11a2c49324d8 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c @@ -70,6 +70,11 @@ * 1. unified use __v4l2_ctrl_handler_setup in the xxx_start_stream * 2. support subscribe hot plug detect v4l2 event * + * V3.06.00 + * 1. support multi-channel information configuration + * 2. mode vc initialization when vc-array isn't configured + * 3. fix the issue of mutex deadlock during hot plug + * */ #include #include @@ -97,7 +102,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x05, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00) #define MAXIM4C_NAME "maxim4c" diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h index 2ecea27f22bd..18ec7828d0f7 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h @@ -49,6 +49,21 @@ struct maxim4c_hot_plug_work { u32 hot_plug_state; }; +struct maxim4c_vc_info { + u32 enable; // 0: disable, !0: enable + + u32 width; + u32 height; + u32 bus_fmt; + + /* + * the following are optional parameters, user-defined data types + * default 0: invalid parameter + */ + u32 data_type; + u32 data_bit; +}; + struct maxim4c_mode { u32 width; u32 height; @@ -61,6 +76,7 @@ struct maxim4c_mode { u32 bpp; const struct regval *reg_list; u32 vc[PAD_MAX]; + struct maxim4c_vc_info vc_info[PAD_MAX]; struct v4l2_rect crop_rect; }; diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c index 583a09af8d71..c0906470039b 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c @@ -103,6 +103,7 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c) struct device_node *node = NULL; struct maxim4c_mode *mode = NULL; u32 value = 0, vc_array[PAD_MAX], crop_array[4]; + struct maxim4c_vc_info vc_info[PAD_MAX]; int ret = 0, i = 0, array_size = 0; dev_info(dev, "=== maxim4c support mode init ===\n"); @@ -239,6 +240,41 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c) for (i = 0; i < PAD_MAX; i++) dev_info(dev, "support mode: vc[%d] = 0x%x\n", i, mode->vc[i]); + /* vc info */ + array_size = of_property_count_u32_elems(node, "vc-info"); + if ((array_size > 0) && + (array_size % sizeof(struct maxim4c_vc_info) == 0) && + (array_size <= sizeof(struct maxim4c_vc_info) * PAD_MAX)) { + + memset((char *)vc_info, 0, sizeof(vc_info)); + + ret = of_property_read_u32_array(node, "vc-info", (u32 *)vc_info, array_size); + if (ret == 0) { + /* */ + for (i = 0; i < PAD_MAX; i++) { + dev_info(dev, "vc-info[%d] property:\n", i); + dev_info(dev, " vc-info[%d].enable = %d:\n", i, vc_info[i].enable); + + dev_info(dev, " vc-info[%d].width = %d:\n", i, vc_info[i].width); + dev_info(dev, " vc-info[%d].height = %d:\n", i, vc_info[i].height); + dev_info(dev, " vc-info[%d].bus_fmt = %d:\n", i, vc_info[i].bus_fmt); + + dev_info(dev, " vc-info[%d].data_type = %d:\n", i, vc_info[i].data_type); + dev_info(dev, " vc-info[%d].data_bit = %d:\n", i, vc_info[i].data_bit); + + mode->vc_info[i].enable = vc_info[i].enable; + + mode->vc_info[i].width = vc_info[i].width; + mode->vc_info[i].height = vc_info[i].height; + mode->vc_info[i].bus_fmt = vc_info[i].bus_fmt; + + mode->vc_info[i].data_type = vc_info[i].data_type; + mode->vc_info[i].data_bit = vc_info[i].data_bit; + + } + } + } + /* crop rect */ array_size = of_property_read_variable_u32_array(node, "crop-rect", crop_array, 1, 4); @@ -354,11 +390,52 @@ static void maxim4c_set_vicap_rst_inf(maxim4c_t *maxim4c, maxim4c->is_reset = rst_info.is_reset; } +static int maxim4c_get_channel_info(maxim4c_t *maxim4c, struct rkmodule_channel_info *ch_info) +{ + const struct maxim4c_mode *mode = maxim4c->cur_mode; + struct device *dev = &maxim4c->client->dev; + + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) + return -EINVAL; + + if (mode->vc_info[ch_info->index].enable) { + ch_info->vc = mode->vc[ch_info->index]; + + ch_info->width = mode->vc_info[ch_info->index].width; + ch_info->height = mode->vc_info[ch_info->index].height; + ch_info->bus_fmt = mode->vc_info[ch_info->index].bus_fmt; + + /* optional parameters, default 0: invalid parameter */ + ch_info->data_type = mode->vc_info[ch_info->index].data_type; + ch_info->data_bit = mode->vc_info[ch_info->index].data_bit; + } else { + ch_info->vc = mode->vc[ch_info->index]; + + ch_info->width = mode->width; + ch_info->height = mode->height; + ch_info->bus_fmt = mode->bus_fmt; + } + + dev_info(dev, "get channel info, ch_info->index = %d\n", ch_info->index); + + dev_info(dev, " ch_info->vc = 0x%x\n", ch_info->vc); + + dev_info(dev, " ch_info->width = %d\n", ch_info->width); + dev_info(dev, " ch_info->height = %d\n", ch_info->height); + dev_info(dev, " ch_info->bus_fmt = 0x%x\n", ch_info->bus_fmt); + + dev_info(dev, " ch_info->data_type = 0x%x:\n", ch_info->data_type); + dev_info(dev, " ch_info->data_bit = %d\n", ch_info->data_bit); + + return 0; +} + static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { maxim4c_t *maxim4c = v4l2_get_subdevdata(sd); struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; + struct rkmodule_channel_info *ch_info; long ret = 0; dev_dbg(&maxim4c->client->dev, "ioctl cmd = 0x%08x\n", cmd); @@ -392,6 +469,10 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) else capture_info->mode = RKMODULE_CAPTURE_MODE_NONE; break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = (struct rkmodule_channel_info *)arg; + ret = maxim4c_get_channel_info(maxim4c, ch_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -409,6 +490,7 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, struct rkmodule_vicap_reset_info *vicap_rst_inf; struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; + struct rkmodule_channel_info *ch_info; long ret = 0; switch (cmd) { @@ -501,6 +583,21 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, } kfree(capture_info); break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + return ret; + } + + ret = maxim4c_ioctl(sd, cmd, ch_info); + if (!ret) { + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); + if (ret) + ret = -EFAULT; + } + kfree(ch_info); + break; default: ret = -ENOIOCTLCMD; break; @@ -914,8 +1011,18 @@ static int maxim4c_get_selection(struct v4l2_subdev *sd, #endif { maxim4c_t *maxim4c = v4l2_get_subdevdata(sd); + int i = 0; if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) { + /* if multiple channel info enable, get_selection isn't support */ + for (i = 0; i < PAD_MAX; i++) { + if (maxim4c->cur_mode->vc_info[i].enable) { + v4l2_warn(sd, + "Multi-channel enable, get_selection isn't support\n"); + return -EINVAL; + } + } + sel->r.left = maxim4c->cur_mode->crop_rect.left; sel->r.width = maxim4c->cur_mode->crop_rect.width; sel->r.top = maxim4c->cur_mode->crop_rect.top;