2005-04-17 02:20:36 +04:00
/*
* bt819 - BT819A VideoStream Decoder ( Rockwell Part )
*
* Copyright ( C ) 1999 Mike Bernson < mike @ mlb . org >
* Copyright ( C ) 1998 Dave Perks < dperks @ ibm . net >
*
* Modifications for LML33 / DC10plus unified driver
* Copyright ( C ) 2000 Serguei Miridonov < mirsev @ cicese . mx >
*
* Changes by Ronald Bultje < rbultje @ ronald . bitfreak . net >
* - moved over to linux > = 2.4 . x i2c protocol ( 9 / 9 / 2002 )
*
* This code was modify / ported from the saa7111 driver written
* by Dave Perks .
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/kernel.h>
# include <linux/major.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/pci.h>
# include <linux/signal.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/page.h>
# include <linux/sched.h>
# include <linux/types.h>
# include <linux/videodev.h>
# include <asm/uaccess.h>
MODULE_DESCRIPTION ( " Brooktree-819 video decoder driver " ) ;
MODULE_AUTHOR ( " Mike Bernson & Dave Perks " ) ;
MODULE_LICENSE ( " GPL " ) ;
# include <linux/i2c.h>
# include <linux/i2c-dev.h>
# define I2C_NAME(s) (s)->name
# include <linux/video_decoder.h>
static int debug = 0 ;
module_param ( debug , int , 0 ) ;
MODULE_PARM_DESC ( debug , " Debug level (0-1) " ) ;
# define dprintk(num, format, args...) \
do { \
if ( debug > = num ) \
printk ( format , # # args ) ; \
} while ( 0 )
/* ----------------------------------------------------------------------- */
struct bt819 {
unsigned char reg [ 32 ] ;
int initialized ;
int norm ;
int input ;
int enable ;
int bright ;
int contrast ;
int hue ;
int sat ;
} ;
struct timing {
int hactive ;
int hdelay ;
int vactive ;
int vdelay ;
int hscale ;
int vscale ;
} ;
/* for values, see the bt819 datasheet */
static struct timing timing_data [ ] = {
{ 864 - 24 , 20 , 625 - 2 , 1 , 0x0504 , 0x0000 } ,
{ 858 - 24 , 20 , 525 - 2 , 1 , 0x00f8 , 0x0000 } ,
} ;
# define I2C_BT819 0x8a
/* ----------------------------------------------------------------------- */
static inline int
bt819_write ( struct i2c_client * client ,
u8 reg ,
u8 value )
{
struct bt819 * decoder = i2c_get_clientdata ( client ) ;
decoder - > reg [ reg ] = value ;
return i2c_smbus_write_byte_data ( client , reg , value ) ;
}
static inline int
bt819_setbit ( struct i2c_client * client ,
u8 reg ,
u8 bit ,
u8 value )
{
struct bt819 * decoder = i2c_get_clientdata ( client ) ;
return bt819_write ( client , reg ,
( decoder - >
reg [ reg ] & ~ ( 1 < < bit ) ) |
( value ? ( 1 < < bit ) : 0 ) ) ;
}
static int
bt819_write_block ( struct i2c_client * client ,
const u8 * data ,
unsigned int len )
{
int ret = - 1 ;
u8 reg ;
/* the bt819 has an autoincrement function, use it if
* the adapter understands raw I2C */
if ( i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
/* do raw I2C, not smbus compatible */
struct bt819 * decoder = i2c_get_clientdata ( client ) ;
struct i2c_msg msg ;
u8 block_data [ 32 ] ;
msg . addr = client - > addr ;
msg . flags = 0 ;
while ( len > = 2 ) {
msg . buf = ( char * ) block_data ;
msg . len = 0 ;
block_data [ msg . len + + ] = reg = data [ 0 ] ;
do {
block_data [ msg . len + + ] =
decoder - > reg [ reg + + ] = data [ 1 ] ;
len - = 2 ;
data + = 2 ;
} while ( len > = 2 & & data [ 0 ] = = reg & &
msg . len < 32 ) ;
if ( ( ret = i2c_transfer ( client - > adapter ,
& msg , 1 ) ) < 0 )
break ;
}
} else {
/* do some slow I2C emulation kind of thing */
while ( len > = 2 ) {
reg = * data + + ;
if ( ( ret = bt819_write ( client , reg , * data + + ) ) < 0 )
break ;
len - = 2 ;
}
}
return ret ;
}
static inline int
bt819_read ( struct i2c_client * client ,
u8 reg )
{
return i2c_smbus_read_byte_data ( client , reg ) ;
}
static int
bt819_init ( struct i2c_client * client )
{
struct bt819 * decoder = i2c_get_clientdata ( client ) ;
static unsigned char init [ ] = {
//0x1f, 0x00, /* Reset */
0x01 , 0x59 , /* 0x01 input format */
0x02 , 0x00 , /* 0x02 temporal decimation */
0x03 , 0x12 , /* 0x03 Cropping msb */
0x04 , 0x16 , /* 0x04 Vertical Delay, lsb */
0x05 , 0xe0 , /* 0x05 Vertical Active lsb */
0x06 , 0x80 , /* 0x06 Horizontal Delay lsb */
0x07 , 0xd0 , /* 0x07 Horizontal Active lsb */
0x08 , 0x00 , /* 0x08 Horizontal Scaling msb */
0x09 , 0xf8 , /* 0x09 Horizontal Scaling lsb */
0x0a , 0x00 , /* 0x0a Brightness control */
0x0b , 0x30 , /* 0x0b Miscellaneous control */
0x0c , 0xd8 , /* 0x0c Luma Gain lsb */
0x0d , 0xfe , /* 0x0d Chroma Gain (U) lsb */
0x0e , 0xb4 , /* 0x0e Chroma Gain (V) msb */
0x0f , 0x00 , /* 0x0f Hue control */
0x12 , 0x04 , /* 0x12 Output Format */
0x13 , 0x20 , /* 0x13 Vertial Scaling msb 0x00
chroma comb OFF , line drop scaling , interlace scaling
BUG ? Why does turning the chroma comb on fuck up color ?
Bug in the bt819 stepping on my board ?
*/
0x14 , 0x00 , /* 0x14 Vertial Scaling lsb */
0x16 , 0x07 , /* 0x16 Video Timing Polarity
ACTIVE = active low
FIELD : high = odd ,
vreset = active high ,
hreset = active high */
0x18 , 0x68 , /* 0x18 AGC Delay */
0x19 , 0x5d , /* 0x19 Burst Gate Delay */
0x1a , 0x80 , /* 0x1a ADC Interface */
} ;
struct timing * timing = & timing_data [ decoder - > norm ] ;
init [ 0x03 * 2 - 1 ] =
( ( ( timing - > vdelay > > 8 ) & 0x03 ) < < 6 ) | ( ( ( timing - >
vactive > > 8 ) &
0x03 ) < < 4 ) |
( ( ( timing - > hdelay > > 8 ) & 0x03 ) < < 2 ) | ( ( timing - >
hactive > > 8 ) &
0x03 ) ;
init [ 0x04 * 2 - 1 ] = timing - > vdelay & 0xff ;
init [ 0x05 * 2 - 1 ] = timing - > vactive & 0xff ;
init [ 0x06 * 2 - 1 ] = timing - > hdelay & 0xff ;
init [ 0x07 * 2 - 1 ] = timing - > hactive & 0xff ;
init [ 0x08 * 2 - 1 ] = timing - > hscale > > 8 ;
init [ 0x09 * 2 - 1 ] = timing - > hscale & 0xff ;
/* 0x15 in array is address 0x19 */
init [ 0x15 * 2 - 1 ] = ( decoder - > norm = = 0 ) ? 115 : 93 ; /* Chroma burst delay */
/* reset */
bt819_write ( client , 0x1f , 0x00 ) ;
mdelay ( 1 ) ;
/* init */
return bt819_write_block ( client , init , sizeof ( init ) ) ;
}
/* ----------------------------------------------------------------------- */
static int
bt819_command ( struct i2c_client * client ,
unsigned int cmd ,
void * arg )
{
int temp ;
struct bt819 * decoder = i2c_get_clientdata ( client ) ;
if ( ! decoder - > initialized ) { // First call to bt819_init could be
bt819_init ( client ) ; // without #FRST = 0
decoder - > initialized = 1 ;
}
switch ( cmd ) {
case 0 :
/* This is just for testing!!! */
bt819_init ( client ) ;
break ;
case DECODER_GET_CAPABILITIES :
{
struct video_decoder_capability * cap = arg ;
cap - > flags = VIDEO_DECODER_PAL |
VIDEO_DECODER_NTSC |
VIDEO_DECODER_AUTO |
VIDEO_DECODER_CCIR ;
cap - > inputs = 8 ;
cap - > outputs = 1 ;
}
break ;
case DECODER_GET_STATUS :
{
int * iarg = arg ;
int status ;
int res ;
status = bt819_read ( client , 0x00 ) ;
res = 0 ;
if ( ( status & 0x80 ) ) {
res | = DECODER_STATUS_GOOD ;
}
switch ( decoder - > norm ) {
case VIDEO_MODE_NTSC :
res | = DECODER_STATUS_NTSC ;
break ;
case VIDEO_MODE_PAL :
res | = DECODER_STATUS_PAL ;
break ;
default :
case VIDEO_MODE_AUTO :
if ( ( status & 0x10 ) ) {
res | = DECODER_STATUS_PAL ;
} else {
res | = DECODER_STATUS_NTSC ;
}
break ;
}
res | = DECODER_STATUS_COLOR ;
* iarg = res ;
dprintk ( 1 , KERN_INFO " %s: get status %x \n " , I2C_NAME ( client ) ,
* iarg ) ;
}
break ;
case DECODER_SET_NORM :
{
int * iarg = arg ;
struct timing * timing = NULL ;
dprintk ( 1 , KERN_INFO " %s: set norm %x \n " , I2C_NAME ( client ) ,
* iarg ) ;
switch ( * iarg ) {
case VIDEO_MODE_NTSC :
bt819_setbit ( client , 0x01 , 0 , 1 ) ;
bt819_setbit ( client , 0x01 , 1 , 0 ) ;
bt819_setbit ( client , 0x01 , 5 , 0 ) ;
bt819_write ( client , 0x18 , 0x68 ) ;
bt819_write ( client , 0x19 , 0x5d ) ;
//bt819_setbit(client, 0x1a, 5, 1);
timing = & timing_data [ VIDEO_MODE_NTSC ] ;
break ;
case VIDEO_MODE_PAL :
bt819_setbit ( client , 0x01 , 0 , 1 ) ;
bt819_setbit ( client , 0x01 , 1 , 1 ) ;
bt819_setbit ( client , 0x01 , 5 , 1 ) ;
bt819_write ( client , 0x18 , 0x7f ) ;
bt819_write ( client , 0x19 , 0x72 ) ;
//bt819_setbit(client, 0x1a, 5, 0);
timing = & timing_data [ VIDEO_MODE_PAL ] ;
break ;
case VIDEO_MODE_AUTO :
bt819_setbit ( client , 0x01 , 0 , 0 ) ;
bt819_setbit ( client , 0x01 , 1 , 0 ) ;
break ;
default :
dprintk ( 1 ,
KERN_ERR
" %s: unsupported norm %d \n " ,
I2C_NAME ( client ) , * iarg ) ;
return - EINVAL ;
}
if ( timing ) {
bt819_write ( client , 0x03 ,
( ( ( timing - > vdelay > > 8 ) & 0x03 ) < < 6 ) |
( ( ( timing - > vactive > > 8 ) & 0x03 ) < < 4 ) |
( ( ( timing - > hdelay > > 8 ) & 0x03 ) < < 2 ) |
( ( timing - > hactive > > 8 ) & 0x03 ) ) ;
bt819_write ( client , 0x04 , timing - > vdelay & 0xff ) ;
bt819_write ( client , 0x05 , timing - > vactive & 0xff ) ;
bt819_write ( client , 0x06 , timing - > hdelay & 0xff ) ;
bt819_write ( client , 0x07 , timing - > hactive & 0xff ) ;
bt819_write ( client , 0x08 , ( timing - > hscale > > 8 ) & 0xff ) ;
bt819_write ( client , 0x09 , timing - > hscale & 0xff ) ;
}
decoder - > norm = * iarg ;
}
break ;
case DECODER_SET_INPUT :
{
int * iarg = arg ;
dprintk ( 1 , KERN_INFO " %s: set input %x \n " , I2C_NAME ( client ) ,
* iarg ) ;
if ( * iarg < 0 | | * iarg > 7 ) {
return - EINVAL ;
}
if ( decoder - > input ! = * iarg ) {
decoder - > input = * iarg ;
/* select mode */
if ( decoder - > input = = 0 ) {
bt819_setbit ( client , 0x0b , 6 , 0 ) ;
bt819_setbit ( client , 0x1a , 1 , 1 ) ;
} else {
bt819_setbit ( client , 0x0b , 6 , 1 ) ;
bt819_setbit ( client , 0x1a , 1 , 0 ) ;
}
}
}
break ;
case DECODER_SET_OUTPUT :
{
int * iarg = arg ;
dprintk ( 1 , KERN_INFO " %s: set output %x \n " , I2C_NAME ( client ) ,
* iarg ) ;
/* not much choice of outputs */
if ( * iarg ! = 0 ) {
return - EINVAL ;
}
}
break ;
case DECODER_ENABLE_OUTPUT :
{
int * iarg = arg ;
int enable = ( * iarg ! = 0 ) ;
dprintk ( 1 , KERN_INFO " %s: enable output %x \n " ,
I2C_NAME ( client ) , * iarg ) ;
if ( decoder - > enable ! = enable ) {
decoder - > enable = enable ;
if ( decoder - > enable ) {
bt819_setbit ( client , 0x16 , 7 , 0 ) ;
} else {
bt819_setbit ( client , 0x16 , 7 , 1 ) ;
}
}
}
break ;
case DECODER_SET_PICTURE :
{
struct video_picture * pic = arg ;
dprintk ( 1 ,
KERN_INFO
" %s: set picture brightness %d contrast %d colour %d \n " ,
I2C_NAME ( client ) , pic - > brightness , pic - > contrast ,
pic - > colour ) ;
if ( decoder - > bright ! = pic - > brightness ) {
/* We want -128 to 127 we get 0-65535 */
decoder - > bright = pic - > brightness ;
bt819_write ( client , 0x0a ,
( decoder - > bright > > 8 ) - 128 ) ;
}
if ( decoder - > contrast ! = pic - > contrast ) {
/* We want 0 to 511 we get 0-65535 */
decoder - > contrast = pic - > contrast ;
bt819_write ( client , 0x0c ,
( decoder - > contrast > > 7 ) & 0xff ) ;
bt819_setbit ( client , 0x0b , 2 ,
( ( decoder - > contrast > > 15 ) & 0x01 ) ) ;
}
if ( decoder - > sat ! = pic - > colour ) {
/* We want 0 to 511 we get 0-65535 */
decoder - > sat = pic - > colour ;
bt819_write ( client , 0x0d ,
( decoder - > sat > > 7 ) & 0xff ) ;
bt819_setbit ( client , 0x0b , 1 ,
( ( decoder - > sat > > 15 ) & 0x01 ) ) ;
temp = ( decoder - > sat * 201 ) / 237 ;
bt819_write ( client , 0x0e , ( temp > > 7 ) & 0xff ) ;
bt819_setbit ( client , 0x0b , 0 , ( temp > > 15 ) & 0x01 ) ;
}
if ( decoder - > hue ! = pic - > hue ) {
/* We want -128 to 127 we get 0-65535 */
decoder - > hue = pic - > hue ;
bt819_write ( client , 0x0f ,
128 - ( decoder - > hue > > 8 ) ) ;
}
}
break ;
default :
return - EINVAL ;
}
return 0 ;
}
/* ----------------------------------------------------------------------- */
/*
* Generic i2c probe
* concerning the addresses : i2c wants 7 bit ( without the r / w bit ) , so ' > > 1 '
*/
static unsigned short normal_i2c [ ] = {
I2C_BT819 > > 1 ,
I2C_CLIENT_END ,
} ;
2005-04-02 22:04:41 +04:00
static unsigned short ignore = I2C_CLIENT_END ;
2005-04-17 02:20:36 +04:00
static struct i2c_client_address_data addr_data = {
. normal_i2c = normal_i2c ,
2005-04-02 22:04:41 +04:00
. probe = & ignore ,
. ignore = & ignore ,
2005-04-17 02:20:36 +04:00
} ;
static struct i2c_driver i2c_driver_bt819 ;
static int
bt819_detect_client ( struct i2c_adapter * adapter ,
int address ,
int kind )
{
int i , id ;
struct bt819 * decoder ;
struct i2c_client * client ;
dprintk ( 1 ,
KERN_INFO
" saa7111.c: detecting bt819 client on address 0x%x \n " ,
address < < 1 ) ;
/* Check if the adapter supports the needed features */
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return 0 ;
2006-01-12 00:40:56 +03:00
client = kzalloc ( sizeof ( struct i2c_client ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( client = = 0 )
return - ENOMEM ;
client - > addr = address ;
client - > adapter = adapter ;
client - > driver = & i2c_driver_bt819 ;
2006-01-12 00:40:56 +03:00
decoder = kzalloc ( sizeof ( struct bt819 ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( decoder = = NULL ) {
kfree ( client ) ;
return - ENOMEM ;
}
decoder - > norm = VIDEO_MODE_NTSC ;
decoder - > input = 0 ;
decoder - > enable = 1 ;
decoder - > bright = 32768 ;
decoder - > contrast = 32768 ;
decoder - > hue = 32768 ;
decoder - > sat = 32768 ;
decoder - > initialized = 0 ;
i2c_set_clientdata ( client , decoder ) ;
id = bt819_read ( client , 0x17 ) ;
switch ( id & 0xf0 ) {
case 0x70 :
strlcpy ( I2C_NAME ( client ) , " bt819a " , sizeof ( I2C_NAME ( client ) ) ) ;
break ;
case 0x60 :
strlcpy ( I2C_NAME ( client ) , " bt817a " , sizeof ( I2C_NAME ( client ) ) ) ;
break ;
case 0x20 :
strlcpy ( I2C_NAME ( client ) , " bt815a " , sizeof ( I2C_NAME ( client ) ) ) ;
break ;
default :
dprintk ( 1 ,
KERN_ERR
" bt819: unknown chip version 0x%x (ver 0x%x) \n " ,
id & 0xf0 , id & 0x0f ) ;
kfree ( decoder ) ;
kfree ( client ) ;
return 0 ;
}
i = i2c_attach_client ( client ) ;
if ( i ) {
kfree ( client ) ;
kfree ( decoder ) ;
return i ;
}
i = bt819_init ( client ) ;
if ( i < 0 ) {
dprintk ( 1 , KERN_ERR " %s_attach: init status %d \n " ,
I2C_NAME ( client ) , i ) ;
} else {
dprintk ( 1 ,
KERN_INFO
" %s_attach: chip version 0x%x at address 0x%x \n " ,
I2C_NAME ( client ) , id & 0x0f ,
client - > addr < < 1 ) ;
}
return 0 ;
}
static int
bt819_attach_adapter ( struct i2c_adapter * adapter )
{
return i2c_probe ( adapter , & addr_data , & bt819_detect_client ) ;
}
static int
bt819_detach_client ( struct i2c_client * client )
{
struct bt819 * decoder = i2c_get_clientdata ( client ) ;
int err ;
err = i2c_detach_client ( client ) ;
if ( err ) {
return err ;
}
kfree ( decoder ) ;
kfree ( client ) ;
return 0 ;
}
/* ----------------------------------------------------------------------- */
static struct i2c_driver i2c_driver_bt819 = {
2005-11-26 22:43:39 +03:00
. driver = {
. name = " bt819 " ,
} ,
2005-04-17 02:20:36 +04:00
. id = I2C_DRIVERID_BT819 ,
. attach_adapter = bt819_attach_adapter ,
. detach_client = bt819_detach_client ,
. command = bt819_command ,
} ;
static int __init
bt819_init_module ( void )
{
return i2c_add_driver ( & i2c_driver_bt819 ) ;
}
static void __exit
bt819_exit ( void )
{
i2c_del_driver ( & i2c_driver_bt819 ) ;
}
module_init ( bt819_init_module ) ;
module_exit ( bt819_exit ) ;