2005-11-09 08:36:40 +03:00
/*
2006-01-23 22:11:05 +03:00
* tvp5150 - Texas Instruments TVP5150A / AM1 video decoder driver
2005-11-09 08:36:40 +03:00
*
2006-01-23 22:11:05 +03:00
* Copyright ( c ) 2005 , 2006 Mauro Carvalho Chehab ( mchehab @ infradead . org )
* This code is placed under the terms of the GNU General Public License v2
2005-11-09 08:36:40 +03:00
*/
# include <linux/i2c.h>
# include <linux/videodev.h>
# include <linux/delay.h>
2005-11-09 08:36:41 +03:00
# include <linux/video_decoder.h>
2006-01-09 20:25:36 +03:00
# include <media/v4l2-common.h>
2006-04-02 20:35:00 +04:00
# include <media/tvp5150.h>
2005-11-09 08:36:40 +03:00
# include "tvp5150_reg.h"
2006-01-23 22:11:05 +03:00
MODULE_DESCRIPTION ( " Texas Instruments TVP5150A video decoder driver " ) ;
2005-11-09 08:36:40 +03:00
MODULE_AUTHOR ( " Mauro Carvalho Chehab " ) ;
MODULE_LICENSE ( " GPL " ) ;
2006-01-23 22:11:05 +03:00
/* standard i2c insmod options */
2005-11-09 08:36:40 +03:00
static unsigned short normal_i2c [ ] = {
2005-11-09 08:36:41 +03:00
0xb8 > > 1 ,
0xba > > 1 ,
2005-11-09 08:36:40 +03:00
I2C_CLIENT_END
} ;
I2C_CLIENT_INSMOD ;
static int debug = 0 ;
module_param ( debug , int , 0 ) ;
MODULE_PARM_DESC ( debug , " Debug level (0-1) " ) ;
2006-01-23 22:11:05 +03:00
# define tvp5150_err(fmt, arg...) do { \
printk ( KERN_ERR " %s %d-%04x: " fmt , c - > driver - > driver . name , \
i2c_adapter_id ( c - > adapter ) , c - > addr , # # arg ) ; } while ( 0 )
2006-01-09 20:25:36 +03:00
# define tvp5150_info(fmt, arg...) do { \
2006-01-09 20:53:26 +03:00
printk ( KERN_INFO " %s %d-%04x: " fmt , c - > driver - > driver . name , \
2006-01-09 20:25:36 +03:00
i2c_adapter_id ( c - > adapter ) , c - > addr , # # arg ) ; } while ( 0 )
# define tvp5150_dbg(num, fmt, arg...) \
2005-11-09 08:36:40 +03:00
do { \
if ( debug > = num ) \
2006-01-09 20:53:26 +03:00
printk ( KERN_DEBUG " %s debug %d-%04x: " fmt , \
c - > driver - > driver . name , \
i2c_adapter_id ( c - > adapter ) , \
c - > addr , # # arg ) ; } while ( 0 )
2005-11-09 08:36:40 +03:00
2005-11-09 08:37:07 +03:00
/* supported controls */
static struct v4l2_queryctrl tvp5150_qctrl [ ] = {
{
2006-01-09 20:25:14 +03:00
. id = V4L2_CID_BRIGHTNESS ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Brightness " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 1 ,
2006-03-28 17:02:28 +04:00
. default_value = 128 ,
2006-01-09 20:25:14 +03:00
. flags = 0 ,
} , {
. id = V4L2_CID_CONTRAST ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Contrast " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
2006-03-28 17:02:28 +04:00
. default_value = 128 ,
2006-01-09 20:25:14 +03:00
. flags = 0 ,
} , {
2005-11-09 08:37:07 +03:00
. id = V4L2_CID_SATURATION ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Saturation " ,
. minimum = 0 ,
. maximum = 255 ,
. step = 0x1 ,
2006-03-28 17:02:28 +04:00
. default_value = 128 ,
2005-11-09 08:37:07 +03:00
. flags = 0 ,
2006-01-09 20:25:14 +03:00
} , {
. id = V4L2_CID_HUE ,
. type = V4L2_CTRL_TYPE_INTEGER ,
. name = " Hue " ,
. minimum = - 128 ,
. maximum = 127 ,
. step = 0x1 ,
2006-03-28 17:02:28 +04:00
. default_value = 0 ,
2006-01-09 20:25:14 +03:00
. flags = 0 ,
}
2005-11-09 08:37:07 +03:00
} ;
2005-11-09 08:36:40 +03:00
struct tvp5150 {
struct i2c_client * client ;
2005-11-09 08:36:41 +03:00
2006-01-23 22:11:05 +03:00
v4l2_std_id norm ; /* Current set standard */
2006-04-02 20:35:00 +04:00
struct v4l2_routing route ;
2005-11-09 08:36:41 +03:00
int enable ;
int bright ;
int contrast ;
int hue ;
int sat ;
2005-11-09 08:36:40 +03:00
} ;
2006-01-15 00:20:43 +03:00
static int tvp5150_read ( struct i2c_client * c , unsigned char addr )
2005-11-09 08:36:40 +03:00
{
unsigned char buffer [ 1 ] ;
int rc ;
buffer [ 0 ] = addr ;
if ( 1 ! = ( rc = i2c_master_send ( c , buffer , 1 ) ) )
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 0 , " i2c i/o error: rc == %d (should be 1) \n " , rc ) ;
2005-11-09 08:36:40 +03:00
msleep ( 10 ) ;
if ( 1 ! = ( rc = i2c_master_recv ( c , buffer , 1 ) ) )
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 0 , " i2c i/o error: rc == %d (should be 1) \n " , rc ) ;
tvp5150_dbg ( 2 , " tvp5150: read 0x%02x = 0x%02x \n " , addr , buffer [ 0 ] ) ;
2005-11-09 08:36:40 +03:00
return ( buffer [ 0 ] ) ;
}
2005-11-09 08:36:41 +03:00
static inline void tvp5150_write ( struct i2c_client * c , unsigned char addr ,
unsigned char value )
2005-11-09 08:36:40 +03:00
{
unsigned char buffer [ 2 ] ;
int rc ;
buffer [ 0 ] = addr ;
2005-11-09 08:36:41 +03:00
buffer [ 1 ] = value ;
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 2 , " tvp5150: writing 0x%02x 0x%02x \n " , buffer [ 0 ] , buffer [ 1 ] ) ;
2005-11-09 08:36:40 +03:00
if ( 2 ! = ( rc = i2c_master_send ( c , buffer , 2 ) ) )
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 0 , " i2c i/o error: rc == %d (should be 2) \n " , rc ) ;
2005-11-09 08:36:40 +03:00
}
2006-01-23 22:11:05 +03:00
static void dump_reg_range ( struct i2c_client * c , char * s , u8 init , const u8 end , int max_line )
{
int i = 0 ;
while ( init ! = ( u8 ) ( end + 1 ) ) {
if ( ( i % max_line ) = = 0 ) {
if ( i > 0 )
printk ( " \n " ) ;
printk ( " tvp5150: %s reg 0x%02x = " , s , init ) ;
}
printk ( " %02x " , tvp5150_read ( c , init ) ) ;
init + + ;
i + + ;
}
printk ( " \n " ) ;
}
2005-11-09 08:36:41 +03:00
static void dump_reg ( struct i2c_client * c )
2005-11-09 08:36:40 +03:00
{
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Video input source selection #1 = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_VD_IN_SRC_SEL_1 ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Analog channel controls = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_ANAL_CHL_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Operation mode controls = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_OP_MODE_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Miscellaneous controls = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_MISC_CTL ) ) ;
printk ( " tvp5150: Autoswitch mask= 0x%02x \n " ,
tvp5150_read ( c , TVP5150_AUTOSW_MSK ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Color killer threshold control = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_COLOR_KIL_THSH_CTL ) ) ;
printk ( " tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x \n " ,
tvp5150_read ( c , TVP5150_LUMA_PROC_CTL_1 ) ,
tvp5150_read ( c , TVP5150_LUMA_PROC_CTL_2 ) ,
tvp5150_read ( c , TVP5150_LUMA_PROC_CTL_3 ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Brightness control = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_BRIGHT_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Color saturation control = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_SATURATION_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Hue control = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_HUE_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Contrast control = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_CONTRAST_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Outputs and data rates select = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_DATA_RATE_SEL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Configuration shared pins = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_CONF_SHARED_PIN ) ) ;
printk ( " tvp5150: Active video cropping start = 0x%02x%02x \n " ,
tvp5150_read ( c , TVP5150_ACT_VD_CROP_ST_MSB ) ,
tvp5150_read ( c , TVP5150_ACT_VD_CROP_ST_LSB ) ) ;
printk ( " tvp5150: Active video cropping stop = 0x%02x%02x \n " ,
tvp5150_read ( c , TVP5150_ACT_VD_CROP_STP_MSB ) ,
tvp5150_read ( c , TVP5150_ACT_VD_CROP_STP_LSB ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Genlock/RTC = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_GENLOCK ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Horizontal sync start = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_HORIZ_SYNC_START ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Vertical blanking start = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_VERT_BLANKING_START ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Vertical blanking stop = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_VERT_BLANKING_STOP ) ) ;
printk ( " tvp5150: Chrominance processing control #1 and #2 = %02x %02x \n " ,
tvp5150_read ( c , TVP5150_CHROMA_PROC_CTL_1 ) ,
tvp5150_read ( c , TVP5150_CHROMA_PROC_CTL_2 ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt reset register B = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_RESET_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt enable register B = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_ENABLE_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt configuration register B = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INTT_CONFIG_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Video standard = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_VIDEO_STD ) ) ;
printk ( " tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x \n " ,
tvp5150_read ( c , TVP5150_CB_GAIN_FACT ) ,
tvp5150_read ( c , TVP5150_CR_GAIN_FACTOR ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Macrovision on counter = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_MACROVISION_ON_CTR ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Macrovision off counter = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_MACROVISION_OFF_CTR ) ) ;
printk ( " tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only) \n " ,
( tvp5150_read ( c , TVP5150_REV_SELECT ) & 1 ) ? 3 : 4 ) ;
printk ( " tvp5150: Device ID = %02x%02x \n " ,
tvp5150_read ( c , TVP5150_MSB_DEV_ID ) ,
tvp5150_read ( c , TVP5150_LSB_DEV_ID ) ) ;
printk ( " tvp5150: ROM version = (hex) %02x.%02x \n " ,
tvp5150_read ( c , TVP5150_ROM_MAJOR_VER ) ,
tvp5150_read ( c , TVP5150_ROM_MINOR_VER ) ) ;
printk ( " tvp5150: Vertical line count = 0x%02x%02x \n " ,
tvp5150_read ( c , TVP5150_VERT_LN_COUNT_MSB ) ,
tvp5150_read ( c , TVP5150_VERT_LN_COUNT_LSB ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt status register B = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_STATUS_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt active register B = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_ACTIVE_REG_B ) ) ;
printk ( " tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x \n " ,
tvp5150_read ( c , TVP5150_STATUS_REG_1 ) ,
tvp5150_read ( c , TVP5150_STATUS_REG_2 ) ,
tvp5150_read ( c , TVP5150_STATUS_REG_3 ) ,
tvp5150_read ( c , TVP5150_STATUS_REG_4 ) ,
tvp5150_read ( c , TVP5150_STATUS_REG_5 ) ) ;
dump_reg_range ( c , " Teletext filter 1 " , TVP5150_TELETEXT_FIL1_INI ,
TVP5150_TELETEXT_FIL1_END , 8 ) ;
dump_reg_range ( c , " Teletext filter 2 " , TVP5150_TELETEXT_FIL2_INI ,
TVP5150_TELETEXT_FIL2_END , 8 ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Teletext filter enable = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_TELETEXT_FIL_ENA ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt status register A = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_STATUS_REG_A ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt enable register A = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_ENABLE_REG_A ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt configuration = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_INT_CONF ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: VDP status register = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_VDP_STATUS_REG ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO word count = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_FIFO_WORD_COUNT ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO interrupt threshold = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_FIFO_INT_THRESHOLD ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO reset = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_FIFO_RESET ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Line number interrupt = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_LINE_NUMBER_INT ) ) ;
printk ( " tvp5150: Pixel alignment register = 0x%02x%02x \n " ,
tvp5150_read ( c , TVP5150_PIX_ALIGN_REG_HIGH ) ,
tvp5150_read ( c , TVP5150_PIX_ALIGN_REG_LOW ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO output control = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_FIFO_OUT_CTRL ) ) ;
printk ( " tvp5150: Full field enable = 0x%02x \n " ,
tvp5150_read ( c , TVP5150_FULL_FIELD_ENA ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Full field mode register = 0x%02x \n " ,
2006-01-23 22:11:05 +03:00
tvp5150_read ( c , TVP5150_FULL_FIELD_MODE_REG ) ) ;
dump_reg_range ( c , " CC data " , TVP5150_CC_DATA_INI ,
TVP5150_CC_DATA_END , 8 ) ;
dump_reg_range ( c , " WSS data " , TVP5150_WSS_DATA_INI ,
TVP5150_WSS_DATA_END , 8 ) ;
dump_reg_range ( c , " VPS data " , TVP5150_VPS_DATA_INI ,
TVP5150_VPS_DATA_END , 8 ) ;
dump_reg_range ( c , " VITC data " , TVP5150_VITC_DATA_INI ,
TVP5150_VITC_DATA_END , 10 ) ;
dump_reg_range ( c , " Line mode " , TVP5150_LINE_MODE_INI ,
TVP5150_LINE_MODE_END , 8 ) ;
2005-11-09 08:36:40 +03:00
}
/****************************************************************************
Basic functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-04-02 20:35:00 +04:00
static inline void tvp5150_selmux ( struct i2c_client * c )
2005-11-09 08:36:40 +03:00
{
2006-01-09 20:25:14 +03:00
int opmode = 0 ;
2005-11-09 08:36:43 +03:00
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
2006-04-02 20:35:00 +04:00
int input = 0 ;
2005-11-09 08:36:41 +03:00
2006-04-02 20:35:00 +04:00
if ( ( decoder - > route . output & TVP5150_BLACK_SCREEN ) | | ! decoder - > enable )
input = 8 ;
2005-11-09 08:36:43 +03:00
2006-01-09 20:25:14 +03:00
switch ( input ) {
2006-04-02 20:35:00 +04:00
case TVP5150_COMPOSITE1 :
input | = 2 ;
/* fall through */
case TVP5150_COMPOSITE0 :
2006-01-09 20:25:14 +03:00
opmode = 0x30 ; /* TV Mode */
break ;
2006-04-02 20:35:00 +04:00
case TVP5150_SVIDEO :
2006-01-09 20:25:14 +03:00
default :
2006-04-02 20:35:00 +04:00
input | = 1 ;
2006-01-09 20:25:14 +03:00
opmode = 0 ; /* Auto Mode */
break ;
}
tvp5150_write ( c , TVP5150_OP_MODE_CTL , opmode ) ;
2005-11-09 08:37:07 +03:00
tvp5150_write ( c , TVP5150_VD_IN_SRC_SEL_1 , input ) ;
2005-11-09 08:36:40 +03:00
} ;
2006-01-09 20:25:36 +03:00
struct i2c_reg_value {
unsigned char reg ;
unsigned char value ;
} ;
/* Default values as sugested at TVP5150AM1 datasheet */
static const struct i2c_reg_value tvp5150_init_default [ ] = {
{ /* 0x00 */
TVP5150_VD_IN_SRC_SEL_1 , 0x00
} ,
{ /* 0x01 */
TVP5150_ANAL_CHL_CTL , 0x15
} ,
{ /* 0x02 */
TVP5150_OP_MODE_CTL , 0x00
} ,
{ /* 0x03 */
TVP5150_MISC_CTL , 0x01
} ,
{ /* 0x06 */
TVP5150_COLOR_KIL_THSH_CTL , 0x10
} ,
{ /* 0x07 */
TVP5150_LUMA_PROC_CTL_1 , 0x60
} ,
{ /* 0x08 */
TVP5150_LUMA_PROC_CTL_2 , 0x00
} ,
{ /* 0x09 */
TVP5150_BRIGHT_CTL , 0x80
} ,
{ /* 0x0a */
TVP5150_SATURATION_CTL , 0x80
} ,
{ /* 0x0b */
TVP5150_HUE_CTL , 0x00
} ,
{ /* 0x0c */
TVP5150_CONTRAST_CTL , 0x80
} ,
{ /* 0x0d */
TVP5150_DATA_RATE_SEL , 0x47
} ,
{ /* 0x0e */
TVP5150_LUMA_PROC_CTL_3 , 0x00
} ,
{ /* 0x0f */
TVP5150_CONF_SHARED_PIN , 0x08
} ,
{ /* 0x11 */
TVP5150_ACT_VD_CROP_ST_MSB , 0x00
} ,
{ /* 0x12 */
TVP5150_ACT_VD_CROP_ST_LSB , 0x00
} ,
{ /* 0x13 */
TVP5150_ACT_VD_CROP_STP_MSB , 0x00
} ,
{ /* 0x14 */
TVP5150_ACT_VD_CROP_STP_LSB , 0x00
} ,
{ /* 0x15 */
TVP5150_GENLOCK , 0x01
} ,
{ /* 0x16 */
TVP5150_HORIZ_SYNC_START , 0x80
} ,
{ /* 0x18 */
TVP5150_VERT_BLANKING_START , 0x00
} ,
{ /* 0x19 */
TVP5150_VERT_BLANKING_STOP , 0x00
} ,
{ /* 0x1a */
TVP5150_CHROMA_PROC_CTL_1 , 0x0c
} ,
{ /* 0x1b */
TVP5150_CHROMA_PROC_CTL_2 , 0x14
} ,
{ /* 0x1c */
TVP5150_INT_RESET_REG_B , 0x00
} ,
{ /* 0x1d */
TVP5150_INT_ENABLE_REG_B , 0x00
} ,
{ /* 0x1e */
TVP5150_INTT_CONFIG_REG_B , 0x00
} ,
{ /* 0x28 */
TVP5150_VIDEO_STD , 0x00
} ,
{ /* 0x2e */
TVP5150_MACROVISION_ON_CTR , 0x0f
} ,
{ /* 0x2f */
TVP5150_MACROVISION_OFF_CTR , 0x01
} ,
{ /* 0xbb */
TVP5150_TELETEXT_FIL_ENA , 0x00
} ,
{ /* 0xc0 */
TVP5150_INT_STATUS_REG_A , 0x00
} ,
{ /* 0xc1 */
TVP5150_INT_ENABLE_REG_A , 0x00
} ,
{ /* 0xc2 */
TVP5150_INT_CONF , 0x04
} ,
{ /* 0xc8 */
TVP5150_FIFO_INT_THRESHOLD , 0x80
} ,
{ /* 0xc9 */
TVP5150_FIFO_RESET , 0x00
} ,
{ /* 0xca */
TVP5150_LINE_NUMBER_INT , 0x00
} ,
{ /* 0xcb */
TVP5150_PIX_ALIGN_REG_LOW , 0x4e
} ,
{ /* 0xcc */
TVP5150_PIX_ALIGN_REG_HIGH , 0x00
} ,
{ /* 0xcd */
TVP5150_FIFO_OUT_CTRL , 0x01
} ,
{ /* 0xcf */
2006-01-23 22:11:05 +03:00
TVP5150_FULL_FIELD_ENA , 0x00
2006-01-09 20:25:36 +03:00
} ,
{ /* 0xd0 */
2006-01-23 22:11:05 +03:00
TVP5150_LINE_MODE_INI , 0x00
2006-01-09 20:25:36 +03:00
} ,
{ /* 0xfc */
TVP5150_FULL_FIELD_MODE_REG , 0x7f
} ,
{ /* end of data */
0xff , 0xff
}
} ;
/* Default values as sugested at TVP5150AM1 datasheet */
static const struct i2c_reg_value tvp5150_init_enable [ ] = {
{
TVP5150_CONF_SHARED_PIN , 2
} , { /* Automatic offset and AGC enabled */
TVP5150_ANAL_CHL_CTL , 0x15
} , { /* Activate YCrCb output 0x9 or 0xd ? */
TVP5150_MISC_CTL , 0x6f
} , { /* Activates video std autodetection for all standards */
TVP5150_AUTOSW_MSK , 0x0
} , { /* Default format: 0x47. For 4:2:2: 0x40 */
TVP5150_DATA_RATE_SEL , 0x47
} , {
TVP5150_CHROMA_PROC_CTL_1 , 0x0c
} , {
TVP5150_CHROMA_PROC_CTL_2 , 0x54
} , { /* Non documented, but initialized on WinTV USB2 */
0x27 , 0x20
} , {
0xff , 0xff
}
} ;
2006-01-23 22:11:05 +03:00
struct tvp5150_vbi_type {
unsigned int vbi_type ;
unsigned int ini_line ;
unsigned int end_line ;
unsigned int by_field : 1 ;
} ;
2006-01-09 20:25:36 +03:00
struct i2c_vbi_ram_value {
u16 reg ;
2006-01-23 22:11:05 +03:00
struct tvp5150_vbi_type type ;
unsigned char values [ 16 ] ;
2006-01-09 20:25:36 +03:00
} ;
2006-01-23 22:11:05 +03:00
/* This struct have the values for each supported VBI Standard
* by
tvp5150_vbi_types should follow the same order as vbi_ram_default
2006-01-23 22:11:05 +03:00
* value 0 means rom position 0x10 , value 1 means rom position 0x30
* and so on . There are 16 possible locations from 0 to 15.
*/
2006-01-15 11:56:15 +03:00
static struct i2c_vbi_ram_value vbi_ram_default [ ] =
2005-11-09 08:36:40 +03:00
{
2006-03-30 01:02:51 +04:00
/* FIXME: Current api doesn't handle all VBI types, those not
yet supported are placed under # if 0 */
#if 0
2006-01-23 22:11:05 +03:00
{ 0x010 , /* Teletext, SECAM, WST System A */
{ V4L2_SLICED_TELETEXT_SECAM , 6 , 23 , 1 } ,
{ 0xaa , 0xaa , 0xff , 0xff , 0xe7 , 0x2e , 0x20 , 0x26 ,
0xe6 , 0xb4 , 0x0e , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-03-30 01:02:51 +04:00
# endif
2006-01-23 22:11:05 +03:00
{ 0x030 , /* Teletext, PAL, WST System B */
2006-03-30 01:02:51 +04:00
{ V4L2_SLICED_TELETEXT_B , 6 , 22 , 1 } ,
2006-01-23 22:11:05 +03:00
{ 0xaa , 0xaa , 0xff , 0xff , 0x27 , 0x2e , 0x20 , 0x2b ,
0xa6 , 0x72 , 0x10 , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-03-30 01:02:51 +04:00
#if 0
2006-01-23 22:11:05 +03:00
{ 0x050 , /* Teletext, PAL, WST System C */
{ V4L2_SLICED_TELETEXT_PAL_C , 6 , 22 , 1 } ,
{ 0xaa , 0xaa , 0xff , 0xff , 0xe7 , 0x2e , 0x20 , 0x22 ,
0xa6 , 0x98 , 0x0d , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x070 , /* Teletext, NTSC, WST System B */
{ V4L2_SLICED_TELETEXT_NTSC_B , 10 , 21 , 1 } ,
{ 0xaa , 0xaa , 0xff , 0xff , 0x27 , 0x2e , 0x20 , 0x23 ,
0x69 , 0x93 , 0x0d , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x090 , /* Tetetext, NTSC NABTS System C */
{ V4L2_SLICED_TELETEXT_NTSC_C , 10 , 21 , 1 } ,
{ 0xaa , 0xaa , 0xff , 0xff , 0xe7 , 0x2e , 0x20 , 0x22 ,
0x69 , 0x93 , 0x0d , 0x00 , 0x00 , 0x00 , 0x15 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x0b0 , /* Teletext, NTSC-J, NABTS System D */
{ V4L2_SLICED_TELETEXT_NTSC_D , 10 , 21 , 1 } ,
{ 0xaa , 0xaa , 0xff , 0xff , 0xa7 , 0x2e , 0x20 , 0x23 ,
0x69 , 0x93 , 0x0d , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x0d0 , /* Closed Caption, PAL/SECAM */
{ V4L2_SLICED_CAPTION_625 , 22 , 22 , 1 } ,
{ 0xaa , 0x2a , 0xff , 0x3f , 0x04 , 0x51 , 0x6e , 0x02 ,
0xa6 , 0x7b , 0x09 , 0x00 , 0x00 , 0x00 , 0x27 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-03-30 01:02:51 +04:00
# endif
2006-01-23 22:11:05 +03:00
{ 0x0f0 , /* Closed Caption, NTSC */
{ V4L2_SLICED_CAPTION_525 , 21 , 21 , 1 } ,
{ 0xaa , 0x2a , 0xff , 0x3f , 0x04 , 0x51 , 0x6e , 0x02 ,
0x69 , 0x8c , 0x09 , 0x00 , 0x00 , 0x00 , 0x27 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x110 , /* Wide Screen Signal, PAL/SECAM */
2006-01-23 22:11:08 +03:00
{ V4L2_SLICED_WSS_625 , 23 , 23 , 1 } ,
2006-01-23 22:11:05 +03:00
{ 0x5b , 0x55 , 0xc5 , 0xff , 0x00 , 0x71 , 0x6e , 0x42 ,
0xa6 , 0xcd , 0x0f , 0x00 , 0x00 , 0x00 , 0x3a , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-03-30 01:02:51 +04:00
#if 0
2006-01-23 22:11:05 +03:00
{ 0x130 , /* Wide Screen Signal, NTSC C */
{ V4L2_SLICED_WSS_525 , 20 , 20 , 1 } ,
{ 0x38 , 0x00 , 0x3f , 0x00 , 0x00 , 0x71 , 0x6e , 0x43 ,
0x69 , 0x7c , 0x08 , 0x00 , 0x00 , 0x00 , 0x39 , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x150 , /* Vertical Interval Timecode (VITC), PAL/SECAM */
{ V4l2_SLICED_VITC_625 , 6 , 22 , 0 } ,
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x8f , 0x6d , 0x49 ,
0xa6 , 0x85 , 0x08 , 0x00 , 0x00 , 0x00 , 0x4c , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-01-23 22:11:05 +03:00
{ 0x170 , /* Vertical Interval Timecode (VITC), NTSC */
{ V4l2_SLICED_VITC_525 , 10 , 20 , 0 } ,
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x8f , 0x6d , 0x49 ,
0x69 , 0x94 , 0x08 , 0x00 , 0x00 , 0x00 , 0x4c , 0x00 }
2006-01-09 20:25:36 +03:00
} ,
2006-03-30 01:02:51 +04:00
# endif
2006-01-23 22:11:05 +03:00
{ 0x190 , /* Video Program System (VPS), PAL */
{ V4L2_SLICED_VPS , 16 , 16 , 0 } ,
{ 0xaa , 0xaa , 0xff , 0xff , 0xba , 0xce , 0x2b , 0x0d ,
0xa6 , 0xda , 0x0b , 0x00 , 0x00 , 0x00 , 0x60 , 0x00 }
2006-01-23 22:11:05 +03:00
} ,
2006-01-23 22:11:05 +03:00
/* 0x1d0 User programmable */
/* End of struct */
{ ( u16 ) - 1 }
2006-01-09 20:25:36 +03:00
} ;
2005-11-09 08:36:43 +03:00
2006-01-09 20:25:36 +03:00
static int tvp5150_write_inittab ( struct i2c_client * c ,
2006-01-23 22:11:05 +03:00
const struct i2c_reg_value * regs )
2006-01-09 20:25:36 +03:00
{
while ( regs - > reg ! = 0xff ) {
tvp5150_write ( c , regs - > reg , regs - > value ) ;
regs + + ;
}
return 0 ;
}
2005-11-09 08:36:41 +03:00
2006-01-09 20:25:36 +03:00
static int tvp5150_vdp_init ( struct i2c_client * c ,
2006-01-23 22:11:05 +03:00
const struct i2c_vbi_ram_value * regs )
2006-01-09 20:25:36 +03:00
{
unsigned int i ;
2005-11-09 08:36:40 +03:00
2006-01-09 20:25:36 +03:00
/* Disable Full Field */
2006-01-23 22:11:05 +03:00
tvp5150_write ( c , TVP5150_FULL_FIELD_ENA , 0 ) ;
2005-11-09 08:36:40 +03:00
2006-01-09 20:25:36 +03:00
/* Before programming, Line mode should be at 0xff */
2006-01-23 22:11:05 +03:00
for ( i = TVP5150_LINE_MODE_INI ; i < = TVP5150_LINE_MODE_END ; i + + )
2006-01-09 20:25:36 +03:00
tvp5150_write ( c , i , 0xff ) ;
2005-11-09 08:36:40 +03:00
2006-01-09 20:25:36 +03:00
/* Load Ram Table */
while ( regs - > reg ! = ( u16 ) - 1 ) {
tvp5150_write ( c , TVP5150_CONF_RAM_ADDR_HIGH , regs - > reg > > 8 ) ;
tvp5150_write ( c , TVP5150_CONF_RAM_ADDR_LOW , regs - > reg ) ;
2005-11-09 08:36:40 +03:00
2006-01-09 20:25:36 +03:00
for ( i = 0 ; i < 16 ; i + + )
tvp5150_write ( c , TVP5150_VDP_CONF_RAM_DATA , regs - > values [ i ] ) ;
2005-11-09 08:36:41 +03:00
2006-01-09 20:25:36 +03:00
regs + + ;
}
return 0 ;
}
2005-11-09 08:36:40 +03:00
2006-01-23 22:11:05 +03:00
/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
static void tvp5150_vbi_get_cap ( const struct i2c_vbi_ram_value * regs ,
struct v4l2_sliced_vbi_cap * cap )
{
int line ;
memset ( cap , 0 , sizeof * cap ) ;
while ( regs - > reg ! = ( u16 ) - 1 ) {
for ( line = regs - > type . ini_line ; line < = regs - > type . end_line ; line + + ) {
cap - > service_lines [ 0 ] [ line ] | = regs - > type . vbi_type ;
}
cap - > service_set | = regs - > type . vbi_type ;
regs + + ;
}
}
2006-01-23 22:11:05 +03:00
/* Set vbi processing
* type - one of tvp5150_vbi_types
* line - line to gather data
* fields : bit 0 field1 , bit 1 , field2
* flags ( default = 0xf0 ) is a bitmask , were set means :
* bit 7 : enable filtering null bytes on CC
* bit 6 : send data also to FIFO
* bit 5 : don ' t allow data with errors on FIFO
* bit 4 : enable ECC when possible
* pix_align = pix alignment :
* LSB = field1
* MSB = field2
*/
2006-01-23 22:11:06 +03:00
static int tvp5150_set_vbi ( struct i2c_client * c ,
const struct i2c_vbi_ram_value * regs ,
unsigned int type , u8 flags , int line ,
const int fields )
2006-01-23 22:11:05 +03:00
{
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
v4l2_std_id std = decoder - > norm ;
u8 reg ;
2006-01-23 22:11:06 +03:00
int pos = 0 ;
2006-01-23 22:11:05 +03:00
if ( std = = V4L2_STD_ALL ) {
tvp5150_err ( " VBI can't be configured without knowing number of lines \n " ) ;
2006-01-23 22:11:08 +03:00
return 0 ;
2006-01-23 22:11:05 +03:00
} else if ( std & & V4L2_STD_625_50 ) {
/* Don't follow NTSC Line number convension */
line + = 3 ;
}
if ( line < 6 | | line > 27 )
2006-01-23 22:11:06 +03:00
return 0 ;
while ( regs - > reg ! = ( u16 ) - 1 ) {
if ( ( type & regs - > type . vbi_type ) & &
( line > = regs - > type . ini_line ) & &
( line < = regs - > type . end_line ) ) {
type = regs - > type . vbi_type ;
break ;
}
regs + + ;
pos + + ;
}
if ( regs - > reg = = ( u16 ) - 1 )
return 0 ;
2006-01-23 22:11:05 +03:00
2006-01-23 22:11:06 +03:00
type = pos | ( flags & 0xf0 ) ;
2006-01-23 22:11:05 +03:00
reg = ( ( line - 6 ) < < 1 ) + TVP5150_LINE_MODE_INI ;
if ( fields & 1 ) {
tvp5150_write ( c , reg , type ) ;
}
if ( fields & 2 ) {
tvp5150_write ( c , reg + 1 , type ) ;
}
2006-01-23 22:11:06 +03:00
return type ;
2006-01-23 22:11:05 +03:00
}
2006-01-23 22:11:08 +03:00
static int tvp5150_get_vbi ( struct i2c_client * c ,
const struct i2c_vbi_ram_value * regs , int line )
{
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
v4l2_std_id std = decoder - > norm ;
u8 reg ;
int pos , type = 0 ;
if ( std = = V4L2_STD_ALL ) {
tvp5150_err ( " VBI can't be configured without knowing number of lines \n " ) ;
return 0 ;
} else if ( std & & V4L2_STD_625_50 ) {
/* Don't follow NTSC Line number convension */
line + = 3 ;
}
if ( line < 6 | | line > 27 )
return 0 ;
reg = ( ( line - 6 ) < < 1 ) + TVP5150_LINE_MODE_INI ;
pos = tvp5150_read ( c , reg ) & 0x0f ;
if ( pos < 0x0f )
type = regs [ pos ] . type . vbi_type ;
pos = tvp5150_read ( c , reg + 1 ) & 0x0f ;
if ( pos < 0x0f )
type | = regs [ pos ] . type . vbi_type ;
return type ;
}
2006-01-09 20:25:36 +03:00
static int tvp5150_set_std ( struct i2c_client * c , v4l2_std_id std )
{
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
int fmt = 0 ;
decoder - > norm = std ;
/* First tests should be against specific std */
if ( std = = V4L2_STD_ALL ) {
fmt = 0 ; /* Autodetect mode */
} else if ( std & V4L2_STD_NTSC_443 ) {
fmt = 0xa ;
} else if ( std & V4L2_STD_PAL_M ) {
fmt = 0x6 ;
} else if ( std & ( V4L2_STD_PAL_N | V4L2_STD_PAL_Nc ) ) {
fmt = 0x8 ;
} else {
/* Then, test against generic ones */
if ( std & V4L2_STD_NTSC ) {
fmt = 0x2 ;
} else if ( std & V4L2_STD_PAL ) {
fmt = 0x4 ;
} else if ( std & V4L2_STD_SECAM ) {
fmt = 0xc ;
}
}
2005-11-09 08:36:41 +03:00
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 1 , " Set video std register to %d. \n " , fmt ) ;
tvp5150_write ( c , TVP5150_VIDEO_STD , fmt ) ;
2005-11-09 08:36:41 +03:00
2006-01-09 20:25:36 +03:00
return 0 ;
}
static inline void tvp5150_reset ( struct i2c_client * c )
{
2006-01-23 14:48:34 +03:00
u8 msb_id , lsb_id , msb_rom , lsb_rom ;
2006-01-09 20:25:36 +03:00
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
msb_id = tvp5150_read ( c , TVP5150_MSB_DEV_ID ) ;
lsb_id = tvp5150_read ( c , TVP5150_LSB_DEV_ID ) ;
msb_rom = tvp5150_read ( c , TVP5150_ROM_MAJOR_VER ) ;
lsb_rom = tvp5150_read ( c , TVP5150_ROM_MINOR_VER ) ;
2006-01-23 14:48:34 +03:00
if ( ( msb_rom = = 4 ) & & ( lsb_rom = = 0 ) ) { /* Is TVP5150AM1 */
tvp5150_info ( " tvp%02x%02xam1 detected. \n " , msb_id , lsb_id ) ;
/* ITU-T BT.656.4 timing */
tvp5150_write ( c , TVP5150_REV_SELECT , 0 ) ;
2006-01-09 20:25:36 +03:00
} else {
2006-01-23 14:48:34 +03:00
if ( ( msb_rom = = 3 ) | | ( lsb_rom = = 0x21 ) ) { /* Is TVP5150A */
tvp5150_info ( " tvp%02x%02xa detected. \n " , msb_id , lsb_id ) ;
} else {
tvp5150_info ( " *** unknown tvp%02x%02x chip detected. \n " , msb_id , lsb_id ) ;
tvp5150_info ( " *** Rom ver is %d.%d \n " , msb_rom , lsb_rom ) ;
}
2006-01-09 20:25:36 +03:00
}
2005-11-09 08:36:41 +03:00
2006-01-09 20:25:36 +03:00
/* Initializes TVP5150 to its default values */
tvp5150_write_inittab ( c , tvp5150_init_default ) ;
/* Initializes VDP registers */
tvp5150_vdp_init ( c , vbi_ram_default ) ;
/* Selects decoder input */
2006-04-02 20:35:00 +04:00
tvp5150_selmux ( c ) ;
2006-01-09 20:25:36 +03:00
/* Initializes TVP5150 to stream enabled values */
tvp5150_write_inittab ( c , tvp5150_init_enable ) ;
/* Initialize image preferences */
2005-11-09 08:36:43 +03:00
tvp5150_write ( c , TVP5150_BRIGHT_CTL , decoder - > bright > > 8 ) ;
tvp5150_write ( c , TVP5150_CONTRAST_CTL , decoder - > contrast > > 8 ) ;
tvp5150_write ( c , TVP5150_SATURATION_CTL , decoder - > contrast > > 8 ) ;
tvp5150_write ( c , TVP5150_HUE_CTL , ( decoder - > hue - 32768 ) > > 8 ) ;
2006-01-09 20:25:36 +03:00
tvp5150_set_std ( c , decoder - > norm ) ;
2005-11-09 08:36:40 +03:00
} ;
2005-11-09 08:37:07 +03:00
static int tvp5150_get_ctrl ( struct i2c_client * c , struct v4l2_control * ctrl )
{
/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
ctrl - > value = tvp5150_read ( c , TVP5150_BRIGHT_CTL ) ;
return 0 ;
case V4L2_CID_CONTRAST :
ctrl - > value = tvp5150_read ( c , TVP5150_CONTRAST_CTL ) ;
return 0 ;
case V4L2_CID_SATURATION :
ctrl - > value = tvp5150_read ( c , TVP5150_SATURATION_CTL ) ;
return 0 ;
case V4L2_CID_HUE :
ctrl - > value = tvp5150_read ( c , TVP5150_HUE_CTL ) ;
return 0 ;
}
2006-01-09 20:25:14 +03:00
return - EINVAL ;
2005-11-09 08:37:07 +03:00
}
static int tvp5150_set_ctrl ( struct i2c_client * c , struct v4l2_control * ctrl )
{
/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
tvp5150_write ( c , TVP5150_BRIGHT_CTL , ctrl - > value ) ;
return 0 ;
case V4L2_CID_CONTRAST :
tvp5150_write ( c , TVP5150_CONTRAST_CTL , ctrl - > value ) ;
return 0 ;
case V4L2_CID_SATURATION :
tvp5150_write ( c , TVP5150_SATURATION_CTL , ctrl - > value ) ;
return 0 ;
case V4L2_CID_HUE :
tvp5150_write ( c , TVP5150_HUE_CTL , ctrl - > value ) ;
return 0 ;
}
2006-01-09 20:25:14 +03:00
return - EINVAL ;
2005-11-09 08:37:07 +03:00
}
2005-11-09 08:36:41 +03:00
/****************************************************************************
I2C Command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-01-09 20:25:36 +03:00
static int tvp5150_command ( struct i2c_client * c ,
2005-11-09 08:36:41 +03:00
unsigned int cmd , void * arg )
{
2006-01-09 20:25:36 +03:00
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
2005-11-09 08:36:41 +03:00
switch ( cmd ) {
case 0 :
2006-01-09 20:25:36 +03:00
case VIDIOC_INT_RESET :
tvp5150_reset ( c ) ;
break ;
2006-04-02 20:35:00 +04:00
case VIDIOC_INT_G_VIDEO_ROUTING :
{
struct v4l2_routing * route = arg ;
* route = decoder - > route ;
break ;
}
case VIDIOC_INT_S_VIDEO_ROUTING :
{
struct v4l2_routing * route = arg ;
decoder - > route = * route ;
tvp5150_selmux ( c ) ;
break ;
}
2006-01-09 20:25:36 +03:00
case VIDIOC_S_STD :
if ( decoder - > norm = = * ( v4l2_std_id * ) arg )
break ;
return tvp5150_set_std ( c , * ( v4l2_std_id * ) arg ) ;
case VIDIOC_G_STD :
* ( v4l2_std_id * ) arg = decoder - > norm ;
2005-11-09 08:36:41 +03:00
break ;
2006-01-23 22:11:05 +03:00
case VIDIOC_G_SLICED_VBI_CAP :
{
struct v4l2_sliced_vbi_cap * cap = arg ;
tvp5150_dbg ( 1 , " VIDIOC_G_SLICED_VBI_CAP \n " ) ;
tvp5150_vbi_get_cap ( vbi_ram_default , cap ) ;
break ;
}
2006-01-23 22:11:06 +03:00
case VIDIOC_S_FMT :
{
struct v4l2_format * fmt ;
struct v4l2_sliced_vbi_format * svbi ;
int i ;
2006-01-23 22:11:05 +03:00
2006-01-23 22:11:06 +03:00
fmt = arg ;
if ( fmt - > type ! = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE )
return - EINVAL ;
svbi = & fmt - > fmt . sliced ;
if ( svbi - > service_set ! = 0 ) {
for ( i = 0 ; i < = 23 ; i + + ) {
svbi - > service_lines [ 1 ] [ i ] = 0 ;
svbi - > service_lines [ 0 ] [ i ] = tvp5150_set_vbi ( c ,
vbi_ram_default ,
svbi - > service_lines [ 0 ] [ i ] , 0xf0 , i , 3 ) ;
}
2006-01-23 22:11:08 +03:00
/* Enables FIFO */
tvp5150_write ( c , TVP5150_FIFO_OUT_CTRL , 1 ) ;
} else {
/* Disables FIFO*/
tvp5150_write ( c , TVP5150_FIFO_OUT_CTRL , 0 ) ;
/* Disable Full Field */
tvp5150_write ( c , TVP5150_FULL_FIELD_ENA , 0 ) ;
/* Disable Line modes */
for ( i = TVP5150_LINE_MODE_INI ; i < = TVP5150_LINE_MODE_END ; i + + )
tvp5150_write ( c , i , 0xff ) ;
}
break ;
}
case VIDIOC_G_FMT :
{
struct v4l2_format * fmt ;
struct v4l2_sliced_vbi_format * svbi ;
int i , mask = 0 ;
fmt = arg ;
if ( fmt - > type ! = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE )
return - EINVAL ;
svbi = & fmt - > fmt . sliced ;
memset ( svbi , 0 , sizeof ( * svbi ) ) ;
for ( i = 0 ; i < = 23 ; i + + ) {
svbi - > service_lines [ 0 ] [ i ] = tvp5150_get_vbi ( c ,
vbi_ram_default , i ) ;
mask | = svbi - > service_lines [ 0 ] [ i ] ;
2006-01-23 22:11:06 +03:00
}
2006-01-23 22:11:08 +03:00
svbi - > service_set = mask ;
2006-01-23 22:11:06 +03:00
break ;
}
2006-01-23 22:11:08 +03:00
2006-01-09 20:25:37 +03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_INT_G_REGISTER :
{
struct v4l2_register * reg = arg ;
if ( reg - > i2c_id ! = I2C_DRIVERID_TVP5150 )
return - EINVAL ;
reg - > val = tvp5150_read ( c , reg - > reg & 0xff ) ;
break ;
}
case VIDIOC_INT_S_REGISTER :
{
struct v4l2_register * reg = arg ;
if ( reg - > i2c_id ! = I2C_DRIVERID_TVP5150 )
return - EINVAL ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
tvp5150_write ( c , reg - > reg & 0xff , reg - > val & 0xff ) ;
break ;
}
# endif
2006-01-23 22:11:08 +03:00
case VIDIOC_LOG_STATUS :
2006-01-09 20:25:36 +03:00
dump_reg ( c ) ;
2005-11-09 08:36:41 +03:00
break ;
2006-04-01 23:40:21 +04:00
case VIDIOC_G_TUNER :
2005-11-09 08:37:07 +03:00
{
2006-04-01 23:40:21 +04:00
struct v4l2_tuner * vt = arg ;
int status = tvp5150_read ( c , 0x88 ) ;
2005-11-09 08:36:41 +03:00
2006-04-01 23:40:21 +04:00
vt - > signal = ( ( status & 0x04 ) & & ( status & 0x02 ) ) ? 0xffff : 0x0 ;
2005-11-09 08:37:07 +03:00
break ;
2005-11-09 08:36:43 +03:00
}
2005-11-09 08:37:07 +03:00
case VIDIOC_QUERYCTRL :
{
struct v4l2_queryctrl * qc = arg ;
2006-01-09 20:25:14 +03:00
int i ;
2005-11-09 08:37:07 +03:00
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 1 , " VIDIOC_QUERYCTRL called \n " ) ;
2005-11-09 08:37:07 +03:00
2006-01-09 20:25:14 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( tvp5150_qctrl ) ; i + + )
2005-11-09 08:37:07 +03:00
if ( qc - > id & & qc - > id = = tvp5150_qctrl [ i ] . id ) {
memcpy ( qc , & ( tvp5150_qctrl [ i ] ) ,
sizeof ( * qc ) ) ;
return 0 ;
}
return - EINVAL ;
2005-11-09 08:36:43 +03:00
}
2005-11-09 08:37:07 +03:00
case VIDIOC_G_CTRL :
{
struct v4l2_control * ctrl = arg ;
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 1 , " VIDIOC_G_CTRL called \n " ) ;
2005-11-09 08:37:07 +03:00
2006-01-09 20:25:36 +03:00
return tvp5150_get_ctrl ( c , ctrl ) ;
2005-11-09 08:36:43 +03:00
}
2005-11-09 08:37:07 +03:00
case VIDIOC_S_CTRL :
{
struct v4l2_control * ctrl = arg ;
u8 i , n ;
n = sizeof ( tvp5150_qctrl ) / sizeof ( tvp5150_qctrl [ 0 ] ) ;
for ( i = 0 ; i < n ; i + + )
if ( ctrl - > id = = tvp5150_qctrl [ i ] . id ) {
if ( ctrl - > value <
tvp5150_qctrl [ i ] . minimum
| | ctrl - > value >
tvp5150_qctrl [ i ] . maximum )
return - ERANGE ;
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 1 ,
" VIDIOC_S_CTRL: id=%d, value=%d \n " ,
2005-11-09 08:37:07 +03:00
ctrl - > id , ctrl - > value ) ;
2006-01-09 20:25:36 +03:00
return tvp5150_set_ctrl ( c , ctrl ) ;
2005-11-09 08:37:07 +03:00
}
return - EINVAL ;
}
2005-11-09 08:36:41 +03:00
default :
return - EINVAL ;
}
return 0 ;
}
2005-11-09 08:36:40 +03:00
/****************************************************************************
I2C Client & Driver
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct i2c_driver driver ;
2005-11-09 08:37:07 +03:00
static struct i2c_client client_template = {
. name = " (unset) " ,
. driver = & driver ,
2005-11-09 08:36:40 +03:00
} ;
2005-11-09 08:37:07 +03:00
static int tvp5150_detect_client ( struct i2c_adapter * adapter ,
int address , int kind )
2005-11-09 08:36:40 +03:00
{
2006-01-09 20:25:36 +03:00
struct i2c_client * c ;
2005-11-09 08:36:40 +03:00
struct tvp5150 * core ;
int rv ;
2006-01-09 20:25:36 +03:00
if ( debug )
printk ( KERN_INFO
2005-11-09 08:36:40 +03:00
" tvp5150.c: detecting tvp5150 client on address 0x%x \n " ,
address < < 1 ) ;
client_template . adapter = adapter ;
client_template . addr = address ;
/* Check if the adapter supports the needed features */
if ( ! i2c_check_functionality
( adapter ,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA ) )
return 0 ;
2006-01-09 20:25:36 +03:00
c = kmalloc ( sizeof ( struct i2c_client ) , GFP_KERNEL ) ;
if ( c = = 0 )
2005-11-09 08:36:40 +03:00
return - ENOMEM ;
2006-01-09 20:25:36 +03:00
memcpy ( c , & client_template , sizeof ( struct i2c_client ) ) ;
2005-11-09 08:36:40 +03:00
2006-01-12 00:40:56 +03:00
core = kzalloc ( sizeof ( struct tvp5150 ) , GFP_KERNEL ) ;
2005-11-09 08:36:40 +03:00
if ( core = = 0 ) {
2006-01-09 20:25:36 +03:00
kfree ( c ) ;
2005-11-09 08:36:40 +03:00
return - ENOMEM ;
}
2006-01-09 20:25:36 +03:00
i2c_set_clientdata ( c , core ) ;
2005-11-09 08:36:40 +03:00
2006-01-09 20:25:36 +03:00
rv = i2c_attach_client ( c ) ;
2005-11-09 08:36:40 +03:00
2006-01-23 22:11:05 +03:00
core - > norm = V4L2_STD_ALL ; /* Default is autodetect */
2006-04-02 20:35:00 +04:00
core - > route . input = TVP5150_COMPOSITE1 ;
2005-11-09 08:36:43 +03:00
core - > enable = 1 ;
core - > bright = 32768 ;
core - > contrast = 32768 ;
core - > hue = 32768 ;
core - > sat = 32768 ;
2005-11-09 08:36:40 +03:00
if ( rv ) {
2006-01-09 20:25:36 +03:00
kfree ( c ) ;
2005-11-09 08:36:40 +03:00
kfree ( core ) ;
return rv ;
}
2006-02-07 06:01:19 +03:00
if ( debug > 1 )
2006-01-09 20:25:36 +03:00
dump_reg ( c ) ;
2005-11-09 08:36:40 +03:00
return 0 ;
}
2005-11-09 08:37:07 +03:00
static int tvp5150_attach_adapter ( struct i2c_adapter * adapter )
2005-11-09 08:36:40 +03:00
{
2006-01-09 20:25:36 +03:00
if ( debug )
printk ( KERN_INFO
2005-11-09 08:36:40 +03:00
" tvp5150.c: starting probe for adapter %s (0x%x) \n " ,
adapter - > name , adapter - > id ) ;
return i2c_probe ( adapter , & addr_data , & tvp5150_detect_client ) ;
}
2006-01-09 20:25:36 +03:00
static int tvp5150_detach_client ( struct i2c_client * c )
2005-11-09 08:36:40 +03:00
{
2006-01-09 20:25:36 +03:00
struct tvp5150 * decoder = i2c_get_clientdata ( c ) ;
2005-11-09 08:36:40 +03:00
int err ;
2006-01-09 20:25:36 +03:00
tvp5150_dbg ( 1 ,
" tvp5150.c: removing tvp5150 adapter on address 0x%x \n " ,
c - > addr < < 1 ) ;
err = i2c_detach_client ( c ) ;
2005-11-09 08:36:40 +03:00
if ( err ) {
return err ;
}
kfree ( decoder ) ;
2006-01-09 20:25:36 +03:00
kfree ( c ) ;
2005-11-09 08:36:40 +03:00
return 0 ;
}
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
2005-11-26 22:43:39 +03:00
. driver = {
. name = " tvp5150 " ,
} ,
2006-01-09 20:53:26 +03:00
. id = I2C_DRIVERID_TVP5150 ,
2005-11-09 08:36:40 +03:00
. attach_adapter = tvp5150_attach_adapter ,
. detach_client = tvp5150_detach_client ,
2005-11-09 08:36:41 +03:00
. command = tvp5150_command ,
2005-11-09 08:36:40 +03:00
} ;
2005-11-09 08:37:07 +03:00
static int __init tvp5150_init ( void )
2005-11-09 08:36:40 +03:00
{
return i2c_add_driver ( & driver ) ;
}
2005-11-09 08:37:07 +03:00
static void __exit tvp5150_exit ( void )
2005-11-09 08:36:40 +03:00
{
i2c_del_driver ( & driver ) ;
}
module_init ( tvp5150_init ) ;
module_exit ( tvp5150_exit ) ;