WinCE下的TVP5146调试助手

     这两天在调试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,  0x03 0x69 );       // phoenix 2008.01.02 modified

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

modified
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x09 0x80 );    
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x0a 0x80 );         // phoenix 2008.01.04 

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

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

modified
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x0d 0x47 );       // phoenix 2008.01.02 modified
    ret  |=  i2c_write_reg( & tvp5146_i2c_client,  0x0F 0x02 );

    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,  0x03 0x69 );       // phoenix 2008.01.02 modified

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

modified
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x09 0x80 );    
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x0a 0x80 );         // phoenix 2008.01.04 

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

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

modified
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x0d 0x47 );       // phoenix 2008.01.02 modified
    ret  |=  i2c_write_reg( & tvp5146_i2c_client,  0x0F 0x02 );
    
    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, 
0 sizeof ( * 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,  0x03 0x69 );       // phoenix 2008.01.02 modified

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

modified
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x09 0x80 );    
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x0a 0x80 );         // phoenix 2008.01.04 

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

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

modified
    ret 
|=  i2c_write_reg( & tvp5146_i2c_client,  0x0d 0x47 );       // phoenix 2008.01.02 modified
    ret  |=  i2c_write_reg( & tvp5146_i2c_client,  0x0F 0x02 );

    
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                                                                             */
/* ************************************************************************ */

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值