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:
Wang Panzhenzhuan
2021-06-29 17:01:47 +08:00
committed by Tao Huang
parent 5b1eeee089
commit 955acd592f
5 changed files with 491 additions and 76 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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