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>
2008-07-25 12:32:50 +04:00
# include <linux/videodev2.h>
2005-11-09 08:36:40 +03:00
# include <linux/delay.h>
2008-12-18 17:17:25 +03:00
# include <media/v4l2-device.h>
2006-04-02 20:35:00 +04:00
# include <media/tvp5150.h>
2009-03-30 00:34:31 +04:00
# include <media/v4l2-i2c-drv.h>
2008-12-23 02:34:18 +03:00
# include <media/v4l2-chip-ident.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 " ) ;
2008-04-22 21:41:48 +04:00
static int debug ;
2005-11-09 08:36:40 +03:00
module_param ( debug , int , 0 ) ;
2008-12-18 17:17:25 +03:00
MODULE_PARM_DESC ( debug , " Debug level (0-2) " ) ;
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 {
2008-12-18 17:17:25 +03:00
struct v4l2_subdev sd ;
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
} ;
2008-12-18 17:17:25 +03:00
static inline struct tvp5150 * to_tvp5150 ( struct v4l2_subdev * sd )
2005-11-09 08:36:40 +03:00
{
2008-12-18 17:17:25 +03:00
return container_of ( sd , struct tvp5150 , sd ) ;
}
static int tvp5150_read ( struct v4l2_subdev * sd , unsigned char addr )
{
struct i2c_client * c = v4l2_get_subdevdata ( sd ) ;
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 ) ) )
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 0 , debug , sd , " 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 ) ) )
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 0 , debug , sd , " i2c i/o error: rc == %d (should be 1) \n " , rc ) ;
2006-01-09 20:25:36 +03:00
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 2 , debug , sd , " tvp5150: read 0x%02x = 0x%02x \n " , addr , buffer [ 0 ] ) ;
2005-11-09 08:36:40 +03:00
return ( buffer [ 0 ] ) ;
}
2008-12-18 17:17:25 +03:00
static inline void tvp5150_write ( struct v4l2_subdev * sd , unsigned char addr ,
2005-11-09 08:36:41 +03:00
unsigned char value )
2005-11-09 08:36:40 +03:00
{
2008-12-18 17:17:25 +03:00
struct i2c_client * c = v4l2_get_subdevdata ( sd ) ;
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 ;
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 2 , debug , sd , " 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 ) ) )
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 0 , debug , sd , " i2c i/o error: rc == %d (should be 2) \n " , rc ) ;
2005-11-09 08:36:40 +03:00
}
2008-12-18 17:17:25 +03:00
static void dump_reg_range ( struct v4l2_subdev * sd , char * s , u8 init ,
const u8 end , int max_line )
2006-01-23 22:11:05 +03:00
{
2008-12-18 17:17:25 +03:00
int i = 0 ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
while ( init ! = ( u8 ) ( end + 1 ) ) {
if ( ( i % max_line ) = = 0 ) {
if ( i > 0 )
2006-01-23 22:11:05 +03:00
printk ( " \n " ) ;
2008-12-18 17:17:25 +03:00
printk ( " tvp5150: %s reg 0x%02x = " , s , init ) ;
2006-01-23 22:11:05 +03:00
}
2008-12-18 17:17:25 +03:00
printk ( " %02x " , tvp5150_read ( sd , init ) ) ;
2006-01-23 22:11:05 +03:00
init + + ;
i + + ;
}
printk ( " \n " ) ;
}
2008-12-18 17:17:25 +03:00
static int tvp5150_log_status ( struct v4l2_subdev * sd )
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 " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_VD_IN_SRC_SEL_1 ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Analog channel controls = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_ANAL_CHL_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Operation mode controls = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_OP_MODE_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Miscellaneous controls = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_MISC_CTL ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Autoswitch mask= 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_AUTOSW_MSK ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Color killer threshold control = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_COLOR_KIL_THSH_CTL ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_LUMA_PROC_CTL_1 ) ,
tvp5150_read ( sd , TVP5150_LUMA_PROC_CTL_2 ) ,
tvp5150_read ( sd , TVP5150_LUMA_PROC_CTL_3 ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Brightness control = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_BRIGHT_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Color saturation control = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_SATURATION_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Hue control = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_HUE_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Contrast control = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_CONTRAST_CTL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Outputs and data rates select = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_DATA_RATE_SEL ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Configuration shared pins = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_CONF_SHARED_PIN ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Active video cropping start = 0x%02x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_ACT_VD_CROP_ST_MSB ) ,
tvp5150_read ( sd , TVP5150_ACT_VD_CROP_ST_LSB ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Active video cropping stop = 0x%02x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_ACT_VD_CROP_STP_MSB ) ,
tvp5150_read ( sd , TVP5150_ACT_VD_CROP_STP_LSB ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Genlock/RTC = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_GENLOCK ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Horizontal sync start = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_HORIZ_SYNC_START ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Vertical blanking start = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_VERT_BLANKING_START ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Vertical blanking stop = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_VERT_BLANKING_STOP ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Chrominance processing control #1 and #2 = %02x %02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_CHROMA_PROC_CTL_1 ) ,
tvp5150_read ( sd , TVP5150_CHROMA_PROC_CTL_2 ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt reset register B = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_RESET_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt enable register B = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_ENABLE_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt configuration register B = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INTT_CONFIG_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Video standard = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_VIDEO_STD ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_CB_GAIN_FACT ) ,
tvp5150_read ( sd , TVP5150_CR_GAIN_FACTOR ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Macrovision on counter = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_MACROVISION_ON_CTR ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Macrovision off counter = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_MACROVISION_OFF_CTR ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only) \n " ,
2008-12-18 17:17:25 +03:00
( tvp5150_read ( sd , TVP5150_REV_SELECT ) & 1 ) ? 3 : 4 ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Device ID = %02x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_MSB_DEV_ID ) ,
tvp5150_read ( sd , TVP5150_LSB_DEV_ID ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: ROM version = (hex) %02x.%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_ROM_MAJOR_VER ) ,
tvp5150_read ( sd , TVP5150_ROM_MINOR_VER ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Vertical line count = 0x%02x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_VERT_LN_COUNT_MSB ) ,
tvp5150_read ( sd , TVP5150_VERT_LN_COUNT_LSB ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt status register B = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_STATUS_REG_B ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt active register B = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_ACTIVE_REG_B ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_STATUS_REG_1 ) ,
tvp5150_read ( sd , TVP5150_STATUS_REG_2 ) ,
tvp5150_read ( sd , TVP5150_STATUS_REG_3 ) ,
tvp5150_read ( sd , TVP5150_STATUS_REG_4 ) ,
tvp5150_read ( sd , TVP5150_STATUS_REG_5 ) ) ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
dump_reg_range ( sd , " Teletext filter 1 " , TVP5150_TELETEXT_FIL1_INI ,
TVP5150_TELETEXT_FIL1_END , 8 ) ;
dump_reg_range ( sd , " Teletext filter 2 " , TVP5150_TELETEXT_FIL2_INI ,
TVP5150_TELETEXT_FIL2_END , 8 ) ;
2006-01-23 22:11:05 +03:00
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Teletext filter enable = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_TELETEXT_FIL_ENA ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt status register A = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_STATUS_REG_A ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt enable register A = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_ENABLE_REG_A ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Interrupt configuration = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_INT_CONF ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: VDP status register = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_VDP_STATUS_REG ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO word count = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_FIFO_WORD_COUNT ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO interrupt threshold = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_FIFO_INT_THRESHOLD ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO reset = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_FIFO_RESET ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Line number interrupt = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_LINE_NUMBER_INT ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Pixel alignment register = 0x%02x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_PIX_ALIGN_REG_HIGH ) ,
tvp5150_read ( sd , TVP5150_PIX_ALIGN_REG_LOW ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: FIFO output control = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_FIFO_OUT_CTRL ) ) ;
2006-01-23 22:11:05 +03:00
printk ( " tvp5150: Full field enable = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_FULL_FIELD_ENA ) ) ;
2005-11-09 08:36:41 +03:00
printk ( " tvp5150: Full field mode register = 0x%02x \n " ,
2008-12-18 17:17:25 +03:00
tvp5150_read ( sd , TVP5150_FULL_FIELD_MODE_REG ) ) ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
dump_reg_range ( sd , " CC data " , TVP5150_CC_DATA_INI ,
TVP5150_CC_DATA_END , 8 ) ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
dump_reg_range ( sd , " WSS data " , TVP5150_WSS_DATA_INI ,
TVP5150_WSS_DATA_END , 8 ) ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
dump_reg_range ( sd , " VPS data " , TVP5150_VPS_DATA_INI ,
TVP5150_VPS_DATA_END , 8 ) ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
dump_reg_range ( sd , " VITC data " , TVP5150_VITC_DATA_INI ,
TVP5150_VITC_DATA_END , 10 ) ;
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
dump_reg_range ( sd , " Line mode " , TVP5150_LINE_MODE_INI ,
TVP5150_LINE_MODE_END , 8 ) ;
return 0 ;
2005-11-09 08:36:40 +03:00
}
/****************************************************************************
Basic functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-18 17:17:25 +03:00
static inline void tvp5150_selmux ( struct v4l2_subdev * sd )
2005-11-09 08:36:40 +03:00
{
2006-01-09 20:25:14 +03:00
int opmode = 0 ;
2008-12-18 17:17:25 +03:00
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
2006-04-02 20:35:00 +04:00
int input = 0 ;
2007-11-04 04:40:24 +03:00
unsigned char val ;
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-08-18 14:31:10 +04:00
switch ( decoder - > route . 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 ;
}
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 1 , debug , sd , " Selecting video route: route input=%i, output=%i "
2006-08-18 14:31:10 +04:00
" => tvp5150 input=%i, opmode=%i \n " ,
decoder - > route . input , decoder - > route . output ,
input , opmode ) ;
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_OP_MODE_CTL , opmode ) ;
tvp5150_write ( sd , TVP5150_VD_IN_SRC_SEL_1 , input ) ;
2007-11-04 04:40:24 +03:00
/* Svideo should enable YCrCb output and disable GPCL output
* For Composite and TV , it should be the reverse
*/
2008-12-18 17:17:25 +03:00
val = tvp5150_read ( sd , TVP5150_MISC_CTL ) ;
2007-11-04 04:40:24 +03:00
if ( decoder - > route . input = = TVP5150_SVIDEO )
val = ( val & ~ 0x40 ) | 0x10 ;
else
val = ( val & ~ 0x10 ) | 0x40 ;
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_MISC_CTL , val ) ;
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
2008-12-18 17:17:25 +03:00
static int tvp5150_write_inittab ( struct v4l2_subdev * sd ,
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 ) {
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , regs - > reg , regs - > value ) ;
2006-01-09 20:25:36 +03:00
regs + + ;
}
return 0 ;
}
2005-11-09 08:36:41 +03:00
2008-12-18 17:17:25 +03:00
static int tvp5150_vdp_init ( struct v4l2_subdev * sd ,
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 */
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , 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 */
2008-12-18 17:17:25 +03:00
for ( i = TVP5150_LINE_MODE_INI ; i < = TVP5150_LINE_MODE_END ; i + + )
tvp5150_write ( sd , i , 0xff ) ;
2005-11-09 08:36:40 +03:00
2006-01-09 20:25:36 +03:00
/* Load Ram Table */
2008-12-18 17:17:25 +03:00
while ( regs - > reg ! = ( u16 ) - 1 ) {
tvp5150_write ( sd , TVP5150_CONF_RAM_ADDR_HIGH , regs - > reg > > 8 ) ;
tvp5150_write ( sd , TVP5150_CONF_RAM_ADDR_LOW , regs - > reg ) ;
2005-11-09 08:36:40 +03:00
2008-12-18 17:17:25 +03:00
for ( i = 0 ; i < 16 ; i + + )
tvp5150_write ( sd , 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 */
2008-12-18 17:17:25 +03:00
static int tvp5150_g_sliced_vbi_cap ( struct v4l2_subdev * sd ,
2006-01-23 22:11:05 +03:00
struct v4l2_sliced_vbi_cap * cap )
{
2008-12-18 17:17:25 +03:00
const struct i2c_vbi_ram_value * regs = vbi_ram_default ;
2006-01-23 22:11:05 +03:00
int line ;
2009-03-30 13:55:27 +04:00
v4l2_dbg ( 1 , debug , sd , " g_sliced_vbi_cap \n " ) ;
2006-01-23 22:11:05 +03:00
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 + + ;
}
2008-12-18 17:17:25 +03:00
return 0 ;
2006-01-23 22:11:05 +03:00
}
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
*/
2008-12-18 17:17:25 +03:00
static int tvp5150_set_vbi ( struct v4l2_subdev * sd ,
2006-01-23 22:11:06 +03:00
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
{
2008-12-18 17:17:25 +03:00
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
v4l2_std_id std = decoder - > norm ;
2006-01-23 22:11:05 +03:00
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 ) {
2008-12-18 17:17:25 +03:00
v4l2_err ( sd , " VBI can't be configured without knowing number of lines \n " ) ;
2006-01-23 22:11:08 +03:00
return 0 ;
2008-03-10 03:19:13 +03:00
} else if ( std & V4L2_STD_625_50 ) {
2006-01-23 22:11:05 +03:00
/* 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 ) {
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , reg , type ) ;
2006-01-23 22:11:05 +03:00
}
if ( fields & 2 ) {
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , reg + 1 , type ) ;
2006-01-23 22:11:05 +03:00
}
2006-01-23 22:11:06 +03:00
return type ;
2006-01-23 22:11:05 +03:00
}
2008-12-18 17:17:25 +03:00
static int tvp5150_get_vbi ( struct v4l2_subdev * sd ,
2006-01-23 22:11:08 +03:00
const struct i2c_vbi_ram_value * regs , int line )
{
2008-12-18 17:17:25 +03:00
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
v4l2_std_id std = decoder - > norm ;
2006-01-23 22:11:08 +03:00
u8 reg ;
2008-12-18 17:17:25 +03:00
int pos , type = 0 ;
2006-01-23 22:11:08 +03:00
if ( std = = V4L2_STD_ALL ) {
2008-12-18 17:17:25 +03:00
v4l2_err ( sd , " VBI can't be configured without knowing number of lines \n " ) ;
2006-01-23 22:11:08 +03:00
return 0 ;
2008-03-10 03:19:13 +03:00
} else if ( std & V4L2_STD_625_50 ) {
2006-01-23 22:11:08 +03:00
/* Don't follow NTSC Line number convension */
line + = 3 ;
}
2008-12-18 17:17:25 +03:00
if ( line < 6 | | line > 27 )
2006-01-23 22:11:08 +03:00
return 0 ;
2008-12-18 17:17:25 +03:00
reg = ( ( line - 6 ) < < 1 ) + TVP5150_LINE_MODE_INI ;
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
pos = tvp5150_read ( sd , reg ) & 0x0f ;
if ( pos < 0x0f )
type = regs [ pos ] . type . vbi_type ;
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
pos = tvp5150_read ( sd , reg + 1 ) & 0x0f ;
if ( pos < 0x0f )
type | = regs [ pos ] . type . vbi_type ;
2006-01-23 22:11:08 +03:00
return type ;
}
2008-12-18 17:17:25 +03:00
static int tvp5150_set_std ( struct v4l2_subdev * sd , v4l2_std_id std )
2006-01-09 20:25:36 +03:00
{
2008-12-18 17:17:25 +03:00
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
int fmt = 0 ;
2006-01-09 20:25:36 +03:00
2008-12-18 17:17:25 +03:00
decoder - > norm = std ;
2006-01-09 20:25:36 +03:00
/* First tests should be against specific std */
if ( std = = V4L2_STD_ALL ) {
2008-12-18 17:17:25 +03:00
fmt = 0 ; /* Autodetect mode */
2006-01-09 20:25:36 +03:00
} else if ( std & V4L2_STD_NTSC_443 ) {
2008-12-18 17:17:25 +03:00
fmt = 0xa ;
2006-01-09 20:25:36 +03:00
} else if ( std & V4L2_STD_PAL_M ) {
2008-12-18 17:17:25 +03:00
fmt = 0x6 ;
} else if ( std & ( V4L2_STD_PAL_N | V4L2_STD_PAL_Nc ) ) {
fmt = 0x8 ;
2006-01-09 20:25:36 +03:00
} else {
/* Then, test against generic ones */
2008-12-18 17:17:25 +03:00
if ( std & V4L2_STD_NTSC )
fmt = 0x2 ;
else if ( std & V4L2_STD_PAL )
fmt = 0x4 ;
else if ( std & V4L2_STD_SECAM )
fmt = 0xc ;
2006-01-09 20:25:36 +03:00
}
2005-11-09 08:36:41 +03:00
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 1 , debug , sd , " Set video std register to %d. \n " , fmt ) ;
tvp5150_write ( sd , TVP5150_VIDEO_STD , fmt ) ;
2006-01-09 20:25:36 +03:00
return 0 ;
}
2008-12-18 17:17:25 +03:00
static int tvp5150_s_std ( struct v4l2_subdev * sd , v4l2_std_id std )
{
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
if ( decoder - > norm = = std )
return 0 ;
return tvp5150_set_std ( sd , std ) ;
}
static int tvp5150_reset ( struct v4l2_subdev * sd , u32 val )
2006-01-09 20:25:36 +03:00
{
2008-12-18 17:17:25 +03:00
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
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
2008-12-18 17:17:25 +03:00
msb_id = tvp5150_read ( sd , TVP5150_MSB_DEV_ID ) ;
lsb_id = tvp5150_read ( sd , TVP5150_LSB_DEV_ID ) ;
msb_rom = tvp5150_read ( sd , TVP5150_ROM_MAJOR_VER ) ;
lsb_rom = tvp5150_read ( sd , TVP5150_ROM_MINOR_VER ) ;
2006-01-09 20:25:36 +03:00
2008-12-18 17:17:25 +03:00
if ( msb_rom = = 4 & & lsb_rom = = 0 ) { /* Is TVP5150AM1 */
v4l2_info ( sd , " tvp%02x%02xam1 detected. \n " , msb_id , lsb_id ) ;
2006-01-23 14:48:34 +03:00
/* ITU-T BT.656.4 timing */
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_REV_SELECT , 0 ) ;
2006-01-09 20:25:36 +03:00
} else {
2008-12-18 17:17:25 +03:00
if ( msb_rom = = 3 | | lsb_rom = = 0x21 ) { /* Is TVP5150A */
v4l2_info ( sd , " tvp%02x%02xa detected. \n " , msb_id , lsb_id ) ;
2006-01-23 14:48:34 +03:00
} else {
2008-12-18 17:17:25 +03:00
v4l2_info ( sd , " *** unknown tvp%02x%02x chip detected. \n " ,
msb_id , lsb_id ) ;
v4l2_info ( sd , " *** Rom ver is %d.%d \n " , msb_rom , lsb_rom ) ;
2006-01-23 14:48:34 +03:00
}
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 */
2008-12-18 17:17:25 +03:00
tvp5150_write_inittab ( sd , tvp5150_init_default ) ;
2006-01-09 20:25:36 +03:00
/* Initializes VDP registers */
2008-12-18 17:17:25 +03:00
tvp5150_vdp_init ( sd , vbi_ram_default ) ;
2006-01-09 20:25:36 +03:00
/* Selects decoder input */
2008-12-18 17:17:25 +03:00
tvp5150_selmux ( sd ) ;
2006-01-09 20:25:36 +03:00
/* Initializes TVP5150 to stream enabled values */
2008-12-18 17:17:25 +03:00
tvp5150_write_inittab ( sd , tvp5150_init_enable ) ;
2006-01-09 20:25:36 +03:00
/* Initialize image preferences */
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_BRIGHT_CTL , decoder - > bright ) ;
tvp5150_write ( sd , TVP5150_CONTRAST_CTL , decoder - > contrast ) ;
tvp5150_write ( sd , TVP5150_SATURATION_CTL , decoder - > contrast ) ;
tvp5150_write ( sd , TVP5150_HUE_CTL , decoder - > hue ) ;
2006-01-09 20:25:36 +03:00
2008-12-18 17:17:25 +03:00
tvp5150_set_std ( sd , decoder - > norm ) ;
return 0 ;
2005-11-09 08:36:40 +03:00
} ;
2008-12-18 17:17:25 +03:00
static int tvp5150_g_ctrl ( struct v4l2_subdev * sd , struct v4l2_control * ctrl )
2005-11-09 08:37:07 +03:00
{
2009-03-30 13:55:27 +04:00
v4l2_dbg ( 1 , debug , sd , " g_ctrl called \n " ) ;
2005-11-09 08:37:07 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
2008-12-18 17:17:25 +03:00
ctrl - > value = tvp5150_read ( sd , TVP5150_BRIGHT_CTL ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
case V4L2_CID_CONTRAST :
2008-12-18 17:17:25 +03:00
ctrl - > value = tvp5150_read ( sd , TVP5150_CONTRAST_CTL ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
case V4L2_CID_SATURATION :
2008-12-18 17:17:25 +03:00
ctrl - > value = tvp5150_read ( sd , TVP5150_SATURATION_CTL ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
case V4L2_CID_HUE :
2008-12-18 17:17:25 +03:00
ctrl - > value = tvp5150_read ( sd , TVP5150_HUE_CTL ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
}
2006-01-09 20:25:14 +03:00
return - EINVAL ;
2005-11-09 08:37:07 +03:00
}
2008-12-18 17:17:25 +03:00
static int tvp5150_s_ctrl ( struct v4l2_subdev * sd , struct v4l2_control * ctrl )
2005-11-09 08:37:07 +03:00
{
2008-12-18 17:17:25 +03:00
u8 i , n ;
n = ARRAY_SIZE ( tvp5150_qctrl ) ;
for ( i = 0 ; i < n ; i + + ) {
if ( ctrl - > id ! = tvp5150_qctrl [ i ] . id )
continue ;
if ( ctrl - > value < tvp5150_qctrl [ i ] . minimum | |
ctrl - > value > tvp5150_qctrl [ i ] . maximum )
return - ERANGE ;
2009-03-30 13:55:27 +04:00
v4l2_dbg ( 1 , debug , sd , " s_ctrl: id=%d, value=%d \n " ,
2008-12-18 17:17:25 +03:00
ctrl - > id , ctrl - > value ) ;
break ;
}
2005-11-09 08:37:07 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_BRIGHT_CTL , ctrl - > value ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
case V4L2_CID_CONTRAST :
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_CONTRAST_CTL , ctrl - > value ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
case V4L2_CID_SATURATION :
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_SATURATION_CTL , ctrl - > value ) ;
2005-11-09 08:37:07 +03:00
return 0 ;
case V4L2_CID_HUE :
2008-12-18 17:17:25 +03:00
tvp5150_write ( sd , TVP5150_HUE_CTL , ctrl - > value ) ;
2005-11-09 08:37:07 +03:00
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-04-02 20:35:00 +04:00
2008-12-18 17:17:25 +03:00
static int tvp5150_s_routing ( struct v4l2_subdev * sd , const struct v4l2_routing * route )
{
struct tvp5150 * decoder = to_tvp5150 ( sd ) ;
2005-11-09 08:36:41 +03:00
2008-12-18 17:17:25 +03:00
decoder - > route = * route ;
tvp5150_selmux ( sd ) ;
return 0 ;
}
2006-01-23 22:11:05 +03:00
2008-12-18 17:17:25 +03:00
static int tvp5150_s_fmt ( struct v4l2_subdev * sd , struct v4l2_format * fmt )
{
struct v4l2_sliced_vbi_format * svbi ;
int i ;
/* raw vbi */
if ( fmt - > type = = V4L2_BUF_TYPE_VBI_CAPTURE ) {
/* this is for capturing 36 raw vbi lines
if there ' s a way to cut off the beginning 2 vbi lines
with the tvp5150 then the vbi line count could be lowered
to 17 lines / field again , although I couldn ' t find a register
which could do that cropping */
if ( fmt - > fmt . vbi . sample_format = = V4L2_PIX_FMT_GREY )
tvp5150_write ( sd , TVP5150_LUMA_PROC_CTL_1 , 0x70 ) ;
if ( fmt - > fmt . vbi . count [ 0 ] = = 18 & & fmt - > fmt . vbi . count [ 1 ] = = 18 ) {
tvp5150_write ( sd , TVP5150_VERT_BLANKING_START , 0x00 ) ;
tvp5150_write ( sd , TVP5150_VERT_BLANKING_STOP , 0x01 ) ;
}
return 0 ;
2006-01-23 22:11:05 +03:00
}
2008-12-18 17:17:25 +03:00
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 ( sd , vbi_ram_default ,
svbi - > service_lines [ 0 ] [ i ] , 0xf0 , i , 3 ) ;
2008-10-24 19:19:14 +04:00
}
2008-12-18 17:17:25 +03:00
/* Enables FIFO */
tvp5150_write ( sd , TVP5150_FIFO_OUT_CTRL , 1 ) ;
} else {
/* Disables FIFO*/
tvp5150_write ( sd , TVP5150_FIFO_OUT_CTRL , 0 ) ;
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
/* Disable Full Field */
tvp5150_write ( sd , TVP5150_FULL_FIELD_ENA , 0 ) ;
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
/* Disable Line modes */
for ( i = TVP5150_LINE_MODE_INI ; i < = TVP5150_LINE_MODE_END ; i + + )
tvp5150_write ( sd , i , 0xff ) ;
2006-01-23 22:11:08 +03:00
}
2008-12-18 17:17:25 +03:00
return 0 ;
}
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
static int tvp5150_g_fmt ( struct v4l2_subdev * sd , struct v4l2_format * fmt )
{
struct v4l2_sliced_vbi_format * svbi ;
int i , mask = 0 ;
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
if ( fmt - > type ! = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE )
return - EINVAL ;
svbi = & fmt - > fmt . sliced ;
memset ( svbi , 0 , sizeof ( * svbi ) ) ;
2006-01-23 22:11:08 +03:00
2008-12-18 17:17:25 +03:00
for ( i = 0 ; i < = 23 ; i + + ) {
svbi - > service_lines [ 0 ] [ i ] =
tvp5150_get_vbi ( sd , vbi_ram_default , i ) ;
mask | = svbi - > service_lines [ 0 ] [ i ] ;
2006-01-23 22:11:06 +03:00
}
2008-12-18 17:17:25 +03:00
svbi - > service_set = mask ;
return 0 ;
}
2006-01-23 22:11:08 +03:00
2008-12-23 02:34:18 +03:00
static int tvp5150_g_chip_ident ( struct v4l2_subdev * sd ,
2008-12-30 13:14:19 +03:00
struct v4l2_dbg_chip_ident * chip )
2008-12-23 02:34:18 +03:00
{
int rev ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
rev = tvp5150_read ( sd , TVP5150_ROM_MAJOR_VER ) < < 8 |
tvp5150_read ( sd , TVP5150_ROM_MINOR_VER ) ;
return v4l2_chip_ident_i2c_client ( client , chip , V4L2_IDENT_TVP5150 ,
rev ) ;
}
2006-01-09 20:25:37 +03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2008-12-30 13:14:19 +03:00
static int tvp5150_g_register ( struct v4l2_subdev * sd , struct v4l2_dbg_register * reg )
2008-12-18 17:17:25 +03:00
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2006-01-09 20:25:37 +03:00
2008-12-30 13:14:19 +03:00
if ( ! v4l2_chip_match_i2c_client ( client , & reg - > match ) )
2008-12-18 17:17:25 +03:00
return - EINVAL ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
reg - > val = tvp5150_read ( sd , reg - > reg & 0xff ) ;
2008-12-30 13:14:19 +03:00
reg - > size = 1 ;
2008-12-18 17:17:25 +03:00
return 0 ;
}
2005-11-09 08:36:41 +03:00
2008-12-30 13:14:19 +03:00
static int tvp5150_s_register ( struct v4l2_subdev * sd , struct v4l2_dbg_register * reg )
2008-12-18 17:17:25 +03:00
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2005-11-09 08:36:41 +03:00
2008-12-30 13:14:19 +03:00
if ( ! v4l2_chip_match_i2c_client ( client , & reg - > match ) )
2008-12-18 17:17:25 +03:00
return - EINVAL ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
tvp5150_write ( sd , reg - > reg & 0xff , reg - > val & 0xff ) ;
return 0 ;
}
# endif
2005-11-09 08:37:07 +03:00
2008-12-18 17:17:25 +03:00
static int tvp5150_g_tuner ( struct v4l2_subdev * sd , struct v4l2_tuner * vt )
{
int status = tvp5150_read ( sd , 0x88 ) ;
2005-11-09 08:37:07 +03:00
2008-12-18 17:17:25 +03:00
vt - > signal = ( ( status & 0x04 ) & & ( status & 0x02 ) ) ? 0xffff : 0x0 ;
return 0 ;
}
2005-11-09 08:37:07 +03:00
2008-12-18 17:17:25 +03:00
static int tvp5150_queryctrl ( struct v4l2_subdev * sd , struct v4l2_queryctrl * qc )
{
int i ;
2005-11-09 08:37:07 +03:00
2009-03-30 13:55:27 +04:00
v4l2_dbg ( 1 , debug , sd , " queryctrl called \n " ) ;
2008-12-18 17:17:25 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( tvp5150_qctrl ) ; i + + )
if ( qc - > id & & qc - > id = = tvp5150_qctrl [ i ] . id ) {
memcpy ( qc , & ( tvp5150_qctrl [ i ] ) ,
sizeof ( * qc ) ) ;
return 0 ;
2005-11-09 08:37:07 +03:00
}
2008-12-18 17:17:25 +03:00
return - EINVAL ;
}
2005-11-09 08:36:41 +03:00
2008-12-18 17:17:25 +03:00
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
. log_status = tvp5150_log_status ,
. g_ctrl = tvp5150_g_ctrl ,
. s_ctrl = tvp5150_s_ctrl ,
. queryctrl = tvp5150_queryctrl ,
2009-04-01 10:52:39 +04:00
. s_std = tvp5150_s_std ,
2008-12-18 17:17:25 +03:00
. reset = tvp5150_reset ,
2008-12-23 02:34:18 +03:00
. g_chip_ident = tvp5150_g_chip_ident ,
2008-12-18 17:17:25 +03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
. g_register = tvp5150_g_register ,
. s_register = tvp5150_s_register ,
# endif
} ;
static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
. g_tuner = tvp5150_g_tuner ,
} ;
static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
. s_routing = tvp5150_s_routing ,
. g_fmt = tvp5150_g_fmt ,
. s_fmt = tvp5150_s_fmt ,
. g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap ,
} ;
static const struct v4l2_subdev_ops tvp5150_ops = {
. core = & tvp5150_core_ops ,
. tuner = & tvp5150_tuner_ops ,
. video = & tvp5150_video_ops ,
} ;
2005-11-09 08:36:40 +03:00
/****************************************************************************
I2C Client & Driver
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-18 17:17:25 +03:00
static int tvp5150_probe ( struct i2c_client * c ,
const struct i2c_device_id * id )
2005-11-09 08:36:40 +03:00
{
struct tvp5150 * core ;
2008-12-18 17:17:25 +03:00
struct v4l2_subdev * sd ;
2005-11-09 08:36:40 +03:00
/* Check if the adapter supports the needed features */
2008-12-18 17:17:25 +03:00
if ( ! i2c_check_functionality ( c - > adapter ,
2005-11-09 08:36:40 +03:00
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA ) )
2008-12-18 17:17:25 +03:00
return - EIO ;
2005-11-09 08:36:40 +03:00
2006-01-12 00:40:56 +03:00
core = kzalloc ( sizeof ( struct tvp5150 ) , GFP_KERNEL ) ;
2008-03-29 06:07:38 +03:00
if ( ! core ) {
2005-11-09 08:36:40 +03:00
return - ENOMEM ;
}
2008-12-18 17:17:25 +03:00
sd = & core - > sd ;
v4l2_i2c_subdev_init ( sd , c , & tvp5150_ops ) ;
v4l_info ( c , " chip found @ 0x%02x (%s) \n " ,
c - > addr < < 1 , c - > adapter - > name ) ;
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 ;
2007-11-02 03:33:38 +03:00
core - > bright = 128 ;
core - > contrast = 128 ;
core - > hue = 0 ;
core - > sat = 128 ;
2005-11-09 08:36:43 +03:00
2006-02-07 06:01:19 +03:00
if ( debug > 1 )
2008-12-18 17:17:25 +03:00
tvp5150_log_status ( sd ) ;
2005-11-09 08:36:40 +03:00
return 0 ;
}
2008-12-18 17:17:25 +03:00
static int tvp5150_remove ( struct i2c_client * c )
2005-11-09 08:36:40 +03:00
{
2008-12-18 17:17:25 +03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( c ) ;
2005-11-09 08:36:40 +03:00
2008-12-18 17:17:25 +03:00
v4l2_dbg ( 1 , debug , sd ,
2006-01-09 20:25:36 +03:00
" tvp5150.c: removing tvp5150 adapter on address 0x%x \n " ,
c - > addr < < 1 ) ;
2008-12-18 17:17:25 +03:00
v4l2_device_unregister_subdev ( sd ) ;
kfree ( to_tvp5150 ( sd ) ) ;
2005-11-09 08:36:40 +03:00
return 0 ;
}
/* ----------------------------------------------------------------------- */
2008-12-18 17:17:25 +03:00
static const struct i2c_device_id tvp5150_id [ ] = {
{ " tvp5150 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tvp5150_id ) ;
2005-11-09 08:36:41 +03:00
2008-12-18 17:17:25 +03:00
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
. name = " tvp5150 " ,
. probe = tvp5150_probe ,
. remove = tvp5150_remove ,
. id_table = tvp5150_id ,
2005-11-09 08:36:40 +03:00
} ;