From 51556b4a249bde75b191b7f876c62220d0f2e571 Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Tue, 3 Sep 2019 10:56:46 +0800 Subject: [PATCH] media: i2c: gc0312 gc2145: synchronize with kernel4.4 and update to v01.01.01 Change-Id: I93a367cfb4e6376847748c693cc834996a599f9e Signed-off-by: Wang Panzhenzhuan Signed-off-by: Hu Kejun --- drivers/media/i2c/gc0312.c | 114 +++++++++++- drivers/media/i2c/gc2145.c | 349 +++++++++++++++++++++++++++++++++---- 2 files changed, 430 insertions(+), 33 deletions(-) diff --git a/drivers/media/i2c/gc0312.c b/drivers/media/i2c/gc0312.c index ee266fc53a60..41ed4c280579 100644 --- a/drivers/media/i2c/gc0312.c +++ b/drivers/media/i2c/gc0312.c @@ -38,7 +38,8 @@ #include #include #include - +#include +#include #include #include #include @@ -49,6 +50,7 @@ #include #include +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) #define DRIVER_NAME "gc0312" #define GC0312_PIXEL_RATE (96 * 1000 * 1000) @@ -116,6 +118,10 @@ struct gc0312 { struct v4l2_ctrl *link_frequency; const struct gc0312_framesize *frame_size; int streaming; + u32 module_index; + const char *module_facing; + const char *module_name; + const char *len_name; }; static const struct sensor_register gc0312_vga_regs[] = { @@ -737,6 +743,76 @@ static int gc0312_set_fmt(struct v4l2_subdev *sd, return ret; } +static void gc0312_get_module_inf(struct gc0312 *gc0312, + struct rkmodule_inf *inf) +{ + memset(inf, 0, sizeof(*inf)); + strlcpy(inf->base.sensor, DRIVER_NAME, sizeof(inf->base.sensor)); + strlcpy(inf->base.module, gc0312->module_name, + sizeof(inf->base.module)); + strlcpy(inf->base.lens, gc0312->len_name, sizeof(inf->base.lens)); +} + +static long gc0312_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct gc0312 *gc0312 = to_gc0312(sd); + long ret = 0; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + gc0312_get_module_inf(gc0312, (struct rkmodule_inf *)arg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long gc0312_compat_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + void __user *up = compat_ptr(arg); + struct rkmodule_inf *inf; + struct rkmodule_awb_cfg *cfg; + long ret; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + inf = kzalloc(sizeof(*inf), GFP_KERNEL); + if (!inf) { + ret = -ENOMEM; + return ret; + } + + ret = gc0312_ioctl(sd, cmd, inf); + if (!ret) + ret = copy_to_user(up, inf, sizeof(*inf)); + kfree(inf); + break; + case RKMODULE_AWB_CFG: + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(cfg, up, sizeof(*cfg)); + if (!ret) + ret = gc0312_ioctl(sd, cmd, cfg); + kfree(cfg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} +#endif + static int gc0312_s_stream(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -841,6 +917,10 @@ static const struct v4l2_subdev_core_ops gc0312_subdev_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, + .ioctl = gc0312_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = gc0312_compat_ioctl32, +#endif }; static const struct v4l2_subdev_video_ops gc0312_subdev_video_ops = { @@ -981,14 +1061,35 @@ static int gc0312_parse_of(struct gc0312 *gc0312) static int gc0312_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; struct v4l2_subdev *sd; struct gc0312 *gc0312; + char facing[2]; int ret; + dev_info(dev, "driver version: %02x.%02x.%02x", + DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, + DRIVER_VERSION & 0x00ff); + gc0312 = devm_kzalloc(&client->dev, sizeof(*gc0312), GFP_KERNEL); if (!gc0312) return -ENOMEM; + ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, + &gc0312->module_index); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, + &gc0312->module_facing); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, + &gc0312->module_name); + ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, + &gc0312->len_name); + if (ret) { + dev_err(dev, "could not get module information!\n"); + return -EINVAL; + } + gc0312->client = client; gc0312->xvclk = devm_clk_get(&client->dev, "xvclk"); if (IS_ERR(gc0312->xvclk)) { @@ -1051,7 +1152,16 @@ static int gc0312_probe(struct i2c_client *client, if (ret < 0) goto error; - ret = v4l2_async_register_subdev(&gc0312->sd); + memset(facing, 0, sizeof(facing)); + if (strcmp(gc0312->module_facing, "back") == 0) + facing[0] = 'b'; + else + facing[0] = 'f'; + + snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", + gc0312->module_index, facing, + DRIVER_NAME, dev_name(sd->dev)); + ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) goto error; diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index cf3e0c726ac7..9cfaa6300f66 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -38,7 +38,8 @@ #include #include #include - +#include +#include #include #include #include @@ -49,6 +50,7 @@ #include #include +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) #define DRIVER_NAME "gc2145" #define GC2145_PIXEL_RATE (120 * 1000 * 1000) @@ -120,6 +122,10 @@ struct gc2145 { const struct gc2145_framesize *framesize_cfg; unsigned int cfg_num; int streaming; + u32 module_index; + const char *module_facing; + const char *module_name; + const char *len_name; }; static const struct sensor_register gc2145_dvp_init_regs[] = { @@ -158,7 +164,7 @@ static const struct sensor_register gc2145_dvp_init_regs[] = { {0x20, 0x03}, {0x21, 0x40}, {0x22, 0xa0}, - {0x24, 0x16}, + {0x24, 0x3f}, {0x25, 0x01}, {0x26, 0x10}, {0x2d, 0x60}, @@ -1663,9 +1669,29 @@ static const struct sensor_register gc2145_mipi_init_regs[] = { }; static const struct sensor_register gc2145_mipi_full[] = { + {0xfe, 0x00}, + {0x05, 0x01}, + {0x06, 0x56}, + {0x07, 0x00}, + {0x08, 0x32}, + {0xfe, 0x01}, + {0x25, 0x00}, + {0x26, 0xfa}, + + {0x27, 0x04}, + {0x28, 0xe2}, + {0x29, 0x04}, + {0x2a, 0xe2}, + {0x2b, 0x04}, + {0x2c, 0xe2}, + {0x2d, 0x04}, + {0x2e, 0xe2}, + {0xfe, 0x00}, + {0xfe, 0x00}, {0xfd, 0x00}, {0xfa, 0x11}, + {0x18, 0x22}, /*crop window*/ {0xfe, 0x00}, {0x90, 0x01}, @@ -1687,6 +1713,13 @@ static const struct sensor_register gc2145_mipi_full[] = { {0xef, 0x90}, {0xfe, 0x01}, {0x74, 0x01}, + + {0xfe, 0x00}, + {0x7e, 0x3c}, + {0x7f, 0x00}, + {0xfe, 0x01}, + {0xa0, 0x03}, + /*AEC*/ {0xfe, 0x01}, {0x01, 0x04}, @@ -1698,6 +1731,8 @@ static const struct sensor_register gc2145_mipi_full[] = { {0x07, 0x30}, {0x08, 0x80}, {0x0a, 0x82}, + {0x1b, 0x01}, + {0xfe, 0x00}, {0xfe, 0x01}, {0x21, 0x15}, {0xfe, 0x00}, @@ -1711,10 +1746,17 @@ static const struct sensor_register gc2145_mipi_full[] = { {REG_NULL, 0x00}, }; -static const struct sensor_register gc2145_mipi_svga[] = { +static const struct sensor_register gc2145_mipi_svga_20fps[] = { + /*frame rate 50Hz*/ {0xfe, 0x00}, - {0xfd, 0x01}, + {0x05, 0x02}, + {0x06, 0x20}, + {0x07, 0x03}, + {0x08, 0x80}, + {0xb6, 0x01}, + {0xfd, 0x03}, {0xfa, 0x00}, + {0x18, 0x42}, /*crop window*/ {0xfe, 0x00}, {0x90, 0x01}, @@ -1738,6 +1780,12 @@ static const struct sensor_register gc2145_mipi_svga[] = { {0x9d, 0x08}, {0xfe, 0x01}, {0x74, 0x00}, + + {0xfe, 0x00}, + {0x7e, 0x00}, + {0x7f, 0x60}, + {0xfe, 0x01}, + {0xa0, 0x0b}, /*AEC*/ {0xfe, 0x01}, {0x01, 0x04}, @@ -1748,7 +1796,8 @@ static const struct sensor_register gc2145_mipi_svga[] = { {0x06, 0x50}, {0x07, 0x10}, {0x08, 0x38}, - {0x0a, 0x80}, + {0x0a, 0xc0}, + {0x1b, 0x04}, {0x21, 0x04}, {0xfe, 0x00}, {0x20, 0x03}, @@ -1760,6 +1809,86 @@ static const struct sensor_register gc2145_mipi_svga[] = { {0xfe, 0x00}, {REG_NULL, 0x00}, }; + +static const struct sensor_register gc2145_mipi_svga_30fps[] = { + /*frame rate 50Hz*/ + {0xfe, 0x00}, + {0x05, 0x02}, + {0x06, 0x20}, + {0x07, 0x00}, + {0x08, 0xb8}, + {0xfe, 0x01}, + {0x25, 0x01}, + {0x26, 0xac}, + + {0x27, 0x05},//4e2 pad + {0x28, 0x04}, + {0x29, 0x05},//6d6 pad + {0x2a, 0x04}, + {0x2b, 0x05},//7d0 pad + {0x2c, 0x04}, + {0x2d, 0x05}, + {0x2e, 0x04}, + {0xfe, 0x00}, + + {0xfe, 0x00}, + {0xfd, 0x01}, + {0xfa, 0x00}, + {0x18, 0x62}, + {0xfd, 0x03}, + /*crop window*/ + {0xfe, 0x00}, + {0x90, 0x01}, + {0x91, 0x00}, + {0x92, 0x00}, + {0x93, 0x00}, + {0x94, 0x00}, + {0x95, 0x02}, + {0x96, 0x58}, + {0x97, 0x03}, + {0x98, 0x20}, + {0x99, 0x11}, + {0x9a, 0x06}, + /*AWB*/ + {0xfe, 0x00}, + {0xec, 0x02}, + {0xed, 0x02}, + {0xee, 0x30}, + {0xef, 0x48}, + {0xfe, 0x02}, + {0x9d, 0x08}, + {0xfe, 0x01}, + {0x74, 0x00}, + + {0xfe, 0x00}, + {0x7e, 0x00}, + {0x7f, 0x60}, + {0xfe, 0x01}, + {0xa0, 0x0b}, + /*AEC*/ + {0xfe, 0x01}, + {0x01, 0x04}, + {0x02, 0x60}, + {0x03, 0x02}, + {0x04, 0x48}, + {0x05, 0x18}, + {0x06, 0x50}, + {0x07, 0x10}, + {0x08, 0x38}, + {0x0a, 0xc0}, + {0x1b, 0x04}, + {0x21, 0x04}, + {0xfe, 0x00}, + {0x20, 0x03}, + {0xfe, 0x03}, + {0x12, 0x40}, + {0x13, 0x06}, + {0x04, 0x01}, + {0x05, 0x00}, + {0xfe, 0x00}, + {REG_NULL, 0x00}, +}; + static const struct gc2145_framesize gc2145_dvp_framesizes[] = { { /* SVGA */ .width = 800, @@ -1780,16 +1909,21 @@ static const struct gc2145_framesize gc2145_dvp_framesizes[] = { }; static const struct gc2145_framesize gc2145_mipi_framesizes[] = { - { - .width = 800, - .height = 600, - .fps = 20, - .regs = gc2145_mipi_svga, - }, { - .width = 1600, - .height = 1200, - .fps = 10, - .regs = gc2145_mipi_full, + { /* SVGA */ + .width = 800, + .height = 600, + .fps = 20, + .regs = gc2145_mipi_svga_20fps, + }, { /* SVGA */ + .width = 800, + .height = 600, + .fps = 30, + .regs = gc2145_mipi_svga_30fps, + }, { /* FULL */ + .width = 1600, + .height = 1200, + .fps = 10, + .regs = gc2145_mipi_full, } }; @@ -1815,6 +1949,8 @@ static int gc2145_write(struct i2c_client *client, u8 reg, u8 val) u8 buf[2]; int ret; + dev_dbg(&client->dev, "write reg(0x%x val:0x%x)!\n", reg, val); + buf[0] = reg & 0xFF; buf[1] = val; @@ -2085,13 +2221,17 @@ static int gc2145_set_fmt(struct v4l2_subdev *sd, return ret; } +static int gc2145_init(struct v4l2_subdev *sd, u32 val); static int gc2145_s_stream(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct gc2145 *gc2145 = to_gc2145(sd); int ret = 0; - dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); + dev_info(&client->dev, "%s: on: %d, %dx%d@%d\n", __func__, on, + gc2145->frame_size->width, + gc2145->frame_size->height, + gc2145->frame_size->fps); mutex_lock(&gc2145->lock); @@ -2104,23 +2244,12 @@ static int gc2145_s_stream(struct v4l2_subdev *sd, int on) /* Stop Streaming Sequence */ gc2145_set_streaming(gc2145, on); gc2145->streaming = on; - if (!IS_ERR(gc2145->pwdn_gpio)) { - gpiod_set_value_cansleep(gc2145->pwdn_gpio, 1); - usleep_range(2000, 5000); - } goto unlock; } - if (!IS_ERR(gc2145->pwdn_gpio)) { - gpiod_set_value_cansleep(gc2145->pwdn_gpio, 0); - usleep_range(2000, 5000); - } - - if (gc2145->bus_cfg.bus_type == V4L2_MBUS_CSI2) - ret = gc2145_write_array(client, gc2145_mipi_init_regs); - else - ret = gc2145_write_array(client, gc2145_dvp_init_regs); + ret = gc2145_init(sd, 0); + usleep_range(10000, 20000); if (ret) - goto unlock; + dev_err(&client->dev, "init error\n"); ret = gc2145_write_array(client, gc2145->frame_size->regs); if (ret) @@ -2188,6 +2317,9 @@ static int gc2145_g_mbus_config(struct v4l2_subdev *sd, if (gc2145->bus_cfg.bus_type == V4L2_MBUS_CSI2) { config->type = V4L2_MBUS_CSI2; + config->flags = V4L2_MBUS_CSI2_1_LANE | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; } else { config->type = V4L2_MBUS_PARALLEL; config->flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH | @@ -2225,13 +2357,18 @@ static int gc2145_s_frame_interval(struct v4l2_subdev *sd, fi->interval.numerator, fi->interval.denominator); mutex_lock(&gc2145->lock); + if (gc2145->format.width == 1600) goto unlock; + fps = DIV_ROUND_CLOSEST(fi->interval.denominator, fi->interval.numerator); mf = gc2145->format; __gc2145_try_frame_size_fps(gc2145, &mf, &size, fps); + if (gc2145->frame_size != size) { + dev_info(&client->dev, "%s match wxh@FPS is %dx%d@%d\n", + __func__, size->width, size->height, size->fps); ret = gc2145_write_array(client, size->regs); if (ret) goto unlock; @@ -2244,10 +2381,128 @@ unlock: return ret; } +static void gc2145_get_module_inf(struct gc2145 *gc2145, + struct rkmodule_inf *inf) +{ + memset(inf, 0, sizeof(*inf)); + strlcpy(inf->base.sensor, DRIVER_NAME, sizeof(inf->base.sensor)); + strlcpy(inf->base.module, gc2145->module_name, + sizeof(inf->base.module)); + strlcpy(inf->base.lens, gc2145->len_name, sizeof(inf->base.lens)); +} + +static long gc2145_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct gc2145 *gc2145 = to_gc2145(sd); + long ret = 0; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + gc2145_get_module_inf(gc2145, (struct rkmodule_inf *)arg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long gc2145_compat_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + void __user *up = compat_ptr(arg); + struct rkmodule_inf *inf; + struct rkmodule_awb_cfg *cfg; + long ret; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + inf = kzalloc(sizeof(*inf), GFP_KERNEL); + if (!inf) { + ret = -ENOMEM; + return ret; + } + + ret = gc2145_ioctl(sd, cmd, inf); + if (!ret) + ret = copy_to_user(up, inf, sizeof(*inf)); + kfree(inf); + break; + case RKMODULE_AWB_CFG: + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(cfg, up, sizeof(*cfg)); + if (!ret) + ret = gc2145_ioctl(sd, cmd, cfg); + kfree(cfg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} +#endif + +static int gc2145_init(struct v4l2_subdev *sd, u32 val) +{ + int ret; + struct gc2145 *gc2145 = to_gc2145(sd); + struct i2c_client *client = gc2145->client; + + dev_info(&client->dev, "%s(%d)\n", __func__, __LINE__); + + /* soft reset */ + ret = gc2145_write(client, 0xfe, 0xf0); + if (gc2145->bus_cfg.bus_type == V4L2_MBUS_CSI2) + ret = gc2145_write_array(client, gc2145_mipi_init_regs); + else + ret = gc2145_write_array(client, gc2145_dvp_init_regs); + + return ret; +} + +static int gc2145_power(struct v4l2_subdev *sd, int on) +{ + int ret; + struct gc2145 *gc2145 = to_gc2145(sd); + struct i2c_client *client = gc2145->client; + + dev_info(&client->dev, "%s(%d) on(%d)\n", __func__, __LINE__, on); + if (on) { + if (!IS_ERR(gc2145->pwdn_gpio)) { + gpiod_set_value_cansleep(gc2145->pwdn_gpio, 0); + usleep_range(2000, 5000); + } + ret = gc2145_init(sd, 0); + usleep_range(10000, 20000); + if (ret) + dev_err(&client->dev, "init error\n"); + } else { + if (!IS_ERR(gc2145->pwdn_gpio)) { + gpiod_set_value_cansleep(gc2145->pwdn_gpio, 1); + usleep_range(2000, 5000); + } + } + return 0; +} + static const struct v4l2_subdev_core_ops gc2145_subdev_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, + .ioctl = gc2145_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = gc2145_compat_ioctl32, +#endif + .s_power = gc2145_power, }; static const struct v4l2_subdev_video_ops gc2145_subdev_video_ops = { @@ -2313,6 +2568,7 @@ static int __gc2145_power_on(struct gc2145 *gc2145) int ret; struct device *dev = &gc2145->client->dev; + dev_info(dev, "%s(%d)\n", __func__, __LINE__); if (!IS_ERR(gc2145->reset_gpio)) { gpiod_set_value_cansleep(gc2145->reset_gpio, 0); usleep_range(2000, 5000); @@ -2357,6 +2613,7 @@ static int __gc2145_power_on(struct gc2145 *gc2145) static void __gc2145_power_off(struct gc2145 *gc2145) { + dev_info(&gc2145->client->dev, "%s(%d)\n", __func__, __LINE__); if (!IS_ERR(gc2145->xvclk)) clk_disable_unprepare(gc2145->xvclk); if (!IS_ERR(gc2145->supplies)) @@ -2423,14 +2680,35 @@ static int gc2145_parse_of(struct gc2145 *gc2145) static int gc2145_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; struct v4l2_subdev *sd; struct gc2145 *gc2145; + char facing[2]; int ret; + dev_info(dev, "driver version: %02x.%02x.%02x", + DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, + DRIVER_VERSION & 0x00ff); + gc2145 = devm_kzalloc(&client->dev, sizeof(*gc2145), GFP_KERNEL); if (!gc2145) return -ENOMEM; + ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, + &gc2145->module_index); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, + &gc2145->module_facing); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, + &gc2145->module_name); + ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, + &gc2145->len_name); + if (ret) { + dev_err(dev, "could not get module information!\n"); + return -EINVAL; + } + gc2145->client = client; gc2145->xvclk = devm_clk_get(&client->dev, "xvclk"); if (IS_ERR(gc2145->xvclk)) { @@ -2500,7 +2778,16 @@ static int gc2145_probe(struct i2c_client *client, if (ret < 0) goto error; - ret = v4l2_async_register_subdev(&gc2145->sd); + memset(facing, 0, sizeof(facing)); + if (strcmp(gc2145->module_facing, "back") == 0) + facing[0] = 'b'; + else + facing[0] = 'f'; + + snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", + gc2145->module_index, facing, + DRIVER_NAME, dev_name(sd->dev)); + ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) goto error;