www.pudn.com > spca5xx-.rar > spca506.h
/*
* SPCA506 chip based cameras function
* M Xhaard 15/04/2004 based on different work Mark Taylor and others
* and my own snoopy file on a pv-321c donate by a german compagny
* "Firma Frank Gmbh" from Saarbruecken
*/
#ifndef SPCA506_INIT_H
#define SPCA506_INIT_H
#define SAA7113_bright 0x0A // defaults 0x80
#define SAA7113_contrast 0x0B // defaults 0x47
#define SAA7113_saturation 0x0C //defaults 0x40
#define SAA7113_hue 0x0D //defaults 0x00
/* define from v4l */
//#define VIDEO_MODE_PAL 0
//#define VIDEO_MODE_NTSC 1
//#define VIDEO_MODE_SECAM 2
//#define VIDEO_MODE_AUTO 3
/*********************** Specific spca506 Usbgrabber ************************/
static void spca506_init (struct usb_spca50x *spca50x);
static void spca506_start (struct usb_spca50x *spca50x);
static void spca506_stop (struct usb_spca50x *spca50x);
static void spca506_Setsize (struct usb_spca50x *spca50x,__u16 code ,__u16 xmult,__u16 ymult);
static void spca506_SetBrightContrastHueColors (struct usb_spca50x *spca50x,__u16 bright ,__u16 contrast,
__u16 hue, __u16 colors);
static void spca506_GetBrightContrastHueColors (struct usb_spca50x *spca50x, __u16 *bright ,
__u16 *contrast, __u16 *hue, __u16 *colors);
static void spca506_SetNormeInput (struct usb_spca50x *spca50x,
__u16 norme,__u16 channel );
static void spca506_GetNormeInput (struct usb_spca50x *spca50x,
__u16 *norme, __u16 *channel );
/****************************************************************************/
static void spca506_Initi2c(struct usb_spca50x *spca50x)
{
spca5xxRegWrite(spca50x->dev,0x07,SAA7113_I2C_BASE_WRITE,0x0004 ,NULL ,0 );
}
static void spca506_WriteI2c(struct usb_spca50x *spca50x,__u16 valeur,__u16 registre)
{ int retry = 60;
unsigned char Data[2];
spca5xxRegWrite(spca50x->dev,0x07,registre ,0x0001 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x07,valeur ,0x0000 ,NULL ,0 );
while (retry--) {
spca5xxRegRead(spca50x->dev,0x07 ,0 ,0x0003 , Data ,2);
if ((Data[0] | Data[1]) == 0x00)
break;
}
}
static int spca506_ReadI2c(struct usb_spca50x *spca50x, __u16 registre)
{ int retry = 60;
unsigned char Data[2];
unsigned char value = 0;
spca5xxRegWrite(spca50x->dev,0x07,SAA7113_I2C_BASE_WRITE,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x07,registre ,0x0001 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x07,0x01,0x0002 ,NULL ,0 );
while (retry--) {
spca5xxRegRead(spca50x->dev,0x07 ,0 ,0x0003 , Data ,2);
if ((Data[0] | Data[1]) == 0x00)
break;
}
if (retry == 0) return -1;
spca5xxRegRead(spca50x->dev,0x07 ,0 ,0x0000 , &value ,1);
return (int) value;
}
static void spca506_SetNormeInput (struct usb_spca50x *spca50x,__u16 norme,__u16 channel )
{
__u8 setbit0 = 0x00;
__u8 setbit1 = 0x00;
__u8 videomask = 0x00;
PDEBUG( 3, "************ Open Set Norme **************");
spca506_Initi2c(spca50x);
/* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l)*/
/* Composite channel bit1 -> 1 S-video bit 1 -> 0 */
/* and exclude SAA7113 reserved channel set default 0 otherwise*/
if (norme == VIDEO_MODE_NTSC)
setbit0 = 0x01;
if( (channel == 4) || (channel == 5) || (channel > 9)) channel = 0;
if (channel < 4)
setbit1 = 0x02;
videomask = (0x48 | setbit0 | setbit1);
spca5xxRegWrite(spca50x->dev,0x08,videomask,0x0000 ,NULL ,0 );
spca506_WriteI2c(spca50x,(0xc0 | (channel & 0x0F)),0x02);
switch (norme) {
case VIDEO_MODE_PAL:
spca506_WriteI2c(spca50x,0x03,0x0e);//Chrominance Control PAL BGHIV
break;
case VIDEO_MODE_NTSC:
spca506_WriteI2c(spca50x,0x33,0x0e);//Chrominance Control NTSC N
break;
case VIDEO_MODE_SECAM:
spca506_WriteI2c(spca50x,0x53,0x0e);//Chrominance Control SECAM
break;
default:
spca506_WriteI2c(spca50x,0x03,0x0e);//Chrominance Control PAL BGHIV
break;
}
spca50x->norme=norme;
spca50x->channel=channel;
PDEBUG( 3, "Set Video Byte to 0x%2X ", videomask );
PDEBUG( 3, "Set Norme : %d Channel %d ", norme , channel );
PDEBUG( 3, "************ Close SetNorme **************");
}
static void spca506_GetNormeInput (struct usb_spca50x *spca50x,
__u16 *norme,__u16 *channel )
{
PDEBUG( 3, "************ Open Get Norme **************");
/* Read the register is not so good value change so
we use your own copy in spca50x struct */
*norme = spca50x->norme;
*channel = spca50x->channel;
PDEBUG( 3, "Get Norme : %d Channel %d ",*norme ,*channel );
PDEBUG( 3, "************ Close Get Norme **************");
}
static void spca506_init (struct usb_spca50x *spca50x)
{
PDEBUG( 3, "************ Open Init spca506 **************");
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0xFF ,0x0003 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x1c ,0x0001 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x18 ,0x0001 ,NULL ,0 );
/* Init on PAL and composite input0 */
spca506_SetNormeInput(spca50x,0,0);
spca5xxRegWrite(spca50x->dev,0x03,0x1c ,1 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x18 ,0x0001 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x05,0x00 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x05,0xef ,0x0001 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x05,0x00 ,0x00c1 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x05,0x00 ,0x00c2 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0x18 ,0x0002 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0xf5 ,0x0011 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0x02 ,0x0012 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0xfb ,0x0013 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0x00 ,0x0014 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0xa4 ,0x0051 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0x40 ,0x0052 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0x71 ,0x0053 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x06,0x40 ,0x0054 ,NULL ,0 );
/***********************************************************/
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0003 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0xFF ,0x0003 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x02,0x00 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x60 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x18 ,0x0001 ,NULL ,0 );
/* for a better reading mx :) */
/*spca506_WriteI2c(value,register)*/
spca506_Initi2c(spca50x);
spca506_WriteI2c(spca50x,0x08,0x01);
spca506_WriteI2c(spca50x,0xc0,0x02); // input composite video
spca506_WriteI2c(spca50x,0x33,0x03);
spca506_WriteI2c(spca50x,0x00,0x04);
spca506_WriteI2c(spca50x,0x00,0x05);
spca506_WriteI2c(spca50x,0x0d,0x06);
spca506_WriteI2c(spca50x,0xf0,0x07);
spca506_WriteI2c(spca50x,0x98,0x08);
spca506_WriteI2c(spca50x,0x03,0x09);
spca506_WriteI2c(spca50x,0x80,0x0a);
spca506_WriteI2c(spca50x,0x47,0x0b);
spca506_WriteI2c(spca50x,0x48,0x0c);
spca506_WriteI2c(spca50x,0x00,0x0d);
spca506_WriteI2c(spca50x,0x03,0x0e);// Chroma Pal adjust
spca506_WriteI2c(spca50x,0x2a,0x0f);
spca506_WriteI2c(spca50x,0x00,0x10);
spca506_WriteI2c(spca50x,0x0c,0x11);
spca506_WriteI2c(spca50x,0xb8,0x12);
spca506_WriteI2c(spca50x,0x01,0x13);
spca506_WriteI2c(spca50x,0x00,0x14);
spca506_WriteI2c(spca50x,0x00,0x15);
spca506_WriteI2c(spca50x,0x00,0x16);
spca506_WriteI2c(spca50x,0x00,0x17);
spca506_WriteI2c(spca50x,0x00,0x18);
spca506_WriteI2c(spca50x,0x00,0x19);
spca506_WriteI2c(spca50x,0x00,0x1a);
spca506_WriteI2c(spca50x,0x00,0x1b);
spca506_WriteI2c(spca50x,0x00,0x1c);
spca506_WriteI2c(spca50x,0x00,0x1d);
spca506_WriteI2c(spca50x,0x00,0x1e);
spca506_WriteI2c(spca50x,0xa1,0x1f);
spca506_WriteI2c(spca50x,0x02,0x40);
spca506_WriteI2c(spca50x,0xff,0x41);
spca506_WriteI2c(spca50x,0xff,0x42);
spca506_WriteI2c(spca50x,0xff,0x43);
spca506_WriteI2c(spca50x,0xff,0x44);
spca506_WriteI2c(spca50x,0xff,0x45);
spca506_WriteI2c(spca50x,0xff,0x46);
spca506_WriteI2c(spca50x,0xff,0x47);
spca506_WriteI2c(spca50x,0xff,0x48);
spca506_WriteI2c(spca50x,0xff,0x49);
spca506_WriteI2c(spca50x,0xff,0x4a);
spca506_WriteI2c(spca50x,0xff,0x4b);
spca506_WriteI2c(spca50x,0xff,0x4c);
spca506_WriteI2c(spca50x,0xff,0x4d);
spca506_WriteI2c(spca50x,0xff,0x4e);
spca506_WriteI2c(spca50x,0xff,0x4f);
spca506_WriteI2c(spca50x,0xff,0x50);
spca506_WriteI2c(spca50x,0xff,0x51);
spca506_WriteI2c(spca50x,0xff,0x52);
spca506_WriteI2c(spca50x,0xff,0x53);
spca506_WriteI2c(spca50x,0xff,0x54);
spca506_WriteI2c(spca50x,0xff,0x55);
spca506_WriteI2c(spca50x,0xff,0x56);
spca506_WriteI2c(spca50x,0xff,0x57);
spca506_WriteI2c(spca50x,0x00,0x58);
spca506_WriteI2c(spca50x,0x54,0x59);
spca506_WriteI2c(spca50x,0x07,0x5a);
spca506_WriteI2c(spca50x,0x83,0x5b);
spca506_WriteI2c(spca50x,0x00,0x5c);
spca506_WriteI2c(spca50x,0x00,0x5d);
spca506_WriteI2c(spca50x,0x00,0x5e);
spca506_WriteI2c(spca50x,0x00,0x5f);
spca506_WriteI2c(spca50x,0x00,0x60);
spca506_WriteI2c(spca50x,0x05,0x61);
spca506_WriteI2c(spca50x,0x9f,0x62);
PDEBUG( 3, "************ Close Init spca506 **************");
}
static void spca506_start (struct usb_spca50x *spca50x)
{ __u16 norme = 0;
__u16 channel = 0;
unsigned char Data[2];
PDEBUG( 3, "************ Open Start spca506 **************");
/***********************************************************/
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0003 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0xFF ,0x0003 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x02,0x00 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x60 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x18 ,0x0001 ,NULL ,0 );
/*spca506_WriteI2c(value,register)*/
spca506_Initi2c(spca50x);
spca506_WriteI2c(spca50x,0x08,0x01);//Increment Delay
//spca506_WriteI2c(spca50x,0xc0,0x02);//Analog Input Control 1
spca506_WriteI2c(spca50x,0x33,0x03);//Analog Input Control 2
spca506_WriteI2c(spca50x,0x00,0x04);//Analog Input Control 3
spca506_WriteI2c(spca50x,0x00,0x05);//Analog Input Control 4
spca506_WriteI2c(spca50x,0x0d,0x06);//Horizontal Sync Start 0xe9-0x0d
spca506_WriteI2c(spca50x,0xf0,0x07);//Horizontal Sync Stop 0x0d-0xf0
spca506_WriteI2c(spca50x,0x98,0x08);//Sync Control
/* Defaults value */
spca506_WriteI2c(spca50x,0x03,0x09);//Luminance Control
spca506_WriteI2c(spca50x,0x80,0x0a);//Luminance Brightness
spca506_WriteI2c(spca50x,0x47,0x0b);//Luminance Contrast
spca506_WriteI2c(spca50x,0x48,0x0c);//Chrominance Saturation
spca506_WriteI2c(spca50x,0x00,0x0d);//Chrominance Hue Control
spca506_WriteI2c(spca50x,0x2a,0x0f);//Chrominance Gain Control
/*************************************************************/
spca506_WriteI2c(spca50x,0x00,0x10);//Format/Delay Control
spca506_WriteI2c(spca50x,0x0c,0x11);//Output Control 1
spca506_WriteI2c(spca50x,0xb8,0x12);//Output Control 2
spca506_WriteI2c(spca50x,0x01,0x13);//Output Control 3
spca506_WriteI2c(spca50x,0x00,0x14);//reserved
spca506_WriteI2c(spca50x,0x00,0x15);//VGATE START
spca506_WriteI2c(spca50x,0x00,0x16);//VGATE STOP
spca506_WriteI2c(spca50x,0x00,0x17);//VGATE Control (MSB)
spca506_WriteI2c(spca50x,0x00,0x18);
spca506_WriteI2c(spca50x,0x00,0x19);
spca506_WriteI2c(spca50x,0x00,0x1a);
spca506_WriteI2c(spca50x,0x00,0x1b);
spca506_WriteI2c(spca50x,0x00,0x1c);
spca506_WriteI2c(spca50x,0x00,0x1d);
spca506_WriteI2c(spca50x,0x00,0x1e);
spca506_WriteI2c(spca50x,0xa1,0x1f);
spca506_WriteI2c(spca50x,0x02,0x40);
spca506_WriteI2c(spca50x,0xff,0x41);
spca506_WriteI2c(spca50x,0xff,0x42);
spca506_WriteI2c(spca50x,0xff,0x43);
spca506_WriteI2c(spca50x,0xff,0x44);
spca506_WriteI2c(spca50x,0xff,0x45);
spca506_WriteI2c(spca50x,0xff,0x46);
spca506_WriteI2c(spca50x,0xff,0x47);
spca506_WriteI2c(spca50x,0xff,0x48);
spca506_WriteI2c(spca50x,0xff,0x49);
spca506_WriteI2c(spca50x,0xff,0x4a);
spca506_WriteI2c(spca50x,0xff,0x4b);
spca506_WriteI2c(spca50x,0xff,0x4c);
spca506_WriteI2c(spca50x,0xff,0x4d);
spca506_WriteI2c(spca50x,0xff,0x4e);
spca506_WriteI2c(spca50x,0xff,0x4f);
spca506_WriteI2c(spca50x,0xff,0x50);
spca506_WriteI2c(spca50x,0xff,0x51);
spca506_WriteI2c(spca50x,0xff,0x52);
spca506_WriteI2c(spca50x,0xff,0x53);
spca506_WriteI2c(spca50x,0xff,0x54);
spca506_WriteI2c(spca50x,0xff,0x55);
spca506_WriteI2c(spca50x,0xff,0x56);
spca506_WriteI2c(spca50x,0xff,0x57);
spca506_WriteI2c(spca50x,0x00,0x58);
spca506_WriteI2c(spca50x,0x54,0x59);
spca506_WriteI2c(spca50x,0x07,0x5a);
spca506_WriteI2c(spca50x,0x83,0x5b);
spca506_WriteI2c(spca50x,0x00,0x5c);
spca506_WriteI2c(spca50x,0x00,0x5d);
spca506_WriteI2c(spca50x,0x00,0x5e);
spca506_WriteI2c(spca50x,0x00,0x5f);
spca506_WriteI2c(spca50x,0x00,0x60);
spca506_WriteI2c(spca50x,0x05,0x61);
spca506_WriteI2c(spca50x,0x9f,0x62);
/***********************************************************/
spca5xxRegWrite(spca50x->dev,0x05,0x00 ,0x0003 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x05,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x10 ,0x0001 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x78 ,0x0000 ,NULL ,0 );
/* compress setting and size */
/* set i2c luma */
spca5xxRegWrite(spca50x->dev,0x02,0x01 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x12 ,0x0001 ,NULL ,0 );
spca5xxRegRead(spca50x->dev,0x04 ,0 ,0x0001 , Data ,2);
PDEBUG( 3, "************ Close Start spca506 **************");
spca506_GetNormeInput(spca50x,&norme,&channel);
spca506_SetNormeInput(spca50x,norme,channel);
}
static void spca506_stop (struct usb_spca50x *spca50x)
{
spca5xxRegWrite(spca50x->dev,0x02,0x00 ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0004 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x03,0x00 ,0x0003 ,NULL ,0 );
}
static void spca506_Setsize (struct usb_spca50x *spca50x,__u16 code ,__u16 xmult,__u16 ymult)
{
PDEBUG( 3, "************ Open SetSize spca506 **************");
spca5xxRegWrite(spca50x->dev,0x04,(0x18 | (code & 0x07)) ,0x0000 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x04,0x41 ,0x0001 ,NULL ,0 );// Soft snap 0x40 Hard 0x41
spca5xxRegWrite(spca50x->dev,0x04,0x00 ,0x0002 ,NULL ,0 );
spca5xxRegWrite(spca50x->dev,0x04,0x00 ,0x0003 ,NULL ,0 );//reserved
spca5xxRegWrite(spca50x->dev,0x04,0x00 ,0x0004 ,NULL ,0 );//reserved
spca5xxRegWrite(spca50x->dev,0x04,0x01 ,0x0005 ,NULL ,0 );//reserved
spca5xxRegWrite(spca50x->dev,0x04,xmult ,0x0006 ,NULL ,0 );//reserced
spca5xxRegWrite(spca50x->dev,0x04,ymult ,0x0007 ,NULL ,0 );//reserved
spca5xxRegWrite(spca50x->dev,0x04,0x00 ,0x0008 ,NULL ,0 ); // compression 1
spca5xxRegWrite(spca50x->dev,0x04,0x00 ,0x0009 ,NULL ,0 ); //T=64 -> 2
spca5xxRegWrite(spca50x->dev,0x04,0x21 ,0x000a ,NULL ,0 );//threshold2D
spca5xxRegWrite(spca50x->dev,0x04,0x00 ,0x000b ,NULL ,0 );//quantization
PDEBUG( 3, "************ Close SetSize spca506 **************");
}
static void spca506_SetBrightContrastHueColors (struct usb_spca50x *spca50x,__u16 bright ,__u16 contrast,
__u16 hue, __u16 colors)
{
spca506_Initi2c(spca50x);
spca506_WriteI2c(spca50x,((bright >> 8) & 0xFF),SAA7113_bright);
spca506_WriteI2c(spca50x,((contrast >> 8) & 0xFF),SAA7113_contrast);
spca506_WriteI2c(spca50x,((hue >> 8) & 0xFF),SAA7113_hue);
spca506_WriteI2c(spca50x,((colors >> 8) & 0xFF),SAA7113_saturation);
spca506_WriteI2c(spca50x,0x01,0x09);
}
static void spca506_GetBrightContrastHueColors (struct usb_spca50x *spca50x, __u16 *bright ,
__u16 *contrast, __u16 *hue, __u16 *colors)
{
*bright = (spca506_ReadI2c(spca50x, SAA7113_bright)) << 8;
*contrast = (spca506_ReadI2c(spca50x, SAA7113_contrast)) << 8;
*hue = (spca506_ReadI2c(spca50x, SAA7113_hue)) << 8;
*colors = (spca506_ReadI2c(spca50x, SAA7113_saturation)) << 8;
}
/************** old code from spca50x *********************************/
/**********************************************************************
*
* Camera interface
*
**********************************************************************/
/* Read a value from the I2C bus. Returns the value read */
static int
spca50x_read_i2c (struct usb_spca50x *spca50x, __u16 device, __u16 address)
{
struct usb_device *dev = spca50x->dev;
int err_code;
int retry;
int ctrl = spca50x->i2c_ctrl_reg; //The I2C control register
int base = spca50x->i2c_base; //The I2C base address
err_code = spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_DEVICE, device);
err_code =
spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_SUBADDR, address);
err_code =
spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_TRIGGER,
SPCA50X_I2C_TRIGGER_BIT);
/* Hmm. 506 docs imply we should poll the ready register before reading the return value */
/* Poll the status register for a ready status */
/* Doesn't look like the windows driver does tho' */
retry = 60;
while (--retry)
{
err_code = spca50x_reg_read (dev, ctrl, base + SPCA50X_I2C_STATUS, 1);
if (err_code < 0)
PDEBUG (1, "Error reading I2C status register");
if (!err_code)
break;
}
if (!retry)
PDEBUG (1, "Too many retries polling I2C status after write to register");
err_code = spca50x_reg_read (dev, ctrl, base + SPCA50X_I2C_READ, 1);
if (err_code < 0)
PDEBUG (1, "Failed to read I2C register at %d:%d", device, address);
PDEBUG (3, "Read %d from %d:%d", err_code, device, address);
return err_code;
}
static int
spca50x_write_i2c (struct usb_spca50x *spca50x, __u16 device,
__u16 subaddress, __u16 data)
{
struct usb_device *dev = spca50x->dev;
int err_code;
int retry;
int ctrl = spca50x->i2c_ctrl_reg; //The I2C control register
int base = spca50x->i2c_base; //The I2C base address
/* Tell the SPCA50x i2c subsystem the device address of the i2c device */
err_code = spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_DEVICE, device);
/* Poll the status register for a ready status */
retry = 60; // Arbitrary
while (--retry)
{
err_code = spca50x_reg_read (dev, ctrl, base + SPCA50X_I2C_STATUS, 1);
if (err_code < 0)
PDEBUG (1, "Error reading I2C status register");
if (!err_code)
break;
}
if (!retry)
PDEBUG (1, "Too many retries polling I2C status");
err_code =
spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_SUBADDR, subaddress);
err_code = spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_VALUE, data);
if (spca50x->i2c_trigger_on_write)
err_code = spca50x_reg_write (dev, ctrl, base + SPCA50X_I2C_TRIGGER,
SPCA50X_I2C_TRIGGER_BIT);
/* Poll the status register for a ready status */
retry = 60;
while (--retry)
{
err_code = spca50x_reg_read (dev, ctrl, SPCA50X_I2C_STATUS, 2);
if (err_code < 0)
PDEBUG (1, "Error reading I2C status register");
if (!err_code)
break;
}
if (!retry)
PDEBUG (1, "Too many retries polling I2C status after write to register");
if (debug > 2)
{
err_code = spca50x_read_i2c (spca50x, device, subaddress);
if (err_code < 0)
{
PDEBUG (3, "Can't read back I2C register value for %d:%d",
device, subaddress);
}
else if ((err_code & 0xff) != (data & 0xff))
PDEBUG (3, "Read back %x should be %x at subaddr %x",
err_code, data, subaddress);
}
return 0;
}
#endif /* SPCA506_INIT_H */
//eof