diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-08-29 21:07:03 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-09-26 11:30:34 -0400 |
commit | 89f75ffc7e97d96ea76556671446d57d77c46beb (patch) | |
tree | 1252810a156b30b1bf1c2a36fc91f90d1f75c25e /drivers/media/video | |
parent | 96ecfc4edf6bdb535b4ae3d87db2ba7f91596dd8 (diff) |
V4L/DVB (4553): Add support for saa7111 and partial support for saa7118
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/saa7115.c | 252 |
1 files changed, 187 insertions, 65 deletions
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index d5052dbd0744..900c65772fa0 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -1,4 +1,6 @@ | |||
1 | /* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver | 1 | /* saa711x - Philips SAA711x video decoder driver |
2 | * This driver can work with saa7111, saa7111a, saa7113, saa7114, | ||
3 | * saa7115 and saa7118. | ||
2 | * | 4 | * |
3 | * Based on saa7114 driver by Maxim Yevtyushkin, which is based on | 5 | * Based on saa7114 driver by Maxim Yevtyushkin, which is based on |
4 | * the saa7111 driver by Dave Perks. | 6 | * the saa7111 driver by Dave Perks. |
@@ -16,7 +18,9 @@ | |||
16 | * (2/17/2003) | 18 | * (2/17/2003) |
17 | * | 19 | * |
18 | * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> | 20 | * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> |
19 | * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org> | 21 | * |
22 | * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> | ||
23 | * SAA7111, SAA7113 and SAA7118 support | ||
20 | * | 24 | * |
21 | * This program is free software; you can redistribute it and/or | 25 | * This program is free software; you can redistribute it and/or |
22 | * modify it under the terms of the GNU General Public License | 26 | * modify it under the terms of the GNU General Public License |
@@ -44,7 +48,7 @@ | |||
44 | #include <media/saa7115.h> | 48 | #include <media/saa7115.h> |
45 | #include <asm/div64.h> | 49 | #include <asm/div64.h> |
46 | 50 | ||
47 | MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver"); | 51 | MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver"); |
48 | MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " | 52 | MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " |
49 | "Hans Verkuil, Mauro Carvalho Chehab"); | 53 | "Hans Verkuil, Mauro Carvalho Chehab"); |
50 | MODULE_LICENSE("GPL"); | 54 | MODULE_LICENSE("GPL"); |
@@ -55,8 +59,8 @@ module_param(debug, bool, 0644); | |||
55 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | 59 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); |
56 | 60 | ||
57 | static unsigned short normal_i2c[] = { | 61 | static unsigned short normal_i2c[] = { |
58 | 0x4a >> 1, 0x48 >> 1, /* SAA7113 */ | 62 | 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ |
59 | 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */ | 63 | 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ |
60 | I2C_CLIENT_END }; | 64 | I2C_CLIENT_END }; |
61 | 65 | ||
62 | 66 | ||
@@ -86,15 +90,58 @@ static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value) | |||
86 | return i2c_smbus_write_byte_data(client, reg, value); | 90 | return i2c_smbus_write_byte_data(client, reg, value); |
87 | } | 91 | } |
88 | 92 | ||
93 | /* Sanity routine to check if a register is present */ | ||
94 | static int saa711x_has_reg(const int id, const u8 reg) | ||
95 | { | ||
96 | switch (id) { | ||
97 | case V4L2_IDENT_SAA7111: | ||
98 | if (reg>0x1f || reg==1 || reg==0x0f || reg==0x14 || reg==0x18 | ||
99 | || reg==0x19 || reg==0x1d || reg==0x1e) | ||
100 | return 0; | ||
101 | case V4L2_IDENT_SAA7113: | ||
102 | if (reg>0x62 || reg==0x14 || (reg>=0x18 && reg<=0x1e) || | ||
103 | (reg>=0x20 && reg<=0x3f) ||reg==0x5f ) | ||
104 | return 0; | ||
105 | case V4L2_IDENT_SAA7114: | ||
106 | if (reg>=0xf0 || (reg>=0x1a && reg<=0x1e) || | ||
107 | (reg>=0x20 && reg<=0x2f) || | ||
108 | (reg>=0x63 && reg<=0x7f) ) | ||
109 | return 0; | ||
110 | case V4L2_IDENT_SAA7115: | ||
111 | if ((reg>=0x20 && reg<=0x2f) || (reg==0x5c) || | ||
112 | (reg>=0xfc && reg<=0xfe) ) | ||
113 | return 0; | ||
114 | case V4L2_IDENT_SAA7118: | ||
115 | if (reg>=0xf0 || (reg>=0x1a && reg<=0x1d) || | ||
116 | (reg>=0x63 && reg<=0x6f) ) | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /* Those registers are reserved for all family */ | ||
121 | if (unlikely((reg>=0x20 && reg<=0x22) || | ||
122 | (reg>=0x26 && reg<=0x28) || | ||
123 | (reg>=0x3b && reg<=0x3f) || (reg==0x5f) || | ||
124 | (reg>=0x63 && reg<=0x6f) ) ) | ||
125 | return 0; | ||
126 | |||
127 | return 1; | ||
128 | } | ||
129 | |||
89 | static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs) | 130 | static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs) |
90 | { | 131 | { |
132 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
91 | unsigned char reg, data; | 133 | unsigned char reg, data; |
92 | 134 | ||
93 | while (*regs != 0x00) { | 135 | while (*regs != 0x00) { |
94 | reg = *(regs++); | 136 | reg = *(regs++); |
95 | data = *(regs++); | 137 | data = *(regs++); |
96 | if (saa7115_write(client, reg, data) < 0) | 138 | |
97 | return -1; | 139 | /* According with datasheets, reserved regs should be |
140 | filled with 0 - seems better not to touch on they */ | ||
141 | if (saa711x_has_reg(state->ident,reg)) { | ||
142 | if (saa7115_write(client, reg, data) < 0) | ||
143 | return -1; | ||
144 | } | ||
98 | } | 145 | } |
99 | return 0; | 146 | return 0; |
100 | } | 147 | } |
@@ -106,10 +153,80 @@ static inline int saa7115_read(struct i2c_client *client, u8 reg) | |||
106 | 153 | ||
107 | /* ----------------------------------------------------------------------- */ | 154 | /* ----------------------------------------------------------------------- */ |
108 | 155 | ||
156 | /* SAA7111 initialization table */ | ||
157 | static const unsigned char saa7111_init_auto_input[] = { | ||
158 | R_01_INC_DELAY, 0x00, /* reserved */ | ||
159 | |||
160 | /*front end */ | ||
161 | R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */ | ||
162 | R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, | ||
163 | * GAFIX=0, GAI1=256, GAI2=256 */ | ||
164 | R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */ | ||
165 | R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */ | ||
166 | |||
167 | /* decoder */ | ||
168 | R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz) | ||
169 | * pixels after end of last line */ | ||
170 | R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to | ||
171 | * work with NTSC, too */ | ||
172 | R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0, | ||
173 | * VTRC=1, HPLL=0, VNOI=0 */ | ||
174 | R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0, | ||
175 | * VBLB=0, UPTCV=0, APER=1 */ | ||
176 | R_0A_LUMA_BRIGHT_CNTL, 0x80, | ||
177 | R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */ | ||
178 | R_0C_CHROMA_SAT_CNTL, 0x40, | ||
179 | R_0D_CHROMA_HUE_CNTL, 0x00, | ||
180 | R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, | ||
181 | * FCTC=0, CHBW=1 */ | ||
182 | R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */ | ||
183 | R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ | ||
184 | R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, | ||
185 | * OEYC=1, OEHV=1, VIPB=0, COLO=0 */ | ||
186 | R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */ | ||
187 | R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */ | ||
188 | R_14_ANAL_ADC_COMPAT_CNTL, 0x00, | ||
189 | R_15_VGATE_START_FID_CHG, 0x00, | ||
190 | R_16_VGATE_STOP, 0x00, | ||
191 | R_17_MISC_VGATE_CONF_AND_MSB, 0x00, | ||
192 | |||
193 | 0x00, 0x00 | ||
194 | }; | ||
195 | |||
196 | /* SAA7113 init codes */ | ||
197 | static const unsigned char saa7113_init_auto_input[] = { | ||
198 | R_01_INC_DELAY, 0x08, | ||
199 | R_02_INPUT_CNTL_1, 0xc2, | ||
200 | R_03_INPUT_CNTL_2, 0x30, | ||
201 | R_04_INPUT_CNTL_3, 0x00, | ||
202 | R_05_INPUT_CNTL_4, 0x00, | ||
203 | R_06_H_SYNC_START, 0x89, | ||
204 | R_07_H_SYNC_STOP, 0x0d, | ||
205 | R_08_SYNC_CNTL, 0x88, | ||
206 | R_09_LUMA_CNTL, 0x01, | ||
207 | R_0A_LUMA_BRIGHT_CNTL, 0x80, | ||
208 | R_0B_LUMA_CONTRAST_CNTL, 0x47, | ||
209 | R_0C_CHROMA_SAT_CNTL, 0x40, | ||
210 | R_0D_CHROMA_HUE_CNTL, 0x00, | ||
211 | R_0E_CHROMA_CNTL_1, 0x01, | ||
212 | R_0F_CHROMA_GAIN_CNTL, 0x2a, | ||
213 | R_10_CHROMA_CNTL_2, 0x08, | ||
214 | R_11_MODE_DELAY_CNTL, 0x0c, | ||
215 | R_12_RT_SIGNAL_CNTL, 0x07, | ||
216 | R_13_RT_X_PORT_OUT_CNTL, 0x00, | ||
217 | R_14_ANAL_ADC_COMPAT_CNTL, 0x00, | ||
218 | R_15_VGATE_START_FID_CHG, 0x00, | ||
219 | R_16_VGATE_STOP, 0x00, | ||
220 | R_17_MISC_VGATE_CONF_AND_MSB, 0x00, | ||
221 | |||
222 | 0x00, 0x00 | ||
223 | }; | ||
224 | |||
109 | /* If a value differs from the Hauppauge driver values, then the comment starts with | 225 | /* If a value differs from the Hauppauge driver values, then the comment starts with |
110 | 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the | 226 | 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the |
111 | Hauppauge driver sets. */ | 227 | Hauppauge driver sets. */ |
112 | 228 | ||
229 | /* SAA7114 and SAA7115 initialization table */ | ||
113 | static const unsigned char saa7115_init_auto_input[] = { | 230 | static const unsigned char saa7115_init_auto_input[] = { |
114 | /* Front-End Part */ | 231 | /* Front-End Part */ |
115 | R_01_INC_DELAY, 0x48, /* white peak control disabled */ | 232 | R_01_INC_DELAY, 0x48, /* white peak control disabled */ |
@@ -142,6 +259,7 @@ static const unsigned char saa7115_init_auto_input[] = { | |||
142 | 0x00, 0x00 | 259 | 0x00, 0x00 |
143 | }; | 260 | }; |
144 | 261 | ||
262 | /* Used to reset saa7113, saa7114 and saa7115 */ | ||
145 | static const unsigned char saa7115_cfg_reset_scaler[] = { | 263 | static const unsigned char saa7115_cfg_reset_scaler[] = { |
146 | R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */ | 264 | R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */ |
147 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ | 265 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ |
@@ -152,6 +270,7 @@ static const unsigned char saa7115_cfg_reset_scaler[] = { | |||
152 | 270 | ||
153 | /* ============== SAA7715 VIDEO templates ============= */ | 271 | /* ============== SAA7715 VIDEO templates ============= */ |
154 | 272 | ||
273 | /* Used on saa7114 and saa7115 */ | ||
155 | static const unsigned char saa7115_cfg_60hz_fullres_x[] = { | 274 | static const unsigned char saa7115_cfg_60hz_fullres_x[] = { |
156 | /* hsize = 0x2d0 = 720 */ | 275 | /* hsize = 0x2d0 = 720 */ |
157 | R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, | 276 | R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, |
@@ -170,6 +289,7 @@ static const unsigned char saa7115_cfg_60hz_fullres_x[] = { | |||
170 | 0x00, 0x00 | 289 | 0x00, 0x00 |
171 | }; | 290 | }; |
172 | 291 | ||
292 | /* Used on saa7114 and saa7115 */ | ||
173 | static const unsigned char saa7115_cfg_60hz_fullres_y[] = { | 293 | static const unsigned char saa7115_cfg_60hz_fullres_y[] = { |
174 | /* output window size = 248 (but 60hz is 240?) */ | 294 | /* output window size = 248 (but 60hz is 240?) */ |
175 | R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0xf8, | 295 | R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0xf8, |
@@ -408,33 +528,6 @@ static const unsigned char saa7115_cfg_vbi_off[] = { | |||
408 | 0x00, 0x00 | 528 | 0x00, 0x00 |
409 | }; | 529 | }; |
410 | 530 | ||
411 | static const unsigned char saa7113_init_auto_input[] = { | ||
412 | R_01_INC_DELAY, 0x08, | ||
413 | R_02_INPUT_CNTL_1, 0xc2, | ||
414 | R_03_INPUT_CNTL_2, 0x30, | ||
415 | R_04_INPUT_CNTL_3, 0x00, | ||
416 | R_05_INPUT_CNTL_4, 0x00, | ||
417 | R_06_H_SYNC_START, 0x89, | ||
418 | R_07_H_SYNC_STOP, 0x0d, | ||
419 | R_08_SYNC_CNTL, 0x88, | ||
420 | R_09_LUMA_CNTL, 0x01, | ||
421 | R_0A_LUMA_BRIGHT_CNTL, 0x80, | ||
422 | R_0B_LUMA_CONTRAST_CNTL, 0x47, | ||
423 | R_0C_CHROMA_SAT_CNTL, 0x40, | ||
424 | R_0D_CHROMA_HUE_CNTL, 0x00, | ||
425 | R_0E_CHROMA_CNTL_1, 0x01, | ||
426 | R_0F_CHROMA_GAIN_CNTL, 0x2a, | ||
427 | R_10_CHROMA_CNTL_2, 0x08, | ||
428 | R_11_MODE_DELAY_CNTL, 0x0c, | ||
429 | R_12_RT_SIGNAL_CNTL, 0x07, | ||
430 | R_13_RT_X_PORT_OUT_CNTL, 0x00, | ||
431 | R_14_ANAL_ADC_COMPAT_CNTL, 0x00, | ||
432 | R_15_VGATE_START_FID_CHG, 0x00, | ||
433 | R_16_VGATE_STOP, 0x00, | ||
434 | R_17_MISC_VGATE_CONF_AND_MSB, 0x00, | ||
435 | |||
436 | 0x00, 0x00 | ||
437 | }; | ||
438 | 531 | ||
439 | static const unsigned char saa7115_init_misc[] = { | 532 | static const unsigned char saa7115_init_misc[] = { |
440 | R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01, | 533 | R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01, |
@@ -662,7 +755,6 @@ static int saa7115_decode_wss(u8 * p) | |||
662 | return wss; | 755 | return wss; |
663 | } | 756 | } |
664 | 757 | ||
665 | |||
666 | static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) | 758 | static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) |
667 | { | 759 | { |
668 | struct saa7115_state *state = i2c_get_clientdata(client); | 760 | 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) | |||
672 | u64 f; | 764 | u64 f; |
673 | u8 acc = 0; /* reg 0x3a, audio clock control */ | 765 | u8 acc = 0; /* reg 0x3a, audio clock control */ |
674 | 766 | ||
767 | /* Checks for chips that don't have audio clock (saa7111, saa7113) */ | ||
768 | if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD)) | ||
769 | return 0; | ||
770 | |||
675 | v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq); | 771 | v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq); |
676 | 772 | ||
677 | /* sanity check */ | 773 | /* sanity check */ |
678 | if (freq < 32000 || freq > 48000) | 774 | if (freq < 32000 || freq > 48000) |
679 | return -EINVAL; | 775 | return -EINVAL; |
680 | 776 | ||
681 | /* The saa7113 has no audio clock */ | ||
682 | if (state->ident == V4L2_IDENT_SAA7113) | ||
683 | return 0; | ||
684 | |||
685 | /* hz is the refresh rate times 100 */ | 777 | /* hz is the refresh rate times 100 */ |
686 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; | 778 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; |
687 | /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ | 779 | /* 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 | |||
799 | static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) | 891 | static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) |
800 | { | 892 | { |
801 | struct saa7115_state *state = i2c_get_clientdata(client); | 893 | struct saa7115_state *state = i2c_get_clientdata(client); |
802 | int taskb = saa7115_read(client, R_80_GLOBAL_CNTL_1) & 0x10; | ||
803 | 894 | ||
804 | /* Prevent unnecessary standard changes. During a standard | 895 | /* Prevent unnecessary standard changes. During a standard |
805 | change the I-Port is temporarily disabled. Any devices | 896 | 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) | |||
821 | } | 912 | } |
822 | 913 | ||
823 | /* Register 0E - Bits D6-D4 on NO-AUTO mode | 914 | /* Register 0E - Bits D6-D4 on NO-AUTO mode |
824 | (SAA7113 doesn't have auto mode) | 915 | (SAA7111 and SAA7113 doesn't have auto mode) |
825 | 50 Hz / 625 lines 60 Hz / 525 lines | 916 | 50 Hz / 625 lines 60 Hz / 525 lines |
826 | 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz) | 917 | 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz) |
827 | 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz) | 918 | 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) | |||
829 | 011 NTSC N (3.58MHz) PAL M (3.58MHz) | 920 | 011 NTSC N (3.58MHz) PAL M (3.58MHz) |
830 | 100 reserved NTSC-Japan (3.58MHz) | 921 | 100 reserved NTSC-Japan (3.58MHz) |
831 | */ | 922 | */ |
832 | if (state->ident == V4L2_IDENT_SAA7113) { | 923 | if (state->ident == V4L2_IDENT_SAA7111 || |
924 | state->ident == V4L2_IDENT_SAA7113) { | ||
833 | u8 reg = saa7115_read(client, R_0E_CHROMA_CNTL_1) & 0x8f; | 925 | u8 reg = saa7115_read(client, R_0E_CHROMA_CNTL_1) & 0x8f; |
834 | 926 | ||
835 | if (std == V4L2_STD_PAL_M) { | 927 | if (std == V4L2_STD_PAL_M) { |
@@ -842,18 +934,19 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) | |||
842 | reg |= 0x40; | 934 | reg |= 0x40; |
843 | } | 935 | } |
844 | saa7115_write(client, R_0E_CHROMA_CNTL_1, reg); | 936 | saa7115_write(client, R_0E_CHROMA_CNTL_1, reg); |
845 | } | 937 | } else { |
846 | 938 | /* restart task B if needed */ | |
939 | int taskb = saa7115_read(client, R_80_GLOBAL_CNTL_1) & 0x10; | ||
847 | 940 | ||
848 | state->std = std; | 941 | if (taskb && state->ident == V4L2_IDENT_SAA7114) { |
942 | saa7115_writeregs(client, saa7115_cfg_vbi_on); | ||
943 | } | ||
849 | 944 | ||
850 | /* restart task B if needed */ | 945 | /* switch audio mode too! */ |
851 | if (taskb && state->ident != V4L2_IDENT_SAA7115) { | 946 | saa7115_set_audio_clock_freq(client, state->audclk_freq); |
852 | saa7115_writeregs(client, saa7115_cfg_vbi_on); | ||
853 | } | 947 | } |
854 | 948 | ||
855 | /* switch audio mode too! */ | 949 | state->std = std; |
856 | saa7115_set_audio_clock_freq(client, state->audclk_freq); | ||
857 | } | 950 | } |
858 | 951 | ||
859 | static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client) | 952 | 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 | |||
919 | u8 lcr[24]; | 1012 | u8 lcr[24]; |
920 | int i, x; | 1013 | int i, x; |
921 | 1014 | ||
922 | /* saa7113/7114 doesn't yet support VBI */ | 1015 | #if 1 |
1016 | /* saa7113/7114/7118 VBI support are experimental */ | ||
1017 | if (!saa711x_has_reg(state->ident,R_41_LCR_BASE)) | ||
1018 | return; | ||
1019 | |||
1020 | #else | ||
1021 | /* SAA7113 and SAA7118 also should support VBI - Need testing */ | ||
923 | if (state->ident != V4L2_IDENT_SAA7115) | 1022 | if (state->ident != V4L2_IDENT_SAA7115) |
924 | return; | 1023 | return; |
1024 | #endif | ||
925 | 1025 | ||
926 | for (i = 0; i <= 23; i++) | 1026 | for (i = 0; i <= 23; i++) |
927 | lcr[i] = 0xff; | 1027 | lcr[i] = 0xff; |
@@ -1021,8 +1121,9 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt | |||
1021 | struct saa7115_state *state = i2c_get_clientdata(client); | 1121 | struct saa7115_state *state = i2c_get_clientdata(client); |
1022 | struct v4l2_pix_format *pix; | 1122 | struct v4l2_pix_format *pix; |
1023 | int HPSC, HFSC; | 1123 | int HPSC, HFSC; |
1024 | int VSCY, Vsrc; | 1124 | int VSCY; |
1025 | int is_50hz = state->std & V4L2_STD_625_50; | 1125 | int is_50hz = state->std & V4L2_STD_625_50; |
1126 | int Vsrc = is_50hz ? 576 : 480; | ||
1026 | 1127 | ||
1027 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | 1128 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { |
1028 | saa7115_set_lcr(client, &fmt->fmt.sliced); | 1129 | saa7115_set_lcr(client, &fmt->fmt.sliced); |
@@ -1041,18 +1142,29 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt | |||
1041 | if ((pix->height < 1) || (pix->height > 960)) | 1142 | if ((pix->height < 1) || (pix->height > 960)) |
1042 | return -EINVAL; | 1143 | return -EINVAL; |
1043 | 1144 | ||
1145 | if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) { | ||
1146 | /* Decoder only supports 720 columns and 480 or 576 lines */ | ||
1147 | if (pix->width != 720) | ||
1148 | return -EINVAL; | ||
1149 | if (pix->height != Vsrc) | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | |||
1044 | /* probably have a valid size, let's set it */ | 1153 | /* probably have a valid size, let's set it */ |
1045 | /* Set output width/height */ | 1154 | /* Set output width/height */ |
1046 | /* width */ | 1155 | /* width */ |
1047 | saa7115_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, | 1156 | |
1048 | (u8) (pix->width & 0xff)); | 1157 | if (!saa711x_has_reg(state->ident,R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH)) { |
1049 | saa7115_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, | 1158 | saa7115_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, |
1050 | (u8) ((pix->width >> 8) & 0xff)); | 1159 | (u8) (pix->width & 0xff)); |
1051 | /* height */ | 1160 | saa7115_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, |
1052 | saa7115_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, | 1161 | (u8) ((pix->width >> 8) & 0xff)); |
1053 | (u8) (pix->height & 0xff)); | 1162 | /* height */ |
1054 | saa7115_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, | 1163 | saa7115_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, |
1055 | (u8) ((pix->height >> 8) & 0xff)); | 1164 | (u8) (pix->height & 0xff)); |
1165 | saa7115_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, | ||
1166 | (u8) ((pix->height >> 8) & 0xff)); | ||
1167 | } | ||
1056 | 1168 | ||
1057 | /* Scaling settings */ | 1169 | /* Scaling settings */ |
1058 | /* Hprescaler is floor(inres/outres) */ | 1170 | /* Hprescaler is floor(inres/outres) */ |
@@ -1090,8 +1202,6 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt | |||
1090 | } | 1202 | } |
1091 | } | 1203 | } |
1092 | 1204 | ||
1093 | Vsrc = is_50hz ? 576 : 480; | ||
1094 | |||
1095 | if (pix->height != Vsrc) { | 1205 | if (pix->height != Vsrc) { |
1096 | VSCY = (int)((1024 * Vsrc) / pix->height); | 1206 | VSCY = (int)((1024 * Vsrc) / pix->height); |
1097 | v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); | 1207 | 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 | |||
1123 | } | 1233 | } |
1124 | 1234 | ||
1125 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); | 1235 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); |
1236 | |||
1126 | return 0; | 1237 | return 0; |
1127 | } | 1238 | } |
1128 | 1239 | ||
@@ -1468,15 +1579,25 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1468 | state->hue = 0; | 1579 | state->hue = 0; |
1469 | state->sat = 64; | 1580 | state->sat = 64; |
1470 | switch (chip_id) { | 1581 | switch (chip_id) { |
1582 | case 1: | ||
1583 | state->ident = V4L2_IDENT_SAA7111; | ||
1584 | break; | ||
1471 | case 3: | 1585 | case 3: |
1472 | state->ident = V4L2_IDENT_SAA7113; | 1586 | state->ident = V4L2_IDENT_SAA7113; |
1473 | break; | 1587 | break; |
1474 | case 4: | 1588 | case 4: |
1475 | state->ident = V4L2_IDENT_SAA7114; | 1589 | state->ident = V4L2_IDENT_SAA7114; |
1476 | break; | 1590 | break; |
1477 | default: | 1591 | case 5: |
1478 | state->ident = V4L2_IDENT_SAA7115; | 1592 | state->ident = V4L2_IDENT_SAA7115; |
1479 | break; | 1593 | break; |
1594 | case 8: | ||
1595 | state->ident = V4L2_IDENT_SAA7118; | ||
1596 | break; | ||
1597 | default: | ||
1598 | state->ident = V4L2_IDENT_SAA7111; | ||
1599 | v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n"); | ||
1600 | |||
1480 | } | 1601 | } |
1481 | 1602 | ||
1482 | state->audclk_freq = 48000; | 1603 | state->audclk_freq = 48000; |
@@ -1484,7 +1605,8 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1484 | v4l_dbg(1, debug, client, "writing init values\n"); | 1605 | v4l_dbg(1, debug, client, "writing init values\n"); |
1485 | 1606 | ||
1486 | /* init to 60hz/48khz */ | 1607 | /* init to 60hz/48khz */ |
1487 | if (state->ident == V4L2_IDENT_SAA7113) { | 1608 | if (state->ident == V4L2_IDENT_SAA7111 || |
1609 | state->ident == V4L2_IDENT_SAA7113) { | ||
1488 | state->crystal_freq = SAA7115_FREQ_24_576_MHZ; | 1610 | state->crystal_freq = SAA7115_FREQ_24_576_MHZ; |
1489 | saa7115_writeregs(client, saa7113_init_auto_input); | 1611 | saa7115_writeregs(client, saa7113_init_auto_input); |
1490 | } else { | 1612 | } else { |