V4L/DVB (4553): Add support for saa7111 and partial support for saa7118
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
96ecfc4edf
commit
89f75ffc7e
|
@ -1,4 +1,6 @@
|
||||||
/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
|
/* saa711x - Philips SAA711x video decoder driver
|
||||||
|
* This driver can work with saa7111, saa7111a, saa7113, saa7114,
|
||||||
|
* saa7115 and saa7118.
|
||||||
*
|
*
|
||||||
* Based on saa7114 driver by Maxim Yevtyushkin, which is based on
|
* Based on saa7114 driver by Maxim Yevtyushkin, which is based on
|
||||||
* the saa7111 driver by Dave Perks.
|
* the saa7111 driver by Dave Perks.
|
||||||
|
@ -16,7 +18,9 @@
|
||||||
* (2/17/2003)
|
* (2/17/2003)
|
||||||
*
|
*
|
||||||
* VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
|
* VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
|
||||||
* SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
|
*
|
||||||
|
* Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||||
|
* SAA7111, SAA7113 and SAA7118 support
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -44,7 +48,7 @@
|
||||||
#include <media/saa7115.h>
|
#include <media/saa7115.h>
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
|
MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
|
||||||
MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
|
MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
|
||||||
"Hans Verkuil, Mauro Carvalho Chehab");
|
"Hans Verkuil, Mauro Carvalho Chehab");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -55,8 +59,8 @@ module_param(debug, bool, 0644);
|
||||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||||
|
|
||||||
static unsigned short normal_i2c[] = {
|
static unsigned short normal_i2c[] = {
|
||||||
0x4a >> 1, 0x48 >> 1, /* SAA7113 */
|
0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
|
||||||
0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */
|
0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
|
||||||
I2C_CLIENT_END };
|
I2C_CLIENT_END };
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,15 +90,58 @@ static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
|
||||||
return i2c_smbus_write_byte_data(client, reg, value);
|
return i2c_smbus_write_byte_data(client, reg, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sanity routine to check if a register is present */
|
||||||
|
static int saa711x_has_reg(const int id, const u8 reg)
|
||||||
|
{
|
||||||
|
switch (id) {
|
||||||
|
case V4L2_IDENT_SAA7111:
|
||||||
|
if (reg>0x1f || reg==1 || reg==0x0f || reg==0x14 || reg==0x18
|
||||||
|
|| reg==0x19 || reg==0x1d || reg==0x1e)
|
||||||
|
return 0;
|
||||||
|
case V4L2_IDENT_SAA7113:
|
||||||
|
if (reg>0x62 || reg==0x14 || (reg>=0x18 && reg<=0x1e) ||
|
||||||
|
(reg>=0x20 && reg<=0x3f) ||reg==0x5f )
|
||||||
|
return 0;
|
||||||
|
case V4L2_IDENT_SAA7114:
|
||||||
|
if (reg>=0xf0 || (reg>=0x1a && reg<=0x1e) ||
|
||||||
|
(reg>=0x20 && reg<=0x2f) ||
|
||||||
|
(reg>=0x63 && reg<=0x7f) )
|
||||||
|
return 0;
|
||||||
|
case V4L2_IDENT_SAA7115:
|
||||||
|
if ((reg>=0x20 && reg<=0x2f) || (reg==0x5c) ||
|
||||||
|
(reg>=0xfc && reg<=0xfe) )
|
||||||
|
return 0;
|
||||||
|
case V4L2_IDENT_SAA7118:
|
||||||
|
if (reg>=0xf0 || (reg>=0x1a && reg<=0x1d) ||
|
||||||
|
(reg>=0x63 && reg<=0x6f) )
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Those registers are reserved for all family */
|
||||||
|
if (unlikely((reg>=0x20 && reg<=0x22) ||
|
||||||
|
(reg>=0x26 && reg<=0x28) ||
|
||||||
|
(reg>=0x3b && reg<=0x3f) || (reg==0x5f) ||
|
||||||
|
(reg>=0x63 && reg<=0x6f) ) )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
|
static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
|
||||||
{
|
{
|
||||||
|
struct saa7115_state *state = i2c_get_clientdata(client);
|
||||||
unsigned char reg, data;
|
unsigned char reg, data;
|
||||||
|
|
||||||
while (*regs != 0x00) {
|
while (*regs != 0x00) {
|
||||||
reg = *(regs++);
|
reg = *(regs++);
|
||||||
data = *(regs++);
|
data = *(regs++);
|
||||||
if (saa7115_write(client, reg, data) < 0)
|
|
||||||
return -1;
|
/* According with datasheets, reserved regs should be
|
||||||
|
filled with 0 - seems better not to touch on they */
|
||||||
|
if (saa711x_has_reg(state->ident,reg)) {
|
||||||
|
if (saa7115_write(client, reg, data) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -106,10 +153,80 @@ static inline int saa7115_read(struct i2c_client *client, u8 reg)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* SAA7111 initialization table */
|
||||||
|
static const unsigned char saa7111_init_auto_input[] = {
|
||||||
|
R_01_INC_DELAY, 0x00, /* reserved */
|
||||||
|
|
||||||
|
/*front end */
|
||||||
|
R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
|
||||||
|
R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
|
||||||
|
* GAFIX=0, GAI1=256, GAI2=256 */
|
||||||
|
R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
|
||||||
|
R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
|
||||||
|
|
||||||
|
/* decoder */
|
||||||
|
R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
|
||||||
|
* pixels after end of last line */
|
||||||
|
R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
|
||||||
|
* work with NTSC, too */
|
||||||
|
R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
|
||||||
|
* VTRC=1, HPLL=0, VNOI=0 */
|
||||||
|
R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
|
||||||
|
* VBLB=0, UPTCV=0, APER=1 */
|
||||||
|
R_0A_LUMA_BRIGHT_CNTL, 0x80,
|
||||||
|
R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
|
||||||
|
R_0C_CHROMA_SAT_CNTL, 0x40,
|
||||||
|
R_0D_CHROMA_HUE_CNTL, 0x00,
|
||||||
|
R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
|
||||||
|
* FCTC=0, CHBW=1 */
|
||||||
|
R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
|
||||||
|
R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
|
||||||
|
R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
|
||||||
|
* OEYC=1, OEHV=1, VIPB=0, COLO=0 */
|
||||||
|
R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
|
||||||
|
R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
|
||||||
|
R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
|
||||||
|
R_15_VGATE_START_FID_CHG, 0x00,
|
||||||
|
R_16_VGATE_STOP, 0x00,
|
||||||
|
R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
|
||||||
|
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SAA7113 init codes */
|
||||||
|
static const unsigned char saa7113_init_auto_input[] = {
|
||||||
|
R_01_INC_DELAY, 0x08,
|
||||||
|
R_02_INPUT_CNTL_1, 0xc2,
|
||||||
|
R_03_INPUT_CNTL_2, 0x30,
|
||||||
|
R_04_INPUT_CNTL_3, 0x00,
|
||||||
|
R_05_INPUT_CNTL_4, 0x00,
|
||||||
|
R_06_H_SYNC_START, 0x89,
|
||||||
|
R_07_H_SYNC_STOP, 0x0d,
|
||||||
|
R_08_SYNC_CNTL, 0x88,
|
||||||
|
R_09_LUMA_CNTL, 0x01,
|
||||||
|
R_0A_LUMA_BRIGHT_CNTL, 0x80,
|
||||||
|
R_0B_LUMA_CONTRAST_CNTL, 0x47,
|
||||||
|
R_0C_CHROMA_SAT_CNTL, 0x40,
|
||||||
|
R_0D_CHROMA_HUE_CNTL, 0x00,
|
||||||
|
R_0E_CHROMA_CNTL_1, 0x01,
|
||||||
|
R_0F_CHROMA_GAIN_CNTL, 0x2a,
|
||||||
|
R_10_CHROMA_CNTL_2, 0x08,
|
||||||
|
R_11_MODE_DELAY_CNTL, 0x0c,
|
||||||
|
R_12_RT_SIGNAL_CNTL, 0x07,
|
||||||
|
R_13_RT_X_PORT_OUT_CNTL, 0x00,
|
||||||
|
R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
|
||||||
|
R_15_VGATE_START_FID_CHG, 0x00,
|
||||||
|
R_16_VGATE_STOP, 0x00,
|
||||||
|
R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
|
||||||
|
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
/* If a value differs from the Hauppauge driver values, then the comment starts with
|
/* If a value differs from the Hauppauge driver values, then the comment starts with
|
||||||
'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
|
'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
|
||||||
Hauppauge driver sets. */
|
Hauppauge driver sets. */
|
||||||
|
|
||||||
|
/* SAA7114 and SAA7115 initialization table */
|
||||||
static const unsigned char saa7115_init_auto_input[] = {
|
static const unsigned char saa7115_init_auto_input[] = {
|
||||||
/* Front-End Part */
|
/* Front-End Part */
|
||||||
R_01_INC_DELAY, 0x48, /* white peak control disabled */
|
R_01_INC_DELAY, 0x48, /* white peak control disabled */
|
||||||
|
@ -142,6 +259,7 @@ static const unsigned char saa7115_init_auto_input[] = {
|
||||||
0x00, 0x00
|
0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Used to reset saa7113, saa7114 and saa7115 */
|
||||||
static const unsigned char saa7115_cfg_reset_scaler[] = {
|
static const unsigned char saa7115_cfg_reset_scaler[] = {
|
||||||
R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
|
R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
|
||||||
R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
|
R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
|
||||||
|
@ -152,6 +270,7 @@ static const unsigned char saa7115_cfg_reset_scaler[] = {
|
||||||
|
|
||||||
/* ============== SAA7715 VIDEO templates ============= */
|
/* ============== SAA7715 VIDEO templates ============= */
|
||||||
|
|
||||||
|
/* Used on saa7114 and saa7115 */
|
||||||
static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
|
static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
|
||||||
/* hsize = 0x2d0 = 720 */
|
/* hsize = 0x2d0 = 720 */
|
||||||
R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
|
R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
|
||||||
|
@ -170,6 +289,7 @@ static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
|
||||||
0x00, 0x00
|
0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Used on saa7114 and saa7115 */
|
||||||
static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
|
static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
|
||||||
/* output window size = 248 (but 60hz is 240?) */
|
/* output window size = 248 (but 60hz is 240?) */
|
||||||
R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0xf8,
|
R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0xf8,
|
||||||
|
@ -408,33 +528,6 @@ static const unsigned char saa7115_cfg_vbi_off[] = {
|
||||||
0x00, 0x00
|
0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char saa7113_init_auto_input[] = {
|
|
||||||
R_01_INC_DELAY, 0x08,
|
|
||||||
R_02_INPUT_CNTL_1, 0xc2,
|
|
||||||
R_03_INPUT_CNTL_2, 0x30,
|
|
||||||
R_04_INPUT_CNTL_3, 0x00,
|
|
||||||
R_05_INPUT_CNTL_4, 0x00,
|
|
||||||
R_06_H_SYNC_START, 0x89,
|
|
||||||
R_07_H_SYNC_STOP, 0x0d,
|
|
||||||
R_08_SYNC_CNTL, 0x88,
|
|
||||||
R_09_LUMA_CNTL, 0x01,
|
|
||||||
R_0A_LUMA_BRIGHT_CNTL, 0x80,
|
|
||||||
R_0B_LUMA_CONTRAST_CNTL, 0x47,
|
|
||||||
R_0C_CHROMA_SAT_CNTL, 0x40,
|
|
||||||
R_0D_CHROMA_HUE_CNTL, 0x00,
|
|
||||||
R_0E_CHROMA_CNTL_1, 0x01,
|
|
||||||
R_0F_CHROMA_GAIN_CNTL, 0x2a,
|
|
||||||
R_10_CHROMA_CNTL_2, 0x08,
|
|
||||||
R_11_MODE_DELAY_CNTL, 0x0c,
|
|
||||||
R_12_RT_SIGNAL_CNTL, 0x07,
|
|
||||||
R_13_RT_X_PORT_OUT_CNTL, 0x00,
|
|
||||||
R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
|
|
||||||
R_15_VGATE_START_FID_CHG, 0x00,
|
|
||||||
R_16_VGATE_STOP, 0x00,
|
|
||||||
R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
|
|
||||||
|
|
||||||
0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned char saa7115_init_misc[] = {
|
static const unsigned char saa7115_init_misc[] = {
|
||||||
R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
|
R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
|
||||||
|
@ -662,7 +755,6 @@ static int saa7115_decode_wss(u8 * p)
|
||||||
return wss;
|
return wss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
|
static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
|
||||||
{
|
{
|
||||||
struct saa7115_state *state = i2c_get_clientdata(client);
|
struct saa7115_state *state = i2c_get_clientdata(client);
|
||||||
|
@ -672,16 +764,16 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
|
||||||
u64 f;
|
u64 f;
|
||||||
u8 acc = 0; /* reg 0x3a, audio clock control */
|
u8 acc = 0; /* reg 0x3a, audio clock control */
|
||||||
|
|
||||||
|
/* Checks for chips that don't have audio clock (saa7111, saa7113) */
|
||||||
|
if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
|
||||||
|
return 0;
|
||||||
|
|
||||||
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
|
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (freq < 32000 || freq > 48000)
|
if (freq < 32000 || freq > 48000)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* The saa7113 has no audio clock */
|
|
||||||
if (state->ident == V4L2_IDENT_SAA7113)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* hz is the refresh rate times 100 */
|
/* hz is the refresh rate times 100 */
|
||||||
hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
|
hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
|
||||||
/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
|
/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
|
||||||
|
@ -799,7 +891,6 @@ static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *c
|
||||||
static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
||||||
{
|
{
|
||||||
struct saa7115_state *state = i2c_get_clientdata(client);
|
struct saa7115_state *state = i2c_get_clientdata(client);
|
||||||
int taskb = saa7115_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
|
|
||||||
|
|
||||||
/* Prevent unnecessary standard changes. During a standard
|
/* Prevent unnecessary standard changes. During a standard
|
||||||
change the I-Port is temporarily disabled. Any devices
|
change the I-Port is temporarily disabled. Any devices
|
||||||
|
@ -821,7 +912,7 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register 0E - Bits D6-D4 on NO-AUTO mode
|
/* Register 0E - Bits D6-D4 on NO-AUTO mode
|
||||||
(SAA7113 doesn't have auto mode)
|
(SAA7111 and SAA7113 doesn't have auto mode)
|
||||||
50 Hz / 625 lines 60 Hz / 525 lines
|
50 Hz / 625 lines 60 Hz / 525 lines
|
||||||
000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
|
000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
|
||||||
001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
|
001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
|
||||||
|
@ -829,7 +920,8 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
||||||
011 NTSC N (3.58MHz) PAL M (3.58MHz)
|
011 NTSC N (3.58MHz) PAL M (3.58MHz)
|
||||||
100 reserved NTSC-Japan (3.58MHz)
|
100 reserved NTSC-Japan (3.58MHz)
|
||||||
*/
|
*/
|
||||||
if (state->ident == V4L2_IDENT_SAA7113) {
|
if (state->ident == V4L2_IDENT_SAA7111 ||
|
||||||
|
state->ident == V4L2_IDENT_SAA7113) {
|
||||||
u8 reg = saa7115_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
|
u8 reg = saa7115_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
|
||||||
|
|
||||||
if (std == V4L2_STD_PAL_M) {
|
if (std == V4L2_STD_PAL_M) {
|
||||||
|
@ -842,18 +934,19 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
|
||||||
reg |= 0x40;
|
reg |= 0x40;
|
||||||
}
|
}
|
||||||
saa7115_write(client, R_0E_CHROMA_CNTL_1, reg);
|
saa7115_write(client, R_0E_CHROMA_CNTL_1, reg);
|
||||||
}
|
} else {
|
||||||
|
/* restart task B if needed */
|
||||||
|
int taskb = saa7115_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
|
||||||
|
|
||||||
|
if (taskb && state->ident == V4L2_IDENT_SAA7114) {
|
||||||
|
saa7115_writeregs(client, saa7115_cfg_vbi_on);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* switch audio mode too! */
|
||||||
|
saa7115_set_audio_clock_freq(client, state->audclk_freq);
|
||||||
|
}
|
||||||
|
|
||||||
state->std = std;
|
state->std = std;
|
||||||
|
|
||||||
/* restart task B if needed */
|
|
||||||
if (taskb && state->ident != V4L2_IDENT_SAA7115) {
|
|
||||||
saa7115_writeregs(client, saa7115_cfg_vbi_on);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* switch audio mode too! */
|
|
||||||
saa7115_set_audio_clock_freq(client, state->audclk_freq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
|
static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
|
||||||
|
@ -919,9 +1012,16 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
|
||||||
u8 lcr[24];
|
u8 lcr[24];
|
||||||
int i, x;
|
int i, x;
|
||||||
|
|
||||||
/* saa7113/7114 doesn't yet support VBI */
|
#if 1
|
||||||
|
/* saa7113/7114/7118 VBI support are experimental */
|
||||||
|
if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* SAA7113 and SAA7118 also should support VBI - Need testing */
|
||||||
if (state->ident != V4L2_IDENT_SAA7115)
|
if (state->ident != V4L2_IDENT_SAA7115)
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i <= 23; i++)
|
for (i = 0; i <= 23; i++)
|
||||||
lcr[i] = 0xff;
|
lcr[i] = 0xff;
|
||||||
|
@ -1021,8 +1121,9 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
||||||
struct saa7115_state *state = i2c_get_clientdata(client);
|
struct saa7115_state *state = i2c_get_clientdata(client);
|
||||||
struct v4l2_pix_format *pix;
|
struct v4l2_pix_format *pix;
|
||||||
int HPSC, HFSC;
|
int HPSC, HFSC;
|
||||||
int VSCY, Vsrc;
|
int VSCY;
|
||||||
int is_50hz = state->std & V4L2_STD_625_50;
|
int is_50hz = state->std & V4L2_STD_625_50;
|
||||||
|
int Vsrc = is_50hz ? 576 : 480;
|
||||||
|
|
||||||
if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
|
if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
|
||||||
saa7115_set_lcr(client, &fmt->fmt.sliced);
|
saa7115_set_lcr(client, &fmt->fmt.sliced);
|
||||||
|
@ -1041,18 +1142,29 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
||||||
if ((pix->height < 1) || (pix->height > 960))
|
if ((pix->height < 1) || (pix->height > 960))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
|
||||||
|
/* Decoder only supports 720 columns and 480 or 576 lines */
|
||||||
|
if (pix->width != 720)
|
||||||
|
return -EINVAL;
|
||||||
|
if (pix->height != Vsrc)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* probably have a valid size, let's set it */
|
/* probably have a valid size, let's set it */
|
||||||
/* Set output width/height */
|
/* Set output width/height */
|
||||||
/* width */
|
/* width */
|
||||||
saa7115_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
|
|
||||||
(u8) (pix->width & 0xff));
|
if (!saa711x_has_reg(state->ident,R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH)) {
|
||||||
saa7115_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
|
saa7115_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
|
||||||
(u8) ((pix->width >> 8) & 0xff));
|
(u8) (pix->width & 0xff));
|
||||||
/* height */
|
saa7115_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
|
||||||
saa7115_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
|
(u8) ((pix->width >> 8) & 0xff));
|
||||||
(u8) (pix->height & 0xff));
|
/* height */
|
||||||
saa7115_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
|
saa7115_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
|
||||||
(u8) ((pix->height >> 8) & 0xff));
|
(u8) (pix->height & 0xff));
|
||||||
|
saa7115_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
|
||||||
|
(u8) ((pix->height >> 8) & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
/* Scaling settings */
|
/* Scaling settings */
|
||||||
/* Hprescaler is floor(inres/outres) */
|
/* Hprescaler is floor(inres/outres) */
|
||||||
|
@ -1090,8 +1202,6 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vsrc = is_50hz ? 576 : 480;
|
|
||||||
|
|
||||||
if (pix->height != Vsrc) {
|
if (pix->height != Vsrc) {
|
||||||
VSCY = (int)((1024 * Vsrc) / pix->height);
|
VSCY = (int)((1024 * Vsrc) / pix->height);
|
||||||
v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
|
v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
|
||||||
|
@ -1123,6 +1233,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
|
||||||
}
|
}
|
||||||
|
|
||||||
saa7115_writeregs(client, saa7115_cfg_reset_scaler);
|
saa7115_writeregs(client, saa7115_cfg_reset_scaler);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,15 +1579,25 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
|
||||||
state->hue = 0;
|
state->hue = 0;
|
||||||
state->sat = 64;
|
state->sat = 64;
|
||||||
switch (chip_id) {
|
switch (chip_id) {
|
||||||
|
case 1:
|
||||||
|
state->ident = V4L2_IDENT_SAA7111;
|
||||||
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
state->ident = V4L2_IDENT_SAA7113;
|
state->ident = V4L2_IDENT_SAA7113;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
state->ident = V4L2_IDENT_SAA7114;
|
state->ident = V4L2_IDENT_SAA7114;
|
||||||
break;
|
break;
|
||||||
default:
|
case 5:
|
||||||
state->ident = V4L2_IDENT_SAA7115;
|
state->ident = V4L2_IDENT_SAA7115;
|
||||||
break;
|
break;
|
||||||
|
case 8:
|
||||||
|
state->ident = V4L2_IDENT_SAA7118;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state->ident = V4L2_IDENT_SAA7111;
|
||||||
|
v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state->audclk_freq = 48000;
|
state->audclk_freq = 48000;
|
||||||
|
@ -1484,7 +1605,8 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
|
||||||
v4l_dbg(1, debug, client, "writing init values\n");
|
v4l_dbg(1, debug, client, "writing init values\n");
|
||||||
|
|
||||||
/* init to 60hz/48khz */
|
/* init to 60hz/48khz */
|
||||||
if (state->ident == V4L2_IDENT_SAA7113) {
|
if (state->ident == V4L2_IDENT_SAA7111 ||
|
||||||
|
state->ident == V4L2_IDENT_SAA7113) {
|
||||||
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
|
state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
|
||||||
saa7115_writeregs(client, saa7113_init_auto_input);
|
saa7115_writeregs(client, saa7113_init_auto_input);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -121,10 +121,17 @@ enum v4l2_chip_ident {
|
||||||
/* general idents: reserved range 0-49 */
|
/* general idents: reserved range 0-49 */
|
||||||
V4L2_IDENT_UNKNOWN = 0,
|
V4L2_IDENT_UNKNOWN = 0,
|
||||||
|
|
||||||
/* module saa7115: reserved range 100-149 */
|
/* module saa7110: just ident= 100 */
|
||||||
|
V4L2_IDENT_SAA7110 = 100,
|
||||||
|
|
||||||
|
/* module saa7111: just ident= 101 */
|
||||||
|
V4L2_IDENT_SAA7111 = 101,
|
||||||
|
|
||||||
|
/* module saa7115: reserved range 102-149 */
|
||||||
V4L2_IDENT_SAA7113 = 103,
|
V4L2_IDENT_SAA7113 = 103,
|
||||||
V4L2_IDENT_SAA7114 = 104,
|
V4L2_IDENT_SAA7114 = 104,
|
||||||
V4L2_IDENT_SAA7115 = 105,
|
V4L2_IDENT_SAA7115 = 105,
|
||||||
|
V4L2_IDENT_SAA7118 = 108,
|
||||||
|
|
||||||
/* module saa7127: reserved range 150-199 */
|
/* module saa7127: reserved range 150-199 */
|
||||||
V4L2_IDENT_SAA7127 = 157,
|
V4L2_IDENT_SAA7127 = 157,
|
||||||
|
|
Loading…
Reference in a new issue