2008-08-08 19:43:59 +04:00
/*
saa6752hs - i2c - driver for the saa6752hs by Philips
Copyright ( C ) 2004 Andrew de Quincey
AC - 3 support :
Copyright ( C ) 2008 Hans Verkuil < hverkuil @ xs4all . nl >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License vs published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mvss Ave , Cambridge , MA 0213 9 , USA .
*/
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/i2c.h>
# include <linux/types.h>
2006-01-09 20:53:26 +03:00
# include <linux/videodev2.h>
2009-01-14 12:54:38 +03:00
# include <media/v4l2-device.h>
2013-06-10 11:51:42 +04:00
# include <media/v4l2-ctrls.h>
2006-01-09 20:53:26 +03:00
# include <media/v4l2-common.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/crc32.h>
# define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
# define MPEG_VIDEO_MAX_BITRATE_MAX 27000
# define MPEG_TOTAL_TARGET_BITRATE_MAX 27000
# define MPEG_PID_MAX ((1 << 14) - 1)
MODULE_DESCRIPTION ( " device driver for saa6752hs MPEG2 encoder " ) ;
MODULE_AUTHOR ( " Andrew de Quincey " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-05-06 03:15:52 +04:00
enum saa6752hs_videoformat {
SAA6752HS_VF_D1 = 0 , /* standard D1 video format: 720x576 */
SAA6752HS_VF_2_3_D1 = 1 , /* 2/3D1 video format: 480x576 */
SAA6752HS_VF_1_2_D1 = 2 , /* 1/2D1 video format: 352x576 */
SAA6752HS_VF_SIF = 3 , /* SIF video format: 352x288 */
SAA6752HS_VF_UNKNOWN ,
} ;
2006-06-18 23:40:10 +04:00
struct saa6752hs_mpeg_params {
/* transport streams */
__u16 ts_pid_pmt ;
__u16 ts_pid_audio ;
__u16 ts_pid_video ;
__u16 ts_pid_pcr ;
/* audio */
2008-08-08 19:43:59 +04:00
enum v4l2_mpeg_audio_encoding au_encoding ;
enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate ;
enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate ;
2006-06-18 23:40:10 +04:00
/* video */
enum v4l2_mpeg_video_aspect vi_aspect ;
enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode ;
__u32 vi_bitrate ;
__u32 vi_bitrate_peak ;
} ;
2005-05-06 03:15:52 +04:00
static const struct v4l2_format v4l2_format_table [ ] =
{
2005-06-24 09:05:09 +04:00
[ SAA6752HS_VF_D1 ] =
{ . fmt = { . pix = { . width = 720 , . height = 576 } } } ,
[ SAA6752HS_VF_2_3_D1 ] =
{ . fmt = { . pix = { . width = 480 , . height = 576 } } } ,
[ SAA6752HS_VF_1_2_D1 ] =
{ . fmt = { . pix = { . width = 352 , . height = 576 } } } ,
[ SAA6752HS_VF_SIF ] =
{ . fmt = { . pix = { . width = 352 , . height = 288 } } } ,
[ SAA6752HS_VF_UNKNOWN ] =
{ . fmt = { . pix = { . width = 0 , . height = 0 } } } ,
2005-05-06 03:15:52 +04:00
} ;
2005-04-17 02:20:36 +04:00
struct saa6752hs_state {
2009-01-14 12:54:38 +03:00
struct v4l2_subdev sd ;
2013-06-10 11:51:42 +04:00
struct v4l2_ctrl_handler hdl ;
struct { /* video bitrate mode control cluster */
struct v4l2_ctrl * video_bitrate_mode ;
struct v4l2_ctrl * video_bitrate ;
struct v4l2_ctrl * video_bitrate_peak ;
} ;
2008-08-08 19:43:59 +04:00
u32 revision ;
int has_ac3 ;
2006-06-18 23:40:10 +04:00
struct saa6752hs_mpeg_params params ;
2005-05-06 03:15:52 +04:00
enum saa6752hs_videoformat video_format ;
2005-11-09 08:36:45 +03:00
v4l2_std_id standard ;
2005-04-17 02:20:36 +04:00
} ;
enum saa6752hs_command {
SAA6752HS_COMMAND_RESET = 0 ,
2006-06-20 07:30:57 +04:00
SAA6752HS_COMMAND_STOP = 1 ,
SAA6752HS_COMMAND_START = 2 ,
SAA6752HS_COMMAND_PAUSE = 3 ,
SAA6752HS_COMMAND_RECONFIGURE = 4 ,
SAA6752HS_COMMAND_SLEEP = 5 ,
2005-04-17 02:20:36 +04:00
SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6 ,
SAA6752HS_COMMAND_MAX
} ;
2009-01-14 12:54:38 +03:00
static inline struct saa6752hs_state * to_state ( struct v4l2_subdev * sd )
{
return container_of ( sd , struct saa6752hs_state , sd ) ;
}
2005-04-17 02:20:36 +04:00
/* ---------------------------------------------------------------------- */
static u8 PAT [ ] = {
2005-11-09 08:36:45 +03:00
0xc2 , /* i2c register */
0x00 , /* table number for encoder */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x47 , /* sync */
0x40 , 0x00 , /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
0x10 , /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , /* PSI pointer to start of table */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , /* tid(0) */
0xb0 , 0x0d , /* section_syntax_indicator(1), section_length(13) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x01 , /* transport_stream_id(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xc1 , /* version_number(0), current_next_indicator(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , /* section_number(0), last_section_number(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x01 , /* program_number(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xe0 , 0x00 , /* PMT PID */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , 0x00 , 0x00 /* CRC32 */
2005-04-17 02:20:36 +04:00
} ;
static u8 PMT [ ] = {
2005-11-09 08:36:45 +03:00
0xc2 , /* i2c register */
0x01 , /* table number for encoder */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x47 , /* sync */
0x40 , 0x00 , /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
0x10 , /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , /* PSI pointer to start of table */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x02 , /* tid(2) */
0xb0 , 0x17 , /* section_syntax_indicator(1), section_length(23) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x01 , /* program_number(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xc1 , /* version_number(0), current_next_indicator(1) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , /* section_number(0), last_section_number(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xe0 , 0x00 , /* PCR_PID */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0xf0 , 0x00 , /* program_info_length(0) */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x02 , 0xe0 , 0x00 , 0xf0 , 0x00 , /* video stream type(2), pid */
0x04 , 0xe0 , 0x00 , 0xf0 , 0x00 , /* audio stream type(4), pid */
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
0x00 , 0x00 , 0x00 , 0x00 /* CRC32 */
2005-04-17 02:20:36 +04:00
} ;
2008-08-08 20:27:16 +04:00
static u8 PMT_AC3 [ ] = {
0xc2 , /* i2c register */
0x01 , /* table number for encoder(1) */
0x47 , /* sync */
0x40 , /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */
0x10 , /* PMT PID (0x0010) */
0x10 , /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
0x00 , /* PSI pointer to start of table */
0x02 , /* TID (2) */
0xb0 , 0x1a , /* section_syntax_indicator(1), section_length(26) */
0x00 , 0x01 , /* program_number(1) */
0xc1 , /* version_number(0), current_next_indicator(1) */
0x00 , 0x00 , /* section_number(0), last_section_number(0) */
0xe1 , 0x04 , /* PCR_PID (0x0104) */
0xf0 , 0x00 , /* program_info_length(0) */
0x02 , 0xe1 , 0x00 , 0xf0 , 0x00 , /* video stream type(2), pid */
0x06 , 0xe1 , 0x03 , 0xf0 , 0x03 , /* audio stream type(6), pid */
0x6a , /* AC3 */
0x01 , /* Descriptor_length(1) */
0x00 , /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */
0xED , 0xDE , 0x2D , 0xF3 /* CRC32 BE */
} ;
2006-06-18 23:40:10 +04:00
static struct saa6752hs_mpeg_params param_defaults =
{
. ts_pid_pmt = 16 ,
. ts_pid_video = 260 ,
. ts_pid_audio = 256 ,
. ts_pid_pcr = 259 ,
. vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3 ,
. vi_bitrate = 4000 ,
. vi_bitrate_peak = 6000 ,
. vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ,
2008-08-08 19:43:59 +04:00
. au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2 ,
2006-06-18 23:40:10 +04:00
. au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K ,
2008-08-08 20:27:16 +04:00
. au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_256K ,
2006-06-18 23:40:10 +04:00
} ;
2005-04-17 02:20:36 +04:00
/* ---------------------------------------------------------------------- */
2008-09-06 14:00:24 +04:00
static int saa6752hs_chip_command ( struct i2c_client * client ,
2005-04-17 02:20:36 +04:00
enum saa6752hs_command command )
{
unsigned char buf [ 3 ] ;
unsigned long timeout ;
int status = 0 ;
2005-11-09 08:36:45 +03:00
/* execute the command */
2005-04-17 02:20:36 +04:00
switch ( command ) {
2005-11-09 08:37:43 +03:00
case SAA6752HS_COMMAND_RESET :
buf [ 0 ] = 0x00 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_STOP :
2005-11-09 08:37:43 +03:00
buf [ 0 ] = 0x03 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_START :
2005-11-09 08:37:43 +03:00
buf [ 0 ] = 0x02 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_PAUSE :
2005-11-09 08:37:43 +03:00
buf [ 0 ] = 0x04 ;
2005-04-17 02:20:36 +04:00
break ;
case SAA6752HS_COMMAND_RECONFIGURE :
buf [ 0 ] = 0x05 ;
break ;
2005-11-09 08:37:43 +03:00
case SAA6752HS_COMMAND_SLEEP :
buf [ 0 ] = 0x06 ;
2005-04-17 02:20:36 +04:00
break ;
2005-11-09 08:37:43 +03:00
case SAA6752HS_COMMAND_RECONFIGURE_FORCE :
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0x07 ;
break ;
default :
return - EINVAL ;
}
2005-11-09 08:37:43 +03:00
/* set it and wait for it to be so */
2005-04-17 02:20:36 +04:00
i2c_master_send ( client , buf , 1 ) ;
timeout = jiffies + HZ * 3 ;
for ( ; ; ) {
2005-11-09 08:36:45 +03:00
/* get the current status */
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0x10 ;
2005-11-09 08:37:43 +03:00
i2c_master_send ( client , buf , 1 ) ;
2005-04-17 02:20:36 +04:00
i2c_master_recv ( client , buf , 1 ) ;
if ( ! ( buf [ 0 ] & 0x20 ) )
break ;
if ( time_after ( jiffies , timeout ) ) {
status = - ETIMEDOUT ;
break ;
}
msleep ( 10 ) ;
}
2005-11-09 08:36:45 +03:00
/* delay a bit to let encoder settle */
2005-04-17 02:20:36 +04:00
msleep ( 50 ) ;
2005-11-09 08:37:43 +03:00
return status ;
2005-04-17 02:20:36 +04:00
}
2008-09-06 14:00:24 +04:00
static inline void set_reg8 ( struct i2c_client * client , uint8_t reg , uint8_t val )
{
u8 buf [ 2 ] ;
buf [ 0 ] = reg ;
buf [ 1 ] = val ;
i2c_master_send ( client , buf , 2 ) ;
}
static inline void set_reg16 ( struct i2c_client * client , uint8_t reg , uint16_t val )
{
u8 buf [ 3 ] ;
buf [ 0 ] = reg ;
buf [ 1 ] = val > > 8 ;
buf [ 2 ] = val & 0xff ;
i2c_master_send ( client , buf , 3 ) ;
}
static int saa6752hs_set_bitrate ( struct i2c_client * client ,
2008-08-08 19:43:59 +04:00
struct saa6752hs_state * h )
2005-04-17 02:20:36 +04:00
{
2008-08-08 19:43:59 +04:00
struct saa6752hs_mpeg_params * params = & h - > params ;
2006-06-23 23:13:56 +04:00
int tot_bitrate ;
2008-09-06 14:00:24 +04:00
int is_384k ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the bitrate mode */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x71 ,
params - > vi_bitrate_mode ! = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the video bitrate */
2006-06-23 23:13:56 +04:00
if ( params - > vi_bitrate_mode = = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) {
2005-11-09 08:36:45 +03:00
/* set the target bitrate */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x80 , params - > vi_bitrate ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the max bitrate */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x81 , params - > vi_bitrate_peak ) ;
2006-06-23 23:13:56 +04:00
tot_bitrate = params - > vi_bitrate_peak ;
2005-04-17 02:20:36 +04:00
} else {
2005-11-09 08:36:45 +03:00
/* set the target bitrate (no max bitrate for CBR) */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x81 , params - > vi_bitrate ) ;
2006-06-23 23:13:56 +04:00
tot_bitrate = params - > vi_bitrate ;
2005-04-17 02:20:36 +04:00
}
2008-08-08 19:43:59 +04:00
/* set the audio encoding */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x93 ,
params - > au_encoding = = V4L2_MPEG_AUDIO_ENCODING_AC3 ) ;
2008-08-08 19:43:59 +04:00
2005-11-09 08:36:45 +03:00
/* set the audio bitrate */
2008-08-08 19:43:59 +04:00
if ( params - > au_encoding = = V4L2_MPEG_AUDIO_ENCODING_AC3 )
2008-09-06 14:00:24 +04:00
is_384k = V4L2_MPEG_AUDIO_AC3_BITRATE_384K = = params - > au_ac3_bitrate ;
2008-08-08 19:43:59 +04:00
else
2008-09-06 14:00:24 +04:00
is_384k = V4L2_MPEG_AUDIO_L2_BITRATE_384K = = params - > au_l2_bitrate ;
set_reg8 ( client , 0x94 , is_384k ) ;
tot_bitrate + = is_384k ? 384 : 256 ;
2006-06-23 23:13:56 +04:00
/* Note: the total max bitrate is determined by adding the video and audio
bitrates together and also adding an extra 768 kbit / s to stay on the
safe side . If more control should be required , then an extra MPEG control
should be added . */
tot_bitrate + = 768 ;
if ( tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX )
tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* set the total bitrate */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xb1 , tot_bitrate ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2013-06-10 11:51:42 +04:00
static int saa6752hs_try_ctrl ( struct v4l2_ctrl * ctrl )
2009-01-14 12:54:38 +03:00
{
2013-06-10 11:51:42 +04:00
struct saa6752hs_state * h =
container_of ( ctrl - > handler , struct saa6752hs_state , hdl ) ;
2009-01-14 12:54:38 +03:00
switch ( ctrl - > id ) {
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE :
2013-06-10 11:51:42 +04:00
/* peak bitrate shall be >= normal bitrate */
if ( ctrl - > val = = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR & &
h - > video_bitrate_peak - > val < h - > video_bitrate - > val )
h - > video_bitrate_peak - > val = h - > video_bitrate - > val ;
2009-01-14 12:54:38 +03:00
break ;
2005-05-06 03:15:52 +04:00
}
2009-01-14 12:54:38 +03:00
return 0 ;
2005-05-06 03:15:52 +04:00
}
2013-06-10 11:51:42 +04:00
static int saa6752hs_s_ctrl ( struct v4l2_ctrl * ctrl )
2006-06-18 23:40:10 +04:00
{
2013-06-10 11:51:42 +04:00
struct saa6752hs_state * h =
container_of ( ctrl - > handler , struct saa6752hs_state , hdl ) ;
struct saa6752hs_mpeg_params * params = & h - > params ;
2006-06-18 23:40:10 +04:00
switch ( ctrl - > id ) {
2009-01-14 12:54:38 +03:00
case V4L2_CID_MPEG_STREAM_TYPE :
break ;
case V4L2_CID_MPEG_STREAM_PID_PMT :
2013-06-10 11:51:42 +04:00
params - > ts_pid_pmt = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_STREAM_PID_AUDIO :
2013-06-10 11:51:42 +04:00
params - > ts_pid_audio = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_STREAM_PID_VIDEO :
2013-06-10 11:51:42 +04:00
params - > ts_pid_video = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_STREAM_PID_PCR :
2013-06-10 11:51:42 +04:00
params - > ts_pid_pcr = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_ENCODING :
2013-06-10 11:51:42 +04:00
params - > au_encoding = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE :
2013-06-10 11:51:42 +04:00
params - > au_l2_bitrate = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_AC3_BITRATE :
2013-06-10 11:51:42 +04:00
params - > au_ac3_bitrate = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ :
break ;
case V4L2_CID_MPEG_VIDEO_ENCODING :
break ;
case V4L2_CID_MPEG_VIDEO_ASPECT :
2013-06-10 11:51:42 +04:00
params - > vi_aspect = ctrl - > val ;
2009-01-14 12:54:38 +03:00
break ;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE :
2013-06-10 11:51:42 +04:00
params - > vi_bitrate_mode = ctrl - > val ;
params - > vi_bitrate = h - > video_bitrate - > val / 1000 ;
params - > vi_bitrate_peak = h - > video_bitrate_peak - > val / 1000 ;
v4l2_ctrl_activate ( h - > video_bitrate_peak ,
ctrl - > val = = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) ;
2009-01-14 12:54:38 +03:00
break ;
default :
return - EINVAL ;
2006-06-18 23:40:10 +04:00
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 12:54:38 +03:00
static int saa6752hs_init ( struct v4l2_subdev * sd , u32 leading_null_bytes )
2005-04-17 02:20:36 +04:00
{
unsigned char buf [ 9 ] , buf2 [ 4 ] ;
2009-01-14 12:54:38 +03:00
struct saa6752hs_state * h = to_state ( sd ) ;
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
2008-08-08 20:27:16 +04:00
unsigned size ;
2005-04-17 02:20:36 +04:00
u32 crc ;
unsigned char localPAT [ 256 ] ;
unsigned char localPMT [ 256 ] ;
2005-11-09 08:36:45 +03:00
/* Set video format - must be done first as it resets other settings */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x41 , h - > video_format ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Set number of lines in input signal */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x40 , ( h - > standard & V4L2_STD_525_60 ) ? 1 : 0 ) ;
2005-11-09 08:36:45 +03:00
2005-11-09 08:37:43 +03:00
/* set bitrate */
2008-08-08 19:43:59 +04:00
saa6752hs_set_bitrate ( client , h ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Set GOP structure {3, 13} */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0x72 , 0x030d ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set minimum Q-scale {4} */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x82 , 0x04 ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set maximum Q-scale {12} */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0x83 , 0x0c ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set Output Protocol */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0xd0 , 0x81 ) ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set video output stream format {TS} */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0xb0 , 0x05 ) ;
2005-04-17 02:20:36 +04:00
2008-08-26 20:44:40 +04:00
/* Set leading null byte for TS */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xf6 , leading_null_bytes ) ;
2008-08-26 20:44:40 +04:00
2005-04-17 02:20:36 +04:00
/* compute PAT */
memcpy ( localPAT , PAT , sizeof ( PAT ) ) ;
localPAT [ 17 ] = 0xe0 | ( ( h - > params . ts_pid_pmt > > 8 ) & 0x0f ) ;
localPAT [ 18 ] = h - > params . ts_pid_pmt & 0xff ;
crc = crc32_be ( ~ 0 , & localPAT [ 7 ] , sizeof ( PAT ) - 7 - 4 ) ;
localPAT [ sizeof ( PAT ) - 4 ] = ( crc > > 24 ) & 0xFF ;
localPAT [ sizeof ( PAT ) - 3 ] = ( crc > > 16 ) & 0xFF ;
localPAT [ sizeof ( PAT ) - 2 ] = ( crc > > 8 ) & 0xFF ;
localPAT [ sizeof ( PAT ) - 1 ] = crc & 0xFF ;
/* compute PMT */
2008-08-08 20:27:16 +04:00
if ( h - > params . au_encoding = = V4L2_MPEG_AUDIO_ENCODING_AC3 ) {
size = sizeof ( PMT_AC3 ) ;
memcpy ( localPMT , PMT_AC3 , size ) ;
} else {
size = sizeof ( PMT ) ;
memcpy ( localPMT , PMT , size ) ;
}
2005-11-09 08:37:43 +03:00
localPMT [ 3 ] = 0x40 | ( ( h - > params . ts_pid_pmt > > 8 ) & 0x0f ) ;
localPMT [ 4 ] = h - > params . ts_pid_pmt & 0xff ;
2005-04-17 02:20:36 +04:00
localPMT [ 15 ] = 0xE0 | ( ( h - > params . ts_pid_pcr > > 8 ) & 0x0F ) ;
localPMT [ 16 ] = h - > params . ts_pid_pcr & 0xFF ;
localPMT [ 20 ] = 0xE0 | ( ( h - > params . ts_pid_video > > 8 ) & 0x0F ) ;
localPMT [ 21 ] = h - > params . ts_pid_video & 0xFF ;
localPMT [ 25 ] = 0xE0 | ( ( h - > params . ts_pid_audio > > 8 ) & 0x0F ) ;
localPMT [ 26 ] = h - > params . ts_pid_audio & 0xFF ;
2008-08-08 20:27:16 +04:00
crc = crc32_be ( ~ 0 , & localPMT [ 7 ] , size - 7 - 4 ) ;
localPMT [ size - 4 ] = ( crc > > 24 ) & 0xFF ;
localPMT [ size - 3 ] = ( crc > > 16 ) & 0xFF ;
localPMT [ size - 2 ] = ( crc > > 8 ) & 0xFF ;
localPMT [ size - 1 ] = crc & 0xFF ;
2005-04-17 02:20:36 +04:00
2006-06-20 07:30:57 +04:00
/* Set Audio PID */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xc1 , h - > params . ts_pid_audio ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Set Video PID */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xc0 , h - > params . ts_pid_video ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:37:43 +03:00
/* Set PCR PID */
2008-09-06 14:00:24 +04:00
set_reg16 ( client , 0xc4 , h - > params . ts_pid_pcr ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* Send SI tables */
2008-08-08 20:27:16 +04:00
i2c_master_send ( client , localPAT , sizeof ( PAT ) ) ;
i2c_master_send ( client , localPMT , size ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* mute then unmute audio. This removes buzzing artefacts */
2008-09-06 14:00:24 +04:00
set_reg8 ( client , 0xa4 , 1 ) ;
set_reg8 ( client , 0xa4 , 0 ) ;
2005-04-17 02:20:36 +04:00
2005-11-09 08:36:45 +03:00
/* start it going */
2005-04-17 02:20:36 +04:00
saa6752hs_chip_command ( client , SAA6752HS_COMMAND_START ) ;
2005-11-09 08:36:45 +03:00
/* readout current state */
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0xE1 ;
buf [ 1 ] = 0xA7 ;
buf [ 2 ] = 0xFE ;
buf [ 3 ] = 0x82 ;
buf [ 4 ] = 0xB0 ;
i2c_master_send ( client , buf , 5 ) ;
i2c_master_recv ( client , buf2 , 4 ) ;
2005-11-09 08:36:45 +03:00
/* change aspect ratio */
2005-04-17 02:20:36 +04:00
buf [ 0 ] = 0xE0 ;
buf [ 1 ] = 0xA7 ;
buf [ 2 ] = 0xFE ;
buf [ 3 ] = 0x82 ;
buf [ 4 ] = 0xB0 ;
buf [ 5 ] = buf2 [ 0 ] ;
2009-01-14 12:54:38 +03:00
switch ( h - > params . vi_aspect ) {
2006-06-18 23:40:10 +04:00
case V4L2_MPEG_VIDEO_ASPECT_16x9 :
2005-04-17 02:20:36 +04:00
buf [ 6 ] = buf2 [ 1 ] | 0x40 ;
break ;
2006-06-18 23:40:10 +04:00
case V4L2_MPEG_VIDEO_ASPECT_4x3 :
2005-04-17 02:20:36 +04:00
default :
buf [ 6 ] = buf2 [ 1 ] & 0xBF ;
break ;
}
buf [ 7 ] = buf2 [ 2 ] ;
buf [ 8 ] = buf2 [ 3 ] ;
i2c_master_send ( client , buf , 9 ) ;
return 0 ;
}
2010-05-09 16:39:58 +04:00
static int saa6752hs_g_mbus_fmt ( struct v4l2_subdev * sd , struct v4l2_mbus_framefmt * f )
2009-01-14 12:54:38 +03:00
{
struct saa6752hs_state * h = to_state ( sd ) ;
2008-08-08 19:43:59 +04:00
2009-01-14 12:54:38 +03:00
if ( h - > video_format = = SAA6752HS_VF_UNKNOWN )
h - > video_format = SAA6752HS_VF_D1 ;
2010-05-09 16:39:58 +04:00
f - > width = v4l2_format_table [ h - > video_format ] . fmt . pix . width ;
f - > height = v4l2_format_table [ h - > video_format ] . fmt . pix . height ;
f - > code = V4L2_MBUS_FMT_FIXED ;
f - > field = V4L2_FIELD_INTERLACED ;
f - > colorspace = V4L2_COLORSPACE_SMPTE170M ;
2009-01-14 12:54:38 +03:00
return 0 ;
}
2013-06-01 17:02:38 +04:00
static int saa6752hs_try_mbus_fmt ( struct v4l2_subdev * sd , struct v4l2_mbus_framefmt * f )
{
int dist_352 , dist_480 , dist_720 ;
f - > code = V4L2_MBUS_FMT_FIXED ;
dist_352 = abs ( f - > width - 352 ) ;
dist_480 = abs ( f - > width - 480 ) ;
dist_720 = abs ( f - > width - 720 ) ;
if ( dist_720 < dist_480 ) {
f - > width = 720 ;
f - > height = 576 ;
} else if ( dist_480 < dist_352 ) {
f - > width = 480 ;
f - > height = 576 ;
} else {
f - > width = 352 ;
if ( abs ( f - > height - 576 ) < abs ( f - > height - 288 ) )
f - > height = 576 ;
else
f - > height = 288 ;
}
f - > field = V4L2_FIELD_INTERLACED ;
f - > colorspace = V4L2_COLORSPACE_SMPTE170M ;
return 0 ;
}
2010-05-09 16:39:58 +04:00
static int saa6752hs_s_mbus_fmt ( struct v4l2_subdev * sd , struct v4l2_mbus_framefmt * f )
2009-01-14 12:54:38 +03:00
{
struct saa6752hs_state * h = to_state ( sd ) ;
2010-05-09 16:39:58 +04:00
if ( f - > code ! = V4L2_MBUS_FMT_FIXED )
return - EINVAL ;
2009-01-14 12:54:38 +03:00
/*
FIXME : translate and round width / height into EMPRESS
subsample type :
type | PAL | NTSC
- - - - - - - - - - - - - - - - - - - - - - - - - - -
SIF | 352 x288 | 352 x240
1 / 2 D1 | 352 x576 | 352 x480
2 / 3 D1 | 480 x576 | 480 x480
D1 | 720 x576 | 720 x480
*/
2013-06-01 17:02:38 +04:00
saa6752hs_try_mbus_fmt ( sd , f ) ;
if ( f - > width = = 720 )
2009-01-14 12:54:38 +03:00
h - > video_format = SAA6752HS_VF_D1 ;
2013-06-01 17:02:38 +04:00
else if ( f - > width = = 480 )
2009-01-14 12:54:38 +03:00
h - > video_format = SAA6752HS_VF_2_3_D1 ;
2013-06-01 17:02:38 +04:00
else if ( f - > height = = 576 )
h - > video_format = SAA6752HS_VF_1_2_D1 ;
else
h - > video_format = SAA6752HS_VF_SIF ;
2009-01-14 12:54:38 +03:00
return 0 ;
}
static int saa6752hs_s_std ( struct v4l2_subdev * sd , v4l2_std_id std )
{
struct saa6752hs_state * h = to_state ( sd ) ;
h - > standard = std ;
return 0 ;
}
/* ----------------------------------------------------------------------- */
2013-06-10 11:51:42 +04:00
static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
. try_ctrl = saa6752hs_try_ctrl ,
. s_ctrl = saa6752hs_s_ctrl ,
} ;
2009-01-14 12:54:38 +03:00
static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
. init = saa6752hs_init ,
2013-06-10 11:51:42 +04:00
. g_ext_ctrls = v4l2_subdev_g_ext_ctrls ,
. try_ext_ctrls = v4l2_subdev_try_ext_ctrls ,
. s_ext_ctrls = v4l2_subdev_s_ext_ctrls ,
. g_ctrl = v4l2_subdev_g_ctrl ,
. s_ctrl = v4l2_subdev_s_ctrl ,
. queryctrl = v4l2_subdev_queryctrl ,
. querymenu = v4l2_subdev_querymenu ,
2009-01-14 12:54:38 +03:00
. s_std = saa6752hs_s_std ,
} ;
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
2010-05-09 16:39:58 +04:00
. s_mbus_fmt = saa6752hs_s_mbus_fmt ,
2013-06-01 17:02:38 +04:00
. try_mbus_fmt = saa6752hs_try_mbus_fmt ,
2010-05-09 16:39:58 +04:00
. g_mbus_fmt = saa6752hs_g_mbus_fmt ,
2009-01-14 12:54:38 +03:00
} ;
static const struct v4l2_subdev_ops saa6752hs_ops = {
. core = & saa6752hs_core_ops ,
. video = & saa6752hs_video_ops ,
} ;
2008-08-08 19:43:59 +04:00
static int saa6752hs_probe ( struct i2c_client * client ,
2009-01-14 12:54:38 +03:00
const struct i2c_device_id * id )
2008-08-08 19:43:59 +04:00
{
struct saa6752hs_state * h = kzalloc ( sizeof ( * h ) , GFP_KERNEL ) ;
2009-01-14 12:54:38 +03:00
struct v4l2_subdev * sd ;
2013-06-10 11:51:42 +04:00
struct v4l2_ctrl_handler * hdl ;
2008-08-08 19:43:59 +04:00
u8 addr = 0x13 ;
u8 data [ 12 ] ;
2005-04-17 02:20:36 +04:00
2008-08-08 19:43:59 +04:00
v4l_info ( client , " chip found @ 0x%x (%s) \n " ,
client - > addr < < 1 , client - > adapter - > name ) ;
if ( h = = NULL )
return - ENOMEM ;
2009-01-14 12:54:38 +03:00
sd = & h - > sd ;
v4l2_i2c_subdev_init ( sd , client , & saa6752hs_ops ) ;
2005-04-17 02:20:36 +04:00
2008-08-08 19:43:59 +04:00
i2c_master_send ( client , & addr , 1 ) ;
i2c_master_recv ( client , data , sizeof ( data ) ) ;
h - > revision = ( data [ 8 ] < < 8 ) | data [ 9 ] ;
h - > has_ac3 = 0 ;
if ( h - > revision = = 0x0206 ) {
h - > has_ac3 = 1 ;
2013-06-10 11:51:42 +04:00
v4l_info ( client , " supports AC-3 \n " ) ;
2008-08-08 19:43:59 +04:00
}
h - > params = param_defaults ;
2013-06-10 11:51:42 +04:00
hdl = & h - > hdl ;
v4l2_ctrl_handler_init ( hdl , 14 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_ENCODING ,
h - > has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 :
V4L2_MPEG_AUDIO_ENCODING_LAYER_2 ,
0x0d , V4L2_MPEG_AUDIO_ENCODING_LAYER_2 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_L2_BITRATE ,
V4L2_MPEG_AUDIO_L2_BITRATE_384K ,
~ ( ( 1 < < V4L2_MPEG_AUDIO_L2_BITRATE_256K ) |
( 1 < < V4L2_MPEG_AUDIO_L2_BITRATE_384K ) ) ,
V4L2_MPEG_AUDIO_L2_BITRATE_256K ) ;
if ( h - > has_ac3 )
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_AC3_BITRATE ,
V4L2_MPEG_AUDIO_AC3_BITRATE_384K ,
~ ( ( 1 < < V4L2_MPEG_AUDIO_AC3_BITRATE_256K ) |
( 1 < < V4L2_MPEG_AUDIO_AC3_BITRATE_384K ) ) ,
V4L2_MPEG_AUDIO_AC3_BITRATE_256K ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ ,
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 ,
~ ( 1 < < V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 ) ,
V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_ENCODING ,
V4L2_MPEG_VIDEO_ENCODING_MPEG_2 ,
~ ( 1 < < V4L2_MPEG_VIDEO_ENCODING_MPEG_2 ) ,
V4L2_MPEG_VIDEO_ENCODING_MPEG_2 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_ASPECT ,
V4L2_MPEG_VIDEO_ASPECT_16x9 , 0x01 ,
V4L2_MPEG_VIDEO_ASPECT_4x3 ) ;
h - > video_bitrate_peak = v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK ,
1000000 , 27000000 , 1000 , 8000000 ) ;
v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_TYPE ,
V4L2_MPEG_STREAM_TYPE_MPEG2_TS ,
~ ( 1 < < V4L2_MPEG_STREAM_TYPE_MPEG2_TS ) ,
V4L2_MPEG_STREAM_TYPE_MPEG2_TS ) ;
h - > video_bitrate_mode = v4l2_ctrl_new_std_menu ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE ,
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR , 0 ,
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR ) ;
h - > video_bitrate = v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_VIDEO_BITRATE , 1000000 , 27000000 , 1000 , 6000000 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_PMT , 0 , ( 1 < < 14 ) - 1 , 1 , 16 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_AUDIO , 0 , ( 1 < < 14 ) - 1 , 1 , 260 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_VIDEO , 0 , ( 1 < < 14 ) - 1 , 1 , 256 ) ;
v4l2_ctrl_new_std ( hdl , & saa6752hs_ctrl_ops ,
V4L2_CID_MPEG_STREAM_PID_PCR , 0 , ( 1 < < 14 ) - 1 , 1 , 259 ) ;
sd - > ctrl_handler = hdl ;
if ( hdl - > error ) {
int err = hdl - > error ;
v4l2_ctrl_handler_free ( hdl ) ;
kfree ( h ) ;
return err ;
}
v4l2_ctrl_cluster ( 3 , & h - > video_bitrate_mode ) ;
v4l2_ctrl_handler_setup ( hdl ) ;
2008-08-08 19:43:59 +04:00
h - > standard = 0 ; /* Assume 625 input lines */
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-08-08 19:43:59 +04:00
static int saa6752hs_remove ( struct i2c_client * client )
2005-04-17 02:20:36 +04:00
{
2009-01-14 12:54:38 +03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
v4l2_device_unregister_subdev ( sd ) ;
2013-06-10 11:51:42 +04:00
v4l2_ctrl_handler_free ( & to_state ( sd ) - > hdl ) ;
2009-01-14 12:54:38 +03:00
kfree ( to_state ( sd ) ) ;
2008-08-08 19:43:59 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-08-08 19:43:59 +04:00
static const struct i2c_device_id saa6752hs_id [ ] = {
{ " saa6752hs " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , saa6752hs_id ) ;
2010-09-15 22:14:36 +04:00
static struct i2c_driver saa6752hs_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = " saa6752hs " ,
} ,
. probe = saa6752hs_probe ,
. remove = saa6752hs_remove ,
. id_table = saa6752hs_id ,
2008-08-08 19:43:59 +04:00
} ;
2005-04-17 02:20:36 +04:00
2012-02-12 13:56:32 +04:00
module_i2c_driver ( saa6752hs_driver ) ;