mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
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:
committed by
Tao Huang
parent
9d4d900830
commit
51556b4a24
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user