sunrain_hjb的BLOG
ARM.WinCE.Android.Robot.Linux.IoT.VR.Automotive.IVI... Develop Helpful and Effective apps to make Jobs easier and Better!
posts - 235,  comments - 2162,  trackbacks - 3

     这两天在调试TVP5146的驱动程序,之前一直都是LF在负责,现在刚刚接手,很多细节都不清楚。不管三七二十一,先做了一个用于读写TVP5146所有内部寄存器的小工具,通过它可以实时修改其中的任意一个寄存器,而不必编译驱动或内核。image

     实现了这个小工具后,首先切换了一下输入的通道,工作得很好,又从AVIN模式切换到DVD模式,也能看见画面了,虽然有些闪烁,而这就是接下来需要解决的细节问题。

     从网上找到了一份Linux下的参考代码,原厂发布出来的,看上去很靠谱,收藏在这,以备不时之需。

/*
 *
 *
 * Copyright (C) 2006 Texas Instruments Inc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
*/
/* tvp5146.c */

//phoenix
//modified 2008.01.04 PM 15:00 
//linger
//last modified 2007.12.27 PM 17:00
//last modified 2007.11.30 PM 18:00
//last modified 2007.11.29 PM 18:00

#include 
<linux/config.h>
#include 
<linux/init.h>
#include 
<linux/fs.h>
#include 
<linux/vmalloc.h>
#include 
<linux/slab.h>
#include 
<linux/proc_fs.h>
#include 
<linux/ctype.h>
#include 
<linux/delay.h>
#include 
<linux/i2c.h>
#include 
<linux/videodev.h>
#include 
<media/tvp5146.h>            //phoenix 2008/05/14    dvs6446 updates to 

dvevm_1_20
#include 
<asm/arch/gio.h>         //linger 2007.11.8

#define debug_print(x...)    //printk(x)


static struct i2c_client tvp5146_i2c_client;
static struct i2c_driver tvp5146_i2c_driver;
static int tvp5146_i2c_registration = 0;
struct device *tvp5146_i2c_dev;

static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 * val);
static int i2c_write_reg(struct i2c_client *client, u8 reg, u8 val);

static int configtvp5146(void *arg);
static int clrtvp5146lostlock(void);
static int enabletvp5146agc(int arg);
static int getctrl(void *arg);
static int gettvp5146status(void *arg);
static int powerdowntvp5146(int powerdownenable);
static int queryctrl(void *arg);
static int resettvp5146(void);
static int setctrl(void *arg);
static int settvp5146amuxmode(int mode);
static int settvp5146brightness(int arg);
static int settvp5146contrast(int arg);
static int settvp5146hue(int arg);
static int settvp5146saturation(int arg);
static int settvp5146std(int arg);
//static int setup656sync(int enable);
static int setup656sync(tvp5146_params * tvp5146params);

/*
 * ======== tvp5146_init  ========
 
*/
/* This function is used initialize TVP5146 i2c client */
static int tvp5146_init(void)
{
    
int err;
    
struct i2c_driver *driver = &tvp5146_i2c_driver;
    err 
= i2c_add_driver(driver);
    
if (err) {
        printk(KERN_ERR 
"Failed to register TVP5146 I2C client.\n");
    } 
else {
        tvp5146_i2c_registration 
= TVP5146_I2C_REGISTERED;
    }
    
return err;
}

/*
 * ======== tvp5146_cleanup  ========
 
*/
/* This function is used detach TVP5146 i2c client */
static void tvp5146_cleanup(void)
{
    
struct i2c_driver *driver = &tvp5146_i2c_driver;
    
if (tvp5146_i2c_registration) {
        i2c_detach_client(
&tvp5146_i2c_client);
        i2c_del_driver(driver);
        tvp5146_i2c_client.adapter 
= NULL;
        tvp5146_i2c_registration 
= TVP5146_I2C_UNREGISTERED;
    }
}


/*
 * ======== configtvp5146 ========
 
*/
 
static int configtvp5146(void *arg)
{
    tvp5146_params 
*tvp5146params = (tvp5146_params *) arg;
    
int ret = 0;
    ret 
|= gpio_set_direction(41,0);
    ret 
|= __gpio_set(41,1);
    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x030x69);      //phoenix 2008.01.02 modified

    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x080x00);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x090x80);    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0a0x80);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0b0x00);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0c0x80);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0d0x47);      //phoenix 2008.01.02 modified
    ret |= i2c_write_reg(&tvp5146_i2c_client, 0x0F0x02);

    ret 
|= setup656sync(tvp5146params);
    ret 
|= settvp5146amuxmode(tvp5146params->amuxmode);
    ret 
|= settvp5146std(tvp5146params->mode);

    
return ret;
}

/*
 * ======== clrtvp5146lostlock  ========
 
*/
static int clrtvp5146lostlock(void)
{
    
//TVP5150 Not Support
}

/*
 * ========  enabletvp5146agc ========
 
*/
static int enabletvp5146agc(int arg)
{
    
int ret = 0;
    
int agc;
    u8 value;
//    ret = i2c_read_reg(&tvp5146_i2c_client, 0x01, &value);
    
    
if (arg == TRUE) {
        agc 
= 0x01;
    } 
else {
        agc 
= 0x00;
    }
//    agc = agc | value;
    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x01, agc);
        
    
return ret;
}

/*
 * ========  gettvpctrl ========
 
*/
static int getctrl(void *arg)
{
    
struct v4l2_control *ctrl = arg;
    
int ret = 0;
    u8 value;

    
switch (ctrl->id) {
    
case V4L2_CID_BRIGHTNESS:
        ret 
= i2c_read_reg(&tvp5146_i2c_client, 0x09&value);
        ctrl
->value = value;
        
break;
    
case V4L2_CID_CONTRAST:
        ret 
= i2c_read_reg(&tvp5146_i2c_client, 0x0C&value);
        ctrl
->value = value;
        
break;
    
case V4L2_CID_SATURATION:
        ret 
= i2c_read_reg(&tvp5146_i2c_client, 0x0A&value);
        ctrl
->value = value;
        
break;
    
case V4L2_CID_HUE:
        ret 
= i2c_read_reg(&tvp5146_i2c_client, 0x0B&value);
        ctrl
->value = value;
        
break;
    
case V4L2_CID_AUTOGAIN:
        ret 
= i2c_read_reg(&tvp5146_i2c_client, 0x01&value);
        
if ((value & 0x3== 0x01) {
            ctrl
->value = TRUE;
        } 
else {
            ctrl
->value = FALSE;
        }
        
break;
    
default:
        ret 
= -EINVAL;
        
break;
    }
    
return ret;
}

/*
 * ========  gettvp5146std ========
 
*/
static int gettvp5146std(tvp5146_mode * mode)
{
    
int ret = 0;
//    u8 output1;
    u8 std;
    u8 lock_status;

    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x28&std);
    std 
&= 0xF;
    
if(std == TVP5146_MODE_AUTO){
        ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x8C&std);
    
//    std    =    std>>1;
    }
    std 
&= 0xF;    
    
*mode = std;    
    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x88&lock_status);
    
if ((lock_status & 0xe!= 0xe) {
        
/* not quite locked */
        ret 
= -EAGAIN;
    }

    
return ret;
}

/*
 * ========  gettvp5146status ========
 
*/

static int gettvp5146status(void *arg)
{
    
int ret = 0;
    tvp5146_status 
*status = (tvp5146_status *) arg;
    u8 agc, brightness, contrast, hue, saturation;
    u8 status_byte;
    u8 std;

    ret 
= i2c_read_reg(&tvp5146_i2c_client, 0x01&agc);
    
if ((agc & 0x3== 0x01) {
        status
->agc_enable = TRUE;
    } 
else {
        status
->agc_enable = FALSE;
    }
    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x09&brightness);
    status
->brightness = brightness;

    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x0C&contrast);
    status
->contrast = contrast;

    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x0A&saturation);
    status
->saturation = saturation;

    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x0B&hue);
    status
->hue = hue;

    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x88&status_byte);
    status
->field_rate = (status_byte & 0x20? 50 : 60;
    status
->lost_lock = (status_byte & 0x10>> 4;
    status
->csubc_lock = (status_byte & 0x8>> 3;
    status
->v_lock = (status_byte & 0x4>> 2;
    status
->h_lock = (status_byte & 0x2>> 1;

    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x8C&std);
    
if (std | 0x80) {    /* auto switch mode */
        status
->video_std = TVP5146_MODE_AUTO;
    } 
else {
        status
->video_std = std;
    }
    
return ret;
}

/*
 * ======== powerdowntvp5146 ========
 
*/
static int powerdowntvp5146(int powerdownenable)
{
    u8 powerdownsettings 
= 0x01;
    
int ret = 0;
    u8 value;
    
/*Put _tvp5146 in power down mode */
    
if (!powerdownenable) {
        powerdownsettings 
= 0x00;
    }
//    ret = i2c_read_reg(&tvp5146_i2c_client, 0x02, &value);
    
//    powerdownsettings |= value;
    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x02, powerdownsettings);

    
return ret; 
}

/*
 * ======== resettvp5146========
 
*/
static int resettvp5146(void)
{
    tvp5146_params tvp5146params 
= { 0 };
    
    dev_dbg(tvp5146_i2c_dev, 
"\nStarting resettvp5146...");

    
int ret = 0;
    ret 
|= gpio_set_direction(41,0);
    ret 
|= __gpio_set(41,1);
    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x030x69);      //phoenix 2008.01.02 modified

    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x080x00);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x090x80);    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0a0x80);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0b0x00);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0c0x80);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0d0x47);      //phoenix 2008.01.02 modified
    ret |= i2c_write_reg(&tvp5146_i2c_client, 0x0F0x02);
    
    tvp5146params.enablebt656sync 
= TRUE;
    tvp5146params.data_width 
= TVP5146_WIDTH_8BIT;

    setup656sync(
&tvp5146params);

    settvp5146amuxmode(TVP5146_AMUX_COMPOSITE);
    dev_dbg(tvp5146_i2c_dev, 
"\nEnd of resettvp5146...");
}

/*
 * ======== queryctrl ========
 
*/
static int queryctrl(void *arg)
{
    
struct v4l2_queryctrl *queryctrl = arg;
    
int ret = 0;
    
int id = queryctrl->id;

    memset(queryctrl, 
0sizeof(*queryctrl));
    queryctrl
->id = id;
    
switch (id) {
    
case V4L2_CID_BRIGHTNESS:
        strcpy(queryctrl
->name, "BRIGHTNESS");
        queryctrl
->type = V4L2_CTRL_TYPE_INTEGER;
        queryctrl
->minimum = 0;
        queryctrl
->maximum = 255;
        queryctrl
->step = 1;
        queryctrl
->default_value = 128;
        
break;
    
case V4L2_CID_CONTRAST:
        strcpy(queryctrl
->name, "CONTRAST");
        queryctrl
->type = V4L2_CTRL_TYPE_INTEGER;
        queryctrl
->minimum = 0;
        queryctrl
->maximum = 255;
        queryctrl
->step = 1;
        queryctrl
->default_value = 128;
        
break;

    
case V4L2_CID_SATURATION:
        strcpy(queryctrl
->name, "SATURATION");
        queryctrl
->type = V4L2_CTRL_TYPE_INTEGER;
        queryctrl
->minimum = 0;
        queryctrl
->maximum = 255;
        queryctrl
->step = 1;
        queryctrl
->default_value = 128;
        
break;
    
case V4L2_CID_HUE:
        strcpy(queryctrl
->name, "HUE");
        queryctrl
->type = V4L2_CTRL_TYPE_INTEGER;
        queryctrl
->minimum = -128;    /* -180 DEGREE */
        queryctrl
->maximum = 127;    /* 180  DEGREE */
        queryctrl
->step = 1;
        queryctrl
->default_value = 0;    /* 0 DEGREE */
        
break;

    
case V4L2_CID_AUTOGAIN:
        strcpy(queryctrl
->name, "Automatic Gain Control");
        queryctrl
->type = V4L2_CTRL_TYPE_BOOLEAN;
        queryctrl
->minimum = 0;
        queryctrl
->maximum = 1;
        queryctrl
->step = 1;
        queryctrl
->default_value = 1;
        
break;
    
default:
        
/*if (id < V4L2_CID_LASTP1)
            queryctrl->flags = V4L2_CTRL_FLAG_DISABLED;
        else
            ret = -EINVAL;
*/
        
break;
    }            
/* end switch (id) */
    
return ret;
}

/*
 * ======== setctrl ========
 
*/
static int setctrl(void *arg)
{
    
struct v4l2_control *ctrl = arg;
    
int ret = 0;

    
switch (ctrl->id) {
    
case V4L2_CID_BRIGHTNESS:
        ret 
= settvp5146brightness(ctrl->value);
        
break;
    
case V4L2_CID_CONTRAST:
        ret 
= settvp5146contrast(ctrl->value);
        
break;
    
case V4L2_CID_SATURATION:
        ret 
= settvp5146saturation(ctrl->value);
        
break;
    
case V4L2_CID_HUE:
        ret 
= settvp5146hue(ctrl->value);
        
break;
    
case V4L2_CID_AUTOGAIN:
        ret 
= enabletvp5146agc(ctrl->value);
        
break;
    
default:
        ret 
= -EINVAL;
        
break;
    }
    
return ret;
}

/*
 * ======== settvp5146amuxmode ========
 
*/
static int settvp5146amuxmode(int arg)
{
    u8 input_sel;
    
int opmode=0;
    
int ret,value;
    
if (arg == TVP5146_AMUX_COMPOSITE) {    /* composite */
        input_sel 
= 0x00;
        opmode
=0x30;
    } 
else if (arg == TVP5146_AMUX_SVIDEO) {    /* s-video */
        input_sel 
= 0x01;
    } 
else {
        
return -EINVAL;
    }
    
    ret
=i2c_write_reg(&tvp5146_i2c_client, 0x02, opmode);
    ret
=i2c_write_reg(&tvp5146_i2c_client, 0x00, input_sel);
    
    ret 
|= i2c_read_reg(&tvp5146_i2c_client, 0x03&value);
    
    value 
= (value & ~0x10| 0x40;
    
    ret
=i2c_write_reg(&tvp5146_i2c_client, 0x03, value);
    
return ret;
}

/*
 * ======== settvp5146brightness ========
 
*/
static int settvp5146brightness(int arg)
{
    
int ret = 0;
    u8 brightness 
= (u8) arg;
    ret 
= i2c_write_reg(&tvp5146_i2c_client, 0x09, brightness);

    
return ret;
}

/*
* ======== settvp5146contrast ========
*/
static int settvp5146contrast(int arg)
{
    
int ret = 0;
    u8 contrast 
= (u8) arg;
    ret 
= i2c_write_reg(&tvp5146_i2c_client, 0x0C, contrast);

    
return ret;
}

/*
* ======== settvp5146hue ========
*/
static int settvp5146hue(int arg)
{
    
int ret = 0;
    u8 hue 
= (u8) arg;
    ret 
= i2c_write_reg(&tvp5146_i2c_client, 0x0C, hue);
    
    
return ret;
}

static int settvp5146saturation(int arg)
{
    
int ret = 0;
    u8 saturation 
= (u8) arg;
    ret 
= i2c_write_reg(&tvp5146_i2c_client, 0x0A, saturation);

    
return ret;
}

static int settvp5146std(int arg)
{
    
int ret = 0;
    u8 std 
= (u8) arg & 0xF;    /* the 4th-bit is for squre pixel sampling */

    
int fmt=0;
    
/* setup the sampling rate: 601 or square pixel */
    debug_print(KERN_INFO 
"reading i2c registers.\n");

    
/* First tests should be against specific std */
    
if (std == V4L2_STD_ALL) {
        fmt
=0;    /* Autodetect mode */
    } 
else if (std & V4L2_STD_PAL_M) {
        fmt
=0x6;
    } 
else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) {
        fmt
=0x8;
    } 
else {
        
/* Then, test against generic ones */
        
if (std & V4L2_STD_NTSC) {
            fmt
=0x2;
        } 
else if (std & V4L2_STD_PAL) {
            fmt
=0x4;
        } 
else if (std & V4L2_STD_SECAM) {
            fmt
=0xc;
        }
    }
    
/* setup the video standard */
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x28, fmt);

    
/* if autoswitch mode, enable all modes for autoswitch */
    
if (std == TVP5146_MODE_AUTO) {
        u8 mask 
= 0x3C;    /* enable autoswitch for  all standards */
        ret 
= i2c_write_reg(&tvp5146_i2c_client, 0x04, mask);
    }

    
return ret;
}

/*
 * ======== setup656sync ========
 
*/
  
//Un
//static int setup656sync(int enable)
static int setup656sync(tvp5146_params * tvp5146params)
{
    
int output1, output2, output3, output4;
    
int output5, output6;
    
int ret = 0;

        
if ((tvp5146params->enablebt656sync)
        
&& (tvp5146params->data_width == TVP5146_WIDTH_8BIT))  {
        output1 
= 0x47;
        output4 
= 0xFF;
        output6 
= 0;
    } 
else {
        output1 
= 0x40;
        output4 
= 0xAF;
        output6 
= 0x1E;
    }

    output2 
= 0x69;        /* enable clock, enable Y[9:0] */
    output3 
= 0x0;
    output5 
= 0x4;

    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0D, output1);
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x03, output2);
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0E, output3);
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x36, output4);
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0E, output3);
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x1B, output5);
    
//ret |= i2c_write_reg(&tvp5146_i2c_client, 0x1B, output5);
    
    
return ret;
}

/*
 * ======== tvp5146_ctrl ========
 
*/
int tvp5146_ctrl(tvp5146_cmd cmd, void *arg)
{
    
int ret = 0;
    
switch (cmd) {
    
case TVP5146_CONFIG:
        ret 
= configtvp5146(arg);
        
break;
    
case TVP5146_RESET:
        ret 
= resettvp5146();
        
break;
    
case TVP5146_POWERDOWN:
        ret 
= powerdowntvp5146(*(int *)arg);
        
break;
    
case TVP5146_SET_AMUXMODE:
        ret 
= settvp5146amuxmode(*(int *)arg);
        
break;
    
case TVP5146_SET_BRIGHTNESS:
        ret 
= settvp5146brightness(*(int *)arg);
        
break;
    
case TVP5146_SET_CONTRAST:
        ret 
= settvp5146contrast(*(int *)arg);
        
break;
    
case TVP5146_SET_HUE:
        ret 
= settvp5146hue(*(int *)arg);
        
break;
    
case TVP5146_SET_SATURATION:
        ret 
= settvp5146saturation(*(int *)arg);
        
break;
    
case TVP5146_SET_AGC:
        ret 
= enabletvp5146agc(*(int *)arg);
        
break;
    
case TVP5146_SET_VIDEOSTD:
        ret 
= settvp5146std(*(int *)arg);
        
break;
    
case TVP5146_CLR_LOSTLOCK:
        ret 
= clrtvp5146lostlock();
        
break;
    
case TVP5146_GET_STATUS:
        ret 
= gettvp5146status(arg);
        
break;
    
case TVP5146_GET_STD:
        ret 
= gettvp5146std(arg);
        
break;
    
case VIDIOC_QUERYCTRL:
        ret 
= queryctrl(arg);
        
break;
    
case TVP5146_INIT:
        ret 
= tvp5146_i2c_init();
        
break;
    
case VIDIOC_G_CTRL:
        ret 
= getctrl(arg);
        
break;
    
case VIDIOC_S_CTRL:
        ret 
= setctrl(arg);
        
break;
    
default:
        ret 
= -EINVAL;
    }
    
return ret;
}

static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 * val)
{
    
int err = 0;

    
struct i2c_msg msg[1];
    unsigned 
char data[1];

    
if (!client->adapter) {
        err 
= -ENODEV;
    } 
else {
        msg
->addr = client->addr;
        msg
->flags = 0;
        msg
->len = 1;
        msg
->buf = data;
        data[
0= reg;
        err 
= i2c_transfer(client->adapter, msg, 1);
        
if (err >= 0) {
            msg
->flags = I2C_M_RD;
            err 
= i2c_transfer(client->adapter, msg, 1);
            
if (err >= 0) {
                
*val = data[0];
            }
        }
    }
    
return err;
}

static int i2c_write_reg(struct i2c_client *client, u8 reg, u8 val)
{
    
int err = 0;

    
struct i2c_msg msg[1];
    unsigned 
char data[2];

    
if (!client->adapter) {
        err 
= -ENODEV;
    } 
else {
        msg
->addr = client->addr;
        msg
->flags = 0;
        msg
->len = 2;
        msg
->buf = data;
        data[
0= reg;
        data[
1= val;
        err 
= i2c_transfer(client->adapter, msg, 1);
    }
    debug_print(KERN_INFO 
" i2c data write \n");

    
return err;
}

static int _i2c_attach_client(struct i2c_client *client,
                  
struct i2c_driver *driver,
                  
struct i2c_adapter *adap, int addr)
{
    
int err = 0;

    
if (client->adapter) {
        err 
= -EBUSY;    /* our client is already attached */
    } 
else {
        client
->addr = addr;
        client
->flags = I2C_CLIENT_ALLOW_USE;
        client
->driver = driver;
        client
->adapter = adap;

        err 
= i2c_attach_client(client);
        
if (err) {
            client
->adapter = NULL;
        }
    }
    
return err;
}

static int _i2c_detach_client(struct i2c_client *client)
{
    
int err = 0;

    
if (!client->adapter) {
        
return -ENODEV;    /* our client isn't attached */
    } 
else {
        err 
= i2c_detach_client(client);
        client
->adapter = NULL;
    }
    
return err;
}

static int tvp5146_i2c_probe_adapter(struct i2c_adapter *adap)
{
    
int ret;
    ret
=_i2c_attach_client(&tvp5146_i2c_client, &tvp5146_i2c_driver,
                  adap, 
0x5D);

//    ret |= gpio_set_direction(41,0);             //linger 2007.11.29 GPIO pins are exchanged on 

V1.
1
//    ret |= __gpio_set(41,1);
    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x030x69);      //phoenix 2008.01.02 modified

    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x080x00);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x090x80);    
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0a0x80);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0b0x00);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0c0x80);        //phoenix 2008.01.04 

modified
    ret 
|= i2c_write_reg(&tvp5146_i2c_client, 0x0d0x47);      //phoenix 2008.01.02 modified
    ret |= i2c_write_reg(&tvp5146_i2c_client, 0x0F0x02);

    
return ret;
//end
}
/*
static int tvp5146_i2c_init(void)
{
    int err;
    struct i2c_driver *driver = &tvp5146_i2c_driver;

    driver->owner = THIS_MODULE;
    strlcpy(driver->name, "TVP5150 Video Decoder I2C driver",
        sizeof(driver->name));
    driver->id = I2C_DRIVERID_EXP0;
    driver->flags = I2C_DF_NOTIFY;
    driver->attach_adapter = tvp5146_i2c_probe_adapter;
    driver->detach_client = _i2c_detach_client;

    err = i2c_add_driver(driver);
    if (err) {
        debug_print(KERN_ERR
            "Failed to register TVP5146 I2C client.\n");
    }
    debug_print(KERN_INFO "tvp5146 driver registered.\n");

    return err;
}

static void tvp5146_i2c_cleanup(void)
{
    struct i2c_driver *driver = &tvp5146_i2c_driver;

    i2c_detach_client(&tvp5146_i2c_client);


    i2c_del_driver(driver);
    tvp5146_i2c_client.adapter = NULL;
}
*/
/*
 * ======== tvp5146_i2c_init  ========
 
*/
/* This function is used initialize TVP5146 i2c client */
static int tvp5146_i2c_init(void)
{
    
int err = 0;
    
struct i2c_driver *driver = &tvp5146_i2c_driver;

    driver
->owner = THIS_MODULE;
    strlcpy(driver
->name, "TVP5150 Video Decoder I2C driver",
        
sizeof(driver->name));
    driver
->id = I2C_DRIVERID_EXP0;
    driver
->flags = I2C_DF_NOTIFY;
    driver
->attach_adapter = tvp5146_i2c_probe_adapter;
    driver
->detach_client = _i2c_detach_client;
    err 
= i2c_add_driver(driver);
    
if (err) {
        debug_print(KERN_ERR
            
"Failed to register TVP5150 I2C client.\n");
    }
    debug_print(KERN_INFO 
"tvp5150 driver registered.\n");
    printk(
"TVP5150 support for SEED_DVS6446 by Stephen Zhang\n");
    
return err;

    
return err;
}

/*
 * ======== tvp5146_i2c_cleanup  ========
 
*/
/* This function is used detach TVP5146 i2c client */
static void tvp5146_i2c_cleanup(void)
{
    
struct i2c_driver *driver = &tvp5146_i2c_driver;

    
if (tvp5146_i2c_registration) {
        i2c_detach_client(
&tvp5146_i2c_client);
        i2c_del_driver(driver);
        tvp5146_i2c_client.adapter 
= NULL;
        tvp5146_i2c_registration 
= TVP5146_I2C_UNREGISTERED;
    }
}
//module_init(tvp5146_i2c_init);
module_exit(tvp5146_i2c_cleanup);

EXPORT_SYMBOL(tvp5146_ctrl);
MODULE_LICENSE(
"GPL");

/**************************************************************************/
/* End of file                                                                            */
/**************************************************************************/

 

 

posted on 2010-05-26 23:51 sunrain_hjb 阅读(...) 评论(...) 编辑 收藏

Map