media: i2c: gc0312 gc2145: synchronize with kernel4.4 and update to v01.01.01

Change-Id: I93a367cfb4e6376847748c693cc834996a599f9e
Signed-off-by: Wang Panzhenzhuan <randy.wang@rock-chips.com>
Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
This commit is contained in:
Wang Panzhenzhuan
2019-09-03 10:56:46 +08:00
committed by Tao Huang
parent 9d4d900830
commit 51556b4a24
2 changed files with 430 additions and 33 deletions

View File

@@ -38,7 +38,8 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
@@ -49,6 +50,7 @@
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#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;

View File

@@ -38,7 +38,8 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
@@ -49,6 +50,7 @@
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#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;