641 lines
20 KiB
C
641 lines
20 KiB
C
/*
|
|
Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/version.h>
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/miscdevice.h>
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/init.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/io.h>
|
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)
|
|
#include <asm/switch_to.h>
|
|
#else
|
|
#include <asm/system.h>
|
|
#endif
|
|
#include <linux/interrupt.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/string.h>
|
|
#include <linux/list.h>
|
|
#include <asm/delay.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/poll.h>
|
|
#include <asm/bitops.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/irq.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/semaphore.h>
|
|
#include <linux/kthread.h>
|
|
|
|
#ifdef I2C_INTERNAL
|
|
#include <linux/i2c.h>
|
|
#include <linux/i2c-dev.h>
|
|
#endif
|
|
#include "video.h"
|
|
#include "coax_protocol.h"
|
|
#include "motion.h"
|
|
#include "common.h"
|
|
#include "audio.h"
|
|
#include "video_auto_detect.h"
|
|
#include "video_eq.h"
|
|
|
|
#include "securec.h"
|
|
|
|
#define AF_CNT 1
|
|
|
|
#ifdef I2C_INTERNAL
|
|
static struct i2c_board_info ot_info = {
|
|
I2C_BOARD_INFO("nvp6158", 0x62 >> 1),
|
|
};
|
|
static struct i2c_client *nvp6158_client;
|
|
#endif
|
|
|
|
#define DRIVER_VER "19.04.09.01"
|
|
|
|
#ifdef I2C_INTERNAL
|
|
void __I2CWriteByte8(unsigned char chip_addr, unsigned char reg_addr, unsigned char value)
|
|
{
|
|
unsigned char buf[2];
|
|
struct i2c_client *client = nvp6158_client;
|
|
|
|
nvp6158_client->addr = (chip_addr >> 1);
|
|
|
|
buf[0] = reg_addr;
|
|
buf[1] = value;
|
|
|
|
i2c_master_send(client, buf, 2);
|
|
udelay(300);
|
|
}
|
|
|
|
unsigned char __I2CReadByte8(unsigned char chip_addr, unsigned char reg_addr)
|
|
{
|
|
unsigned char ret_data = 0xFF;
|
|
int ret;
|
|
struct i2c_client *client = nvp6158_client;
|
|
static struct i2c_msg msg[2];
|
|
unsigned char buffer[2];
|
|
const unsigned int data_width = 1;
|
|
|
|
(void)chip_addr;
|
|
buffer[0] = reg_addr & 0xFF;
|
|
|
|
msg[0].addr = client->addr;
|
|
msg[0].flags = 0;
|
|
msg[0].len = 1;
|
|
msg[0].buf = buffer;
|
|
|
|
msg[1].addr = client->addr;
|
|
msg[1].flags = client->flags | I2C_M_RD;
|
|
msg[1].len = 1;
|
|
msg[1].buf = buffer;
|
|
|
|
ret = i2c_transfer(client->adapter, msg, 2);
|
|
if (ret != 2) {
|
|
printk("[%s %d] ot_i2c_transfer error, ret=%d.\n", __FUNCTION__, __LINE__, ret);
|
|
return 0xff;
|
|
}
|
|
|
|
ret = memcpy_s(&ret_data, sizeof(unsigned char), buffer, data_width);
|
|
if (ret != EOK) {
|
|
printk("[%s %d] memcpy_s error, ret=%d.\n", __FUNCTION__, __LINE__, ret);
|
|
return 0xff;
|
|
}
|
|
|
|
return ret_data;
|
|
}
|
|
#endif
|
|
|
|
int g_soc_chiptype = 0x3521;
|
|
int chip_id[4];
|
|
int rev_id[4];
|
|
unsigned int nvp6158_mode = NTSC; // 0:ntsc, 1: pal
|
|
unsigned int nvp6158_cnt = 0;
|
|
unsigned int nvp6158_iic_addr[4] = {0x60, 0x62, 0x64, 0x66};
|
|
module_param(nvp6158_mode, uint, S_IRUGO);
|
|
unsigned int kthread = 0;
|
|
unsigned int detect_kthread = 1;
|
|
module_param(kthread, uint, S_IRUGO);
|
|
unsigned int chnl = TVI_HD_B_25P;
|
|
unsigned int port = NVP6158_OUTMODE_1MUX_HD;
|
|
module_param(chnl, uint, S_IRUGO);
|
|
module_param(port, uint, S_IRUGO);
|
|
|
|
struct semaphore nvp6158_lock;
|
|
unsigned char det_mode[16] = { NVP6158_DET_MODE_AUTO };
|
|
extern unsigned char ch_mode_status[16];
|
|
extern unsigned char ch_vfmt_status[16];
|
|
extern unsigned char acp_isp_wr_en[16];
|
|
unsigned int gCoaxFirmUpdateFlag[16] = { 0 };
|
|
|
|
static struct task_struct *nvp6158_kt = NULL;
|
|
static struct task_struct *nvp6158_detect_kt = NULL;
|
|
|
|
int check_rev(unsigned int dec)
|
|
{
|
|
int ret;
|
|
gpio_i2c_write(dec, 0xFF, 0x00);
|
|
ret = gpio_i2c_read(dec, 0xf5);
|
|
return ret;
|
|
}
|
|
|
|
int check_id(unsigned int dec)
|
|
{
|
|
int ret;
|
|
gpio_i2c_write(dec, 0xFF, 0x00);
|
|
ret = gpio_i2c_read(dec, 0xf4);
|
|
return ret;
|
|
}
|
|
|
|
int nvp6158_open(struct inode *inode, struct file *file)
|
|
{
|
|
(void)inode;
|
|
(void)file;
|
|
return 0;
|
|
}
|
|
|
|
int nvp6158_close(struct inode *inode, struct file *file)
|
|
{
|
|
(void)inode;
|
|
(void)file;
|
|
return 0;
|
|
}
|
|
|
|
unsigned int g_vloss = 0xFFFF;
|
|
|
|
long nvp6158_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
unsigned int __user *argp = (unsigned int __user *)(uintptr_t)arg;
|
|
const int cpy2usr_ret = 0;
|
|
nvp6158_opt_mode optmode;
|
|
nvp6158_chn_mode schnmode;
|
|
nvp6158_audio_format audio_format;
|
|
|
|
if (argp == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
(void)file;
|
|
down(&nvp6158_lock);
|
|
|
|
switch (cmd) {
|
|
case IOC_VDEC_SET_CHNMODE:
|
|
if (copy_from_user(&schnmode, argp, sizeof(nvp6158_chn_mode))) {
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
|
|
if (schnmode.ch >= nvp6158_cnt * CH_PER_CHIP) {
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
|
|
if (chip_id[0] == NVP6158C_R0_ID || chip_id[0] == NVP6158_R0_ID) {
|
|
if (0 == nvp6158_set_chnmode(schnmode.ch, schnmode.chmode)) {
|
|
}
|
|
} else {
|
|
if (0 == nvp6168_set_chnmode(schnmode.ch, schnmode.chmode)) {
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case IOC_VDEC_SET_OUTPORTMODE:
|
|
if (copy_from_user(&optmode, argp, sizeof(nvp6158_opt_mode))) {
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
|
|
if (optmode.chipsel >= nvp6158_cnt || optmode.chipsel >= 4 || optmode.chid >= CH_PER_CHIP) {
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
|
|
if (chip_id[optmode.chipsel] == NVP6158C_R0_ID) {
|
|
if (optmode.portsel != 1 && optmode.portsel != 2) {
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (optmode.portsel >= 4) {
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
nvp6158_set_portmode(optmode.chipsel, optmode.portsel, optmode.portmode, optmode.chid);
|
|
break;
|
|
|
|
case NVP6158_SET_AUDIO_PB_FORMAT:
|
|
if (copy_from_user(&audio_format, argp, sizeof(nvp6158_audio_format))) {
|
|
printk("NVP6158_SET_AUDIO_PB_FORMAT error\n");
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
|
|
nvp6158_audio_set_format(1, &audio_format);
|
|
break;
|
|
case NVP6158_SET_AUDIO_R_FORMAT:
|
|
if (copy_from_user(&audio_format, argp, sizeof(nvp6158_audio_format))) {
|
|
printk("NVP6158_SET_AUDIO_R_FORMAT error\n");
|
|
up(&nvp6158_lock);
|
|
return -1;
|
|
}
|
|
|
|
nvp6158_audio_set_format(0, &audio_format);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (cpy2usr_ret) {
|
|
printk("copy to user return 0x%x\n", cpy2usr_ret);
|
|
}
|
|
|
|
up(&nvp6158_lock);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef I2C_INTERNAL
|
|
static int i2c_client_init(void)
|
|
{
|
|
struct i2c_adapter *i2c_adap;
|
|
|
|
i2c_adap = i2c_get_adapter(0);
|
|
nvp6158_client = i2c_new_device(i2c_adap, &ot_info);
|
|
if (nvp6158_client == NULL) {
|
|
return -1;
|
|
}
|
|
i2c_put_adapter(i2c_adap);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void i2c_client_exit(void)
|
|
{
|
|
if (nvp6158_client != NULL) {
|
|
i2c_unregister_device(nvp6158_client);
|
|
nvp6158_client = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations nvp6158_fops = {
|
|
.owner = THIS_MODULE,
|
|
.unlocked_ioctl = nvp6158_ioctl,
|
|
.open = nvp6158_open,
|
|
.release = nvp6158_close,
|
|
};
|
|
|
|
static struct miscdevice nvp6158_dev = {
|
|
.minor = MISC_DYNAMIC_MINOR,
|
|
.name = "nc_vdec",
|
|
.fops = &nvp6158_fops,
|
|
};
|
|
|
|
static int nvp6158_detect_kernel_thread(void *data)
|
|
{
|
|
unsigned char ch, val_5xf0;
|
|
int chip;
|
|
|
|
(void)data;
|
|
while (!kthread_should_stop()) {
|
|
down(&nvp6158_lock);
|
|
|
|
for (chip = 0; chip < 1; chip++) {
|
|
for (ch = 0; ch < 4; ch++) {
|
|
if (ch_mode_status[0] <= AHD20_SD_H960_2EX_Btype_PAL && ch_mode_status[0] >= AHD20_SD_H960_NT) {
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x05 + ch % 4);
|
|
val_5xf0 = gpio_i2c_read(nvp6158_iic_addr[chip], 0xf0);
|
|
if (val_5xf0 == 0xff) {
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x05 + ch % 4);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x69, 0x00);
|
|
} else {
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x05 + ch % 4);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x69, 0x01);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
up(&nvp6158_lock);
|
|
schedule_timeout_interruptible(msecs_to_jiffies(200));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nvp6158_kernel_thread(void *data)
|
|
{
|
|
NVP6158_INFORMATION_S s_nvp6158_vfmts;
|
|
video_equalizer_info_s s_eq_info;
|
|
unsigned char prefmt, curfmt, chvloss;
|
|
unsigned char ch = 0;
|
|
|
|
(void)data;
|
|
(void)memset_s(&s_nvp6158_vfmts, sizeof(NVP6158_INFORMATION_S), 0, sizeof(NVP6158_INFORMATION_S));
|
|
|
|
while (!kthread_should_stop()) {
|
|
down(&nvp6158_lock);
|
|
ch = ch % (nvp6158_cnt * 4);
|
|
nvp6158_getvideoloss();
|
|
|
|
if (chip_id[0] == NVP6158C_R0_ID || chip_id[0] == NVP6158_R0_ID) {
|
|
video_fmt_det(ch, &s_nvp6158_vfmts);
|
|
curfmt = s_nvp6158_vfmts.curvideofmt[ch];
|
|
prefmt = s_nvp6158_vfmts.prevideofmt[ch];
|
|
chvloss = s_nvp6158_vfmts.curvideoloss[ch];
|
|
|
|
if (chvloss == 0x00) {
|
|
if (ch_mode_status[ch] != prefmt) {
|
|
nvp6158_set_chnmode(ch, curfmt);
|
|
nvp6158_set_portmode(0, ch % 4, NVP6158_OUTMODE_1MUX_FHD, ch % 4);
|
|
s_eq_info.Ch = ch % 4;
|
|
s_eq_info.devnum = ch / 4;
|
|
s_eq_info.FmtDef = curfmt;
|
|
nvp6158_get_eq_dist(&s_eq_info);
|
|
s_nvp6158_vfmts.prevideofmt[ch] = curfmt;
|
|
nvp6158_set_equalizer(&s_eq_info);
|
|
}
|
|
} else {
|
|
if (ch_mode_status[ch] != NC_VIVO_CH_FORMATDEF_UNKNOWN) {
|
|
nvp6158_set_chnmode(ch, NC_VIVO_CH_FORMATDEF_UNKNOWN);
|
|
nvp6158_set_portmode(0, ch % 4, NVP6158_OUTMODE_1MUX_FHD, ch % 4);
|
|
}
|
|
}
|
|
} else {
|
|
nvp6168_video_fmt_det(ch, &s_nvp6158_vfmts);
|
|
curfmt = s_nvp6158_vfmts.curvideofmt[ch];
|
|
prefmt = s_nvp6158_vfmts.prevideofmt[ch];
|
|
chvloss = s_nvp6158_vfmts.curvideoloss[ch];
|
|
|
|
if (chvloss == 0x00) {
|
|
if (ch_mode_status[ch] != prefmt) {
|
|
nvp6168_set_chnmode(ch, curfmt);
|
|
nvp6158_set_portmode(0, ch % 4, NVP6158_OUTMODE_1MUX_FHD, ch % 4);
|
|
s_eq_info.Ch = ch % 4;
|
|
s_eq_info.devnum = ch / 4;
|
|
s_eq_info.FmtDef = curfmt;
|
|
nvp6158_get_eq_dist(&s_eq_info);
|
|
s_nvp6158_vfmts.prevideofmt[ch] = curfmt;
|
|
nvp6168_set_equalizer(&s_eq_info);
|
|
}
|
|
} else {
|
|
if (ch_mode_status[ch] != NC_VIVO_CH_FORMATDEF_UNKNOWN) {
|
|
nvp6168_set_chnmode(ch, NC_VIVO_CH_FORMATDEF_UNKNOWN);
|
|
nvp6158_set_portmode(0, ch % 4, NVP6158_OUTMODE_1MUX_FHD, ch % 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
ch++;
|
|
up(&nvp6158_lock);
|
|
schedule_timeout_interruptible(msecs_to_jiffies(200));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct proc_dir_entry *nvp6158_dir;
|
|
#define NVP6158_PROC_ENTRY "nvp6158"
|
|
static int __init nvp6158_module_init(void)
|
|
{
|
|
int ret = 0;
|
|
unsigned int chip = 0;
|
|
unsigned char ch = 0;
|
|
video_input_auto_detect vin_auto_det;
|
|
ret = misc_register(&nvp6158_dev);
|
|
|
|
if (ret) {
|
|
printk("ERROR: could not register nvp6158_dev devices:%#x \n", ret);
|
|
return -1;
|
|
}
|
|
|
|
|
|
printk("NVP6158/68(C) ex Driver %s COMPILE TIME[%s %s]\n", DRIVER_VER, __DATE__, __TIME__);
|
|
#ifdef I2C_INTERNAL
|
|
if (i2c_client_init() != 0) {
|
|
goto dev_deregister;
|
|
}
|
|
#endif
|
|
|
|
/* check Device ID of maximum 4chip on the slave address,
|
|
* manage slave address. chip count. */
|
|
for (chip = 0; chip < 1; chip++) {
|
|
chip_id[chip] = check_id(nvp6158_iic_addr[chip]);
|
|
rev_id[chip] = check_rev(nvp6158_iic_addr[chip]);
|
|
|
|
if ((chip_id[chip] != NVP6158_R0_ID) && (chip_id[chip] != NVP6158C_R0_ID) && (chip_id[chip] != NVP6168_R0_ID) &&
|
|
(chip_id[chip] != NVP6168C_R0_ID)) {
|
|
} else {
|
|
nvp6158_iic_addr[nvp6158_cnt] = nvp6158_iic_addr[chip];
|
|
|
|
if (nvp6158_cnt < chip) {
|
|
nvp6158_iic_addr[chip] = 0xFF;
|
|
}
|
|
|
|
chip_id[nvp6158_cnt] = chip_id[chip];
|
|
rev_id[nvp6158_cnt] = rev_id[chip];
|
|
nvp6158_cnt++;
|
|
}
|
|
}
|
|
|
|
/* initialize semaphore */
|
|
sema_init(&nvp6158_lock, 1);
|
|
|
|
/* initialize common value of AHD */
|
|
for (chip = 0; (chip < nvp6158_cnt) && (chip < 4); chip++) {
|
|
nvp6158_common_init(chip);
|
|
|
|
if (chip_id[chip] == NVP6158C_R0_ID || chip_id[chip] == NVP6158_R0_ID) {
|
|
nvp6158_additional_for3MoverDef(chip);
|
|
} else {
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x01);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x97, 0x00); // CH_RST ON
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x97, 0x0f); // CH_RST OFF
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x7a, 0x0f); // Clock Auto ON
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xca, 0xff); // VCLK_EN, VDO_EN
|
|
|
|
for (ch = 0; ch < 4; ch++) {
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x05 + ch);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x00, 0xd0);
|
|
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x05, 0x04);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x08, 0x55);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x47, 0xEE);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x59, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x76, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x77, 0x80);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x78, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x79, 0x11);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xB8, 0xB8); // H_PLL_BYPASS
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x7B, 0x11); // v_rst_on
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xb9, 0x72);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xB8, 0xB8); // No Video Set
|
|
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x00 + ch, 0x10);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x22 + (ch * 0x04), 0x0b);
|
|
}
|
|
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x13);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x12, 0x04);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x2E, 0x10);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x30, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x77, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x3a, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x3b, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x3c, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x3d, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x3e, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x3f, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x70, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x72, 0x05);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x7A, 0x10);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x07, 0x47);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x59, 0x24);
|
|
|
|
/* SAM Range */
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x74, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x76, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x78, 0x00);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x75, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x77, 0xff);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x79, 0xff);
|
|
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x01, 0x0c);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x2f, 0xc8);
|
|
|
|
// EQ Stage Get
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x73, 0x23);
|
|
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x09);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x96, 0x03);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xB6, 0x03);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xD6, 0x03);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xF6, 0x03);
|
|
|
|
/* Audio Default Setting */
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0xff, 0x01);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x05, 0x09);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x58, 0x02);
|
|
gpio_i2c_write(nvp6158_iic_addr[chip], 0x59, 0x00);
|
|
}
|
|
}
|
|
|
|
for (ch = 0; ch < nvp6158_cnt * 4; ch++) {
|
|
det_mode[ch] = NVP6158_DET_MODE_AUTO;
|
|
vin_auto_det.ch = ch % 4;
|
|
vin_auto_det.devnum = ch / 4;
|
|
|
|
if (chip_id[0] == NVP6158C_R0_ID || chip_id[0] == NVP6158_R0_ID) {
|
|
video_input_auto_detect_set(&vin_auto_det);
|
|
nvp6158_set_chnmode(ch, chnl);
|
|
} else {
|
|
nvp6168_video_input_auto_detect_set(&vin_auto_det);
|
|
nvp6168_set_chnmode(ch, TVI_HD_B_25P);
|
|
}
|
|
}
|
|
|
|
for (chip = 0; (chip < nvp6158_cnt) && (chip < 4); chip++) {
|
|
if (chip_id[chip] == NVP6158_R0_ID || chip_id[chip] == NVP6168_R0_ID) {
|
|
// nvp6158 4 port output: 0~3 port
|
|
if (port < NVP6158_OUTMODE_1MUX_BT1120S) {
|
|
nvp6158_set_portmode(chip, 0, port, 0);
|
|
nvp6158_set_portmode(chip, 1, port, 1);
|
|
nvp6158_set_portmode(chip, 2, port, 2);
|
|
nvp6158_set_portmode(chip, 3, port, 3);
|
|
} else {
|
|
nvp6158_set_portmode(chip, 0, port, 0);
|
|
nvp6158_set_portmode(chip, 1, port, 1);
|
|
}
|
|
} else {
|
|
// nvp6158C 2 port output: 1~2 port
|
|
nvp6158_set_portmode(chip, 1, NVP6158_OUTMODE_2MUX_FHD, 0);
|
|
nvp6158_set_portmode(chip, 2, NVP6158_OUTMODE_2MUX_FHD, 1);
|
|
}
|
|
}
|
|
/* initialize Audio
|
|
* recmaster, pbmaster, ch_num, samplerate, bits */
|
|
if (chip_id[0] == NVP6158C_R0_ID || chip_id[0] == NVP6158_R0_ID) {
|
|
audio_init(1, 0, 16, 0, 0);
|
|
} else {
|
|
nvp6168_audio_init(1, 0, 16, 0, 0);
|
|
}
|
|
|
|
/* create kernel thread for EQ, But Now not used. */
|
|
if (kthread == 1) {
|
|
nvp6158_kt = kthread_create(nvp6158_kernel_thread, NULL, "nvp6158_kt");
|
|
|
|
if (!IS_ERR(nvp6158_kt)) {
|
|
wake_up_process(nvp6158_kt);
|
|
} else {
|
|
printk("create nvp6158 watchdog thread failed!!\n");
|
|
nvp6158_kt = NULL;
|
|
goto i2c_exit;
|
|
}
|
|
}
|
|
|
|
if (detect_kthread == 1) {
|
|
nvp6158_detect_kt = kthread_create(nvp6158_detect_kernel_thread, NULL, "detect_kt");
|
|
|
|
if (!IS_ERR(nvp6158_detect_kt)) {
|
|
wake_up_process(nvp6158_detect_kt);
|
|
} else {
|
|
printk("create nvp6158 detect thread failed!!\n");
|
|
nvp6158_detect_kt = NULL;
|
|
goto stop_nvp6158_kt_thread;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
stop_nvp6158_kt_thread:
|
|
if (nvp6158_kt != NULL) {
|
|
kthread_stop(nvp6158_kt);
|
|
}
|
|
i2c_exit:
|
|
#ifdef I2C_INTERNAL
|
|
i2c_client_exit();
|
|
dev_deregister:
|
|
#endif
|
|
misc_deregister(&nvp6158_dev);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void __exit nvp6158_module_exit(void)
|
|
{
|
|
if (nvp6158_detect_kt != NULL) {
|
|
kthread_stop(nvp6158_detect_kt);
|
|
}
|
|
|
|
if (nvp6158_kt != NULL) {
|
|
kthread_stop(nvp6158_kt);
|
|
}
|
|
|
|
misc_deregister(&nvp6158_dev);
|
|
#ifdef I2C_INTERNAL
|
|
i2c_client_exit();
|
|
#endif
|
|
printk("NVP6158(C) ex Driver %s COMPILE TIME[%s %s] removed\n", DRIVER_VER, __DATE__, __TIME__);
|
|
}
|
|
|
|
module_init(nvp6158_module_init);
|
|
module_exit(nvp6158_module_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|