2005-09-07 02:19:37 +04:00
/*
* saa7191 . c - Philips SAA7191 video decoder driver
*
* Copyright ( C ) 2003 Ladislav Michl < ladis @ linux - mips . org >
* Copyright ( C ) 2004 , 2005 Mikael Nousiainen < tmnousia @ cc . hut . fi >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/fs.h>
2005-09-23 14:52:27 +04:00
# include <linux/init.h>
2005-09-07 02:19:37 +04:00
# include <linux/kernel.h>
# include <linux/major.h>
2005-09-23 14:52:27 +04:00
# include <linux/module.h>
2005-09-07 02:19:37 +04:00
# include <linux/mm.h>
2005-09-23 14:52:27 +04:00
# include <linux/slab.h>
2005-09-07 02:19:37 +04:00
2009-02-27 15:05:10 +03:00
# include <linux/videodev2.h>
2005-09-07 02:19:37 +04:00
# include <linux/i2c.h>
2009-02-14 01:58:12 +03:00
# include <media/v4l2-device.h>
# include <media/v4l2-chip-ident.h>
2005-09-07 02:19:37 +04:00
# include "saa7191.h"
2005-09-01 19:07:34 +04:00
# define SAA7191_MODULE_VERSION "0.0.5"
2005-09-07 02:19:37 +04:00
MODULE_DESCRIPTION ( " Philips SAA7191 video decoder driver " ) ;
MODULE_VERSION ( SAA7191_MODULE_VERSION ) ;
MODULE_AUTHOR ( " Mikael Nousiainen <tmnousia@cc.hut.fi> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-02-13 13:31:05 +03:00
2005-09-01 19:07:34 +04:00
// #define SAA7191_DEBUG
# ifdef SAA7191_DEBUG
# define dprintk(x...) printk("SAA7191: " x);
# else
# define dprintk(x...)
# endif
# define SAA7191_SYNC_COUNT 30
# define SAA7191_SYNC_DELAY 100 /* milliseconds */
2005-09-07 02:19:37 +04:00
struct saa7191 {
2009-02-14 01:58:12 +03:00
struct v4l2_subdev sd ;
2005-09-07 02:19:37 +04:00
/* the register values are stored here as the actual
* I2C - registers are write - only */
2005-09-01 19:07:34 +04:00
u8 reg [ 25 ] ;
2005-09-07 02:19:37 +04:00
2005-09-01 19:07:34 +04:00
int input ;
2009-02-27 15:05:10 +03:00
v4l2_std_id norm ;
2005-09-07 02:19:37 +04:00
} ;
2009-02-14 01:58:12 +03:00
static inline struct saa7191 * to_saa7191 ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct saa7191 , sd ) ;
}
2005-09-01 19:07:34 +04:00
static const u8 initseq [ ] = {
2005-09-07 02:19:37 +04:00
0 , /* Subaddress */
2005-09-01 19:07:34 +04:00
0x50 , /* (0x50) SAA7191_REG_IDEL */
/* 50 Hz signal timing */
0x30 , /* (0x30) SAA7191_REG_HSYB */
0x00 , /* (0x00) SAA7191_REG_HSYS */
0xe8 , /* (0xe8) SAA7191_REG_HCLB */
0xb6 , /* (0xb6) SAA7191_REG_HCLS */
0xf4 , /* (0xf4) SAA7191_REG_HPHI */
/* control */
SAA7191_LUMA_APER_1 , /* (0x01) SAA7191_REG_LUMA - CVBS mode */
0x00 , /* (0x00) SAA7191_REG_HUEC */
0xf8 , /* (0xf8) SAA7191_REG_CKTQ */
0xf8 , /* (0xf8) SAA7191_REG_CKTS */
0x90 , /* (0x90) SAA7191_REG_PLSE */
0x90 , /* (0x90) SAA7191_REG_SESE */
0x00 , /* (0x00) SAA7191_REG_GAIN */
SAA7191_STDC_NFEN | SAA7191_STDC_HRMV , /* (0x0c) SAA7191_REG_STDC
* - not SECAM ,
* slow time constant */
SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS
| SAA7191_IOCK_OEDY , /* (0x78) SAA7191_REG_IOCK
* - chroma from CVBS , GPSW1 & 2 off */
SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS
| SAA7191_CTL3_YDEL0 , /* (0x99) SAA7191_REG_CTL3
* - automatic field detection */
0x00 , /* (0x00) SAA7191_REG_CTL4 */
0x2c , /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */
2005-09-07 02:19:37 +04:00
0x00 , /* unused */
0x00 , /* unused */
2005-09-01 19:07:34 +04:00
/* 60 Hz signal timing */
0x34 , /* (0x34) SAA7191_REG_HS6B */
0x0a , /* (0x0a) SAA7191_REG_HS6S */
0xf4 , /* (0xf4) SAA7191_REG_HC6B */
0xce , /* (0xce) SAA7191_REG_HC6S */
0xf4 , /* (0xf4) SAA7191_REG_HP6I */
2005-09-07 02:19:37 +04:00
} ;
/* SAA7191 register handling */
2009-02-14 01:58:12 +03:00
static u8 saa7191_read_reg ( struct v4l2_subdev * sd , u8 reg )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
return to_saa7191 ( sd ) - > reg [ reg ] ;
2005-09-07 02:19:37 +04:00
}
2009-02-14 01:58:12 +03:00
static int saa7191_read_status ( struct v4l2_subdev * sd , u8 * value )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2005-09-07 02:19:37 +04:00
int ret ;
ret = i2c_master_recv ( client , value , 1 ) ;
if ( ret < 0 ) {
2005-09-01 19:07:34 +04:00
printk ( KERN_ERR " SAA7191: saa7191_read_status(): read failed \n " ) ;
2005-09-07 02:19:37 +04:00
return ret ;
}
return 0 ;
}
2009-02-14 01:58:12 +03:00
static int saa7191_write_reg ( struct v4l2_subdev * sd , u8 reg , u8 value )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
to_saa7191 ( sd ) - > reg [ reg ] = value ;
2005-09-07 02:19:37 +04:00
return i2c_smbus_write_byte_data ( client , reg , value ) ;
}
/* the first byte of data must be the first subaddress number (register) */
2009-02-14 01:58:12 +03:00
static int saa7191_write_block ( struct v4l2_subdev * sd ,
2007-09-03 19:01:51 +04:00
u8 length , const u8 * data )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
struct saa7191 * decoder = to_saa7191 ( sd ) ;
2005-09-07 02:19:37 +04:00
int i ;
int ret ;
for ( i = 0 ; i < ( length - 1 ) ; i + + ) {
decoder - > reg [ data [ 0 ] + i ] = data [ i + 1 ] ;
}
ret = i2c_master_send ( client , data , length ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " SAA7191: saa7191_write_block(): "
2005-09-01 19:07:34 +04:00
" write failed \n " ) ;
2005-09-07 02:19:37 +04:00
return ret ;
}
return 0 ;
}
/* Helper functions */
2009-02-14 01:58:12 +03:00
static int saa7191_s_routing ( struct v4l2_subdev * sd ,
2009-04-02 18:26:22 +04:00
u32 input , u32 output , u32 config )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct saa7191 * decoder = to_saa7191 ( sd ) ;
u8 luma = saa7191_read_reg ( sd , SAA7191_REG_LUMA ) ;
u8 iock = saa7191_read_reg ( sd , SAA7191_REG_IOCK ) ;
2005-09-07 02:19:37 +04:00
int err ;
2009-04-02 18:26:22 +04:00
switch ( input ) {
2005-09-07 02:19:37 +04:00
case SAA7191_INPUT_COMPOSITE : /* Set Composite input */
iock & = ~ ( SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
| SAA7191_IOCK_GPSW2 ) ;
/* Chrominance trap active */
luma & = ~ SAA7191_LUMA_BYPS ;
break ;
case SAA7191_INPUT_SVIDEO : /* Set S-Video input */
iock | = SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2 ;
/* Chrominance trap bypassed */
luma | = SAA7191_LUMA_BYPS ;
break ;
default :
return - EINVAL ;
}
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_LUMA , luma ) ;
2005-09-07 02:19:37 +04:00
if ( err )
return - EIO ;
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_IOCK , iock ) ;
2005-09-07 02:19:37 +04:00
if ( err )
return - EIO ;
2009-04-02 18:26:22 +04:00
decoder - > input = input ;
2005-09-01 19:07:34 +04:00
2005-09-07 02:19:37 +04:00
return 0 ;
}
2009-02-14 01:58:12 +03:00
static int saa7191_s_std ( struct v4l2_subdev * sd , v4l2_std_id norm )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct saa7191 * decoder = to_saa7191 ( sd ) ;
u8 stdc = saa7191_read_reg ( sd , SAA7191_REG_STDC ) ;
u8 ctl3 = saa7191_read_reg ( sd , SAA7191_REG_CTL3 ) ;
u8 chcv = saa7191_read_reg ( sd , SAA7191_REG_CHCV ) ;
2005-09-07 02:19:37 +04:00
int err ;
2009-02-27 15:05:10 +03:00
if ( norm & V4L2_STD_PAL ) {
2005-09-07 02:19:37 +04:00
stdc & = ~ SAA7191_STDC_SECS ;
ctl3 & = ~ ( SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL ) ;
chcv = SAA7191_CHCV_PAL ;
2009-02-27 15:05:10 +03:00
} else if ( norm & V4L2_STD_NTSC ) {
2005-09-07 02:19:37 +04:00
stdc & = ~ SAA7191_STDC_SECS ;
ctl3 & = ~ SAA7191_CTL3_AUFD ;
ctl3 | = SAA7191_CTL3_FSEL ;
chcv = SAA7191_CHCV_NTSC ;
2009-02-27 15:05:10 +03:00
} else if ( norm & V4L2_STD_SECAM ) {
2005-09-07 02:19:37 +04:00
stdc | = SAA7191_STDC_SECS ;
ctl3 & = ~ ( SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL ) ;
chcv = SAA7191_CHCV_PAL ;
2009-02-27 15:05:10 +03:00
} else {
2005-09-07 02:19:37 +04:00
return - EINVAL ;
}
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_CTL3 , ctl3 ) ;
2005-09-07 02:19:37 +04:00
if ( err )
return - EIO ;
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_STDC , stdc ) ;
2005-09-07 02:19:37 +04:00
if ( err )
return - EIO ;
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_CHCV , chcv ) ;
2005-09-07 02:19:37 +04:00
if ( err )
return - EIO ;
decoder - > norm = norm ;
2005-09-01 19:07:34 +04:00
dprintk ( " ctl3: %02x stdc: %02x chcv: %02x \n " , ctl3 ,
stdc , chcv ) ;
2009-02-27 15:05:10 +03:00
dprintk ( " norm: %llx \n " , norm ) ;
2005-09-01 19:07:34 +04:00
2005-09-07 02:19:37 +04:00
return 0 ;
}
2009-02-14 01:58:12 +03:00
static int saa7191_wait_for_signal ( struct v4l2_subdev * sd , u8 * status )
2005-09-07 02:19:37 +04:00
{
2005-09-01 19:07:34 +04:00
int i = 0 ;
2005-09-07 02:19:37 +04:00
2005-09-01 19:07:34 +04:00
dprintk ( " Checking for signal... \n " ) ;
for ( i = 0 ; i < SAA7191_SYNC_COUNT ; i + + ) {
2009-02-14 01:58:12 +03:00
if ( saa7191_read_status ( sd , status ) )
2005-09-01 19:07:34 +04:00
return - EIO ;
if ( ( ( * status ) & SAA7191_STATUS_HLCK ) = = 0 ) {
dprintk ( " Signal found \n " ) ;
return 0 ;
}
msleep ( SAA7191_SYNC_DELAY ) ;
2005-09-07 02:19:37 +04:00
}
2005-09-01 19:07:34 +04:00
dprintk ( " No signal \n " ) ;
2005-09-07 02:19:37 +04:00
2005-09-01 19:07:34 +04:00
return - EBUSY ;
2005-09-07 02:19:37 +04:00
}
2009-02-14 01:58:12 +03:00
static int saa7191_querystd ( struct v4l2_subdev * sd , v4l2_std_id * norm )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct saa7191 * decoder = to_saa7191 ( sd ) ;
u8 stdc = saa7191_read_reg ( sd , SAA7191_REG_STDC ) ;
u8 ctl3 = saa7191_read_reg ( sd , SAA7191_REG_CTL3 ) ;
2005-09-01 19:07:34 +04:00
u8 status ;
2009-02-27 15:05:10 +03:00
v4l2_std_id old_norm = decoder - > norm ;
2005-09-01 19:07:34 +04:00
int err = 0 ;
2005-09-07 02:19:37 +04:00
2005-09-01 19:07:34 +04:00
dprintk ( " SAA7191 extended signal auto-detection... \n " ) ;
2009-02-27 15:05:10 +03:00
* norm = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM ;
2005-09-01 19:07:34 +04:00
stdc & = ~ SAA7191_STDC_SECS ;
ctl3 & = ~ ( SAA7191_CTL3_FSEL ) ;
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_STDC , stdc ) ;
2005-09-01 19:07:34 +04:00
if ( err ) {
err = - EIO ;
goto out ;
}
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_CTL3 , ctl3 ) ;
2005-09-01 19:07:34 +04:00
if ( err ) {
err = - EIO ;
goto out ;
}
ctl3 | = SAA7191_CTL3_AUFD ;
2009-02-14 01:58:12 +03:00
err = saa7191_write_reg ( sd , SAA7191_REG_CTL3 , ctl3 ) ;
2005-09-01 19:07:34 +04:00
if ( err ) {
err = - EIO ;
goto out ;
}
msleep ( SAA7191_SYNC_DELAY ) ;
2009-02-14 01:58:12 +03:00
err = saa7191_wait_for_signal ( sd , & status ) ;
2005-09-01 19:07:34 +04:00
if ( err )
goto out ;
if ( status & SAA7191_STATUS_FIDT ) {
/* 60Hz signal -> NTSC */
dprintk ( " 60Hz signal: NTSC \n " ) ;
2009-02-27 15:05:10 +03:00
* norm = V4L2_STD_NTSC ;
return 0 ;
2005-09-01 19:07:34 +04:00
}
/* 50Hz signal */
dprintk ( " 50Hz signal: Trying PAL... \n " ) ;
/* try PAL first */
2009-02-14 01:58:12 +03:00
err = saa7191_s_std ( sd , V4L2_STD_PAL ) ;
2005-09-01 19:07:34 +04:00
if ( err )
goto out ;
msleep ( SAA7191_SYNC_DELAY ) ;
2009-02-14 01:58:12 +03:00
err = saa7191_wait_for_signal ( sd , & status ) ;
2005-09-01 19:07:34 +04:00
if ( err )
goto out ;
/* not 50Hz ? */
if ( status & SAA7191_STATUS_FIDT ) {
dprintk ( " No 50Hz signal \n " ) ;
2009-02-14 01:58:12 +03:00
saa7191_s_std ( sd , old_norm ) ;
2009-02-27 15:05:10 +03:00
return - EAGAIN ;
2005-09-01 19:07:34 +04:00
}
if ( status & SAA7191_STATUS_CODE ) {
dprintk ( " PAL \n " ) ;
2009-02-27 15:05:10 +03:00
* norm = V4L2_STD_PAL ;
2009-02-14 01:58:12 +03:00
return saa7191_s_std ( sd , old_norm ) ;
2005-09-01 19:07:34 +04:00
}
dprintk ( " No color detected with PAL - Trying SECAM... \n " ) ;
/* no color detected ? -> try SECAM */
2009-02-14 01:58:12 +03:00
err = saa7191_s_std ( sd , V4L2_STD_SECAM ) ;
2005-09-01 19:07:34 +04:00
if ( err )
goto out ;
msleep ( SAA7191_SYNC_DELAY ) ;
2009-02-14 01:58:12 +03:00
err = saa7191_wait_for_signal ( sd , & status ) ;
2005-09-01 19:07:34 +04:00
if ( err )
goto out ;
/* not 50Hz ? */
if ( status & SAA7191_STATUS_FIDT ) {
dprintk ( " No 50Hz signal \n " ) ;
err = - EAGAIN ;
goto out ;
}
if ( status & SAA7191_STATUS_CODE ) {
/* Color detected -> SECAM */
dprintk ( " SECAM \n " ) ;
2009-02-27 15:05:10 +03:00
* norm = V4L2_STD_SECAM ;
2009-02-14 01:58:12 +03:00
return saa7191_s_std ( sd , old_norm ) ;
2005-09-01 19:07:34 +04:00
}
dprintk ( " No color detected with SECAM - Going back to PAL. \n " ) ;
out :
2009-02-14 01:58:12 +03:00
return saa7191_s_std ( sd , old_norm ) ;
2005-09-01 19:07:34 +04:00
}
2009-02-14 01:58:12 +03:00
static int saa7191_autodetect_norm ( struct v4l2_subdev * sd )
2005-09-01 19:07:34 +04:00
{
u8 status ;
dprintk ( " SAA7191 signal auto-detection... \n " ) ;
dprintk ( " Reading status... \n " ) ;
2009-02-14 01:58:12 +03:00
if ( saa7191_read_status ( sd , & status ) )
2005-09-01 19:07:34 +04:00
return - EIO ;
dprintk ( " Checking for signal... \n " ) ;
/* no signal ? */
if ( status & SAA7191_STATUS_HLCK ) {
dprintk ( " No signal \n " ) ;
return - EBUSY ;
}
dprintk ( " Signal found \n " ) ;
if ( status & SAA7191_STATUS_FIDT ) {
/* 60hz signal -> NTSC */
dprintk ( " NTSC \n " ) ;
2009-02-14 01:58:12 +03:00
return saa7191_s_std ( sd , V4L2_STD_NTSC ) ;
2005-09-01 19:07:34 +04:00
} else {
/* 50hz signal -> PAL */
dprintk ( " PAL \n " ) ;
2009-02-14 01:58:12 +03:00
return saa7191_s_std ( sd , V4L2_STD_PAL ) ;
2005-09-01 19:07:34 +04:00
}
}
2009-02-14 01:58:12 +03:00
static int saa7191_g_ctrl ( struct v4l2_subdev * sd , struct v4l2_control * ctrl )
2005-09-01 19:07:34 +04:00
{
u8 reg ;
int ret = 0 ;
2009-02-27 15:05:10 +03:00
switch ( ctrl - > id ) {
2005-09-01 19:07:34 +04:00
case SAA7191_CONTROL_BANDPASS :
case SAA7191_CONTROL_BANDPASS_WEIGHT :
case SAA7191_CONTROL_CORING :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_LUMA ) ;
2009-02-27 15:05:10 +03:00
switch ( ctrl - > id ) {
2005-09-01 19:07:34 +04:00
case SAA7191_CONTROL_BANDPASS :
ctrl - > value = ( ( s32 ) reg & SAA7191_LUMA_BPSS_MASK )
> > SAA7191_LUMA_BPSS_SHIFT ;
break ;
case SAA7191_CONTROL_BANDPASS_WEIGHT :
ctrl - > value = ( ( s32 ) reg & SAA7191_LUMA_APER_MASK )
> > SAA7191_LUMA_APER_SHIFT ;
break ;
case SAA7191_CONTROL_CORING :
ctrl - > value = ( ( s32 ) reg & SAA7191_LUMA_CORI_MASK )
> > SAA7191_LUMA_CORI_SHIFT ;
break ;
2005-09-07 02:19:37 +04:00
}
2005-09-01 19:07:34 +04:00
break ;
case SAA7191_CONTROL_FORCE_COLOUR :
case SAA7191_CONTROL_CHROMA_GAIN :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_GAIN ) ;
2009-02-27 15:05:10 +03:00
if ( ctrl - > id = = SAA7191_CONTROL_FORCE_COLOUR )
2005-09-01 19:07:34 +04:00
ctrl - > value = ( ( s32 ) reg & SAA7191_GAIN_COLO ) ? 1 : 0 ;
else
ctrl - > value = ( ( s32 ) reg & SAA7191_GAIN_LFIS_MASK )
> > SAA7191_GAIN_LFIS_SHIFT ;
break ;
2009-02-27 15:05:10 +03:00
case V4L2_CID_HUE :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_HUEC ) ;
2005-09-01 19:07:34 +04:00
if ( reg < 0x80 )
reg + = 0x80 ;
else
reg - = 0x80 ;
ctrl - > value = ( s32 ) reg ;
break ;
case SAA7191_CONTROL_VTRC :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_STDC ) ;
2005-09-01 19:07:34 +04:00
ctrl - > value = ( ( s32 ) reg & SAA7191_STDC_VTRC ) ? 1 : 0 ;
break ;
case SAA7191_CONTROL_LUMA_DELAY :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_CTL3 ) ;
2005-09-01 19:07:34 +04:00
ctrl - > value = ( ( s32 ) reg & SAA7191_CTL3_YDEL_MASK )
> > SAA7191_CTL3_YDEL_SHIFT ;
if ( ctrl - > value > = 4 )
ctrl - > value - = 8 ;
break ;
case SAA7191_CONTROL_VNR :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_CTL4 ) ;
2005-09-01 19:07:34 +04:00
ctrl - > value = ( ( s32 ) reg & SAA7191_CTL4_VNOI_MASK )
> > SAA7191_CTL4_VNOI_SHIFT ;
break ;
default :
ret = - EINVAL ;
}
2005-09-07 02:19:37 +04:00
2005-09-01 19:07:34 +04:00
return ret ;
}
2009-02-14 01:58:12 +03:00
static int saa7191_s_ctrl ( struct v4l2_subdev * sd , struct v4l2_control * ctrl )
2005-09-01 19:07:34 +04:00
{
u8 reg ;
int ret = 0 ;
2009-02-27 15:05:10 +03:00
switch ( ctrl - > id ) {
2005-09-01 19:07:34 +04:00
case SAA7191_CONTROL_BANDPASS :
case SAA7191_CONTROL_BANDPASS_WEIGHT :
case SAA7191_CONTROL_CORING :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_LUMA ) ;
2009-02-27 15:05:10 +03:00
switch ( ctrl - > id ) {
2005-09-01 19:07:34 +04:00
case SAA7191_CONTROL_BANDPASS :
reg & = ~ SAA7191_LUMA_BPSS_MASK ;
reg | = ( ctrl - > value < < SAA7191_LUMA_BPSS_SHIFT )
& SAA7191_LUMA_BPSS_MASK ;
break ;
case SAA7191_CONTROL_BANDPASS_WEIGHT :
reg & = ~ SAA7191_LUMA_APER_MASK ;
reg | = ( ctrl - > value < < SAA7191_LUMA_APER_SHIFT )
& SAA7191_LUMA_APER_MASK ;
break ;
case SAA7191_CONTROL_CORING :
reg & = ~ SAA7191_LUMA_CORI_MASK ;
reg | = ( ctrl - > value < < SAA7191_LUMA_CORI_SHIFT )
& SAA7191_LUMA_CORI_MASK ;
break ;
}
2009-02-14 01:58:12 +03:00
ret = saa7191_write_reg ( sd , SAA7191_REG_LUMA , reg ) ;
2005-09-01 19:07:34 +04:00
break ;
case SAA7191_CONTROL_FORCE_COLOUR :
case SAA7191_CONTROL_CHROMA_GAIN :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_GAIN ) ;
2009-02-27 15:05:10 +03:00
if ( ctrl - > id = = SAA7191_CONTROL_FORCE_COLOUR ) {
2005-09-01 19:07:34 +04:00
if ( ctrl - > value )
reg | = SAA7191_GAIN_COLO ;
else
reg & = ~ SAA7191_GAIN_COLO ;
} else {
reg & = ~ SAA7191_GAIN_LFIS_MASK ;
reg | = ( ctrl - > value < < SAA7191_GAIN_LFIS_SHIFT )
& SAA7191_GAIN_LFIS_MASK ;
}
2009-02-14 01:58:12 +03:00
ret = saa7191_write_reg ( sd , SAA7191_REG_GAIN , reg ) ;
2005-09-01 19:07:34 +04:00
break ;
2009-02-27 15:05:10 +03:00
case V4L2_CID_HUE :
2005-09-01 19:07:34 +04:00
reg = ctrl - > value & 0xff ;
if ( reg < 0x80 )
reg + = 0x80 ;
else
reg - = 0x80 ;
2009-02-14 01:58:12 +03:00
ret = saa7191_write_reg ( sd , SAA7191_REG_HUEC , reg ) ;
2005-09-01 19:07:34 +04:00
break ;
case SAA7191_CONTROL_VTRC :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_STDC ) ;
2005-09-01 19:07:34 +04:00
if ( ctrl - > value )
reg | = SAA7191_STDC_VTRC ;
else
reg & = ~ SAA7191_STDC_VTRC ;
2009-02-14 01:58:12 +03:00
ret = saa7191_write_reg ( sd , SAA7191_REG_STDC , reg ) ;
2005-09-01 19:07:34 +04:00
break ;
case SAA7191_CONTROL_LUMA_DELAY : {
s32 value = ctrl - > value ;
if ( value < 0 )
value + = 8 ;
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_CTL3 ) ;
2005-09-01 19:07:34 +04:00
reg & = ~ SAA7191_CTL3_YDEL_MASK ;
reg | = ( value < < SAA7191_CTL3_YDEL_SHIFT )
& SAA7191_CTL3_YDEL_MASK ;
2009-02-14 01:58:12 +03:00
ret = saa7191_write_reg ( sd , SAA7191_REG_CTL3 , reg ) ;
2005-09-01 19:07:34 +04:00
break ;
}
case SAA7191_CONTROL_VNR :
2009-02-14 01:58:12 +03:00
reg = saa7191_read_reg ( sd , SAA7191_REG_CTL4 ) ;
2005-09-01 19:07:34 +04:00
reg & = ~ SAA7191_CTL4_VNOI_MASK ;
reg | = ( ctrl - > value < < SAA7191_CTL4_VNOI_SHIFT )
& SAA7191_CTL4_VNOI_MASK ;
2009-02-14 01:58:12 +03:00
ret = saa7191_write_reg ( sd , SAA7191_REG_CTL4 , reg ) ;
2005-09-01 19:07:34 +04:00
break ;
default :
ret = - EINVAL ;
2005-09-07 02:19:37 +04:00
}
2005-09-01 19:07:34 +04:00
return ret ;
2005-09-07 02:19:37 +04:00
}
/* I2C-interface */
2009-02-14 01:58:12 +03:00
static int saa7191_g_input_status ( struct v4l2_subdev * sd , u32 * status )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
u8 status_reg ;
int res = V4L2_IN_ST_NO_SIGNAL ;
2005-09-07 02:19:37 +04:00
2009-02-14 01:58:12 +03:00
if ( saa7191_read_status ( sd , & status_reg ) )
return - EIO ;
if ( ( status_reg & SAA7191_STATUS_HLCK ) = = 0 )
res = 0 ;
if ( ! ( status_reg & SAA7191_STATUS_CODE ) )
res | = V4L2_IN_ST_NO_COLOR ;
* status = res ;
return 0 ;
}
2005-09-07 02:19:37 +04:00
2005-09-01 19:07:34 +04:00
2009-02-14 01:58:12 +03:00
static int saa7191_g_chip_ident ( struct v4l2_subdev * sd ,
struct v4l2_dbg_chip_ident * chip )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2005-09-01 19:07:34 +04:00
2009-02-14 01:58:12 +03:00
return v4l2_chip_ident_i2c_client ( client , chip , V4L2_IDENT_SAA7191 , 0 ) ;
}
2005-09-07 02:19:37 +04:00
2009-02-14 01:58:12 +03:00
/* ----------------------------------------------------------------------- */
2009-02-27 15:05:10 +03:00
2009-02-14 01:58:12 +03:00
static const struct v4l2_subdev_core_ops saa7191_core_ops = {
. g_chip_ident = saa7191_g_chip_ident ,
. g_ctrl = saa7191_g_ctrl ,
. s_ctrl = saa7191_s_ctrl ,
. s_std = saa7191_s_std ,
} ;
2005-09-07 02:19:37 +04:00
2009-02-14 01:58:12 +03:00
static const struct v4l2_subdev_video_ops saa7191_video_ops = {
. s_routing = saa7191_s_routing ,
. querystd = saa7191_querystd ,
. g_input_status = saa7191_g_input_status ,
} ;
static const struct v4l2_subdev_ops saa7191_ops = {
. core = & saa7191_core_ops ,
. video = & saa7191_video_ops ,
} ;
2005-09-07 02:19:37 +04:00
2009-02-13 13:31:05 +03:00
static int saa7191_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
int err = 0 ;
struct saa7191 * decoder ;
2009-02-14 01:58:12 +03:00
struct v4l2_subdev * sd ;
2005-09-07 02:19:37 +04:00
2009-02-13 13:31:05 +03:00
v4l_info ( client , " chip found @ 0x%x (%s) \n " ,
client - > addr < < 1 , client - > adapter - > name ) ;
decoder = kzalloc ( sizeof ( * decoder ) , GFP_KERNEL ) ;
if ( ! decoder )
return - ENOMEM ;
2009-02-14 01:58:12 +03:00
sd = & decoder - > sd ;
v4l2_i2c_subdev_init ( sd , client , & saa7191_ops ) ;
2009-02-13 13:31:05 +03:00
2009-02-14 01:58:12 +03:00
err = saa7191_write_block ( sd , sizeof ( initseq ) , initseq ) ;
2009-02-13 13:31:05 +03:00
if ( err ) {
printk ( KERN_ERR " SAA7191 initialization failed \n " ) ;
kfree ( decoder ) ;
return err ;
}
printk ( KERN_INFO " SAA7191 initialized \n " ) ;
decoder - > input = SAA7191_INPUT_COMPOSITE ;
2009-02-27 15:05:10 +03:00
decoder - > norm = V4L2_STD_PAL ;
2009-02-13 13:31:05 +03:00
2009-02-14 01:58:12 +03:00
err = saa7191_autodetect_norm ( sd ) ;
2009-02-13 13:31:05 +03:00
if ( err & & ( err ! = - EBUSY ) )
printk ( KERN_ERR " SAA7191: Signal auto-detection failed \n " ) ;
return 0 ;
}
static int saa7191_remove ( struct i2c_client * client )
2005-09-07 02:19:37 +04:00
{
2009-02-14 01:58:12 +03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
2009-02-13 13:31:05 +03:00
2009-02-14 01:58:12 +03:00
v4l2_device_unregister_subdev ( sd ) ;
kfree ( to_saa7191 ( sd ) ) ;
2009-02-13 13:31:05 +03:00
return 0 ;
2005-09-07 02:19:37 +04:00
}
2009-02-13 13:31:05 +03:00
static const struct i2c_device_id saa7191_id [ ] = {
{ " saa7191 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , saa7191_id ) ;
2010-09-15 22:31:11 +04:00
static struct i2c_driver saa7191_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = " saa7191 " ,
} ,
. probe = saa7191_probe ,
. remove = saa7191_remove ,
. id_table = saa7191_id ,
2009-02-13 13:31:05 +03:00
} ;
2010-09-15 22:31:11 +04:00
2012-02-12 13:56:32 +04:00
module_i2c_driver ( saa7191_driver ) ;