mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
media: i2c: nvp6158: add workqueue & more resolution support
1. add workqueue to detect ahd state.
2. add following resolution support:
AHD30_3M_18P //2048 x 1536@18
AHD30_4M_15P //2560x1440@15
AHD30_4M_30P //2560x1440@30
AHD30_5M_12_5P //2592x 1944 @12.5
AHD30_5M_20P //2592x 1944 @20
AHD30_8M_7_5P //3840x2160 @7.5
AHD30_8M_15P //3840x2160 @15
Signed-off-by: Wang Panzhenzhuan <randy.wang@rock-chips.com>
Change-Id: I6c7b762cacefe7de473a63cb275e1861c9ef096b
This commit is contained in:
committed by
Tao Huang
parent
5b1eeee089
commit
955acd592f
@@ -352,7 +352,7 @@ unsigned int nvp6158_g_vloss=0xFFFF;
|
||||
|
||||
long nvp6158_native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int __user *argp = (unsigned int __user *)arg;
|
||||
unsigned int __user *argp = (unsigned int __user *)arg;
|
||||
int cpy2usr_ret;
|
||||
unsigned char i;
|
||||
//unsigned char oCableDistance = 0;
|
||||
@@ -743,7 +743,7 @@ void nvp6158_set_bt1120_1080P_mode(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
void nvp6158_start(video_init_all *video_init)
|
||||
void nvp6158_start(video_init_all *video_init, bool dual_edge)
|
||||
{
|
||||
unsigned char ch = 0;
|
||||
int chip = 0;
|
||||
@@ -765,59 +765,75 @@ void nvp6158_start(video_init_all *video_init)
|
||||
{
|
||||
/* normal output */
|
||||
case AHD20_720P_25P:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
nvp6158_set_chnmode(ch, AHD20_720P_25P);
|
||||
}
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_720P_25P);
|
||||
break;
|
||||
case AHD20_720P_30P:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
nvp6158_set_chnmode(ch, AHD20_720P_30P);
|
||||
}
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_720P_30P);
|
||||
break;
|
||||
case AHD20_1080P_25P:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
nvp6158_set_chnmode(ch, AHD20_1080P_25P);
|
||||
}
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_1080P_25P);
|
||||
break;
|
||||
case AHD20_1080P_30P:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
nvp6158_set_chnmode(ch, AHD20_1080P_30P);
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_1080P_30P);
|
||||
break;
|
||||
case AHD30_3M_18P:
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++) {
|
||||
if (dual_edge)
|
||||
nvp6158_set_chnmode(ch, AHD30_3M_30P);
|
||||
else
|
||||
nvp6158_set_chnmode(ch, AHD30_3M_18P);
|
||||
|
||||
}
|
||||
break;
|
||||
case AHD30_4M_15P:
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++) {
|
||||
if (dual_edge)
|
||||
nvp6158_set_chnmode(ch, AHD30_4M_30P);
|
||||
else
|
||||
nvp6158_set_chnmode(ch, AHD30_4M_15P);
|
||||
}
|
||||
break;
|
||||
case AHD30_5M_12_5P:
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++) {
|
||||
if (dual_edge)
|
||||
nvp6158_set_chnmode(ch, AHD30_5M_20P);
|
||||
else
|
||||
nvp6158_set_chnmode(ch, AHD30_5M_12_5P);
|
||||
}
|
||||
break;
|
||||
case AHD30_8M_7_5P:
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++) {
|
||||
if (dual_edge)
|
||||
nvp6158_set_chnmode(ch, AHD30_8M_15P);
|
||||
else
|
||||
nvp6158_set_chnmode(ch, AHD30_8M_7_5P);
|
||||
}
|
||||
break;
|
||||
|
||||
/* test output */
|
||||
case AHD20_SD_SH720_NT:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_SD_SH720_NT); /* 720*480i*/
|
||||
}
|
||||
break;
|
||||
case AHD20_SD_SH720_PAL:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_SD_SH720_PAL); /* 720*576i*/
|
||||
}
|
||||
break;
|
||||
case AHD20_SD_H960_PAL:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_SD_H960_PAL); /* 960*576i*/
|
||||
}
|
||||
break;
|
||||
case AHD20_SD_H960_EX_PAL:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_SD_H960_EX_PAL); /*1920*576i*/
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for(ch=0;ch<nvp6158_cnt*4;ch++)
|
||||
{
|
||||
for (ch = 0; ch < nvp6158_cnt * 4; ch++)
|
||||
nvp6158_set_chnmode(ch, AHD20_1080P_30P);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -830,35 +846,45 @@ void nvp6158_start(video_init_all *video_init)
|
||||
/* normal output */
|
||||
case BT656_1MUX:
|
||||
if ((fmt_idx == AHD20_1080P_25P) || (fmt_idx == AHD20_1080P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_FHD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_FHD, 1);
|
||||
}
|
||||
} else if ((fmt_idx == AHD20_720P_25P) || (fmt_idx == AHD20_720P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_HD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_HD, 1);
|
||||
}
|
||||
} else if ((fmt_idx == AHD30_3M_18P) || (fmt_idx == AHD30_4M_15P) ||
|
||||
(fmt_idx == AHD30_5M_12_5P) || (fmt_idx == AHD30_8M_7_5P)) {
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_FHD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_FHD, 1);
|
||||
}
|
||||
} else if ((fmt_idx == AHD20_1080P_50P) || (fmt_idx == AHD20_1080P_60P) ||
|
||||
(fmt_idx == AHD30_3M_30P) || (fmt_idx == AHD30_4M_30P) ||
|
||||
(fmt_idx == AHD30_3M_25P) || (fmt_idx == AHD30_4M_25P) ||
|
||||
(fmt_idx == AHD30_5M_20P) || (fmt_idx == AHD30_8M_15P)) {
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_FHD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_FHD, 1);
|
||||
}
|
||||
}
|
||||
//standard sync head
|
||||
gpio_i2c_write(0x60, 0xFF, 0x00);
|
||||
gpio_i2c_write(0x60, 0x54, 0x00);
|
||||
//VDO2 enabled VDO1 disabled VCLK_1_EN
|
||||
//VDO2/VDO1 enabled VCLK_1/2_EN
|
||||
gpio_i2c_write(0x60, 0xFF, 0x01);
|
||||
gpio_i2c_write(0x60, 0xCA, 0x64);
|
||||
gpio_i2c_write(0x60, 0xCA, 0x66);
|
||||
break;
|
||||
case BT656_2MUX:
|
||||
if ((fmt_idx == AHD20_1080P_25P) || (fmt_idx == AHD20_1080P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_2MUX_FHD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_2MUX_FHD, 0);
|
||||
}
|
||||
} else if ((fmt_idx == AHD20_720P_25P) || (fmt_idx == AHD20_720P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_2MUX_HD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_2MUX_HD, 0);
|
||||
}
|
||||
@@ -872,14 +898,12 @@ void nvp6158_start(video_init_all *video_init)
|
||||
break;
|
||||
case BT1120_1MUX:
|
||||
if ((fmt_idx == AHD20_1080P_25P) || (fmt_idx == AHD20_1080P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_BT1120S_1080P, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_BT1120S_1080P, 0);
|
||||
}
|
||||
} else if ((fmt_idx == AHD20_720P_25P) || (fmt_idx == AHD20_720P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_BT1120S_720P, 1);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_BT1120S_720P, 1);
|
||||
}
|
||||
@@ -890,14 +914,12 @@ void nvp6158_start(video_init_all *video_init)
|
||||
break;
|
||||
case BT1120_2MUX:
|
||||
if ((fmt_idx == AHD20_1080P_25P) || (fmt_idx == AHD20_1080P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_2MUX_BT1120S_1080P, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_2MUX_BT1120S_1080P, 1);
|
||||
}
|
||||
} else if ((fmt_idx == AHD20_720P_25P) || (fmt_idx == AHD20_720P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_2MUX_BT1120S_720P, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_2MUX_BT1120S_720P, 1);
|
||||
}
|
||||
@@ -908,16 +930,19 @@ void nvp6158_start(video_init_all *video_init)
|
||||
break;
|
||||
case BT1120_4MUX:
|
||||
if ((fmt_idx == AHD20_1080P_25P) || (fmt_idx == AHD20_1080P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_4MUX_BT1120S_1080P, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_4MUX_BT1120S_1080P, 1);
|
||||
}
|
||||
} else if ((fmt_idx == AHD20_720P_25P) || (fmt_idx == AHD20_720P_30P)) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_4MUX_BT1120S, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_4MUX_BT1120S, 1);
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
if (dual_edge) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_4MUX_BT1120S_DDR, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_4MUX_BT1120S_DDR, 1);
|
||||
} else {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_4MUX_BT1120S, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_4MUX_BT1120S, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//VDO2/VDO1 enabled VCLK_1_EN/VCLK_2_EN
|
||||
@@ -927,21 +952,21 @@ void nvp6158_start(video_init_all *video_init)
|
||||
/* test output */
|
||||
case BT656I_TEST_MODES:
|
||||
if (fmt_idx == AHD20_SD_H960_EX_PAL) {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_HD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_HD, 1);
|
||||
}
|
||||
} else {
|
||||
for(chip=0;chip<nvp6158_cnt;chip++)
|
||||
{
|
||||
for (chip = 0; chip < nvp6158_cnt; chip++) {
|
||||
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_1MUX_SD, 0);
|
||||
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_1MUX_SD, 1);
|
||||
}
|
||||
}
|
||||
//VDO2 enabled VDO1 disabled VCLK_1_EN
|
||||
gpio_i2c_write(0x60, 0xFF, 0x01);
|
||||
gpio_i2c_write(0x60, 0xCA, 0x64);
|
||||
//gpio_i2c_write(0x60, 0xCA, 0x64);
|
||||
//VDO2/VDO1 enabled VCLK_1_EN/VCLK_2_EN
|
||||
gpio_i2c_write(0x60, 0xCA, 0x66);
|
||||
break;
|
||||
default:
|
||||
printk("mode %d not supported yet\n", mode);
|
||||
|
||||
@@ -26,7 +26,7 @@ long nvp6158_native_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
||||
void nvp6158_i2c_client_exit(void);
|
||||
|
||||
void nvp6158_set_mclk(unsigned int mclk);
|
||||
void nvp6158_start(video_init_all *video_init);
|
||||
void nvp6158_start(video_init_all *video_init, bool dual_edge);
|
||||
void nvp6158_stop(void);
|
||||
int nvp6158_init(int i2c_bus);
|
||||
void nvp6158_exit(void);
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* V0.0X01.0X00 first version.
|
||||
*
|
||||
* V0.0X01.0X01
|
||||
* 1. add workqueue to detect ahd state.
|
||||
* 2. add more resolution support.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -43,7 +45,19 @@
|
||||
#include "nvp6158_video_auto_detect.h"
|
||||
#include "nvp6158_drv.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0)
|
||||
//#define WORK_QUEUE
|
||||
|
||||
#ifdef WORK_QUEUE
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct sensor_state_check_work {
|
||||
struct workqueue_struct *state_check_wq;
|
||||
struct delayed_work d_work;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x1)
|
||||
|
||||
#ifndef V4L2_CID_DIGITAL_GAIN
|
||||
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
|
||||
@@ -115,6 +129,14 @@ struct nvp6158_default_rect {
|
||||
unsigned int height;
|
||||
};
|
||||
|
||||
#ifdef WORK_QUEUE
|
||||
enum nvp6158_hot_plug_state {
|
||||
PLUG_IN = 0,
|
||||
PLUG_OUT,
|
||||
PLUG_STATE_MAX,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct nvp6158 {
|
||||
struct i2c_client *client;
|
||||
struct clk *xvclk;
|
||||
@@ -149,6 +171,14 @@ struct nvp6158 {
|
||||
const struct nvp6158_framesize *frame_size;
|
||||
int streaming;
|
||||
struct nvp6158_default_rect defrect;
|
||||
#ifdef WORK_QUEUE
|
||||
struct sensor_state_check_work plug_state_check;
|
||||
u8 cur_detect_status;
|
||||
u8 last_detect_status;
|
||||
#endif
|
||||
bool hot_plug;
|
||||
u8 is_reset;
|
||||
|
||||
};
|
||||
|
||||
#define to_nvp6158(sd) container_of(sd, struct nvp6158, subdev)
|
||||
@@ -172,6 +202,52 @@ static const struct nvp6158_framesize nvp6158_framesizes[] = {
|
||||
.denominator = 250000,
|
||||
},
|
||||
},
|
||||
{
|
||||
.width = 2048,
|
||||
.height = 1536,
|
||||
.fmt_idx = AHD30_3M_18P,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 180000,
|
||||
},
|
||||
},
|
||||
{
|
||||
.width = 1280,
|
||||
.height = 1440,
|
||||
.fmt_idx = AHD30_4M_30P,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 300000,
|
||||
},
|
||||
},
|
||||
{
|
||||
.width = 2560,
|
||||
.height = 1440,
|
||||
.fmt_idx = AHD30_4M_15P,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 150000,
|
||||
},
|
||||
},
|
||||
{
|
||||
.width = 2592,
|
||||
.height = 1944,
|
||||
.fmt_idx = AHD30_5M_12_5P,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 125000,
|
||||
},
|
||||
},
|
||||
{
|
||||
.width = 3840,
|
||||
.height = 2160,
|
||||
.fmt_idx = AHD30_8M_7_5P,
|
||||
.max_fps = {
|
||||
.numerator = 10000,
|
||||
.denominator = 75000,
|
||||
},
|
||||
},
|
||||
|
||||
/* test modes, Interlace mode*/
|
||||
{
|
||||
.width = 720,
|
||||
@@ -242,6 +318,62 @@ static int nvp6158_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sensor register write */
|
||||
static int nvp6158_write(struct i2c_client *client, u8 reg, u8 val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
dev_info(&client->dev, "write reg(0x%x val:0x%x)!\n", reg, val);
|
||||
buf[0] = reg & 0xFF;
|
||||
buf[1] = val;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags;
|
||||
msg.buf = buf;
|
||||
msg.len = sizeof(buf);
|
||||
|
||||
ret = i2c_transfer(client->adapter, &msg, 1);
|
||||
if (ret >= 0)
|
||||
return 0;
|
||||
|
||||
dev_err(&client->dev,
|
||||
"nvp6158 write reg(0x%x val:0x%x) failed !\n", reg, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sensor register read */
|
||||
static int nvp6158_read(struct i2c_client *client, u8 reg, u8 *val)
|
||||
{
|
||||
struct i2c_msg msg[2];
|
||||
u8 buf[1];
|
||||
int ret;
|
||||
|
||||
buf[0] = reg & 0xFF;
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = client->flags;
|
||||
msg[0].buf = buf;
|
||||
msg[0].len = sizeof(buf);
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = client->flags | I2C_M_RD;
|
||||
msg[1].buf = buf;
|
||||
msg[1].len = 1;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
if (ret >= 0) {
|
||||
*val = buf[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(&client->dev, "nvp6158 read reg(0x%x) failed !\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __nvp6158_power_on(struct nvp6158 *nvp6158)
|
||||
{
|
||||
u32 i;
|
||||
@@ -375,7 +507,7 @@ static int nvp6158_power(struct v4l2_subdev *sd, int on)
|
||||
struct nvp6158 *nvp6158 = to_nvp6158(sd);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: on %d\n", __func__, on);
|
||||
dev_info(&client->dev, "%s: on %d\n", __func__, on);
|
||||
mutex_lock(&nvp6158->mutex);
|
||||
|
||||
/* If the power state is not modified - no work to do. */
|
||||
@@ -514,8 +646,20 @@ static int nvp6158_stream(struct v4l2_subdev *sd, int on)
|
||||
video_init.ch_param[ch].format = fmt_idx;
|
||||
}
|
||||
video_init.mode = nvp6158->mode;
|
||||
nvp6158_start(&video_init);
|
||||
nvp6158_start(&video_init, nvp6158->dual_edge ? true : false);
|
||||
#ifdef WORK_QUEUE
|
||||
if (nvp6158->plug_state_check.state_check_wq) {
|
||||
dev_info(&client->dev, "%s queue_delayed_work 1000ms", __func__);
|
||||
queue_delayed_work(nvp6158->plug_state_check.state_check_wq,
|
||||
&nvp6158->plug_state_check.d_work,
|
||||
msecs_to_jiffies(1000));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#ifdef WORK_QUEUE
|
||||
cancel_delayed_work_sync(&nvp6158->plug_state_check.d_work);
|
||||
dev_info(&client->dev, "cancle_queue_delayed_work");
|
||||
#endif
|
||||
nvp6158_stop();
|
||||
}
|
||||
|
||||
@@ -583,6 +727,100 @@ static int nvp6158_enum_frame_sizes(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* indicate N4 no signal channel */
|
||||
static inline bool nvp6158_no_signal(struct v4l2_subdev *sd, u8 *novid)
|
||||
{
|
||||
struct nvp6158 *nvp6158 = to_nvp6158(sd);
|
||||
struct i2c_client *client = nvp6158->client;
|
||||
u8 videoloss = 0;
|
||||
int ret;
|
||||
bool no_signal = false;
|
||||
|
||||
nvp6158_write(client, 0xff, 0x00);
|
||||
ret = nvp6158_read(client, 0xa8, &videoloss);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Failed to read videoloss state!\n");
|
||||
|
||||
*novid = videoloss;
|
||||
dev_info(&client->dev, "%s: video loss status:0x%x.\n", __func__, videoloss);
|
||||
if (videoloss == 0xf) {
|
||||
dev_info(&client->dev, "%s: all channels No Video detected.\n", __func__);
|
||||
no_signal = true;
|
||||
} else {
|
||||
dev_info(&client->dev, "%s: channel has some video detection.\n", __func__);
|
||||
no_signal = false;
|
||||
}
|
||||
return no_signal;
|
||||
}
|
||||
|
||||
/* indicate N4 channel locked status */
|
||||
static inline bool nvp6158_sync(struct v4l2_subdev *sd, u8 *lock_st)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
u8 video_lock_status = 0;
|
||||
int ret;
|
||||
bool has_sync = false;
|
||||
|
||||
nvp6158_write(client, 0xff, 0x00);
|
||||
ret = nvp6158_read(client, 0xe0, &video_lock_status);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Failed to read sync state!\n");
|
||||
|
||||
dev_info(&client->dev, "%s: video AGC LOCK status:0x%x.\n",
|
||||
__func__, video_lock_status);
|
||||
*lock_st = video_lock_status;
|
||||
if (video_lock_status) {
|
||||
dev_info(&client->dev, "%s: channel has AGC LOCK.\n", __func__);
|
||||
has_sync = true;
|
||||
} else {
|
||||
dev_info(&client->dev, "%s: channel has no AGC LOCK.\n", __func__);
|
||||
has_sync = false;
|
||||
}
|
||||
return has_sync;
|
||||
}
|
||||
|
||||
#ifdef WORK_QUEUE
|
||||
static void nvp6158_plug_state_check_work(struct work_struct *work)
|
||||
{
|
||||
struct sensor_state_check_work *params_check =
|
||||
container_of(work, struct sensor_state_check_work, d_work.work);
|
||||
struct nvp6158 *nvp6158 =
|
||||
container_of(params_check, struct nvp6158, plug_state_check);
|
||||
struct i2c_client *client = nvp6158->client;
|
||||
struct v4l2_subdev *sd = &nvp6158->subdev;
|
||||
u8 novid_status = 0x00;
|
||||
u8 sync_status = 0x00;
|
||||
|
||||
nvp6158_no_signal(sd, &novid_status);
|
||||
nvp6158_sync(sd, &sync_status);
|
||||
nvp6158->cur_detect_status = novid_status;
|
||||
|
||||
/* detect state change to determine is there has plug motion */
|
||||
novid_status = nvp6158->cur_detect_status ^ nvp6158->last_detect_status;
|
||||
if (novid_status)
|
||||
nvp6158->hot_plug = true;
|
||||
else
|
||||
nvp6158->hot_plug = false;
|
||||
nvp6158->last_detect_status = nvp6158->cur_detect_status;
|
||||
|
||||
dev_info(&client->dev, "%s has plug motion? (%s)", __func__,
|
||||
nvp6158->hot_plug ? "true" : "false");
|
||||
if (nvp6158->hot_plug) {
|
||||
dev_info(&client->dev, "queue_delayed_work 1500ms, if has hot plug motion.");
|
||||
queue_delayed_work(nvp6158->plug_state_check.state_check_wq,
|
||||
&nvp6158->plug_state_check.d_work, msecs_to_jiffies(1500));
|
||||
nvp6158_write(client, 0xFF, 0x20);
|
||||
nvp6158_write(client, 0x00, (sync_status << 4) | sync_status);
|
||||
usleep_range(3000, 5000);
|
||||
nvp6158_write(client, 0x00, 0xFF);
|
||||
} else {
|
||||
dev_info(&client->dev, "queue_delayed_work 100ms, if no hot plug motion.");
|
||||
queue_delayed_work(nvp6158->plug_state_check.state_check_wq,
|
||||
&nvp6158->plug_state_check.d_work, msecs_to_jiffies(100));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int nvp6158_g_mbus_config(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_config *cfg)
|
||||
{
|
||||
@@ -738,10 +976,46 @@ nvp6158_get_bt656_module_inf(struct nvp6158 *nvp6158,
|
||||
}
|
||||
}
|
||||
|
||||
static void nvp6158_get_vicap_rst_inf(struct nvp6158 *nvp6158,
|
||||
struct rkmodule_vicap_reset_info *rst_info)
|
||||
{
|
||||
struct i2c_client *client = nvp6158->client;
|
||||
|
||||
rst_info->is_reset = nvp6158->hot_plug;
|
||||
nvp6158->hot_plug = false;
|
||||
rst_info->src = RKCIF_RESET_SRC_ERR_HOTPLUG;
|
||||
dev_info(&client->dev, "%s: rst_info->is_reset:%d.\n", __func__, rst_info->is_reset);
|
||||
}
|
||||
|
||||
static void nvp6158_set_vicap_rst_inf(struct nvp6158 *nvp6158,
|
||||
struct rkmodule_vicap_reset_info rst_info)
|
||||
{
|
||||
nvp6158->is_reset = rst_info.is_reset;
|
||||
}
|
||||
|
||||
static void nvp6158_set_streaming(struct nvp6158 *nvp6158, int on)
|
||||
{
|
||||
struct i2c_client *client = nvp6158->client;
|
||||
|
||||
|
||||
dev_info(&client->dev, "%s: on: %d\n", __func__, on);
|
||||
|
||||
if (on) {
|
||||
//VDO2/VDO1 enabled VCLK_1_EN/VCLK_2_EN
|
||||
nvp6158_write(client, 0xFF, 0x01);
|
||||
nvp6158_write(client, 0xCA, 0x66);
|
||||
} else {
|
||||
//VDO2/VDO1 disable VCLK_1/VCLK_2_DISABLE
|
||||
nvp6158_write(client, 0xFF, 0x01);
|
||||
nvp6158_write(client, 0xCA, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
static long nvp6158_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct nvp6158 *nvp6158 = to_nvp6158(sd);
|
||||
long ret = 0;
|
||||
u32 stream = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case RKMODULE_GET_MODULE_INFO:
|
||||
@@ -757,6 +1031,16 @@ static long nvp6158_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
(nvp6158->mode < NVP6158_DVP_MODES_END))
|
||||
*(int *)arg = RKMODULE_START_STREAM_FRONT;
|
||||
break;
|
||||
case RKMODULE_GET_VICAP_RST_INFO:
|
||||
nvp6158_get_vicap_rst_inf(nvp6158, (struct rkmodule_vicap_reset_info *)arg);
|
||||
break;
|
||||
case RKMODULE_SET_VICAP_RST_INFO:
|
||||
nvp6158_set_vicap_rst_inf(nvp6158, *(struct rkmodule_vicap_reset_info *)arg);
|
||||
break;
|
||||
case RKMODULE_SET_QUICK_STREAM:
|
||||
stream = *((u32 *)arg);
|
||||
nvp6158_set_streaming(nvp6158, !!stream);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
@@ -775,6 +1059,8 @@ static long nvp6158_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
long ret;
|
||||
struct rkmodule_bt656_mbus_info *bt565_inf;
|
||||
int *seq;
|
||||
struct rkmodule_vicap_reset_info *vicap_rst_inf;
|
||||
u32 stream = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case RKMODULE_GET_MODULE_INFO:
|
||||
@@ -785,8 +1071,11 @@ static long nvp6158_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
}
|
||||
|
||||
ret = nvp6158_ioctl(sd, cmd, inf);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, inf, sizeof(*inf));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(inf);
|
||||
break;
|
||||
case RKMODULE_AWB_CFG:
|
||||
@@ -799,6 +1088,8 @@ static long nvp6158_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
ret = copy_from_user(cfg, up, sizeof(*cfg));
|
||||
if (!ret)
|
||||
ret = nvp6158_ioctl(sd, cmd, cfg);
|
||||
else
|
||||
ret = -EFAULT;
|
||||
kfree(cfg);
|
||||
break;
|
||||
case RKMODULE_GET_BT656_MBUS_INFO:
|
||||
@@ -809,8 +1100,11 @@ static long nvp6158_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
}
|
||||
|
||||
ret = nvp6158_ioctl(sd, cmd, bt565_inf);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, bt565_inf, sizeof(*bt565_inf));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(bt565_inf);
|
||||
break;
|
||||
case RKMODULE_GET_START_STREAM_SEQ:
|
||||
@@ -820,11 +1114,49 @@ static long nvp6158_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
return ret;
|
||||
}
|
||||
ret = nvp6158_ioctl(sd, cmd, seq);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, seq, sizeof(*seq));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(seq);
|
||||
break;
|
||||
case RKMODULE_GET_VICAP_RST_INFO:
|
||||
vicap_rst_inf = kzalloc(sizeof(*vicap_rst_inf), GFP_KERNEL);
|
||||
if (!vicap_rst_inf) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvp6158_ioctl(sd, cmd, vicap_rst_inf);
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, vicap_rst_inf, sizeof(*vicap_rst_inf));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(vicap_rst_inf);
|
||||
break;
|
||||
case RKMODULE_SET_VICAP_RST_INFO:
|
||||
vicap_rst_inf = kzalloc(sizeof(*vicap_rst_inf), GFP_KERNEL);
|
||||
if (!vicap_rst_inf) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = copy_from_user(vicap_rst_inf, up, sizeof(*vicap_rst_inf));
|
||||
if (!ret)
|
||||
ret = nvp6158_ioctl(sd, cmd, vicap_rst_inf);
|
||||
else
|
||||
ret = -EFAULT;
|
||||
kfree(vicap_rst_inf);
|
||||
break;
|
||||
case RKMODULE_SET_QUICK_STREAM:
|
||||
ret = copy_from_user(&stream, up, sizeof(u32));
|
||||
if (!ret)
|
||||
ret = nvp6158_ioctl(sd, cmd, &stream);
|
||||
else
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -1178,7 +1510,21 @@ static int nvp6158_probe(struct i2c_client *client,
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_idle(dev);
|
||||
#ifdef WORK_QUEUE
|
||||
/* init work_queue for state_check */
|
||||
INIT_DELAYED_WORK(&nvp6158->plug_state_check.d_work, nvp6158_plug_state_check_work);
|
||||
nvp6158->plug_state_check.state_check_wq =
|
||||
create_singlethread_workqueue("nvp6158_work_queue");
|
||||
if (nvp6158->plug_state_check.state_check_wq == NULL) {
|
||||
dev_err(dev, "%s(%d): %s create failed.\n", __func__, __LINE__,
|
||||
"nvp6158_work_queue");
|
||||
}
|
||||
nvp6158->cur_detect_status = 0x0;
|
||||
nvp6158->last_detect_status = 0x0;
|
||||
nvp6158->hot_plug = false;
|
||||
nvp6158->is_reset = 0;
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
err_clean_entity:
|
||||
@@ -1206,7 +1552,10 @@ static int nvp6158_remove(struct i2c_client *client)
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
__nvp6158_power_off(nvp6158);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
#ifdef WORK_QUEUE
|
||||
if (nvp6158->plug_state_check.state_check_wq != NULL)
|
||||
destroy_workqueue(nvp6158->plug_state_check.state_check_wq);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1140,7 +1140,7 @@ int nvp6168_set_chnmode(const unsigned char ch, const unsigned char chnmode)
|
||||
video_equalizer_info_s vin_eq_set;
|
||||
video_input_novid auto_novid;
|
||||
nvp6158_coax_str s_coax_str;
|
||||
|
||||
|
||||
if(ch >= (nvp6158_cnt*4))
|
||||
{
|
||||
printk("func[nvp6168_set_chnmode] Channel %d is out of range!!!\n", ch);
|
||||
@@ -1258,7 +1258,18 @@ int nvp6158_set_portmode(const unsigned char chip, const unsigned char portsel,
|
||||
gpio_i2c_write(chipaddr, 0xC1+portsel*2, (chid<<4)|chid);
|
||||
tmp = gpio_i2c_read(chipaddr, 0xC8+(portsel/2)) & (portsel%2?0x0F:0xF0);
|
||||
gpio_i2c_write(chipaddr, 0xC8+(portsel/2), tmp);
|
||||
gpio_i2c_write(chipaddr, 0xCC+portsel, 0x58);
|
||||
gpio_i2c_write(chipaddr, 0xCC+portsel, 0x56); //0x40~0x5f adjust delay
|
||||
break;
|
||||
case NVP6158_OUTMODE_1MUX_FHD_DDR:
|
||||
/*Output 720P@5060 /1080P Single Channel data,Data Rate 148.5MHz,Pclk 148.5MHz, Single Edge.*/
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x00);
|
||||
gpio_i2c_write(chipaddr, 0x56, 0x10);
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x01);
|
||||
gpio_i2c_write(chipaddr, 0xC0+portsel*2, (chid<<4)|chid);
|
||||
gpio_i2c_write(chipaddr, 0xC1+portsel*2, (chid<<4)|chid);
|
||||
tmp = gpio_i2c_read(chipaddr, 0xC8+(portsel/2)) & (portsel%2?0x0F:0xF0);
|
||||
gpio_i2c_write(chipaddr, 0xC8+(portsel/2), tmp);
|
||||
gpio_i2c_write(chipaddr, 0xCC+portsel, 0x06); //0x00~0x3f adjust delay
|
||||
break;
|
||||
case NVP6158_OUTMODE_2MUX_SD:
|
||||
/*Output 720H/960H 2 Channel data,Data Rate 74.25MHz,Pclk 74.25MHz, Single Edge.*/
|
||||
@@ -1526,6 +1537,36 @@ int nvp6158_set_portmode(const unsigned char chip, const unsigned char portsel,
|
||||
}
|
||||
break;
|
||||
case NVP6158_OUTMODE_4MUX_BT1120S:
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x00);
|
||||
gpio_i2c_write(chipaddr, 0x56, 0x32);
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x01);
|
||||
if (nvp6158_chip_id[chip] == NVP6158C_R0_ID ||
|
||||
nvp6158_chip_id[chip] == NVP6168C_R0_ID) {
|
||||
//6158C makes 2 bt656 ports to 1 bt1120 port. portsel=[1,2] to choose clock.
|
||||
gpio_i2c_write(chipaddr, 0xC2, 0x54);
|
||||
gpio_i2c_write(chipaddr, 0xC3, 0x76);
|
||||
gpio_i2c_write(chipaddr, 0xC4, 0xdc);
|
||||
gpio_i2c_write(chipaddr, 0xC5, 0xfe);
|
||||
gpio_i2c_write(chipaddr, 0xC8, 0x88);
|
||||
gpio_i2c_write(chipaddr, 0xC9, 0x88);
|
||||
|
||||
//single edge
|
||||
gpio_i2c_write(chipaddr, 0xCD, 0x46); //148.5MHz clock
|
||||
gpio_i2c_write(chipaddr, 0xCE, 0x46); //148.5MHz clock
|
||||
// //dual_edge
|
||||
// gpio_i2c_write(chipaddr, 0xCD, 0x06); //74.25MHz clock
|
||||
// gpio_i2c_write(chipaddr, 0xCE, 0x06); //74.25MHz clock
|
||||
} else {
|
||||
//6158 makes 4 bt656 ports to 2 bt1120 port. portsel=[0,1] to choose clock.
|
||||
gpio_i2c_write(chipaddr, 0xC0+portsel*4, 0xdc);
|
||||
gpio_i2c_write(chipaddr, 0xC1+portsel*4, 0xfe);
|
||||
gpio_i2c_write(chipaddr, 0xC2+portsel*4, 0x54);
|
||||
gpio_i2c_write(chipaddr, 0xC3+portsel*4, 0x76);
|
||||
gpio_i2c_write(chipaddr, 0xC8+(portsel), 0x88);
|
||||
gpio_i2c_write(chipaddr, 0xCC+portsel*2, 0x58); //148.5MHz clock
|
||||
}
|
||||
break;
|
||||
case NVP6158_OUTMODE_4MUX_BT1120S_DDR:
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x00);
|
||||
gpio_i2c_write(chipaddr, 0x56, 0x32);
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x01);
|
||||
@@ -1541,9 +1582,6 @@ int nvp6158_set_portmode(const unsigned char chip, const unsigned char portsel,
|
||||
//dual_edge
|
||||
gpio_i2c_write(chipaddr, 0xCD, 0x06); //74.25MHz clock
|
||||
gpio_i2c_write(chipaddr, 0xCE, 0x06); //74.25MHz clock
|
||||
// //single edge
|
||||
// gpio_i2c_write(chipaddr, 0xCD, 0x46); //148.5MHz clock
|
||||
// gpio_i2c_write(chipaddr, 0xCE, 0x46); //148.5MHz clock
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1553,9 +1591,10 @@ int nvp6158_set_portmode(const unsigned char chip, const unsigned char portsel,
|
||||
gpio_i2c_write(chipaddr, 0xC2+portsel*4, 0x54);
|
||||
gpio_i2c_write(chipaddr, 0xC3+portsel*4, 0x76);
|
||||
gpio_i2c_write(chipaddr, 0xC8+(portsel), 0x88);
|
||||
gpio_i2c_write(chipaddr, 0xCC+portsel*2, 0x58); //148.5MHz clock
|
||||
gpio_i2c_write(chipaddr, 0xCC+portsel*2, 0x58); //148.5MHz clock
|
||||
}
|
||||
break;
|
||||
|
||||
case NVP6158_OUTMODE_4MUX_BT1120S_1080P:
|
||||
gpio_i2c_write(chipaddr, 0xFF, 0x00);
|
||||
gpio_i2c_write(chipaddr, 0x56, 0x32);
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef enum _nvp6158_outmode_sel
|
||||
NVP6158_OUTMODE_1MUX_SD = 0,
|
||||
NVP6158_OUTMODE_1MUX_HD,
|
||||
NVP6158_OUTMODE_1MUX_FHD,
|
||||
NVP6158_OUTMODE_1MUX_FHD_DDR,
|
||||
NVP6158_OUTMODE_2MUX_SD,
|
||||
NVP6158_OUTMODE_2MUX_HD,
|
||||
NVP6158_OUTMODE_2MUX_MIX,
|
||||
@@ -57,6 +58,7 @@ typedef enum _nvp6158_outmode_sel
|
||||
NVP6158_OUTMODE_2MUX_BT1120S_720P,
|
||||
NVP6158_OUTMODE_2MUX_BT1120S_1080P,
|
||||
NVP6158_OUTMODE_4MUX_BT1120S,
|
||||
NVP6158_OUTMODE_4MUX_BT1120S_DDR,
|
||||
NVP6158_OUTMODE_4MUX_BT1120S_720P,
|
||||
NVP6158_OUTMODE_4MUX_BT1120S_1080P,
|
||||
NVP6158_OUTMODE_BUTT
|
||||
|
||||
Reference in New Issue
Block a user