2005-04-17 02:20:36 +04:00
/*
* saa7110 - Philips SAA7110 ( A ) video decoder driver
*
* Copyright ( C ) 1998 Pauline Middelink < middelin @ polyware . nl >
*
* Copyright ( C ) 1999 Wolfgang Scherr < scherr @ net4you . net >
* Copyright ( C ) 2000 Serguei Miridonov < mirsev @ cicese . mx >
* - some corrections for Pinnacle Systems Inc . DC10plus card .
*
* Changes by Ronald Bultje < rbultje @ ronald . bitfreak . net >
* - moved over to linux > = 2.4 . x i2c protocol ( 1 / 1 / 2003 )
*
* 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 .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/wait.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2008-09-07 15:00:32 +04:00
# include <linux/i2c.h>
2009-02-19 18:24:27 +03:00
# include <linux/videodev2.h>
# include <media/v4l2-device.h>
2010-12-12 14:27:48 +03:00
# include <media/v4l2-ctrls.h>
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " Philips SAA7110 video decoder driver " ) ;
MODULE_AUTHOR ( " Pauline Middelink " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-02-19 18:24:27 +03:00
2008-04-22 21:41:48 +04:00
static int debug ;
2005-04-17 02:20:36 +04:00
module_param ( debug , int , 0 ) ;
MODULE_PARM_DESC ( debug , " Debug level (0-1) " ) ;
# define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */
2008-10-24 22:08:28 +04:00
# define SAA7110_MAX_OUTPUT 1 /* 1 YUV */
2005-04-17 02:20:36 +04:00
# define SAA7110_NR_REG 0x35
struct saa7110 {
2009-02-19 18:24:27 +03:00
struct v4l2_subdev sd ;
2010-12-12 14:27:48 +03:00
struct v4l2_ctrl_handler hdl ;
2005-04-17 02:20:36 +04:00
u8 reg [ SAA7110_NR_REG ] ;
2009-02-18 23:26:06 +03:00
v4l2_std_id norm ;
2005-04-17 02:20:36 +04:00
int input ;
int enable ;
wait_queue_head_t wq ;
} ;
2009-02-19 18:24:27 +03:00
static inline struct saa7110 * to_saa7110 ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct saa7110 , sd ) ;
}
2010-12-12 14:27:48 +03:00
static inline struct v4l2_subdev * to_sd ( struct v4l2_ctrl * ctrl )
{
return & container_of ( ctrl - > handler , struct saa7110 , hdl ) - > sd ;
}
2005-04-17 02:20:36 +04:00
/* ----------------------------------------------------------------------- */
/* I2C support functions */
/* ----------------------------------------------------------------------- */
2009-02-19 18:24:27 +03:00
static int saa7110_write ( struct v4l2_subdev * sd , u8 reg , u8 value )
2005-04-17 02:20:36 +04:00
{
2009-02-19 18:24:27 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct saa7110 * decoder = to_saa7110 ( sd ) ;
2005-04-17 02:20:36 +04:00
decoder - > reg [ reg ] = value ;
return i2c_smbus_write_byte_data ( client , reg , value ) ;
}
2009-02-19 18:24:27 +03:00
static int saa7110_write_block ( struct v4l2_subdev * sd , const u8 * data , unsigned int len )
2005-04-17 02:20:36 +04:00
{
2009-02-19 18:24:27 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct saa7110 * decoder = to_saa7110 ( sd ) ;
2005-04-17 02:20:36 +04:00
int ret = - 1 ;
u8 reg = * data ; /* first register to write to */
/* Sanity check */
if ( reg + ( len - 1 ) > SAA7110_NR_REG )
return ret ;
/* the saa7110 has an autoincrement function, use it if
* the adapter understands raw I2C */
if ( i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
2006-03-22 09:48:35 +03:00
ret = i2c_master_send ( client , data , len ) ;
2005-04-17 02:20:36 +04:00
/* Cache the written data */
memcpy ( decoder - > reg + reg , data + 1 , len - 1 ) ;
} else {
for ( + + data , - - len ; len ; len - - ) {
2009-02-19 18:24:27 +03:00
ret = saa7110_write ( sd , reg + + , * data + + ) ;
2008-09-07 15:00:32 +04:00
if ( ret < 0 )
2005-04-17 02:20:36 +04:00
break ;
}
}
return ret ;
}
2009-02-19 18:24:27 +03:00
static inline int saa7110_read ( struct v4l2_subdev * sd )
2005-04-17 02:20:36 +04:00
{
2009-02-19 18:24:27 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2005-04-17 02:20:36 +04:00
return i2c_smbus_read_byte ( client ) ;
}
/* ----------------------------------------------------------------------- */
/* SAA7110 functions */
/* ----------------------------------------------------------------------- */
2009-02-19 18:24:27 +03:00
# define FRESP_06H_COMPST 0x03 /*0x13*/
# define FRESP_06H_SVIDEO 0x83 /*0xC0*/
2005-04-17 02:20:36 +04:00
2009-02-19 18:24:27 +03:00
static int saa7110_selmux ( struct v4l2_subdev * sd , int chan )
2005-04-17 02:20:36 +04:00
{
static const unsigned char modes [ 9 ] [ 8 ] = {
/* mode 0 */
{ FRESP_06H_COMPST , 0xD9 , 0x17 , 0x40 , 0x03 ,
0x44 , 0x75 , 0x16 } ,
/* mode 1 */
{ FRESP_06H_COMPST , 0xD8 , 0x17 , 0x40 , 0x03 ,
0x44 , 0x75 , 0x16 } ,
/* mode 2 */
{ FRESP_06H_COMPST , 0xBA , 0x07 , 0x91 , 0x03 ,
0x60 , 0xB5 , 0x05 } ,
/* mode 3 */
{ FRESP_06H_COMPST , 0xB8 , 0x07 , 0x91 , 0x03 ,
0x60 , 0xB5 , 0x05 } ,
/* mode 4 */
{ FRESP_06H_COMPST , 0x7C , 0x07 , 0xD2 , 0x83 ,
0x60 , 0xB5 , 0x03 } ,
/* mode 5 */
{ FRESP_06H_COMPST , 0x78 , 0x07 , 0xD2 , 0x83 ,
0x60 , 0xB5 , 0x03 } ,
/* mode 6 */
{ FRESP_06H_SVIDEO , 0x59 , 0x17 , 0x42 , 0xA3 ,
0x44 , 0x75 , 0x12 } ,
/* mode 7 */
{ FRESP_06H_SVIDEO , 0x9A , 0x17 , 0xB1 , 0x13 ,
0x60 , 0xB5 , 0x14 } ,
/* mode 8 */
{ FRESP_06H_SVIDEO , 0x3C , 0x27 , 0xC1 , 0x23 ,
0x44 , 0x75 , 0x21 }
} ;
2009-02-19 18:24:27 +03:00
struct saa7110 * decoder = to_saa7110 ( sd ) ;
2005-04-17 02:20:36 +04:00
const unsigned char * ptr = modes [ chan ] ;
2009-02-19 18:24:27 +03:00
saa7110_write ( sd , 0x06 , ptr [ 0 ] ) ; /* Luminance control */
saa7110_write ( sd , 0x20 , ptr [ 1 ] ) ; /* Analog Control #1 */
saa7110_write ( sd , 0x21 , ptr [ 2 ] ) ; /* Analog Control #2 */
saa7110_write ( sd , 0x22 , ptr [ 3 ] ) ; /* Mixer Control #1 */
saa7110_write ( sd , 0x2C , ptr [ 4 ] ) ; /* Mixer Control #2 */
saa7110_write ( sd , 0x30 , ptr [ 5 ] ) ; /* ADCs gain control */
saa7110_write ( sd , 0x31 , ptr [ 6 ] ) ; /* Mixer Control #3 */
saa7110_write ( sd , 0x21 , ptr [ 7 ] ) ; /* Analog Control #2 */
2005-04-17 02:20:36 +04:00
decoder - > input = chan ;
return 0 ;
}
static const unsigned char initseq [ 1 + SAA7110_NR_REG ] = {
0 , 0x4C , 0x3C , 0x0D , 0xEF , 0xBD , 0xF2 , 0x03 , 0x00 ,
/* 0x08 */ 0xF8 , 0xF8 , 0x60 , 0x60 , 0x00 , 0x86 , 0x18 , 0x90 ,
/* 0x10 */ 0x00 , 0x59 , 0x40 , 0x46 , 0x42 , 0x1A , 0xFF , 0xDA ,
/* 0x18 */ 0xF2 , 0x8B , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
/* 0x20 */ 0xD9 , 0x16 , 0x40 , 0x41 , 0x80 , 0x41 , 0x80 , 0x4F ,
/* 0x28 */ 0xFE , 0x01 , 0xCF , 0x0F , 0x03 , 0x01 , 0x03 , 0x0C ,
/* 0x30 */ 0x44 , 0x71 , 0x02 , 0x8C , 0x02
} ;
2009-02-19 18:24:27 +03:00
static v4l2_std_id determine_norm ( struct v4l2_subdev * sd )
2005-04-17 02:20:36 +04:00
{
DEFINE_WAIT ( wait ) ;
2009-02-19 18:24:27 +03:00
struct saa7110 * decoder = to_saa7110 ( sd ) ;
2005-04-17 02:20:36 +04:00
int status ;
/* mode changed, start automatic detection */
2009-02-19 18:24:27 +03:00
saa7110_write_block ( sd , initseq , sizeof ( initseq ) ) ;
saa7110_selmux ( sd , decoder - > input ) ;
2005-04-17 02:20:36 +04:00
prepare_to_wait ( & decoder - > wq , & wait , TASK_UNINTERRUPTIBLE ) ;
2007-07-17 23:25:38 +04:00
schedule_timeout ( msecs_to_jiffies ( 250 ) ) ;
2005-04-17 02:20:36 +04:00
finish_wait ( & decoder - > wq , & wait ) ;
2009-02-19 18:24:27 +03:00
status = saa7110_read ( sd ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x40 ) {
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " status=0x%02x (no signal) \n " , status ) ;
2013-05-29 17:18:57 +04:00
return V4L2_STD_UNKNOWN ;
2005-04-17 02:20:36 +04:00
}
if ( ( status & 3 ) = = 0 ) {
2009-02-19 18:24:27 +03:00
saa7110_write ( sd , 0x06 , 0x83 ) ;
2005-04-17 02:20:36 +04:00
if ( status & 0x20 ) {
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " status=0x%02x (NTSC/no color) \n " , status ) ;
/*saa7110_write(sd,0x2E,0x81);*/
2009-02-18 23:26:06 +03:00
return V4L2_STD_NTSC ;
2005-04-17 02:20:36 +04:00
}
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " status=0x%02x (PAL/no color) \n " , status ) ;
/*saa7110_write(sd,0x2E,0x9A);*/
2009-02-18 23:26:06 +03:00
return V4L2_STD_PAL ;
2005-04-17 02:20:36 +04:00
}
2009-02-19 18:24:27 +03:00
/*saa7110_write(sd,0x06,0x03);*/
2005-04-17 02:20:36 +04:00
if ( status & 0x20 ) { /* 60Hz */
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " status=0x%02x (NTSC) \n " , status ) ;
saa7110_write ( sd , 0x0D , 0x86 ) ;
saa7110_write ( sd , 0x0F , 0x50 ) ;
saa7110_write ( sd , 0x11 , 0x2C ) ;
/*saa7110_write(sd,0x2E,0x81);*/
2009-02-18 23:26:06 +03:00
return V4L2_STD_NTSC ;
2005-04-17 02:20:36 +04:00
}
/* 50Hz -> PAL/SECAM */
2009-02-19 18:24:27 +03:00
saa7110_write ( sd , 0x0D , 0x86 ) ;
saa7110_write ( sd , 0x0F , 0x10 ) ;
saa7110_write ( sd , 0x11 , 0x59 ) ;
/*saa7110_write(sd,0x2E,0x9A);*/
2005-04-17 02:20:36 +04:00
prepare_to_wait ( & decoder - > wq , & wait , TASK_UNINTERRUPTIBLE ) ;
2007-07-17 23:25:38 +04:00
schedule_timeout ( msecs_to_jiffies ( 250 ) ) ;
2005-04-17 02:20:36 +04:00
finish_wait ( & decoder - > wq , & wait ) ;
2009-02-19 18:24:27 +03:00
status = saa7110_read ( sd ) ;
2005-04-17 02:20:36 +04:00
if ( ( status & 0x03 ) = = 0x01 ) {
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " status=0x%02x (SECAM) \n " , status ) ;
saa7110_write ( sd , 0x0D , 0x87 ) ;
2009-02-18 23:26:06 +03:00
return V4L2_STD_SECAM ;
2005-04-17 02:20:36 +04:00
}
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " status=0x%02x (PAL) \n " , status ) ;
2009-02-18 23:26:06 +03:00
return V4L2_STD_PAL ;
2005-04-17 02:20:36 +04:00
}
2009-02-19 18:24:27 +03:00
static int saa7110_g_input_status ( struct v4l2_subdev * sd , u32 * pstatus )
2005-04-17 02:20:36 +04:00
{
2009-02-19 18:24:27 +03:00
struct saa7110 * decoder = to_saa7110 ( sd ) ;
int res = V4L2_IN_ST_NO_SIGNAL ;
int status = saa7110_read ( sd ) ;
v4l2_dbg ( 1 , debug , sd , " status=0x%02x norm=%llx \n " ,
2009-03-06 16:15:01 +03:00
status , ( unsigned long long ) decoder - > norm ) ;
2009-02-19 18:24:27 +03:00
if ( ! ( status & 0x40 ) )
res = 0 ;
if ( ! ( status & 0x03 ) )
res | = V4L2_IN_ST_NO_COLOR ;
* pstatus = res ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-02-19 18:24:27 +03:00
static int saa7110_querystd ( struct v4l2_subdev * sd , v4l2_std_id * std )
{
2013-05-29 17:18:57 +04:00
* std & = determine_norm ( sd ) ;
2009-02-19 18:24:27 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-02-19 18:24:27 +03:00
static int saa7110_s_std ( struct v4l2_subdev * sd , v4l2_std_id std )
{
struct saa7110 * decoder = to_saa7110 ( sd ) ;
if ( decoder - > norm ! = std ) {
decoder - > norm = std ;
/*saa7110_write(sd, 0x06, 0x03);*/
if ( std & V4L2_STD_NTSC ) {
saa7110_write ( sd , 0x0D , 0x86 ) ;
saa7110_write ( sd , 0x0F , 0x50 ) ;
saa7110_write ( sd , 0x11 , 0x2C ) ;
/*saa7110_write(sd, 0x2E, 0x81);*/
v4l2_dbg ( 1 , debug , sd , " switched to NTSC \n " ) ;
} else if ( std & V4L2_STD_PAL ) {
saa7110_write ( sd , 0x0D , 0x86 ) ;
saa7110_write ( sd , 0x0F , 0x10 ) ;
saa7110_write ( sd , 0x11 , 0x59 ) ;
/*saa7110_write(sd, 0x2E, 0x9A);*/
v4l2_dbg ( 1 , debug , sd , " switched to PAL \n " ) ;
} else if ( std & V4L2_STD_SECAM ) {
saa7110_write ( sd , 0x0D , 0x87 ) ;
saa7110_write ( sd , 0x0F , 0x10 ) ;
saa7110_write ( sd , 0x11 , 0x59 ) ;
/*saa7110_write(sd, 0x2E, 0x9A);*/
v4l2_dbg ( 1 , debug , sd , " switched to SECAM \n " ) ;
} else {
return - EINVAL ;
}
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-04-02 18:26:22 +04:00
static int saa7110_s_routing ( struct v4l2_subdev * sd ,
u32 input , u32 output , u32 config )
2009-02-19 18:24:27 +03:00
{
struct saa7110 * decoder = to_saa7110 ( sd ) ;
2009-10-23 14:59:42 +04:00
if ( input > = SAA7110_MAX_INPUT ) {
2009-04-02 18:26:22 +04:00
v4l2_dbg ( 1 , debug , sd , " input=%d not available \n " , input ) ;
2009-02-19 18:24:27 +03:00
return - EINVAL ;
2008-09-07 15:00:32 +04:00
}
2009-04-02 18:26:22 +04:00
if ( decoder - > input ! = input ) {
saa7110_selmux ( sd , input ) ;
v4l2_dbg ( 1 , debug , sd , " switched to input=%d \n " , input ) ;
2009-02-19 18:24:27 +03:00
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-02-19 18:24:27 +03:00
static int saa7110_s_stream ( struct v4l2_subdev * sd , int enable )
{
struct saa7110 * decoder = to_saa7110 ( sd ) ;
if ( decoder - > enable ! = enable ) {
decoder - > enable = enable ;
saa7110_write ( sd , 0x0E , enable ? 0x18 : 0x80 ) ;
v4l2_dbg ( 1 , debug , sd , " YUV %s \n " , enable ? " on " : " off " ) ;
2009-02-18 23:26:06 +03:00
}
2009-02-19 18:24:27 +03:00
return 0 ;
}
2009-02-18 23:26:06 +03:00
2010-12-12 14:27:48 +03:00
static int saa7110_s_ctrl ( struct v4l2_ctrl * ctrl )
2009-02-19 18:24:27 +03:00
{
2010-12-12 14:27:48 +03:00
struct v4l2_subdev * sd = to_sd ( ctrl ) ;
2009-02-19 18:24:27 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
2010-12-12 14:27:48 +03:00
saa7110_write ( sd , 0x19 , ctrl - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
2009-02-19 18:24:27 +03:00
case V4L2_CID_CONTRAST :
2010-12-12 14:27:48 +03:00
saa7110_write ( sd , 0x13 , ctrl - > val ) ;
2009-02-18 23:26:06 +03:00
break ;
2009-02-19 18:24:27 +03:00
case V4L2_CID_SATURATION :
2010-12-12 14:27:48 +03:00
saa7110_write ( sd , 0x12 , ctrl - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
2009-02-19 18:24:27 +03:00
case V4L2_CID_HUE :
2010-12-12 14:27:48 +03:00
saa7110_write ( sd , 0x07 , ctrl - > val ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
/* ----------------------------------------------------------------------- */
2010-12-12 14:27:48 +03:00
static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
. s_ctrl = saa7110_s_ctrl ,
} ;
2009-02-19 18:24:27 +03:00
static const struct v4l2_subdev_video_ops saa7110_video_ops = {
2014-04-28 23:53:01 +04:00
. s_std = saa7110_s_std ,
2009-02-19 18:24:27 +03:00
. s_routing = saa7110_s_routing ,
. s_stream = saa7110_s_stream ,
. querystd = saa7110_querystd ,
. g_input_status = saa7110_g_input_status ,
} ;
static const struct v4l2_subdev_ops saa7110_ops = {
. video = & saa7110_video_ops ,
} ;
/* ----------------------------------------------------------------------- */
2005-04-17 02:20:36 +04:00
2008-09-07 15:00:32 +04:00
static int saa7110_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2005-04-17 02:20:36 +04:00
{
struct saa7110 * decoder ;
2009-02-19 18:24:27 +03:00
struct v4l2_subdev * sd ;
2005-04-17 02:20:36 +04:00
int rv ;
/* Check if the adapter supports the needed features */
2008-09-07 15:00:32 +04:00
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA ) )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2008-09-07 15:00:32 +04:00
v4l_info ( client , " chip found @ 0x%x (%s) \n " ,
client - > addr < < 1 , client - > adapter - > name ) ;
2005-04-17 02:20:36 +04:00
2013-05-02 15:29:43 +04:00
decoder = devm_kzalloc ( & client - > dev , sizeof ( * decoder ) , GFP_KERNEL ) ;
2008-09-07 15:00:32 +04:00
if ( ! decoder )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-02-19 18:24:27 +03:00
sd = & decoder - > sd ;
v4l2_i2c_subdev_init ( sd , client , & saa7110_ops ) ;
2009-02-18 23:26:06 +03:00
decoder - > norm = V4L2_STD_PAL ;
2005-04-17 02:20:36 +04:00
decoder - > input = 0 ;
decoder - > enable = 1 ;
2010-12-12 14:27:48 +03:00
v4l2_ctrl_handler_init ( & decoder - > hdl , 2 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & saa7110_ctrl_ops ,
V4L2_CID_BRIGHTNESS , 0 , 255 , 1 , 128 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & saa7110_ctrl_ops ,
V4L2_CID_CONTRAST , 0 , 127 , 1 , 64 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & saa7110_ctrl_ops ,
V4L2_CID_SATURATION , 0 , 127 , 1 , 64 ) ;
v4l2_ctrl_new_std ( & decoder - > hdl , & saa7110_ctrl_ops ,
V4L2_CID_HUE , - 128 , 127 , 1 , 0 ) ;
sd - > ctrl_handler = & decoder - > hdl ;
if ( decoder - > hdl . error ) {
int err = decoder - > hdl . error ;
v4l2_ctrl_handler_free ( & decoder - > hdl ) ;
return err ;
}
v4l2_ctrl_handler_setup ( & decoder - > hdl ) ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & decoder - > wq ) ;
2009-02-19 18:24:27 +03:00
rv = saa7110_write_block ( sd , initseq , sizeof ( initseq ) ) ;
2008-09-07 15:00:32 +04:00
if ( rv < 0 ) {
2009-02-19 18:24:27 +03:00
v4l2_dbg ( 1 , debug , sd , " init status %d \n " , rv ) ;
2008-09-07 15:00:32 +04:00
} else {
2005-04-17 02:20:36 +04:00
int ver , status ;
2009-02-19 18:24:27 +03:00
saa7110_write ( sd , 0x21 , 0x10 ) ;
saa7110_write ( sd , 0x0e , 0x18 ) ;
saa7110_write ( sd , 0x0D , 0x04 ) ;
ver = saa7110_read ( sd ) ;
saa7110_write ( sd , 0x0D , 0x06 ) ;
/*mdelay(150);*/
status = saa7110_read ( sd ) ;
v4l2_dbg ( 1 , debug , sd , " version %x, status=0x%02x \n " ,
2008-09-07 15:00:32 +04:00
ver , status ) ;
2009-02-19 18:24:27 +03:00
saa7110_write ( sd , 0x0D , 0x86 ) ;
saa7110_write ( sd , 0x0F , 0x10 ) ;
saa7110_write ( sd , 0x11 , 0x59 ) ;
/*saa7110_write(sd, 0x2E, 0x9A);*/
2005-04-17 02:20:36 +04:00
}
2009-02-19 18:24:27 +03:00
/*saa7110_selmux(sd,0);*/
/*determine_norm(sd);*/
2005-04-17 02:20:36 +04:00
/* setup and implicit mode 0 select has been performed */
return 0 ;
}
2008-09-07 15:00:32 +04:00
static int saa7110_remove ( struct i2c_client * client )
2005-04-17 02:20:36 +04:00
{
2009-02-19 18:24:27 +03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
2010-12-12 14:27:48 +03:00
struct saa7110 * decoder = to_saa7110 ( sd ) ;
2009-02-19 18:24:27 +03:00
v4l2_device_unregister_subdev ( sd ) ;
2010-12-12 14:27:48 +03:00
v4l2_ctrl_handler_free ( & decoder - > hdl ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* ----------------------------------------------------------------------- */
2008-09-07 15:00:32 +04:00
static const struct i2c_device_id saa7110_id [ ] = {
{ " saa7110 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , saa7110_id ) ;
2005-04-17 02:20:36 +04:00
2010-09-15 22:38:54 +04:00
static struct i2c_driver saa7110_driver = {
. driver = {
. name = " saa7110 " ,
} ,
. probe = saa7110_probe ,
. remove = saa7110_remove ,
. id_table = saa7110_id ,
2005-04-17 02:20:36 +04:00
} ;
2010-09-15 22:38:54 +04:00
2012-02-12 13:56:32 +04:00
module_i2c_driver ( saa7110_driver ) ;