2005-04-17 02:20:36 +04:00
/* Driver for Bt832 CMOS Camera Video Processor
i2c - addresses : 0x88 or 0x8a
The BT832 interfaces to a Quartzsight Digital Camera ( 352 x288 , 25 or 30 fps )
via a 9 pin connector ( 4 - wire SDATA , 2 - wire i2c , SCLK , VCC , GND ) .
It outputs an 8 - bit 4 : 2 : 2 YUV or YCrCb video signal which can be directly
connected to bt848 / bt878 GPIO pins on this purpose .
( see : VLSI Vision Ltd . www . vvl . co . uk for camera datasheets )
2005-06-24 09:05:07 +04:00
2005-04-17 02:20:36 +04:00
Supported Cards :
- Pixelview Rev .4 E : 0x8a
GPIO 0x400000 toggles Bt832 RESET , and the chip changes to i2c 0x88 !
( c ) Gunther Mayer , 2002
STATUS :
- detect chip and hexdump
- reset chip and leave low power mode
- detect camera present
TODO :
- make it work ( find correct setup for Bt832 and Bt878 )
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/i2c.h>
# include <linux/types.h>
# include <linux/videodev.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/slab.h>
2005-06-24 09:05:07 +04:00
# include <media/audiochip.h>
# include <media/id.h>
2005-04-17 02:20:36 +04:00
# include "bttv.h"
# include "bt832.h"
MODULE_LICENSE ( " GPL " ) ;
/* Addresses to scan */
2005-06-24 09:05:13 +04:00
static unsigned short normal_i2c [ ] = { I2C_BT832_ALT1 > > 1 , I2C_BT832_ALT2 > > 1 ,
I2C_CLIENT_END } ;
2005-04-17 02:20:36 +04:00
I2C_CLIENT_INSMOD ;
/* ---------------------------------------------------------------------- */
# define dprintk if (debug) printk
static int bt832_detach ( struct i2c_client * client ) ;
static struct i2c_driver driver ;
static struct i2c_client client_template ;
struct bt832 {
struct i2c_client client ;
} ;
int bt832_hexdump ( struct i2c_client * i2c_client_s , unsigned char * buf )
{
int i , rc ;
buf [ 0 ] = 0x80 ; // start at register 0 with auto-increment
if ( 1 ! = ( rc = i2c_master_send ( i2c_client_s , buf , 1 ) ) )
printk ( " bt832: i2c i/o error: rc == %d (should be 1) \n " , rc ) ;
for ( i = 0 ; i < 65 ; i + + )
buf [ i ] = 0 ;
if ( 65 ! = ( rc = i2c_master_recv ( i2c_client_s , buf , 65 ) ) )
printk ( " bt832: i2c i/o error: rc == %d (should be 65) \n " , rc ) ;
// Note: On READ the first byte is the current index
// (e.g. 0x80, what we just wrote)
if ( 1 ) {
int i ;
printk ( " BT832 hexdump: \n " ) ;
for ( i = 1 ; i < 65 ; i + + ) {
if ( i ! = 1 ) {
if ( ( ( i - 1 ) % 8 ) = = 0 ) printk ( " " ) ;
if ( ( ( i - 1 ) % 16 ) = = 0 ) printk ( " \n " ) ;
}
printk ( " %02x " , buf [ i ] ) ;
}
printk ( " \n " ) ;
}
return 0 ;
}
// Return: 1 (is a bt832), 0 (No bt832 here)
int bt832_init ( struct i2c_client * i2c_client_s )
{
unsigned char * buf ;
int rc ;
buf = kmalloc ( 65 , GFP_KERNEL ) ;
bt832_hexdump ( i2c_client_s , buf ) ;
2005-06-24 09:05:07 +04:00
2005-04-17 02:20:36 +04:00
if ( buf [ 0x40 ] ! = 0x31 ) {
printk ( " bt832: this i2c chip is no bt832 (id=%02x). Detaching. \n " , buf [ 0x40 ] ) ;
kfree ( buf ) ;
return 0 ;
}
printk ( " Write 0 tp VPSTATUS \n " ) ;
buf [ 0 ] = BT832_VP_STATUS ; // Reg.52
buf [ 1 ] = 0x00 ;
if ( 2 ! = ( rc = i2c_master_send ( i2c_client_s , buf , 2 ) ) )
printk ( " bt832: i2c i/o error VPS: rc == %d (should be 2) \n " , rc ) ;
bt832_hexdump ( i2c_client_s , buf ) ;
// Leave low power mode:
printk ( " Bt832: leave low power mode. \n " ) ;
buf [ 0 ] = BT832_CAM_SETUP0 ; //0x39 57
buf [ 1 ] = 0x08 ;
if ( 2 ! = ( rc = i2c_master_send ( i2c_client_s , buf , 2 ) ) )
printk ( " bt832: i2c i/o error LLPM: rc == %d (should be 2) \n " , rc ) ;
bt832_hexdump ( i2c_client_s , buf ) ;
printk ( " Write 0 tp VPSTATUS \n " ) ;
buf [ 0 ] = BT832_VP_STATUS ; // Reg.52
buf [ 1 ] = 0x00 ;
if ( 2 ! = ( rc = i2c_master_send ( i2c_client_s , buf , 2 ) ) )
printk ( " bt832: i2c i/o error VPS: rc == %d (should be 2) \n " , rc ) ;
bt832_hexdump ( i2c_client_s , buf ) ;
// Enable Output
printk ( " Enable Output \n " ) ;
buf [ 0 ] = BT832_VP_CONTROL1 ; // Reg.40
buf [ 1 ] = 0x27 & ( ~ 0x01 ) ; // Default | !skip
if ( 2 ! = ( rc = i2c_master_send ( i2c_client_s , buf , 2 ) ) )
printk ( " bt832: i2c i/o error EO: rc == %d (should be 2) \n " , rc ) ;
2005-06-24 09:05:07 +04:00
2005-04-17 02:20:36 +04:00
bt832_hexdump ( i2c_client_s , buf ) ;
// for testing (even works when no camera attached)
printk ( " bt832: *** Generate NTSC M Bars ***** \n " ) ;
buf [ 0 ] = BT832_VP_TESTCONTROL0 ; // Reg. 42
buf [ 1 ] = 3 ; // Generate NTSC System M bars, Generate Frame timing internally
if ( 2 ! = ( rc = i2c_master_send ( i2c_client_s , buf , 2 ) ) )
printk ( " bt832: i2c i/o error MBAR: rc == %d (should be 2) \n " , rc ) ;
printk ( " Bt832: Camera Present: %s \n " ,
( buf [ 1 + BT832_CAM_STATUS ] & BT832_56_CAMERA_PRESENT ) ? " yes " : " no " ) ;
bt832_hexdump ( i2c_client_s , buf ) ;
kfree ( buf ) ;
return 1 ;
}
2005-06-24 09:05:07 +04:00
static int bt832_attach ( struct i2c_adapter * adap , int addr , int kind )
2005-04-17 02:20:36 +04:00
{
struct bt832 * t ;
printk ( " bt832_attach \n " ) ;
client_template . adapter = adap ;
client_template . addr = addr ;
printk ( " bt832: chip found @ 0x%x \n " , addr < < 1 ) ;
if ( NULL = = ( t = kmalloc ( sizeof ( * t ) , GFP_KERNEL ) ) )
return - ENOMEM ;
memset ( t , 0 , sizeof ( * t ) ) ;
t - > client = client_template ;
2005-06-24 09:05:07 +04:00
i2c_set_clientdata ( & t - > client , t ) ;
2005-04-17 02:20:36 +04:00
i2c_attach_client ( & t - > client ) ;
if ( ! bt832_init ( & t - > client ) ) {
bt832_detach ( & t - > client ) ;
return - 1 ;
}
2005-06-24 09:05:07 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int bt832_probe ( struct i2c_adapter * adap )
{
2005-06-24 09:05:07 +04:00
# ifdef I2C_CLASS_TV_ANALOG
2005-04-17 02:20:36 +04:00
if ( adap - > class & I2C_CLASS_TV_ANALOG )
return i2c_probe ( adap , & addr_data , bt832_attach ) ;
2005-06-24 09:05:07 +04:00
# else
2005-08-12 01:41:56 +04:00
if ( adap - > id = = I2C_HW_B_BT848 )
2005-06-24 09:05:07 +04:00
return i2c_probe ( adap , & addr_data , bt832_attach ) ;
# endif
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int bt832_detach ( struct i2c_client * client )
{
2005-06-24 09:05:07 +04:00
struct bt832 * t = i2c_get_clientdata ( client ) ;
2005-04-17 02:20:36 +04:00
printk ( " bt832: detach. \n " ) ;
i2c_detach_client ( client ) ;
kfree ( t ) ;
return 0 ;
}
static int
bt832_command ( struct i2c_client * client , unsigned int cmd , void * arg )
{
2005-06-24 09:05:07 +04:00
struct bt832 * t = i2c_get_clientdata ( client ) ;
2005-04-17 02:20:36 +04:00
printk ( " bt832: command %x \n " , cmd ) ;
switch ( cmd ) {
case BT832_HEXDUMP : {
unsigned char * buf ;
buf = kmalloc ( 65 , GFP_KERNEL ) ;
bt832_hexdump ( & t - > client , buf ) ;
kfree ( buf ) ;
}
break ;
case BT832_REATTACH :
printk ( " bt832: re-attach \n " ) ;
i2c_del_driver ( & driver ) ;
i2c_add_driver ( & driver ) ;
break ;
}
return 0 ;
}
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
. owner = THIS_MODULE ,
. name = " i2c bt832 driver " ,
. id = - 1 , /* FIXME */
. flags = I2C_DF_NOTIFY ,
. attach_adapter = bt832_probe ,
. detach_client = bt832_detach ,
. command = bt832_command ,
} ;
static struct i2c_client client_template =
{
2005-08-15 21:57:04 +04:00
. name = " bt832 " ,
2005-06-24 09:05:07 +04:00
. flags = I2C_CLIENT_ALLOW_USE ,
. driver = & driver ,
2005-04-17 02:20:36 +04:00
} ;
2005-06-24 09:05:07 +04:00
static int __init bt832_init_module ( void )
2005-04-17 02:20:36 +04:00
{
2005-06-24 09:05:07 +04:00
return i2c_add_driver ( & driver ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-24 09:05:07 +04:00
static void __exit bt832_cleanup_module ( void )
2005-04-17 02:20:36 +04:00
{
i2c_del_driver ( & driver ) ;
}
module_init ( bt832_init_module ) ;
module_exit ( bt832_cleanup_module ) ;
2005-06-24 09:05:07 +04:00
/*
* Overrides for Emacs so that we follow Linus ' s tabbing style .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Local variables :
* c - basic - offset : 8
* End :
*/